@gears-frontx/react 0.1.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 ADDED
@@ -0,0 +1,421 @@
1
+ # @gears-frontx/react
2
+
3
+ React bindings and hooks for HAI3 applications. Provides the React integration layer with MFE (Microfrontend) support.
4
+
5
+ ## React Layer
6
+
7
+ This package is part of the **React Layer (L3)** - it depends only on @gears-frontx/framework (not directly on SDK packages) and provides React-specific components and hooks.
8
+
9
+ ## Core Concepts
10
+
11
+ ### HAI3Provider
12
+
13
+ Wrap your app with HAI3Provider to enable all hooks:
14
+
15
+ ```tsx
16
+ import { HAI3Provider } from '@gears-frontx/react';
17
+
18
+ function App() {
19
+ return (
20
+ <HAI3Provider>
21
+ <YourApp />
22
+ </HAI3Provider>
23
+ );
24
+ }
25
+
26
+ // With configuration
27
+ <HAI3Provider config={{ devMode: true }}>
28
+ <YourApp />
29
+ </HAI3Provider>
30
+
31
+ // With pre-built app
32
+ const app = createHAI3().use(screensets()).build();
33
+ <HAI3Provider app={app}>
34
+ <YourApp />
35
+ </HAI3Provider>
36
+ ```
37
+
38
+ ### Available Hooks
39
+
40
+ #### useHAI3
41
+
42
+ Access the HAI3 app instance:
43
+
44
+ ```tsx
45
+ import { useHAI3 } from '@gears-frontx/react';
46
+
47
+ function MyComponent() {
48
+ const app = useHAI3();
49
+
50
+ // Access MFE-enabled registry
51
+ const extensions = app.screensetsRegistry.getRegisteredExtensions();
52
+
53
+ // Access MFE actions
54
+ await app.actions.loadExtension({ extensionId: 'home' });
55
+ await app.actions.mountExtension({ extensionId: 'home', domainId: 'screen', container });
56
+ }
57
+ ```
58
+
59
+ #### useAppDispatch / useAppSelector
60
+
61
+ Type-safe Redux hooks:
62
+
63
+ ```tsx
64
+ import { useAppDispatch, useAppSelector } from '@gears-frontx/react';
65
+
66
+ function MyComponent() {
67
+ const dispatch = useAppDispatch();
68
+ const activeScreen = useAppSelector((state) => state.layout.screen.activeScreen);
69
+ }
70
+ ```
71
+
72
+ #### useTranslation
73
+
74
+ Access translation utilities:
75
+
76
+ ```tsx
77
+ import { useTranslation } from '@gears-frontx/react';
78
+
79
+ function MyComponent() {
80
+ const { t, language, setLanguage, isRTL } = useTranslation();
81
+
82
+ return (
83
+ <div dir={isRTL ? 'rtl' : 'ltr'}>
84
+ <h1>{t('common:title')}</h1>
85
+ <p>{t('common:welcome', { name: 'John' })}</p>
86
+ </div>
87
+ );
88
+ }
89
+ ```
90
+
91
+ #### useScreenTranslations
92
+
93
+ Load screen-level translations:
94
+
95
+ ```tsx
96
+ import { useScreenTranslations } from '@gears-frontx/react';
97
+
98
+ const translations = {
99
+ en: () => import('./i18n/en.json'),
100
+ es: () => import('./i18n/es.json'),
101
+ };
102
+
103
+ function HomeScreen() {
104
+ const { isLoaded, error } = useScreenTranslations('demo', 'home', translations);
105
+
106
+ if (!isLoaded) return <Loading />;
107
+ if (error) return <Error error={error} />;
108
+
109
+ return <div>...</div>;
110
+ }
111
+ ```
112
+
113
+ #### useTheme
114
+
115
+ Access theme utilities:
116
+
117
+ ```tsx
118
+ import { useTheme } from '@gears-frontx/react';
119
+
120
+ function ThemeToggle() {
121
+ const { currentTheme, themes, setTheme } = useTheme();
122
+
123
+ return (
124
+ <select value={currentTheme} onChange={(e) => setTheme(e.target.value)}>
125
+ {themes.map((theme) => (
126
+ <option key={theme.id} value={theme.id}>{theme.name}</option>
127
+ ))}
128
+ </select>
129
+ );
130
+ }
131
+ ```
132
+
133
+ ### MFE Hooks
134
+
135
+ #### useMfeBridge
136
+
137
+ Access the MFE bridge for child MFEs:
138
+
139
+ ```tsx
140
+ import { useMfeBridge } from '@gears-frontx/react';
141
+ import { HAI3_ACTION_LOAD_EXT, HAI3_SHARED_PROPERTY_THEME } from '@gears-frontx/react';
142
+
143
+ function MyExtension() {
144
+ const bridge = useMfeBridge();
145
+
146
+ // Execute actions chain on parent
147
+ await bridge.executeActionsChain({
148
+ action: { type: HAI3_ACTION_LOAD_EXT, target: 'screen', payload: { extensionId: 'other' } }
149
+ });
150
+
151
+ // Get shared property
152
+ const theme = bridge.getProperty(HAI3_SHARED_PROPERTY_THEME);
153
+ }
154
+ ```
155
+
156
+ #### useSharedProperty
157
+
158
+ Subscribe to shared property changes:
159
+
160
+ ```tsx
161
+ import { useSharedProperty, HAI3_SHARED_PROPERTY_THEME } from '@gears-frontx/react';
162
+
163
+ function ThemedComponent() {
164
+ const theme = useSharedProperty(HAI3_SHARED_PROPERTY_THEME);
165
+
166
+ return <div style={{ backgroundColor: theme?.primaryColor }}>...</div>;
167
+ }
168
+ ```
169
+
170
+ #### useHostAction
171
+
172
+ Invoke actions on the host application:
173
+
174
+ ```tsx
175
+ import { useHostAction, HAI3_ACTION_LOAD_EXT } from '@gears-frontx/react';
176
+
177
+ function MyExtension() {
178
+ const loadExtension = useHostAction(HAI3_ACTION_LOAD_EXT);
179
+
180
+ const handleClick = () => {
181
+ loadExtension({ extensionId: 'other' });
182
+ };
183
+
184
+ return <button onClick={handleClick}>Load Extension</button>;
185
+ }
186
+ ```
187
+
188
+ #### useDomainExtensions
189
+
190
+ Subscribe to extensions in a domain:
191
+
192
+ ```tsx
193
+ import { useDomainExtensions } from '@gears-frontx/react';
194
+
195
+ function ScreenList() {
196
+ const screenExtensions = useDomainExtensions('screen');
197
+
198
+ return (
199
+ <ul>
200
+ {screenExtensions.map((ext) => (
201
+ <li key={ext.id}>{ext.title}</li>
202
+ ))}
203
+ </ul>
204
+ );
205
+ }
206
+ ```
207
+
208
+ #### useRegisteredPackages
209
+
210
+ Subscribe to registered GTS packages:
211
+
212
+ ```tsx
213
+ import { useRegisteredPackages } from '@gears-frontx/react';
214
+
215
+ function PackageList() {
216
+ const packages = useRegisteredPackages();
217
+
218
+ return (
219
+ <ul>
220
+ {packages.map((pkg) => (
221
+ <li key={pkg}>{pkg}</li>
222
+ ))}
223
+ </ul>
224
+ );
225
+ }
226
+ ```
227
+
228
+ #### useActivePackage
229
+
230
+ Subscribe to the active GTS package (the package of the currently mounted screen extension):
231
+
232
+ ```tsx
233
+ import { useActivePackage } from '@gears-frontx/react';
234
+
235
+ function ActivePackageIndicator() {
236
+ const activePackage = useActivePackage();
237
+
238
+ if (!activePackage) {
239
+ return <div>No active screen</div>;
240
+ }
241
+
242
+ return <div>Active: {activePackage}</div>;
243
+ }
244
+ ```
245
+
246
+ ### MFE Components
247
+
248
+ #### MfeProvider
249
+
250
+ Provide MFE context for child extensions:
251
+
252
+ ```tsx
253
+ import { MfeProvider } from '@gears-frontx/react';
254
+
255
+ function MfeHost() {
256
+ return (
257
+ <MfeProvider bridge={parentBridge}>
258
+ <ExtensionContainer />
259
+ </MfeProvider>
260
+ );
261
+ }
262
+ ```
263
+
264
+ #### ExtensionDomainSlot
265
+
266
+ Render extensions into a domain slot:
267
+
268
+ ```tsx
269
+ import { ExtensionDomainSlot } from '@gears-frontx/react';
270
+
271
+ function LayoutScreen() {
272
+ return (
273
+ <div>
274
+ <ExtensionDomainSlot
275
+ domainId="screen"
276
+ containerRef={screenContainerRef}
277
+ fallback={<Loading />}
278
+ />
279
+ </div>
280
+ );
281
+ }
282
+ ```
283
+
284
+ #### RefContainerProvider
285
+
286
+ Provide container references for MFE mounting:
287
+
288
+ ```tsx
289
+ import { RefContainerProvider } from '@gears-frontx/react';
290
+
291
+ function Layout() {
292
+ return (
293
+ <RefContainerProvider>
294
+ <ScreenContainer />
295
+ <SidebarContainer />
296
+ </RefContainerProvider>
297
+ );
298
+ }
299
+ ```
300
+
301
+ ### Components
302
+
303
+ ## Key Rules
304
+
305
+ 1. **Wrap with HAI3Provider** - Required for all hooks to work
306
+ 2. **Use hooks for state access** - Don't import selectors directly from @gears-frontx/framework
307
+ 3. **Lazy load translations** - Use `useScreenTranslations` for screen-level i18n
308
+ 4. **Use MFE hooks for extensions** - `useMfeBridge`, `useSharedProperty`, `useHostAction`, `useDomainExtensions`
309
+ 5. **NO Layout components here** - Layout and UI components belong in L4 (user's project via CLI scaffolding)
310
+
311
+ ## Re-exports
312
+
313
+ For convenience, this package re-exports everything from @gears-frontx/framework:
314
+
315
+ - All SDK primitives (eventBus, createStore, etc.)
316
+ - All plugins (screensets, themes, layout, microfrontends, etc.)
317
+ - All registries and factory functions
318
+ - All types (including MFE types)
319
+ - All MFE actions, selectors, and domain constants
320
+
321
+ This allows users to import everything from `@gears-frontx/react` without needing `@gears-frontx/framework` directly.
322
+
323
+ ## Exports
324
+
325
+ ### Components
326
+ - `HAI3Provider` - Main context provider
327
+ - `MfeProvider` - MFE context provider
328
+ - `ExtensionDomainSlot` - Domain slot renderer
329
+ - `RefContainerProvider` - Container reference provider
330
+
331
+ ### Hooks
332
+ - `useHAI3` - Access app instance
333
+ - `useAppDispatch` - Typed dispatch
334
+ - `useAppSelector` - Typed selector
335
+ - `useTranslation` - Translation utilities
336
+ - `useScreenTranslations` - Screen translation loading
337
+ - `useTheme` - Theme utilities
338
+ - `useMfeBridge` - Access MFE bridge
339
+ - `useSharedProperty` - Subscribe to shared property
340
+ - `useHostAction` - Invoke host action
341
+ - `useDomainExtensions` - Subscribe to domain extensions
342
+ - `useRegisteredPackages` - Subscribe to registered GTS packages
343
+ - `useActivePackage` - Subscribe to active GTS package
344
+
345
+ ### Context
346
+ - `HAI3Context` - React context (for advanced use)
347
+ - `MfeContext` - MFE context (for advanced use)
348
+
349
+ ### Types
350
+ - `HAI3ProviderProps`
351
+ - `MfeProviderProps`, `ExtensionDomainSlotProps`
352
+ - `UseTranslationReturn`, `UseThemeReturn`
353
+ - All types from @gears-frontx/framework
354
+
355
+ ## Migration from Legacy API
356
+
357
+ The `useNavigation` hook has been removed. Use MFE hooks and actions instead:
358
+
359
+ ### Removed Hook
360
+ - `useNavigation()` (replaced by MFE actions and hooks)
361
+
362
+ ### Migration Examples
363
+
364
+ **OLD**: Navigate using hook
365
+ ```tsx
366
+ import { useNavigation } from '@gears-frontx/react';
367
+
368
+ function MyComponent() {
369
+ const { navigateToScreen } = useNavigation();
370
+
371
+ return (
372
+ <button onClick={() => navigateToScreen('demo', 'home')}>
373
+ Go Home
374
+ </button>
375
+ );
376
+ }
377
+ ```
378
+
379
+ **NEW**: Mount extension using app actions
380
+ ```tsx
381
+ import { useHAI3 } from '@gears-frontx/react';
382
+
383
+ function MyComponent() {
384
+ const app = useHAI3();
385
+ const containerRef = useRef<HTMLDivElement>(null);
386
+
387
+ const handleNavigate = async () => {
388
+ if (containerRef.current) {
389
+ await app.actions.mountExtension({
390
+ extensionId: 'home',
391
+ domainId: 'screen',
392
+ container: containerRef.current,
393
+ });
394
+ }
395
+ };
396
+
397
+ return (
398
+ <>
399
+ <button onClick={handleNavigate}>Go Home</button>
400
+ <div ref={containerRef} />
401
+ </>
402
+ );
403
+ }
404
+ ```
405
+
406
+ **NEW (Alternative)**: Use ExtensionDomainSlot
407
+ ```tsx
408
+ import { ExtensionDomainSlot } from '@gears-frontx/react';
409
+
410
+ function MyComponent() {
411
+ return (
412
+ <ExtensionDomainSlot
413
+ domainId="screen"
414
+ containerRef={screenContainerRef}
415
+ fallback={<Loading />}
416
+ />
417
+ );
418
+ }
419
+ ```
420
+
421
+ See the MFE migration guide in the project documentation for detailed migration steps.
@@ -0,0 +1,58 @@
1
+ <!-- @standalone -->
2
+ # hai3:duplicate-screenset - Duplicate Screenset
3
+
4
+ ## AI WORKFLOW (REQUIRED)
5
+ 1) Read .ai/targets/SCREENSETS.md before starting.
6
+ 2) Gather requirements from user.
7
+ 3) Follow steps below.
8
+
9
+ REQUIRED: Copy folder and update ids.ts only (2 steps, 96% reduction).
10
+ REQUIRED: Pass arch:check with zero errors.
11
+ REQUIRED: Test via Chrome DevTools MCP (never skip).
12
+
13
+ ## GATHER REQUIREMENTS
14
+ Ask user for:
15
+ - SOURCE screenset name (existing screenset to copy).
16
+ - TARGET screenset name (camelCase, single word preferred).
17
+ - TARGET category: Drafts | Mockups | Production.
18
+
19
+ ## STEP 1: Copy Screenset via CLI
20
+ ```bash
21
+ hai3 screenset copy SOURCE TARGET --category={category}
22
+ ```
23
+ The CLI automatically:
24
+ - Copies all files (screens, slices, actions, events, effects, API, icons, i18n).
25
+ - Updates ids.ts with TARGET_SCREENSET_ID and all SCREEN_IDs.
26
+ - Everything auto-updates via template literals:
27
+ - Event enums: ${TARGET_SCREENSET_ID}/${DOMAIN_ID}/eventName.
28
+ - Icon IDs: ${TARGET_SCREENSET_ID}:iconName.
29
+ - API domain: ${TARGET_SCREENSET_ID}:serviceName.
30
+ - Redux state key.
31
+ - Screenset auto-discovered (no manual registration).
32
+
33
+ ## STEP 2: Validate
34
+ ```bash
35
+ npm run type-check
36
+ npm run arch:check
37
+ npm run lint
38
+ grep -rn "OLD_SCREENSET_ID" src/screensets/TARGET/ # Must return 0 matches
39
+ ```
40
+
41
+ ## STEP 3: Test via Chrome DevTools MCP
42
+ STOP: If MCP connection is broken, fix it first. NEVER skip testing.
43
+ - npm run dev.
44
+ - Verify TARGET in screenset selector.
45
+ - Click TARGET screenset in dev panel.
46
+ - Verify URL changes to target screenset.
47
+ - Check 0 console errors.
48
+ - Test all primary features.
49
+ - Verify auto-discovery worked (screenset appears without manual registration).
50
+
51
+ ## CHECKLIST
52
+ - [ ] Gather requirements (source, target name, category).
53
+ - [ ] Run `hai3 screenset copy SOURCE TARGET --category={category}`.
54
+ - [ ] Run type-check (MUST pass).
55
+ - [ ] Run arch:check (MUST pass).
56
+ - [ ] Run lint (MUST pass).
57
+ - [ ] Verify zero occurrences of old screenset ID.
58
+ - [ ] Test via Chrome DevTools MCP (NEVER skip).
@@ -0,0 +1,48 @@
1
+ <!-- @standalone -->
2
+ # hai3:new-component - Add New UI Component
3
+
4
+ ## AI WORKFLOW (REQUIRED)
5
+ 1) Check for existing equivalent in project (e.g. components/ui/) and configured UI library first.
6
+ 2) Gather requirements from user.
7
+ 3) Implement.
8
+
9
+ ## CHECK EXISTING COMPONENTS FIRST
10
+ - REQUIRED: Read `frontx.config.json` to find the `uikit` value.
11
+ - If uikit is a third-party package (not `shadcn` or `none`): read its exports from `node_modules/<package>/` to check for existing components.
12
+ - REQUIRED: Before creating a new component, scan the project AND the configured UI library for existing equivalents.
13
+ - REQUIRED: Reuse existing components if equivalent exists.
14
+
15
+ ## GATHER REQUIREMENTS
16
+ Ask user for:
17
+ - Component name (e.g., "DataTable", "ColorPicker").
18
+ - Component description and props.
19
+
20
+ ## IF SCREENSET COMPONENT
21
+
22
+ ### STEP 0: Determine Subfolder
23
+ - components/ui/: Base UI primitives (shadcn components or custom).
24
+ - screens/{screen}/components/: Screen-specific components.
25
+ - components/: Shared composites used across screens.
26
+
27
+ ### STEP 1: Implementation
28
+
29
+ #### 1.1 Create Component
30
+ File: src/components/ui/{ComponentName}.tsx (base primitives)
31
+ or: src/screens/{screen}/components/{ComponentName}.tsx (screen-specific)
32
+ or: src/components/{ComponentName}.tsx (shared composites)
33
+ - Must be reusable within the MFE.
34
+ - NO Redux or state management.
35
+ - Accept value/onChange pattern for state.
36
+
37
+ #### 1.2 Export
38
+ Export from local index if needed.
39
+
40
+ #### 1.3 Validation
41
+ Run: npm run arch:check && npm run dev
42
+ Test component in UI.
43
+
44
+ ## RULES
45
+ - REQUIRED: Check existing project UI components first; create new only if missing.
46
+ - FORBIDDEN: Redux, business logic, side effects in components.
47
+ - FORBIDDEN: Inline styles outside components/ui/.
48
+ - REQUIRED: Accept value/onChange pattern for state.
@@ -0,0 +1,166 @@
1
+ <!-- @standalone -->
2
+ # hai3:new-mfe - Create New Microfrontend Package
3
+
4
+ ## PREREQUISITES (CRITICAL - STOP IF FAILED)
5
+
6
+ 1. MFE must be associated with a screenset
7
+ 2. Screenset must exist (run `hai3-new-screenset` first if needed)
8
+ 3. Vite and Module Federation must be configured
9
+
10
+ ## QUICK START
11
+
12
+ For a screenset named `{screensetName}` with a new MFE:
13
+
14
+ ```bash
15
+ # 1. Create the MFE package in src/mfe_packages/{screensetName}-mfe/
16
+ cp -r packages/cli/template-sources/mfe-package/ src/mfe_packages/{screensetName}-mfe/
17
+
18
+ # 2. Update variables in package.json and vite.config.ts:
19
+ # - Replace {{mfeName}} with your screenset name (camelCase)
20
+ # - Replace {{port}} with available port (3001, 3010, 3020, etc)
21
+ # - IMPORTANT: set preview script to "vite preview --port {{port}}"
22
+
23
+ # 3. Install dependencies
24
+ cd src/mfe_packages/{screensetName}-mfe
25
+ npm install
26
+
27
+ # 4. Create src/lifecycle.tsx that extends ThemeAwareReactLifecycle
28
+
29
+ # 5. Regenerate MFE manifests so bootstrap.ts picks up the new package
30
+ npm run generate:mfe-manifests
31
+ ```
32
+
33
+ ## CONFIGURATION REQUIREMENTS
34
+
35
+ ✅ **Correct preview script** (required for port auto-discovery):
36
+ ```json
37
+ "preview": "vite preview --port {{port}}"
38
+ ```
39
+
40
+ ✅ **Correct dev script** (for hot reload):
41
+ ```json
42
+ "dev": "vite --port {{port}}"
43
+ ```
44
+
45
+ ❌ **WRONG** (don't use this for dev):
46
+ ```json
47
+ "dev": "vite build && vite preview --port {{port}}"
48
+ ```
49
+
50
+ ## PORT ALLOCATION
51
+
52
+ Reserve ports for MFE packages:
53
+ - **3001**: demo-mfe
54
+ - **3010+**: (next available: 3010, 3020, 3030, ...)
55
+ - **5173**: Main app
56
+
57
+ ## LIFECYCLE TEMPLATE
58
+
59
+ Create `src/lifecycle.tsx`:
60
+
61
+ ```typescript
62
+ import React from 'react';
63
+ import type { ChildMfeBridge } from '@gears-frontx/react';
64
+ import { ThemeAwareReactLifecycle } from '@gears-frontx/screensets/mfe/handler';
65
+ import { YourScreen } from './screens/YourScreen';
66
+
67
+ class Lifecycle extends ThemeAwareReactLifecycle {
68
+ constructor() {
69
+ super({
70
+ name: '{screensetName}',
71
+ version: '1.0.0',
72
+ });
73
+ }
74
+
75
+ async mount(shadowRoot: ShadowRoot, bridge: ChildMfeBridge) {
76
+ const div = document.createElement('div');
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 };
88
+ }
89
+ }
90
+
91
+ export default new Lifecycle();
92
+ ```
93
+
94
+ ## dev:all INTEGRATION (AUTOMATIC)
95
+
96
+ After creating the MFE and running `npm run generate:mfe-manifests`, the `dev:all`
97
+ script auto-discovers your new package — no manual configuration needed.
98
+
99
+ `dev-all.ts` scans `src/mfe_packages/*/package.json` and reads the port from the
100
+ `preview` (or `dev`) script using `--port NNNN`. The new MFE will automatically
101
+ appear in the next `npm run dev:all` run.
102
+
103
+ ## VALIDATION
104
+
105
+ After creation:
106
+
107
+ ```bash
108
+ # Regenerate manifests (required after adding new MFE)
109
+ npm run generate:mfe-manifests
110
+
111
+ # Validate TypeScript
112
+ npm run type-check
113
+
114
+ # Check architecture compliance
115
+ npm run arch:check
116
+
117
+ # Run the dev server (picks up new MFE automatically)
118
+ npm run dev:all
119
+
120
+ # Verify MFE loads at http://localhost:5173
121
+ # Open Studio Overlay (Ctrl+`) and check screenset
122
+ ```
123
+
124
+ ## TROUBLESHOOTING
125
+
126
+ ### Issue: MFE not appearing in screenset selector
127
+ - Run `npm run generate:mfe-manifests` to regenerate manifests
128
+ - Check mfe.json manifest is properly exported
129
+ - Verify extensions are registered in manifest
130
+ - Check browser console for errors
131
+
132
+ ### Issue: dev:all not picking up MFE port
133
+ - Verify `preview` script has `--port NNNN` (e.g., `"vite preview --port 3010"`)
134
+ - Check port is not in use (`lsof -i :3010`)
135
+ - Restart dev server
136
+
137
+ ### Issue: Hot reload not working
138
+ - Verify dev script uses `vite --port` (not `vite build && vite preview`)
139
+ - Check port is not in use
140
+ - Restart dev server
141
+
142
+ ### Issue: Redux/useSelector errors
143
+ - MFE must use mock data (no Redux Provider in isolation)
144
+ - Use `useState` for local state management
145
+ - Do not import Redux hooks (@gears-frontx/react)
146
+
147
+ ## BEST PRACTICES
148
+
149
+ ✅ **DO:**
150
+ - Set `preview` script with `--port NNNN` for port auto-discovery
151
+ - Use mock data with useState for UI-only MFEs
152
+ - Keep MFE logic isolated and simple
153
+ - Use local components (e.g. components/ui/)
154
+ - Run `npm run generate:mfe-manifests` after creating the MFE
155
+
156
+ ❌ **DON'T:**
157
+ - Import Redux hooks directly
158
+ - Use vite build && vite preview in dev mode
159
+ - Create complex state management in MFE
160
+ - Hardcode ports without updating package.json preview script
161
+
162
+ ---
163
+
164
+ See also:
165
+ - `/packages/cli/template-sources/mfe-package/` for templates
166
+ - `hai3-new-screenset.md` for screenset creation