@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
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { ChildMfeBridge, AccessRecord, AccessQuery, FrontXApp, RootState, Formatters, Language } from '@gears-frontx/framework';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* MFE Context Value
|
|
7
|
+
* Contains bridge and metadata about the MFE instance.
|
|
8
|
+
*/
|
|
9
|
+
interface MfeContextValue {
|
|
10
|
+
/** Child bridge for communication with host */
|
|
11
|
+
bridge: ChildMfeBridge;
|
|
12
|
+
/** Extension ID */
|
|
13
|
+
extensionId: string;
|
|
14
|
+
/** Domain ID where MFE is mounted */
|
|
15
|
+
domainId: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* MFE Context
|
|
19
|
+
* Holds the MFE bridge and metadata for child components.
|
|
20
|
+
*/
|
|
21
|
+
declare const MfeContext: React.Context<MfeContextValue | null>;
|
|
22
|
+
/**
|
|
23
|
+
* Use the MFE context.
|
|
24
|
+
* Throws if used outside of MFE context.
|
|
25
|
+
*
|
|
26
|
+
* @returns The MFE context value
|
|
27
|
+
*/
|
|
28
|
+
declare function useMfeContext(): MfeContextValue;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @gears-frontx/react - Type Definitions
|
|
32
|
+
*
|
|
33
|
+
* Core types for FrontX React bindings.
|
|
34
|
+
* Provides type-safe hooks and components.
|
|
35
|
+
*
|
|
36
|
+
* Now using real imports from @gears-frontx/framework since packages are built together.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Gears FrontX-owned query result type.
|
|
41
|
+
* Returned by useApiQuery — callers depend on this contract, not on TanStack internals.
|
|
42
|
+
*/
|
|
43
|
+
interface ApiQueryResult<TData, TError = Error> {
|
|
44
|
+
data: TData | undefined;
|
|
45
|
+
error: TError | null;
|
|
46
|
+
isLoading: boolean;
|
|
47
|
+
isFetching: boolean;
|
|
48
|
+
isError: boolean;
|
|
49
|
+
refetch: () => Promise<unknown>;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Gears FrontX-owned suspense query result type.
|
|
53
|
+
* Returned by useApiSuspenseQuery — callers depend on this contract, not on TanStack internals.
|
|
54
|
+
*/
|
|
55
|
+
interface ApiSuspenseQueryResult<TData, TError = Error> {
|
|
56
|
+
data: TData;
|
|
57
|
+
error: TError | null;
|
|
58
|
+
isFetching: boolean;
|
|
59
|
+
refetch: () => Promise<void>;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Gears FrontX-owned infinite query result type.
|
|
63
|
+
* Returned by useApiInfiniteQuery for descriptor-driven pagination.
|
|
64
|
+
*/
|
|
65
|
+
interface ApiInfiniteQueryResult<TPage, TError = Error> {
|
|
66
|
+
data: readonly TPage[] | undefined;
|
|
67
|
+
error: TError | null;
|
|
68
|
+
isLoading: boolean;
|
|
69
|
+
isFetching: boolean;
|
|
70
|
+
isError: boolean;
|
|
71
|
+
hasNextPage: boolean;
|
|
72
|
+
hasPreviousPage: boolean;
|
|
73
|
+
isFetchingNextPage: boolean;
|
|
74
|
+
isFetchingPreviousPage: boolean;
|
|
75
|
+
fetchNextPage: () => Promise<void>;
|
|
76
|
+
fetchPreviousPage: () => Promise<void>;
|
|
77
|
+
refetch: () => Promise<void>;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Gears FrontX-owned suspense infinite query result type.
|
|
81
|
+
* Returned by useApiSuspenseInfiniteQuery for descriptor-driven pagination.
|
|
82
|
+
*/
|
|
83
|
+
interface ApiSuspenseInfiniteQueryResult<TPage, TError = Error> {
|
|
84
|
+
data: readonly TPage[];
|
|
85
|
+
error: TError | null;
|
|
86
|
+
isFetching: boolean;
|
|
87
|
+
hasNextPage: boolean;
|
|
88
|
+
hasPreviousPage: boolean;
|
|
89
|
+
isFetchingNextPage: boolean;
|
|
90
|
+
isFetchingPreviousPage: boolean;
|
|
91
|
+
fetchNextPage: () => Promise<void>;
|
|
92
|
+
fetchPreviousPage: () => Promise<void>;
|
|
93
|
+
refetch: () => Promise<void>;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Gears FrontX-owned mutation result type.
|
|
97
|
+
* Returned by useApiMutation — callers depend on this contract, not on TanStack internals.
|
|
98
|
+
*/
|
|
99
|
+
interface ApiMutationResult<TData, TError = Error, TVariables = void> {
|
|
100
|
+
mutate: (variables: TVariables) => void;
|
|
101
|
+
mutateAsync: (variables: TVariables) => Promise<TData>;
|
|
102
|
+
isPending: boolean;
|
|
103
|
+
error: TError | null;
|
|
104
|
+
data: TData | undefined;
|
|
105
|
+
reset: () => void;
|
|
106
|
+
}
|
|
107
|
+
type Selector<TResult, TState = RootState> = (state: TState) => TResult;
|
|
108
|
+
type TranslationParams = Record<string, string | number | boolean>;
|
|
109
|
+
/**
|
|
110
|
+
* FrontX Provider Props
|
|
111
|
+
* Props for the main FrontXProvider component.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```tsx
|
|
115
|
+
* const app = createFrontX().use(microfrontends(config)).build();
|
|
116
|
+
* <FrontXProvider app={app}>
|
|
117
|
+
* <App />
|
|
118
|
+
* </FrontXProvider>
|
|
119
|
+
*
|
|
120
|
+
* // With MFE bridge (for MFE components)
|
|
121
|
+
* <FrontXProvider app={app} mfeBridge={{ bridge, extensionId, domainId }}>
|
|
122
|
+
* <MyMfeApp />
|
|
123
|
+
* </FrontXProvider>
|
|
124
|
+
*
|
|
125
|
+
* // QueryCache is resolved from the app's plugin composition
|
|
126
|
+
* <FrontXProvider app={app}>
|
|
127
|
+
* <MyMfeApp />
|
|
128
|
+
* </FrontXProvider>
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
interface FrontXProviderProps {
|
|
132
|
+
/** Child components */
|
|
133
|
+
children: ReactNode;
|
|
134
|
+
/** The runtime's FrontX app, built once by the caller */
|
|
135
|
+
app: FrontXApp;
|
|
136
|
+
/** MFE bridge context (for MFE components) */
|
|
137
|
+
mfeBridge?: MfeContextValue;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* useFrontX Hook Return Type
|
|
141
|
+
* Returns the FrontX app instance from context.
|
|
142
|
+
*/
|
|
143
|
+
type UseFrontXReturn = FrontXApp;
|
|
144
|
+
/**
|
|
145
|
+
* useAppSelector Hook
|
|
146
|
+
* Type-safe selector hook for Redux state.
|
|
147
|
+
*
|
|
148
|
+
* @template TResult - The result type of the selector
|
|
149
|
+
*/
|
|
150
|
+
type UseAppSelector = <TResult>(selector: Selector<TResult>) => TResult;
|
|
151
|
+
/**
|
|
152
|
+
* useAppDispatch Hook Return Type
|
|
153
|
+
* Returns the typed dispatch function.
|
|
154
|
+
*/
|
|
155
|
+
type UseAppDispatchReturn = (action: unknown) => unknown;
|
|
156
|
+
/**
|
|
157
|
+
* useTranslation Hook Return Type
|
|
158
|
+
* Translation utilities.
|
|
159
|
+
*/
|
|
160
|
+
interface UseTranslationReturn {
|
|
161
|
+
/** Translate a key */
|
|
162
|
+
t: (key: string, params?: TranslationParams) => string;
|
|
163
|
+
/** Current language */
|
|
164
|
+
language: Language | null;
|
|
165
|
+
/** Change language */
|
|
166
|
+
setLanguage: (language: Language) => void;
|
|
167
|
+
/** Check if current language is RTL */
|
|
168
|
+
isRTL: boolean;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* useScreenTranslations Hook Return Type
|
|
172
|
+
* Screen-level translation loading state.
|
|
173
|
+
*/
|
|
174
|
+
interface UseScreenTranslationsReturn {
|
|
175
|
+
/** Whether translations are loaded */
|
|
176
|
+
isLoaded: boolean;
|
|
177
|
+
/** Loading error (if any) */
|
|
178
|
+
error: Error | null;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* useTheme Hook Return Type
|
|
182
|
+
* Theme utilities.
|
|
183
|
+
*/
|
|
184
|
+
interface UseThemeReturn {
|
|
185
|
+
/** Current theme ID */
|
|
186
|
+
currentTheme: string | undefined;
|
|
187
|
+
/** All available themes */
|
|
188
|
+
themes: Array<{
|
|
189
|
+
id: string;
|
|
190
|
+
name: string;
|
|
191
|
+
}>;
|
|
192
|
+
/** Change theme */
|
|
193
|
+
setTheme: (themeId: string) => void;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* useFormatters Hook Return Type
|
|
197
|
+
* Locale-aware formatters (locale from i18nRegistry.getLanguage()).
|
|
198
|
+
* References @gears-frontx/i18n Formatters so signatures stay in sync.
|
|
199
|
+
*/
|
|
200
|
+
type UseFormattersReturn = Formatters;
|
|
201
|
+
/**
|
|
202
|
+
* useCanAccess Hook Return Type
|
|
203
|
+
* Result of an RBAC access check.
|
|
204
|
+
* allow is false until an explicit 'allow' decision arrives (pessimistic default).
|
|
205
|
+
*/
|
|
206
|
+
interface UseCanAccessResult {
|
|
207
|
+
allow: boolean;
|
|
208
|
+
isResolving: boolean;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* CanAccess Component Props.
|
|
212
|
+
* Pessimistic: renders `denied` (or `loading`) until an authoritative 'allow' arrives.
|
|
213
|
+
*/
|
|
214
|
+
interface CanAccessProps<TRecord extends AccessRecord = AccessRecord> {
|
|
215
|
+
query: AccessQuery<TRecord>;
|
|
216
|
+
/** Content rendered when access is explicitly allowed. */
|
|
217
|
+
allowed: ReactNode;
|
|
218
|
+
/** Content rendered on deny or error. Defaults to null. */
|
|
219
|
+
denied?: ReactNode;
|
|
220
|
+
/** Optional slot shown while the decision is resolving. Falls back to `denied`. */
|
|
221
|
+
loading?: ReactNode;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export { type ApiQueryResult as A, type CanAccessProps as C, type FrontXProviderProps as F, type MfeContextValue as M, type UseTranslationReturn as U, type ApiInfiniteQueryResult as a, type ApiMutationResult as b, type UseScreenTranslationsReturn as c, type UseFormattersReturn as d, type UseThemeReturn as e, type ApiSuspenseQueryResult as f, type ApiSuspenseInfiniteQueryResult as g, type UseCanAccessResult as h, MfeContext as i, type UseAppDispatchReturn as j, type UseAppSelector as k, type UseFrontXReturn as l, useMfeContext as u };
|
package/dist/types.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["/**\n * @gears-frontx/react - Type Definitions\n *\n * Core types for
|
|
1
|
+
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["/**\n * @gears-frontx/react - Type Definitions\n *\n * Core types for FrontX React bindings.\n * Provides type-safe hooks and components.\n *\n * Now using real imports from @gears-frontx/framework since packages are built together.\n */\n\nimport type { ReactNode } from 'react';\nimport type {\n FrontXConfig,\n FrontXApp,\n RootState,\n Language,\n Formatters,\n AccessQuery,\n AccessRecord,\n} from '@gears-frontx/framework';\nimport type { MfeContextValue } from './mfe/MfeContext';\n\n// Re-export imported types for convenience\nexport type { FrontXConfig, FrontXApp };\n\n// ============================================================================\n// API Hook Result Types\n// ============================================================================\n\n/**\n * Gears FrontX-owned query result type.\n * Returned by useApiQuery — callers depend on this contract, not on TanStack internals.\n */\n// @cpt-FEATURE:implement-endpoint-descriptors:p3\n// @cpt-begin:implement-endpoint-descriptors:p3:inst-api-query-result\nexport interface ApiQueryResult<TData, TError = Error> {\n data: TData | undefined;\n error: TError | null;\n isLoading: boolean;\n isFetching: boolean;\n isError: boolean;\n refetch: () => Promise<unknown>;\n}\n// @cpt-end:implement-endpoint-descriptors:p3:inst-api-query-result\n\n/**\n * Gears FrontX-owned suspense query result type.\n * Returned by useApiSuspenseQuery — callers depend on this contract, not on TanStack internals.\n */\n// @cpt-begin:cpt-frontx-dod-request-lifecycle-use-api-query:p2:inst-suspense-query-result\nexport interface ApiSuspenseQueryResult<TData, TError = Error> {\n data: TData;\n error: TError | null;\n isFetching: boolean;\n refetch: () => Promise<void>;\n}\n// @cpt-end:cpt-frontx-dod-request-lifecycle-use-api-query:p2:inst-suspense-query-result\n\n/**\n * Gears FrontX-owned infinite query result type.\n * Returned by useApiInfiniteQuery for descriptor-driven pagination.\n */\n// @cpt-begin:cpt-frontx-dod-request-lifecycle-use-api-query:p2:inst-infinite-query-result\nexport interface ApiInfiniteQueryResult<TPage, TError = Error> {\n data: readonly TPage[] | undefined;\n error: TError | null;\n isLoading: boolean;\n isFetching: boolean;\n isError: boolean;\n hasNextPage: boolean;\n hasPreviousPage: boolean;\n isFetchingNextPage: boolean;\n isFetchingPreviousPage: boolean;\n fetchNextPage: () => Promise<void>;\n fetchPreviousPage: () => Promise<void>;\n refetch: () => Promise<void>;\n}\n// @cpt-end:cpt-frontx-dod-request-lifecycle-use-api-query:p2:inst-infinite-query-result\n\n/**\n * Gears FrontX-owned suspense infinite query result type.\n * Returned by useApiSuspenseInfiniteQuery for descriptor-driven pagination.\n */\n// @cpt-begin:cpt-frontx-dod-request-lifecycle-use-api-query:p2:inst-suspense-infinite-query-result\nexport interface ApiSuspenseInfiniteQueryResult<TPage, TError = Error> {\n data: readonly TPage[];\n error: TError | null;\n isFetching: boolean;\n hasNextPage: boolean;\n hasPreviousPage: boolean;\n isFetchingNextPage: boolean;\n isFetchingPreviousPage: boolean;\n fetchNextPage: () => Promise<void>;\n fetchPreviousPage: () => Promise<void>;\n refetch: () => Promise<void>;\n}\n// @cpt-end:cpt-frontx-dod-request-lifecycle-use-api-query:p2:inst-suspense-infinite-query-result\n\n/**\n * Gears FrontX-owned mutation result type.\n * Returned by useApiMutation — callers depend on this contract, not on TanStack internals.\n */\n// @cpt-begin:implement-endpoint-descriptors:p3:inst-api-mutation-result\nexport interface ApiMutationResult<TData, TError = Error, TVariables = void> {\n mutate: (variables: TVariables) => void;\n mutateAsync: (variables: TVariables) => Promise<TData>;\n isPending: boolean;\n error: TError | null;\n data: TData | undefined;\n reset: () => void;\n}\n// @cpt-end:implement-endpoint-descriptors:p3:inst-api-mutation-result\n\n// ============================================================================\n// Type Aliases\n// ============================================================================\n\n// From @gears-frontx/store\ntype Selector<TResult, TState = RootState> = (state: TState) => TResult;\n\n// Language is imported from @gears-frontx/framework\ntype TranslationParams = Record<string, string | number | boolean>;\n\n// ============================================================================\n// FrontX Provider Props\n// ============================================================================\n\n/**\n * FrontX Provider Props\n * Props for the main FrontXProvider component.\n *\n * @example\n * ```tsx\n * const app = createFrontX().use(microfrontends(config)).build();\n * <FrontXProvider app={app}>\n * <App />\n * </FrontXProvider>\n *\n * // With MFE bridge (for MFE components)\n * <FrontXProvider app={app} mfeBridge={{ bridge, extensionId, domainId }}>\n * <MyMfeApp />\n * </FrontXProvider>\n *\n * // QueryCache is resolved from the app's plugin composition\n * <FrontXProvider app={app}>\n * <MyMfeApp />\n * </FrontXProvider>\n * ```\n */\nexport interface FrontXProviderProps {\n /** Child components */\n children: ReactNode;\n /** The runtime's FrontX app, built once by the caller */\n app: FrontXApp;\n /** MFE bridge context (for MFE components) */\n mfeBridge?: MfeContextValue;\n}\n\n// ============================================================================\n// Hook Return Types\n// ============================================================================\n\n/**\n * useFrontX Hook Return Type\n * Returns the FrontX app instance from context.\n */\nexport type UseFrontXReturn = FrontXApp;\n\n/**\n * useAppSelector Hook\n * Type-safe selector hook for Redux state.\n *\n * @template TResult - The result type of the selector\n */\nexport type UseAppSelector = <TResult>(selector: Selector<TResult>) => TResult;\n\n/**\n * useAppDispatch Hook Return Type\n * Returns the typed dispatch function.\n */\nexport type UseAppDispatchReturn = (action: unknown) => unknown;\n\n/**\n * useTranslation Hook Return Type\n * Translation utilities.\n */\nexport interface UseTranslationReturn {\n /** Translate a key */\n t: (key: string, params?: TranslationParams) => string;\n /** Current language */\n language: Language | null;\n /** Change language */\n setLanguage: (language: Language) => void;\n /** Check if current language is RTL */\n isRTL: boolean;\n}\n\n/**\n * useScreenTranslations Hook Return Type\n * Screen-level translation loading state.\n */\nexport interface UseScreenTranslationsReturn {\n /** Whether translations are loaded */\n isLoaded: boolean;\n /** Loading error (if any) */\n error: Error | null;\n}\n\n/**\n * useTheme Hook Return Type\n * Theme utilities.\n */\nexport interface UseThemeReturn {\n /** Current theme ID */\n currentTheme: string | undefined;\n /** All available themes */\n themes: Array<{ id: string; name: string }>;\n /** Change theme */\n setTheme: (themeId: string) => void;\n}\n\n/**\n * useFormatters Hook Return Type\n * Locale-aware formatters (locale from i18nRegistry.getLanguage()).\n * References @gears-frontx/i18n Formatters so signatures stay in sync.\n */\nexport type UseFormattersReturn = Formatters;\n\n/**\n * useCanAccess Hook Return Type\n * Result of an RBAC access check.\n * allow is false until an explicit 'allow' decision arrives (pessimistic default).\n */\nexport interface UseCanAccessResult {\n allow: boolean;\n isResolving: boolean;\n}\n\n/**\n * CanAccess Component Props.\n * Pessimistic: renders `denied` (or `loading`) until an authoritative 'allow' arrives.\n */\nexport interface CanAccessProps<TRecord extends AccessRecord = AccessRecord> {\n query: AccessQuery<TRecord>;\n /** Content rendered when access is explicitly allowed. */\n allowed: ReactNode;\n /** Content rendered on deny or error. Defaults to null. */\n denied?: ReactNode;\n /** Optional slot shown while the decision is resolving. Falls back to `denied`. */\n loading?: ReactNode;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
|
package/dist/types.d.cts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import 'react';
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
2
|
+
export { FrontXApp, FrontXConfig } from '@gears-frontx/framework';
|
|
3
|
+
export { a as ApiInfiniteQueryResult, b as ApiMutationResult, A as ApiQueryResult, g as ApiSuspenseInfiniteQueryResult, f as ApiSuspenseQueryResult, C as CanAccessProps, F as FrontXProviderProps, j as UseAppDispatchReturn, k as UseAppSelector, h as UseCanAccessResult, d as UseFormattersReturn, l as UseFrontXReturn, c as UseScreenTranslationsReturn, e as UseThemeReturn, U as UseTranslationReturn } from './types-JtpziA_B.cjs';
|
package/dist/types.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import 'react';
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
2
|
+
export { FrontXApp, FrontXConfig } from '@gears-frontx/framework';
|
|
3
|
+
export { a as ApiInfiniteQueryResult, b as ApiMutationResult, A as ApiQueryResult, g as ApiSuspenseInfiniteQueryResult, f as ApiSuspenseQueryResult, C as CanAccessProps, F as FrontXProviderProps, j as UseAppDispatchReturn, k as UseAppSelector, h as UseCanAccessResult, d as UseFormattersReturn, l as UseFrontXReturn, c as UseScreenTranslationsReturn, e as UseThemeReturn, U as UseTranslationReturn } from './types-JtpziA_B.js';
|
package/llms.txt
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
# @gears-frontx/react
|
|
2
2
|
|
|
3
|
-
> React bindings, hooks, and components for
|
|
3
|
+
> React bindings, hooks, and components for FrontX SDK. Provides type-safe integration with React applications including MFE (Microfrontend) support.
|
|
4
4
|
|
|
5
|
-
Part of the
|
|
5
|
+
Part of the FrontX React Layer (L3) - depends on @gears-frontx/framework. Peer dependency on react and react-dom.
|
|
6
6
|
|
|
7
7
|
## Core API
|
|
8
8
|
|
|
9
|
-
- [
|
|
10
|
-
- [MFE Components](https://
|
|
9
|
+
- [FrontXProvider](https://frontx.dev/docs/react/provider): Root context provider
|
|
10
|
+
- [MFE Components](https://frontx.dev/docs/react/mfe): ExtensionDomainSlot, MfeProvider
|
|
11
|
+
- `FrontXProvider` resolves the shared `QueryClient` from `queryCache()` / `queryCacheShared()` through the app instance; mounted MFEs reuse the host cache by building their local app with `queryCacheShared()`, which joins the same shared `QueryClient` without mutating L1 contracts
|
|
11
12
|
|
|
12
13
|
## Hooks
|
|
13
14
|
|
|
14
15
|
| Hook | Purpose |
|
|
15
16
|
|------|---------|
|
|
16
|
-
| `
|
|
17
|
+
| `useFrontX()` | Access app instance |
|
|
17
18
|
| `useAppDispatch()` | Type-safe dispatch |
|
|
18
19
|
| `useAppSelector()` | Type-safe selector |
|
|
19
20
|
| `useTranslation()` | Translation utilities (t, language, setLanguage, isRTL) |
|
|
@@ -25,30 +26,34 @@ Part of the HAI3 React Layer (L3) - depends on @gears-frontx/framework. Peer dep
|
|
|
25
26
|
| Hook | Purpose |
|
|
26
27
|
|------|---------|
|
|
27
28
|
| `useMfeBridge()` | Access MFE bridge (child MFEs) |
|
|
28
|
-
| `useSharedProperty()` | Subscribe to shared property changes |
|
|
29
|
+
| `useSharedProperty()` | Subscribe to shared property changes, via `MfeContext` or an explicit `bridge` option |
|
|
29
30
|
| `useHostAction()` | Invoke actions on host application |
|
|
30
31
|
| `useDomainExtensions()` | Subscribe to extensions in a domain |
|
|
31
32
|
|
|
32
33
|
## Quick Start
|
|
33
34
|
|
|
34
35
|
```tsx
|
|
35
|
-
import {
|
|
36
|
+
import { createFrontX, FrontXProvider, presets, useTranslation, useFrontX } from '@gears-frontx/react';
|
|
37
|
+
|
|
38
|
+
// One app per runtime, built once at module level (the full preset here;
|
|
39
|
+
// `presets.full({ microfrontends: config })` also adds microfrontends)
|
|
40
|
+
const app = createFrontX().useAll(presets.full()).build();
|
|
36
41
|
|
|
37
42
|
// Wrap app with provider
|
|
38
43
|
function App() {
|
|
39
44
|
return (
|
|
40
|
-
<
|
|
45
|
+
<FrontXProvider app={app}>
|
|
41
46
|
<Layout>
|
|
42
|
-
<
|
|
47
|
+
<MainScreen />
|
|
43
48
|
</Layout>
|
|
44
|
-
</
|
|
49
|
+
</FrontXProvider>
|
|
45
50
|
);
|
|
46
51
|
}
|
|
47
52
|
|
|
48
53
|
// Use hooks in components
|
|
49
54
|
function MyComponent() {
|
|
50
55
|
const { t, isRTL } = useTranslation();
|
|
51
|
-
const app =
|
|
56
|
+
const app = useFrontX();
|
|
52
57
|
|
|
53
58
|
return (
|
|
54
59
|
<div dir={isRTL ? 'rtl' : 'ltr'}>
|
|
@@ -66,13 +71,12 @@ function MyComponent() {
|
|
|
66
71
|
import { ExtensionDomainSlot } from '@gears-frontx/react';
|
|
67
72
|
|
|
68
73
|
function LayoutScreen() {
|
|
69
|
-
const screenContainerRef = useRef<HTMLDivElement>(null);
|
|
70
|
-
|
|
71
74
|
return (
|
|
72
75
|
<ExtensionDomainSlot
|
|
76
|
+
registry={registry}
|
|
73
77
|
domainId="screen"
|
|
74
|
-
|
|
75
|
-
|
|
78
|
+
extensionId="home"
|
|
79
|
+
loadingComponent={<Loading />}
|
|
76
80
|
/>
|
|
77
81
|
);
|
|
78
82
|
}
|
|
@@ -81,15 +85,17 @@ function LayoutScreen() {
|
|
|
81
85
|
### Using MFE Bridge
|
|
82
86
|
|
|
83
87
|
```tsx
|
|
84
|
-
import { useMfeBridge, useSharedProperty,
|
|
88
|
+
import { useMfeBridge, useSharedProperty, FRONTX_ACTION_LOAD_EXT, FRONTX_SHARED_PROPERTY_THEME } from '@gears-frontx/react';
|
|
85
89
|
|
|
86
90
|
function MyExtension() {
|
|
87
91
|
const bridge = useMfeBridge();
|
|
88
|
-
const theme = useSharedProperty(
|
|
92
|
+
const theme = useSharedProperty(FRONTX_SHARED_PROPERTY_THEME);
|
|
89
93
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
94
|
+
// executeActionsChain is acceptance-only: it returns void, never throws,
|
|
95
|
+
// and never yields anything to await for the chain's own execution.
|
|
96
|
+
const handleAction = () => {
|
|
97
|
+
bridge.executeActionsChain({
|
|
98
|
+
action: { type: FRONTX_ACTION_LOAD_EXT, target: 'screen', payload: { subject: 'other' } }
|
|
93
99
|
});
|
|
94
100
|
};
|
|
95
101
|
|
|
@@ -97,6 +103,26 @@ function MyExtension() {
|
|
|
97
103
|
}
|
|
98
104
|
```
|
|
99
105
|
|
|
106
|
+
### Shared Properties Without MfeProvider
|
|
107
|
+
|
|
108
|
+
`useSharedProperty(propertyTypeId, options)` takes an explicit `bridge` for components that never mount `MfeProvider`, plus a `fallback` returned until the host publishes the property (only `undefined` is substituted; a published `null` is a value). With `fallback` set the result type is `T`. There is no consumer-side validation option: the host validates published values against the property's schema before delivery, so `T` is the caller's declaration of that schema.
|
|
109
|
+
|
|
110
|
+
```tsx
|
|
111
|
+
import { useSharedProperty } from '@gears-frontx/react';
|
|
112
|
+
import type { ChildMfeBridge } from '@gears-frontx/framework';
|
|
113
|
+
|
|
114
|
+
function StandaloneComponent({ bridge }: { bridge: ChildMfeBridge }) {
|
|
115
|
+
const label = useSharedProperty<string>(LABEL_PROPERTY_ID, {
|
|
116
|
+
bridge,
|
|
117
|
+
fallback: 'Untitled',
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
return <span>{label}</span>;
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Omitting `bridge` falls back to `MfeContext`; the hook still throws when neither is available. Changing `bridge` or `propertyTypeId` moves the subscription and the value follows on the same render.
|
|
125
|
+
|
|
100
126
|
### Subscribing to Domain Extensions
|
|
101
127
|
|
|
102
128
|
```tsx
|
|
@@ -117,6 +143,6 @@ function ScreenList() {
|
|
|
117
143
|
|
|
118
144
|
## Optional
|
|
119
145
|
|
|
120
|
-
- [Screen Translations](https://
|
|
121
|
-
- [Custom Hooks](https://
|
|
122
|
-
- [MFE Bridge Communication](https://
|
|
146
|
+
- [Screen Translations](https://frontx.dev/docs/react/translations): Per-screen lazy loading
|
|
147
|
+
- [Custom Hooks](https://frontx.dev/docs/react/hooks): Building on FrontX hooks
|
|
148
|
+
- [MFE Bridge Communication](https://frontx.dev/docs/react/mfe-bridge): Parent-child patterns
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gears-frontx/react",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "React bindings and hooks for
|
|
3
|
+
"version": "0.2.0-alpha.15",
|
|
4
|
+
"description": "React bindings and hooks for FrontX framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
7
7
|
"module": "./dist/index.js",
|
|
@@ -12,6 +12,11 @@
|
|
|
12
12
|
"import": "./dist/index.js",
|
|
13
13
|
"require": "./dist/index.cjs"
|
|
14
14
|
},
|
|
15
|
+
"./testing": {
|
|
16
|
+
"types": "./dist/testing.d.ts",
|
|
17
|
+
"import": "./dist/testing.js",
|
|
18
|
+
"require": "./dist/testing.cjs"
|
|
19
|
+
},
|
|
15
20
|
"./types": {
|
|
16
21
|
"types": "./dist/types.d.ts",
|
|
17
22
|
"import": "./dist/types.js",
|
|
@@ -21,33 +26,39 @@
|
|
|
21
26
|
"files": [
|
|
22
27
|
"dist",
|
|
23
28
|
"CLAUDE.md",
|
|
24
|
-
"llms.txt"
|
|
25
|
-
"commands"
|
|
29
|
+
"llms.txt"
|
|
26
30
|
],
|
|
27
31
|
"scripts": {
|
|
28
32
|
"build": "tsup",
|
|
29
|
-
"type-check": "tsc --noEmit",
|
|
30
|
-
"test": "
|
|
31
|
-
"test
|
|
33
|
+
"type-check": "tsc --noEmit && npm run type-check:test",
|
|
34
|
+
"type-check:test": "tsc -p tsconfig.test.json",
|
|
35
|
+
"test": "npm run test:unit",
|
|
36
|
+
"test:unit": "vitest --run --passWithNoTests=false",
|
|
37
|
+
"test:unit:watch": "vitest --watch"
|
|
32
38
|
},
|
|
33
|
-
"dependencies": {},
|
|
34
39
|
"devDependencies": {
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"react": "
|
|
38
|
-
"@types/
|
|
39
|
-
"react
|
|
40
|
-
"@types/react-redux": "
|
|
41
|
-
"
|
|
42
|
-
"@vitest/coverage-v8": "
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
40
|
+
"@reduxjs/toolkit": "2.12.0",
|
|
41
|
+
"@tanstack/react-query": "5.101.4",
|
|
42
|
+
"@testing-library/react": "16.3.2",
|
|
43
|
+
"@types/node": "^24.0.0",
|
|
44
|
+
"@types/react": "19.2.18",
|
|
45
|
+
"@types/react-redux": "7.1.34",
|
|
46
|
+
"@vitejs/plugin-react": "4.3.4",
|
|
47
|
+
"@vitest/coverage-v8": "4.1.4",
|
|
48
|
+
"jsdom": "26.1.0",
|
|
49
|
+
"react": "19.2.4",
|
|
50
|
+
"react-dom": "19.2.4",
|
|
51
|
+
"react-redux": "9.3.0",
|
|
52
|
+
"tsup": "8.5.1",
|
|
53
|
+
"typescript": "5.9.3",
|
|
54
|
+
"vitest": "4.1.4"
|
|
46
55
|
},
|
|
47
56
|
"peerDependencies": {
|
|
48
57
|
"@gears-frontx/framework": "*",
|
|
49
|
-
"react": "
|
|
50
|
-
"react
|
|
58
|
+
"@tanstack/react-query": "5.101.4",
|
|
59
|
+
"react": "19.2.4",
|
|
60
|
+
"react-dom": "19.2.4",
|
|
61
|
+
"react-redux": "9.3.0"
|
|
51
62
|
},
|
|
52
63
|
"peerDependenciesMeta": {
|
|
53
64
|
"@gears-frontx/framework": {
|
|
@@ -56,20 +67,26 @@
|
|
|
56
67
|
"react": {
|
|
57
68
|
"optional": false
|
|
58
69
|
},
|
|
70
|
+
"react-dom": {
|
|
71
|
+
"optional": false
|
|
72
|
+
},
|
|
59
73
|
"react-redux": {
|
|
60
74
|
"optional": false
|
|
75
|
+
},
|
|
76
|
+
"@tanstack/react-query": {
|
|
77
|
+
"optional": false
|
|
61
78
|
}
|
|
62
79
|
},
|
|
63
80
|
"publishConfig": {
|
|
64
81
|
"access": "public"
|
|
65
82
|
},
|
|
66
83
|
"keywords": [
|
|
67
|
-
"
|
|
84
|
+
"frontx",
|
|
68
85
|
"react",
|
|
69
86
|
"hooks",
|
|
70
87
|
"provider",
|
|
71
88
|
"typescript"
|
|
72
89
|
],
|
|
73
|
-
"author": "
|
|
90
|
+
"author": "Cyber Fabric",
|
|
74
91
|
"license": "Apache-2.0"
|
|
75
92
|
}
|
|
@@ -1,58 +0,0 @@
|
|
|
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).
|
|
@@ -1,48 +0,0 @@
|
|
|
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.
|