@hai3/react 0.2.0-alpha.2 → 0.2.0-alpha.4
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/dist/index.cjs +74 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +99 -5
- package/dist/index.d.ts +99 -5
- package/dist/index.js +59 -13
- package/dist/index.js.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +24 -4
- package/dist/types.d.ts +24 -4
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -41,6 +41,8 @@ __export(src_exports, {
|
|
|
41
41
|
RestPlugin: () => import_framework2.RestPlugin,
|
|
42
42
|
RestPluginWithConfig: () => import_framework2.RestPluginWithConfig,
|
|
43
43
|
RestProtocol: () => import_framework2.RestProtocol,
|
|
44
|
+
RouteParamsContext: () => RouteParamsContext,
|
|
45
|
+
RouteParamsProvider: () => RouteParamsProvider,
|
|
44
46
|
SUPPORTED_LANGUAGES: () => import_framework2.SUPPORTED_LANGUAGES,
|
|
45
47
|
ScreensetCategory: () => import_framework2.ScreensetCategory,
|
|
46
48
|
SseMockPlugin: () => import_framework2.SseMockPlugin,
|
|
@@ -68,7 +70,7 @@ __export(src_exports, {
|
|
|
68
70
|
createStore: () => import_framework2.createStore,
|
|
69
71
|
createThemeRegistry: () => import_framework2.createThemeRegistry,
|
|
70
72
|
effects: () => import_framework2.effects,
|
|
71
|
-
eventBus: () =>
|
|
73
|
+
eventBus: () => eventBus,
|
|
72
74
|
footerActions: () => import_framework2.footerActions,
|
|
73
75
|
footerSlice: () => import_framework2.footerSlice,
|
|
74
76
|
getLanguageMetadata: () => import_framework2.getLanguageMetadata,
|
|
@@ -142,6 +144,7 @@ __export(src_exports, {
|
|
|
142
144
|
useAppSelector: () => useAppSelector,
|
|
143
145
|
useHAI3: () => useHAI3,
|
|
144
146
|
useNavigation: () => useNavigation,
|
|
147
|
+
useRouteParams: () => useRouteParams,
|
|
145
148
|
useScreenTranslations: () => useScreenTranslations,
|
|
146
149
|
useTheme: () => useTheme,
|
|
147
150
|
useTranslation: () => useTranslation
|
|
@@ -171,14 +174,20 @@ var import_jsx_runtime = require("react/jsx-runtime");
|
|
|
171
174
|
var HAI3Provider = ({
|
|
172
175
|
children,
|
|
173
176
|
config,
|
|
174
|
-
app: providedApp
|
|
177
|
+
app: providedApp,
|
|
178
|
+
router
|
|
175
179
|
}) => {
|
|
176
180
|
const app = (0, import_react2.useMemo)(() => {
|
|
177
181
|
if (providedApp) {
|
|
178
182
|
return providedApp;
|
|
179
183
|
}
|
|
180
|
-
|
|
181
|
-
|
|
184
|
+
const mergedConfig = {
|
|
185
|
+
...config,
|
|
186
|
+
routerMode: router?.type,
|
|
187
|
+
autoNavigate: router?.autoNavigate ?? config?.autoNavigate
|
|
188
|
+
};
|
|
189
|
+
return (0, import_framework.createHAI3App)(mergedConfig);
|
|
190
|
+
}, [providedApp, config, router]);
|
|
182
191
|
(0, import_react2.useEffect)(() => {
|
|
183
192
|
return () => {
|
|
184
193
|
if (!providedApp) {
|
|
@@ -326,9 +335,9 @@ function useNavigation() {
|
|
|
326
335
|
}
|
|
327
336
|
);
|
|
328
337
|
const navigateToScreen = (0, import_react5.useCallback)(
|
|
329
|
-
(screensetId, screenId) => {
|
|
338
|
+
(screensetId, screenId, params) => {
|
|
330
339
|
if (app.actions.navigateToScreen) {
|
|
331
|
-
app.actions.navigateToScreen({ screensetId, screenId });
|
|
340
|
+
app.actions.navigateToScreen({ screensetId, screenId, params });
|
|
332
341
|
}
|
|
333
342
|
},
|
|
334
343
|
[app.actions]
|
|
@@ -350,13 +359,29 @@ function useNavigation() {
|
|
|
350
359
|
};
|
|
351
360
|
}
|
|
352
361
|
|
|
353
|
-
// src/
|
|
362
|
+
// src/contexts/RouteParamsContext.tsx
|
|
354
363
|
var import_react6 = require("react");
|
|
364
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
365
|
+
var RouteParamsContext = (0, import_react6.createContext)({});
|
|
366
|
+
function RouteParamsProvider({ params, children }) {
|
|
367
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RouteParamsContext.Provider, { value: params, children });
|
|
368
|
+
}
|
|
369
|
+
function useRouteParamsContext() {
|
|
370
|
+
return (0, import_react6.useContext)(RouteParamsContext);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// src/hooks/useRouteParams.ts
|
|
374
|
+
function useRouteParams() {
|
|
375
|
+
return useRouteParamsContext();
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// src/hooks/useTheme.ts
|
|
379
|
+
var import_react7 = require("react");
|
|
355
380
|
function useTheme() {
|
|
356
381
|
const app = useHAI3();
|
|
357
382
|
const { themeRegistry } = app;
|
|
358
|
-
const version = (0,
|
|
359
|
-
(0,
|
|
383
|
+
const version = (0, import_react7.useSyncExternalStore)(
|
|
384
|
+
(0, import_react7.useCallback)(
|
|
360
385
|
(callback) => {
|
|
361
386
|
return themeRegistry.subscribe(callback);
|
|
362
387
|
},
|
|
@@ -365,18 +390,18 @@ function useTheme() {
|
|
|
365
390
|
() => themeRegistry.getVersion(),
|
|
366
391
|
() => themeRegistry.getVersion()
|
|
367
392
|
);
|
|
368
|
-
const currentTheme = (0,
|
|
393
|
+
const currentTheme = (0, import_react7.useMemo)(() => {
|
|
369
394
|
void version;
|
|
370
395
|
const theme = themeRegistry.getCurrent();
|
|
371
396
|
return theme?.id;
|
|
372
397
|
}, [themeRegistry, version]);
|
|
373
|
-
const themes2 = (0,
|
|
398
|
+
const themes2 = (0, import_react7.useMemo)(() => {
|
|
374
399
|
return themeRegistry.getAll().map((theme) => ({
|
|
375
400
|
id: theme.id,
|
|
376
401
|
name: theme.name
|
|
377
402
|
}));
|
|
378
403
|
}, [themeRegistry]);
|
|
379
|
-
const setTheme = (0,
|
|
404
|
+
const setTheme = (0, import_react7.useCallback)(
|
|
380
405
|
(themeId) => {
|
|
381
406
|
if (app.actions.changeTheme) {
|
|
382
407
|
app.actions.changeTheme({ themeId });
|
|
@@ -392,17 +417,37 @@ function useTheme() {
|
|
|
392
417
|
}
|
|
393
418
|
|
|
394
419
|
// src/components/AppRouter.tsx
|
|
395
|
-
var
|
|
396
|
-
var
|
|
420
|
+
var import_react8 = require("react");
|
|
421
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
397
422
|
var AppRouter = ({
|
|
398
423
|
fallback = null,
|
|
399
424
|
errorFallback
|
|
400
425
|
}) => {
|
|
401
426
|
const app = useHAI3();
|
|
402
427
|
const { currentScreenset, currentScreen } = useNavigation();
|
|
403
|
-
const [ScreenComponent, setScreenComponent] = (0,
|
|
404
|
-
const [error, setError] = (0,
|
|
405
|
-
(0,
|
|
428
|
+
const [ScreenComponent, setScreenComponent] = (0, import_react8.useState)(null);
|
|
429
|
+
const [error, setError] = (0, import_react8.useState)(null);
|
|
430
|
+
const [routeParams, setRouteParams] = (0, import_react8.useState)(() => {
|
|
431
|
+
if (typeof window === "undefined") {
|
|
432
|
+
return {};
|
|
433
|
+
}
|
|
434
|
+
const pathname = window.location.pathname;
|
|
435
|
+
const base = app.config.base || "";
|
|
436
|
+
const internalPath = base && pathname.startsWith(base) ? pathname.slice(base.length) || "/" : pathname;
|
|
437
|
+
const match = app.routeRegistry?.matchRoute(internalPath);
|
|
438
|
+
return match?.params ?? {};
|
|
439
|
+
});
|
|
440
|
+
(0, import_react8.useEffect)(() => {
|
|
441
|
+
if (typeof window === "undefined") {
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
const pathname = window.location.pathname;
|
|
445
|
+
const base = app.config.base || "";
|
|
446
|
+
const internalPath = base && pathname.startsWith(base) ? pathname.slice(base.length) || "/" : pathname;
|
|
447
|
+
const match = app.routeRegistry?.matchRoute(internalPath);
|
|
448
|
+
setRouteParams(match?.params ?? {});
|
|
449
|
+
}, [app.config.base, app.routeRegistry, currentScreen]);
|
|
450
|
+
(0, import_react8.useEffect)(() => {
|
|
406
451
|
let cancelled = false;
|
|
407
452
|
const loadScreen = async () => {
|
|
408
453
|
if (!currentScreenset || !currentScreen) {
|
|
@@ -436,24 +481,26 @@ var AppRouter = ({
|
|
|
436
481
|
if (error) {
|
|
437
482
|
if (errorFallback) {
|
|
438
483
|
if (typeof errorFallback === "function") {
|
|
439
|
-
return /* @__PURE__ */ (0,
|
|
484
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: errorFallback(error) });
|
|
440
485
|
}
|
|
441
|
-
return /* @__PURE__ */ (0,
|
|
486
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: errorFallback });
|
|
442
487
|
}
|
|
443
|
-
return /* @__PURE__ */ (0,
|
|
444
|
-
/* @__PURE__ */ (0,
|
|
445
|
-
/* @__PURE__ */ (0,
|
|
488
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "p-5 text-destructive", children: [
|
|
489
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { children: "Error loading screen" }),
|
|
490
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: error.message })
|
|
446
491
|
] });
|
|
447
492
|
}
|
|
448
493
|
if (!ScreenComponent) {
|
|
449
|
-
return /* @__PURE__ */ (0,
|
|
494
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: fallback });
|
|
450
495
|
}
|
|
451
|
-
return /* @__PURE__ */ (0,
|
|
496
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(RouteParamsProvider, { params: routeParams, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react8.Suspense, { fallback, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ScreenComponent, {}) }) });
|
|
452
497
|
};
|
|
453
498
|
|
|
454
499
|
// src/index.ts
|
|
455
500
|
var import_framework2 = require("@hai3/framework");
|
|
456
501
|
var import_framework3 = require("@hai3/framework");
|
|
502
|
+
var import_framework4 = require("@hai3/framework");
|
|
503
|
+
var eventBus = import_framework4.eventBus;
|
|
457
504
|
// Annotate the CommonJS export names for ESM import in node:
|
|
458
505
|
0 && (module.exports = {
|
|
459
506
|
ACCOUNTS_DOMAIN,
|
|
@@ -477,6 +524,8 @@ var import_framework3 = require("@hai3/framework");
|
|
|
477
524
|
RestPlugin,
|
|
478
525
|
RestPluginWithConfig,
|
|
479
526
|
RestProtocol,
|
|
527
|
+
RouteParamsContext,
|
|
528
|
+
RouteParamsProvider,
|
|
480
529
|
SUPPORTED_LANGUAGES,
|
|
481
530
|
ScreensetCategory,
|
|
482
531
|
SseMockPlugin,
|
|
@@ -578,6 +627,7 @@ var import_framework3 = require("@hai3/framework");
|
|
|
578
627
|
useAppSelector,
|
|
579
628
|
useHAI3,
|
|
580
629
|
useNavigation,
|
|
630
|
+
useRouteParams,
|
|
581
631
|
useScreenTranslations,
|
|
582
632
|
useTheme,
|
|
583
633
|
useTranslation
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/HAI3Provider.tsx","../src/HAI3Context.tsx","../src/hooks/useAppDispatch.ts","../src/hooks/useAppSelector.ts","../src/hooks/useTranslation.ts","../src/hooks/useScreenTranslations.ts","../src/hooks/useNavigation.ts","../src/hooks/useTheme.ts","../src/components/AppRouter.tsx"],"sourcesContent":["/**\n * @hai3/react - React Bindings\n *\n * This package provides:\n * - HAI3Provider context provider\n * - Type-safe hooks for state and actions\n * - AppRouter for screen rendering\n *\n * Layer: L3 (Depends on @hai3/framework)\n */\n\n// ============================================================================\n// Provider\n// ============================================================================\n\nexport { HAI3Provider } from './HAI3Provider';\nexport { HAI3Context, useHAI3 } from './HAI3Context';\n\n// ============================================================================\n// Hooks\n// ============================================================================\n\nexport {\n useAppDispatch,\n useAppSelector,\n useTranslation,\n useScreenTranslations,\n useNavigation,\n useTheme,\n} from './hooks';\n\n// ============================================================================\n// Components\n// ============================================================================\n\nexport { AppRouter } from './components';\n\n// ============================================================================\n// Type Exports\n// ============================================================================\n\nexport type {\n HAI3ProviderProps,\n UseHAI3Return,\n UseAppSelector,\n UseAppDispatchReturn,\n UseTranslationReturn,\n UseScreenTranslationsReturn,\n UseLanguageReturn,\n UseThemeReturn,\n UseMenuReturn,\n UseScreenReturn,\n UseNavigationReturn,\n UseScreensetReturn,\n UsePopupReturn,\n UseOverlayReturn,\n AppRouterProps,\n HAI3ProviderComponent,\n AppRouterComponent,\n} from './types';\n\n// ============================================================================\n// Re-exports from @hai3/framework for convenience\n// ============================================================================\n\n// These re-exports allow users to import everything from @hai3/react\n// without needing to import from @hai3/framework directly\n\nexport {\n // Core\n createHAI3,\n createHAI3App,\n presets,\n\n // Backward compatibility singletons\n screensetRegistry,\n\n // Backward compatibility constants\n ACCOUNTS_DOMAIN,\n\n // I18nRegistry class (capital I for backward compat)\n I18nRegistry,\n\n // Plugins\n screensets,\n themes,\n layout,\n navigation,\n routing,\n i18n,\n effects,\n\n // Registries\n createScreensetRegistry,\n createThemeRegistry,\n createRouteRegistry,\n\n // Flux (Event bus + Store)\n eventBus,\n\n // Store\n createStore,\n getStore,\n registerSlice,\n hasSlice,\n createSlice,\n\n // Layout domain exports\n LayoutDomain,\n ScreensetCategory,\n layoutReducer,\n layoutDomainReducers,\n LAYOUT_SLICE_NAME,\n headerSlice,\n footerSlice,\n menuSlice,\n sidebarSlice,\n screenSlice,\n popupSlice,\n overlaySlice,\n headerActions,\n footerActions,\n menuActions,\n sidebarActions,\n screenActions,\n popupActions,\n overlayActions,\n // Individual reducer functions - header\n setUser,\n setHeaderLoading,\n clearUser,\n // Individual reducer functions - footer\n setFooterVisible,\n setFooterConfig,\n toggleMenu,\n setMenuCollapsed,\n setMenuItems,\n setMenuVisible,\n setMenuConfig,\n toggleSidebar,\n setSidebarCollapsed,\n setSidebarPosition,\n setSidebarTitle,\n setSidebarContent,\n setSidebarVisible,\n setSidebarWidth,\n setSidebarConfig,\n setActiveScreen,\n setScreenLoading,\n navigateTo,\n clearActiveScreen,\n openPopup,\n closePopup,\n closeTopPopup,\n closeAllPopups,\n showOverlay,\n hideOverlay,\n setOverlayVisible,\n\n // Tenant (app-level, not layout)\n TENANT_SLICE_NAME,\n tenantSlice,\n tenantActions,\n tenantReducer,\n setTenant,\n setTenantLoading,\n clearTenant,\n // Tenant effects and events\n initTenantEffects,\n changeTenant,\n clearTenantAction,\n setTenantLoadingState,\n TenantEvents,\n\n // Mock (app-level, not layout)\n mockSlice,\n mockActions,\n setMockEnabled,\n // Mock effects and events\n initMockEffects,\n toggleMockMode,\n MockEvents,\n\n // API\n apiRegistry,\n BaseApiService,\n RestProtocol,\n SseProtocol,\n // Protocol-specific mock plugins (replaces generic MockPlugin)\n RestMockPlugin,\n SseMockPlugin,\n MockEventSource,\n // Plugin base classes\n ApiPluginBase,\n ApiPlugin,\n ApiProtocol,\n RestPlugin,\n RestPluginWithConfig,\n SsePlugin,\n SsePluginWithConfig,\n // Type guards\n isShortCircuit,\n isRestShortCircuit,\n isSseShortCircuit,\n // Mock plugin identification\n MOCK_PLUGIN,\n isMockPlugin,\n\n // I18n\n i18nRegistry,\n I18nRegistryImpl,\n createI18nRegistry,\n SUPPORTED_LANGUAGES,\n getLanguageMetadata,\n} from '@hai3/framework';\n\n// Re-export i18n types from @hai3/framework (correct layer access)\nexport { Language, TextDirection, LanguageDisplayMode } from '@hai3/framework';\n\n// Re-export types from @hai3/framework\nexport type {\n // Config\n HAI3Config,\n HAI3Plugin,\n HAI3AppBuilder,\n HAI3App,\n PluginFactory,\n PluginProvides,\n PluginLifecycle,\n ScreensetRegistry,\n ThemeRegistry,\n ThemeConfig,\n RouteRegistry,\n Preset,\n Presets,\n ScreensetsConfig,\n NavigateToScreenPayload,\n NavigateToScreensetPayload,\n ShowPopupPayload,\n ChangeThemePayload,\n SetLanguagePayload,\n\n // Flux (Events + Store)\n EventPayloadMap,\n EventHandler,\n Subscription,\n\n // Store\n RootState,\n AppDispatch,\n SliceObject,\n HAI3Store,\n\n // Layout\n ScreensetId,\n ScreenId,\n MenuItemConfig,\n ScreenLoader,\n ScreenConfig,\n MenuScreenItem,\n ScreensetDefinition,\n LayoutDomainState,\n HeaderUser,\n HeaderConfig,\n HeaderState,\n FooterConfig,\n FooterState,\n MenuItem,\n MenuState,\n SidebarPosition,\n SidebarState,\n ScreenState,\n PopupConfig,\n PopupState,\n PopupSliceState,\n OverlayConfig,\n OverlayState,\n LayoutState,\n RootStateWithLayout,\n LayoutDomainReducers,\n\n // Tenant types\n Tenant,\n TenantState,\n TenantChangedPayload,\n TenantClearedPayload,\n\n // Mock types\n MockState,\n MockTogglePayload,\n\n // API\n MockMap,\n ApiServiceConfig,\n JsonValue,\n JsonObject,\n JsonPrimitive,\n JsonCompatible,\n SseProtocolConfig,\n RestProtocolConfig,\n // Plugin context types (class-based plugin system)\n ApiRequestContext,\n ApiResponseContext,\n ShortCircuitResponse,\n PluginClass,\n ProtocolClass,\n ProtocolPluginType,\n BasePluginHooks,\n // Protocol-specific types\n RestPluginHooks,\n SsePluginHooks,\n RestRequestContext,\n RestResponseContext,\n ApiPluginErrorContext,\n SseConnectContext,\n EventSourceLike,\n RestShortCircuitResponse,\n SseShortCircuitResponse,\n RestMockConfig,\n SseMockConfig,\n SseMockEvent,\n\n // Backward compatibility type aliases\n ScreensetConfig,\n\n // Theme types\n ThemeApplyFn,\n UikitTheme,\n\n // I18n\n I18nConfig,\n TranslationLoader,\n TranslationMap,\n TranslationDictionary,\n LanguageMetadata,\n I18nRegistryType,\n} from '@hai3/framework';\n","/**\n * HAI3 Provider - Main provider component for HAI3 applications\n *\n * React Layer: L3 (Depends on @hai3/framework)\n */\n\nimport React, { useMemo, useEffect } from 'react';\nimport { Provider as ReduxProvider } from 'react-redux';\nimport { createHAI3App } from '@hai3/framework';\nimport type { HAI3App } from '@hai3/framework';\nimport { HAI3Context } from './HAI3Context';\nimport type { HAI3ProviderProps } from './types';\n\n/**\n * HAI3 Provider Component\n *\n * Provides the HAI3 application context to all child components.\n * Creates the HAI3 app instance with the full preset by default.\n *\n * @example\n * ```tsx\n * // Default - creates app with full preset\n * <HAI3Provider>\n * <App />\n * </HAI3Provider>\n *\n * // With configuration\n * <HAI3Provider config={{ devMode: true }}>\n * <App />\n * </HAI3Provider>\n *\n * // With pre-built app\n * const app = createHAI3().use(screensets()).build();\n * <HAI3Provider app={app}>\n * <App />\n * </HAI3Provider>\n * ```\n */\nexport const HAI3Provider: React.FC<HAI3ProviderProps> = ({\n children,\n config,\n app: providedApp,\n}) => {\n // Create or use provided app instance\n const app = useMemo<HAI3App>(() => {\n if (providedApp) {\n return providedApp;\n }\n\n return createHAI3App(config);\n }, [providedApp, config]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n // Only destroy if we created the app (not provided)\n if (!providedApp) {\n app.destroy();\n }\n };\n }, [app, providedApp]);\n\n return (\n <HAI3Context.Provider value={app}>\n <ReduxProvider store={app.store as Parameters<typeof ReduxProvider>[0]['store']}>\n {children}\n </ReduxProvider>\n </HAI3Context.Provider>\n );\n};\n","/**\n * HAI3 Context - React context for HAI3 application\n *\n * React Layer: L3 (Depends on @hai3/framework)\n */\n\nimport { createContext, useContext } from 'react';\nimport type { HAI3App } from '@hai3/framework';\n\n// ============================================================================\n// Context Definition\n// ============================================================================\n\n/**\n * HAI3 Context\n * Holds the HAI3 app instance for the application.\n */\nexport const HAI3Context = createContext<HAI3App | null>(null);\n\n/**\n * Use the HAI3 context.\n * Throws if used outside of HAI3Provider.\n *\n * @returns The HAI3 app instance\n */\nexport function useHAI3(): HAI3App {\n const context = useContext(HAI3Context);\n\n if (!context) {\n throw new Error(\n 'useHAI3 must be used within a HAI3Provider. ' +\n 'Wrap your application with <HAI3Provider> to access HAI3 features.'\n );\n }\n\n return context;\n}\n","/**\n * useAppDispatch Hook - Type-safe dispatch hook\n *\n * React Layer: L3\n */\n\nimport { useDispatch } from 'react-redux';\nimport type { AppDispatch } from '@hai3/framework';\n\n/**\n * Type-safe dispatch hook.\n *\n * @returns The typed dispatch function\n *\n * @example\n * ```tsx\n * const dispatch = useAppDispatch();\n * dispatch(someAction());\n * ```\n */\nexport function useAppDispatch(): AppDispatch {\n // Use untyped useDispatch and cast the result\n // This avoids type constraint issues with react-redux's generic\n return useDispatch() as AppDispatch;\n}\n","/**\n * useAppSelector Hook - Type-safe selector hook\n *\n * React Layer: L3\n */\n\nimport { useSelector, type TypedUseSelectorHook } from 'react-redux';\nimport type { RootState } from '@hai3/framework';\n\n/**\n * Type-safe selector hook.\n *\n * @example\n * ```tsx\n * const activeScreen = useAppSelector(selectActiveScreen);\n * const menuCollapsed = useAppSelector(selectMenuCollapsed);\n * ```\n */\nexport const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;\n","/**\n * useTranslation Hook - Translation utilities\n *\n * React Layer: L3\n */\n\nimport { useMemo, useCallback, useSyncExternalStore } from 'react';\nimport type { Language } from '@hai3/framework';\nimport { useHAI3 } from '../HAI3Context';\nimport type { UseTranslationReturn } from '../types';\n\n/**\n * Hook for accessing translation utilities.\n *\n * @returns Translation utilities\n *\n * @example\n * ```tsx\n * const { t, language, setLanguage, isRTL } = useTranslation();\n *\n * return (\n * <div dir={isRTL ? 'rtl' : 'ltr'}>\n * <h1>{t('common:app.title')}</h1>\n * <p>{t('common:app.welcome', { name: 'John' })}</p>\n * </div>\n * );\n * ```\n */\nexport function useTranslation(): UseTranslationReturn {\n const app = useHAI3();\n const { i18nRegistry } = app;\n\n // Subscribe to translation changes using useSyncExternalStore\n // Uses version counter to trigger re-renders when translations change\n const version = useSyncExternalStore(\n useCallback(\n (callback: () => void) => {\n // Subscribe to translation changes (new translations registered)\n return i18nRegistry.subscribe(callback);\n },\n [i18nRegistry]\n ),\n () => i18nRegistry.getVersion(),\n () => i18nRegistry.getVersion()\n );\n\n // Get current language (memoized to avoid unnecessary recalculations)\n // version is used to trigger recalculation when translations change\n const language = useMemo(() => {\n void version; // Trigger recalculation when version changes\n return i18nRegistry.getLanguage();\n }, [i18nRegistry, version]);\n\n // Translation function\n const t = useCallback(\n (key: string, params?: Record<string, string | number | boolean>) => {\n return i18nRegistry.t(key, params);\n },\n [i18nRegistry]\n );\n\n // Set language function\n const setLanguage = useCallback(\n async (lang: Language) => {\n await i18nRegistry.setLanguage(lang);\n },\n [i18nRegistry]\n );\n\n // Check RTL - recomputes when language changes\n const isRTL = useMemo(() => {\n // Reference language to trigger recalculation on language change\n void language;\n return i18nRegistry.isRTL();\n }, [i18nRegistry, language]);\n\n return {\n t,\n language,\n setLanguage,\n isRTL,\n };\n}\n","/**\n * useScreenTranslations Hook - Screen-level translation loading\n *\n * React Layer: L3\n */\n\nimport { useState, useEffect, useMemo, useCallback, useSyncExternalStore } from 'react';\nimport type { TranslationMap, TranslationLoader } from '@hai3/framework';\nimport { useHAI3 } from '../HAI3Context';\nimport type { UseScreenTranslationsReturn } from '../types';\n\n// Re-export TranslationMap for consumers who need it\nexport type { TranslationMap };\n\n/**\n * Check if the input is a TranslationLoader function (from I18nRegistry.createLoader)\n * vs a TranslationMap object\n */\nfunction isTranslationLoader(\n input: TranslationMap | TranslationLoader\n): input is TranslationLoader {\n return typeof input === 'function';\n}\n\n/**\n * Hook for loading screen-level translations.\n * Use this in screen components to lazy-load translations.\n * Automatically reloads translations when language changes.\n *\n * @param screensetId - The screenset ID\n * @param screenId - The screen ID\n * @param translations - Either a TranslationMap object or a TranslationLoader function\n * (from I18nRegistry.createLoader)\n * @returns Loading state\n *\n * @example\n * ```tsx\n * // Option 1: Using I18nRegistry.createLoader (recommended)\n * const translations = I18nRegistry.createLoader({\n * en: () => import('./i18n/en.json'),\n * es: () => import('./i18n/es.json'),\n * });\n *\n * // Option 2: Using raw TranslationMap\n * const translations = {\n * en: () => import('./i18n/en.json'),\n * es: () => import('./i18n/es.json'),\n * };\n *\n * export const HomeScreen: React.FC = () => {\n * const { isLoaded, error } = useScreenTranslations(\n * 'demo',\n * 'home',\n * translations\n * );\n *\n * if (!isLoaded) return <LoadingSpinner />;\n * if (error) return <ErrorMessage error={error} />;\n *\n * return <div>...</div>;\n * };\n * ```\n */\nexport function useScreenTranslations(\n screensetId: string,\n screenId: string,\n translations: TranslationMap | TranslationLoader\n): UseScreenTranslationsReturn {\n const app = useHAI3();\n const { i18nRegistry } = app;\n\n // Track loading state per language to handle language changes\n const [loadedLanguage, setLoadedLanguage] = useState<string | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n // Subscribe to translation changes using useSyncExternalStore\n // This ensures we reload when language changes\n const version = useSyncExternalStore(\n useCallback(\n (callback: () => void) => i18nRegistry.subscribe(callback),\n [i18nRegistry]\n ),\n () => i18nRegistry.getVersion(),\n () => i18nRegistry.getVersion()\n );\n\n // Get current language (changes when version changes)\n // version is used to trigger recalculation when translations change\n const currentLanguage = useMemo(() => {\n void version; // Trigger recalculation when version changes\n return i18nRegistry.getLanguage();\n }, [i18nRegistry, version]);\n\n // Create a TranslationLoader function from the translation map or use directly if already a loader\n const loader: TranslationLoader = useMemo(() => {\n if (isTranslationLoader(translations)) {\n // Already a loader function (from I18nRegistry.createLoader)\n return translations;\n }\n\n // Convert TranslationMap to TranslationLoader\n return async (language: string) => {\n const importFn = translations[language as keyof typeof translations];\n if (!importFn) {\n // Return empty dictionary if language not in map\n return {};\n }\n const module = await importFn();\n return module.default;\n };\n }, [translations]);\n\n useEffect(() => {\n // Skip if no language or already loaded for this language\n if (!currentLanguage || currentLanguage === loadedLanguage) {\n return;\n }\n\n let cancelled = false;\n setIsLoading(true);\n\n const loadTranslations = async () => {\n try {\n const namespace = `screen.${screensetId}.${screenId}`;\n\n // Register the loader for future language changes\n i18nRegistry.registerLoader(namespace, loader);\n\n // Actually load the translations for current language\n const loadedTranslations = await loader(currentLanguage);\n i18nRegistry.register(namespace, currentLanguage, loadedTranslations);\n\n if (!cancelled) {\n setLoadedLanguage(currentLanguage);\n setIsLoading(false);\n setError(null);\n }\n } catch (err) {\n if (!cancelled) {\n setError(err instanceof Error ? err : new Error(String(err)));\n setIsLoading(false);\n }\n }\n };\n\n loadTranslations();\n\n return () => {\n cancelled = true;\n };\n }, [screensetId, screenId, loader, i18nRegistry, currentLanguage, loadedLanguage]);\n\n // Derive isLoaded from whether we've loaded translations for the current language\n const isLoaded = currentLanguage !== null && currentLanguage === loadedLanguage && !isLoading;\n\n return { isLoaded, error };\n}\n","/**\n * useNavigation Hook - Navigation utilities\n *\n * React Layer: L3\n */\n\nimport { useCallback } from 'react';\nimport { useHAI3 } from '../HAI3Context';\nimport { useAppSelector } from './useAppSelector';\nimport type { RootStateWithLayout } from '@hai3/framework';\nimport type { UseNavigationReturn } from '../types';\n\n/**\n * Hook for navigation utilities.\n *\n * @returns Navigation utilities\n *\n * @example\n * ```tsx\n * const { navigateToScreen, navigateToScreenset, currentScreen } = useNavigation();\n *\n * return (\n * <button onClick={() => navigateToScreen('demo', 'home')}>\n * Go to Home\n * </button>\n * );\n * ```\n */\nexport function useNavigation(): UseNavigationReturn {\n const app = useHAI3();\n // Access state directly via useAppSelector - no selectors needed\n // Layout slices use flat keys like 'layout/screen', not nested 'layout.screen'\n const currentScreen = useAppSelector(\n (state) => {\n // Try flat key first (current SDK architecture)\n const flatKey = state as Record<string, { activeScreen?: string | null }>;\n if (flatKey['layout/screen']) {\n return flatKey['layout/screen'].activeScreen ?? null;\n }\n // Fallback to nested structure (for backward compatibility)\n const nested = state as unknown as RootStateWithLayout;\n return nested.layout?.screen?.activeScreen ?? null;\n }\n );\n\n // Navigate to a specific screen\n const navigateToScreen = useCallback(\n (screensetId: string, screenId: string) => {\n if (app.actions.navigateToScreen) {\n app.actions.navigateToScreen({ screensetId, screenId });\n }\n },\n [app.actions]\n );\n\n // Navigate to a screenset (uses default screen)\n const navigateToScreenset = useCallback(\n (screensetId: string) => {\n if (app.actions.navigateToScreenset) {\n app.actions.navigateToScreenset({ screensetId });\n }\n },\n [app.actions]\n );\n\n /**\n * Derived state: screenset looked up from currentScreen via routeRegistry.\n * Single source of truth (Redux), automatic reactivity.\n */\n const currentScreenset = currentScreen\n ? app.routeRegistry?.getScreensetForScreen(currentScreen) ?? null\n : null;\n\n return {\n navigateToScreen,\n navigateToScreenset,\n currentScreenset,\n currentScreen,\n };\n}\n","/**\n * useTheme Hook - Theme utilities\n *\n * React Layer: L3\n */\n\nimport { useCallback, useMemo, useSyncExternalStore } from 'react';\nimport { useHAI3 } from '../HAI3Context';\nimport type { UseThemeReturn } from '../types';\n\n/**\n * Hook for theme utilities.\n *\n * @returns Theme utilities\n *\n * @example\n * ```tsx\n * const { currentTheme, themes, setTheme } = useTheme();\n *\n * return (\n * <select\n * value={currentTheme}\n * onChange={(e) => setTheme(e.target.value)}\n * >\n * {themes.map((theme) => (\n * <option key={theme.id} value={theme.id}>\n * {theme.name}\n * </option>\n * ))}\n * </select>\n * );\n * ```\n */\nexport function useTheme(): UseThemeReturn {\n const app = useHAI3();\n const { themeRegistry } = app;\n\n // Subscribe to theme changes using useSyncExternalStore\n // Uses version counter to trigger re-renders when theme changes\n const version = useSyncExternalStore(\n useCallback(\n (callback: () => void) => {\n return themeRegistry.subscribe(callback);\n },\n [themeRegistry]\n ),\n () => themeRegistry.getVersion(),\n () => themeRegistry.getVersion()\n );\n\n // Get current theme (memoized, recalculates on version change)\n const currentTheme = useMemo(() => {\n // Reference version to trigger recalculation on theme change\n void version;\n const theme = themeRegistry.getCurrent();\n return theme?.id;\n }, [themeRegistry, version]);\n\n // Get all themes\n const themes = useMemo(() => {\n return themeRegistry.getAll().map((theme) => ({\n id: theme.id,\n name: theme.name,\n }));\n }, [themeRegistry]);\n\n // Set theme\n const setTheme = useCallback(\n (themeId: string) => {\n if (app.actions.changeTheme) {\n app.actions.changeTheme({ themeId });\n }\n },\n [app.actions]\n );\n\n return {\n currentTheme,\n themes,\n setTheme,\n };\n}\n","/**\n * AppRouter Component - Renders the active screen\n *\n * React Layer: L3\n */\n\nimport React, { Suspense, useState, useEffect } from 'react';\nimport { useHAI3 } from '../HAI3Context';\nimport { useNavigation } from '../hooks/useNavigation';\nimport type { AppRouterProps } from '../types';\n\n/**\n * AppRouter Component\n *\n * Renders the currently active screen based on navigation state.\n * Handles lazy loading and error boundaries.\n *\n * @example\n * ```tsx\n * <HAI3Provider>\n * <Layout>\n * <AppRouter\n * fallback={<LoadingSpinner />}\n * errorFallback={(error) => <ErrorPage error={error} />}\n * />\n * </Layout>\n * </HAI3Provider>\n * ```\n */\nexport const AppRouter: React.FC<AppRouterProps> = ({\n fallback = null,\n errorFallback,\n}) => {\n const app = useHAI3();\n const { currentScreenset, currentScreen } = useNavigation();\n const [ScreenComponent, setScreenComponent] = useState<React.ComponentType | null>(null);\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n\n const loadScreen = async () => {\n if (!currentScreenset || !currentScreen) {\n setScreenComponent(null);\n return;\n }\n\n try {\n // Get screen loader from route registry\n const loader = app.routeRegistry.getScreen(currentScreenset, currentScreen);\n\n if (!loader) {\n throw new Error(\n `Screen \"${currentScreen}\" not found in screenset \"${currentScreenset}\".`\n );\n }\n\n // Load the screen component\n const module = await loader();\n\n if (!cancelled) {\n setScreenComponent(() => module.default);\n setError(null);\n }\n } catch (err) {\n if (!cancelled) {\n setError(err instanceof Error ? err : new Error(String(err)));\n setScreenComponent(null);\n }\n }\n };\n\n loadScreen();\n\n return () => {\n cancelled = true;\n };\n }, [currentScreenset, currentScreen, app.routeRegistry]);\n\n // Handle error state\n if (error) {\n if (errorFallback) {\n if (typeof errorFallback === 'function') {\n return <>{errorFallback(error)}</>;\n }\n return <>{errorFallback}</>;\n }\n // Default error display\n return (\n <div className=\"p-5 text-destructive\">\n <h2>Error loading screen</h2>\n <p>{error.message}</p>\n </div>\n );\n }\n\n // Handle loading state\n if (!ScreenComponent) {\n return <>{fallback}</>;\n }\n\n // Render the screen component\n return (\n <Suspense fallback={fallback}>\n <ScreenComponent />\n </Suspense>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACMA,IAAAA,gBAA0C;AAC1C,yBAA0C;AAC1C,uBAA8B;;;ACF9B,mBAA0C;AAWnC,IAAM,kBAAc,4BAA8B,IAAI;AAQtD,SAAS,UAAmB;AACjC,QAAM,cAAU,yBAAW,WAAW;AAEtC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AAEA,SAAO;AACT;;;AD4BM;AA1BC,IAAM,eAA4C,CAAC;AAAA,EACxD;AAAA,EACA;AAAA,EACA,KAAK;AACP,MAAM;AAEJ,QAAM,UAAM,uBAAiB,MAAM;AACjC,QAAI,aAAa;AACf,aAAO;AAAA,IACT;AAEA,eAAO,gCAAc,MAAM;AAAA,EAC7B,GAAG,CAAC,aAAa,MAAM,CAAC;AAGxB,+BAAU,MAAM;AACd,WAAO,MAAM;AAEX,UAAI,CAAC,aAAa;AAChB,YAAI,QAAQ;AAAA,MACd;AAAA,IACF;AAAA,EACF,GAAG,CAAC,KAAK,WAAW,CAAC;AAErB,SACE,4CAAC,YAAY,UAAZ,EAAqB,OAAO,KAC3B,sDAAC,mBAAAC,UAAA,EAAc,OAAO,IAAI,OACvB,UACH,GACF;AAEJ;;;AE/DA,IAAAC,sBAA4B;AAcrB,SAAS,iBAA8B;AAG5C,aAAO,iCAAY;AACrB;;;AClBA,IAAAC,sBAAuD;AAYhD,IAAM,iBAAkD;;;ACZ/D,IAAAC,gBAA2D;AAsBpD,SAAS,iBAAuC;AACrD,QAAM,MAAM,QAAQ;AACpB,QAAM,EAAE,cAAAC,cAAa,IAAI;AAIzB,QAAM,cAAU;AAAA,QACd;AAAA,MACE,CAAC,aAAyB;AAExB,eAAOA,cAAa,UAAU,QAAQ;AAAA,MACxC;AAAA,MACA,CAACA,aAAY;AAAA,IACf;AAAA,IACA,MAAMA,cAAa,WAAW;AAAA,IAC9B,MAAMA,cAAa,WAAW;AAAA,EAChC;AAIA,QAAM,eAAW,uBAAQ,MAAM;AAC7B,SAAK;AACL,WAAOA,cAAa,YAAY;AAAA,EAClC,GAAG,CAACA,eAAc,OAAO,CAAC;AAG1B,QAAM,QAAI;AAAA,IACR,CAAC,KAAa,WAAuD;AACnE,aAAOA,cAAa,EAAE,KAAK,MAAM;AAAA,IACnC;AAAA,IACA,CAACA,aAAY;AAAA,EACf;AAGA,QAAM,kBAAc;AAAA,IAClB,OAAO,SAAmB;AACxB,YAAMA,cAAa,YAAY,IAAI;AAAA,IACrC;AAAA,IACA,CAACA,aAAY;AAAA,EACf;AAGA,QAAM,YAAQ,uBAAQ,MAAM;AAE1B,SAAK;AACL,WAAOA,cAAa,MAAM;AAAA,EAC5B,GAAG,CAACA,eAAc,QAAQ,CAAC;AAE3B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AC5EA,IAAAC,gBAAgF;AAYhF,SAAS,oBACP,OAC4B;AAC5B,SAAO,OAAO,UAAU;AAC1B;AAyCO,SAAS,sBACd,aACA,UACA,cAC6B;AAC7B,QAAM,MAAM,QAAQ;AACpB,QAAM,EAAE,cAAAC,cAAa,IAAI;AAGzB,QAAM,CAAC,gBAAgB,iBAAiB,QAAI,wBAAwB,IAAI;AACxE,QAAM,CAAC,WAAW,YAAY,QAAI,wBAAS,KAAK;AAChD,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAuB,IAAI;AAIrD,QAAM,cAAU;AAAA,QACd;AAAA,MACE,CAAC,aAAyBA,cAAa,UAAU,QAAQ;AAAA,MACzD,CAACA,aAAY;AAAA,IACf;AAAA,IACA,MAAMA,cAAa,WAAW;AAAA,IAC9B,MAAMA,cAAa,WAAW;AAAA,EAChC;AAIA,QAAM,sBAAkB,uBAAQ,MAAM;AACpC,SAAK;AACL,WAAOA,cAAa,YAAY;AAAA,EAClC,GAAG,CAACA,eAAc,OAAO,CAAC;AAG1B,QAAM,aAA4B,uBAAQ,MAAM;AAC9C,QAAI,oBAAoB,YAAY,GAAG;AAErC,aAAO;AAAA,IACT;AAGA,WAAO,OAAO,aAAqB;AACjC,YAAM,WAAW,aAAa,QAAqC;AACnE,UAAI,CAAC,UAAU;AAEb,eAAO,CAAC;AAAA,MACV;AACA,YAAMC,UAAS,MAAM,SAAS;AAC9B,aAAOA,QAAO;AAAA,IAChB;AAAA,EACF,GAAG,CAAC,YAAY,CAAC;AAEjB,+BAAU,MAAM;AAEd,QAAI,CAAC,mBAAmB,oBAAoB,gBAAgB;AAC1D;AAAA,IACF;AAEA,QAAI,YAAY;AAChB,iBAAa,IAAI;AAEjB,UAAM,mBAAmB,YAAY;AACnC,UAAI;AACF,cAAM,YAAY,UAAU,WAAW,IAAI,QAAQ;AAGnD,QAAAD,cAAa,eAAe,WAAW,MAAM;AAG7C,cAAM,qBAAqB,MAAM,OAAO,eAAe;AACvD,QAAAA,cAAa,SAAS,WAAW,iBAAiB,kBAAkB;AAEpE,YAAI,CAAC,WAAW;AACd,4BAAkB,eAAe;AACjC,uBAAa,KAAK;AAClB,mBAAS,IAAI;AAAA,QACf;AAAA,MACF,SAAS,KAAK;AACZ,YAAI,CAAC,WAAW;AACd,mBAAS,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;AAC5D,uBAAa,KAAK;AAAA,QACpB;AAAA,MACF;AAAA,IACF;AAEA,qBAAiB;AAEjB,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,aAAa,UAAU,QAAQA,eAAc,iBAAiB,cAAc,CAAC;AAGjF,QAAM,WAAW,oBAAoB,QAAQ,oBAAoB,kBAAkB,CAAC;AAEpF,SAAO,EAAE,UAAU,MAAM;AAC3B;;;ACvJA,IAAAE,gBAA4B;AAsBrB,SAAS,gBAAqC;AACnD,QAAM,MAAM,QAAQ;AAGpB,QAAM,gBAAgB;AAAA,IACpB,CAAC,UAAU;AAET,YAAM,UAAU;AAChB,UAAI,QAAQ,eAAe,GAAG;AAC5B,eAAO,QAAQ,eAAe,EAAE,gBAAgB;AAAA,MAClD;AAEA,YAAM,SAAS;AACf,aAAO,OAAO,QAAQ,QAAQ,gBAAgB;AAAA,IAChD;AAAA,EACF;AAGA,QAAM,uBAAmB;AAAA,IACvB,CAAC,aAAqB,aAAqB;AACzC,UAAI,IAAI,QAAQ,kBAAkB;AAChC,YAAI,QAAQ,iBAAiB,EAAE,aAAa,SAAS,CAAC;AAAA,MACxD;AAAA,IACF;AAAA,IACA,CAAC,IAAI,OAAO;AAAA,EACd;AAGA,QAAM,0BAAsB;AAAA,IAC1B,CAAC,gBAAwB;AACvB,UAAI,IAAI,QAAQ,qBAAqB;AACnC,YAAI,QAAQ,oBAAoB,EAAE,YAAY,CAAC;AAAA,MACjD;AAAA,IACF;AAAA,IACA,CAAC,IAAI,OAAO;AAAA,EACd;AAMA,QAAM,mBAAmB,gBACrB,IAAI,eAAe,sBAAsB,aAAa,KAAK,OAC3D;AAEJ,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACzEA,IAAAC,gBAA2D;AA2BpD,SAAS,WAA2B;AACzC,QAAM,MAAM,QAAQ;AACpB,QAAM,EAAE,cAAc,IAAI;AAI1B,QAAM,cAAU;AAAA,QACd;AAAA,MACE,CAAC,aAAyB;AACxB,eAAO,cAAc,UAAU,QAAQ;AAAA,MACzC;AAAA,MACA,CAAC,aAAa;AAAA,IAChB;AAAA,IACA,MAAM,cAAc,WAAW;AAAA,IAC/B,MAAM,cAAc,WAAW;AAAA,EACjC;AAGA,QAAM,mBAAe,uBAAQ,MAAM;AAEjC,SAAK;AACL,UAAM,QAAQ,cAAc,WAAW;AACvC,WAAO,OAAO;AAAA,EAChB,GAAG,CAAC,eAAe,OAAO,CAAC;AAG3B,QAAMC,cAAS,uBAAQ,MAAM;AAC3B,WAAO,cAAc,OAAO,EAAE,IAAI,CAAC,WAAW;AAAA,MAC5C,IAAI,MAAM;AAAA,MACV,MAAM,MAAM;AAAA,IACd,EAAE;AAAA,EACJ,GAAG,CAAC,aAAa,CAAC;AAGlB,QAAM,eAAW;AAAA,IACf,CAAC,YAAoB;AACnB,UAAI,IAAI,QAAQ,aAAa;AAC3B,YAAI,QAAQ,YAAY,EAAE,QAAQ,CAAC;AAAA,MACrC;AAAA,IACF;AAAA,IACA,CAAC,IAAI,OAAO;AAAA,EACd;AAEA,SAAO;AAAA,IACL;AAAA,IACA,QAAAA;AAAA,IACA;AAAA,EACF;AACF;;;AC3EA,IAAAC,gBAAqD;AA6EtC,IAAAC,sBAAA;AAtDR,IAAM,YAAsC,CAAC;AAAA,EAClD,WAAW;AAAA,EACX;AACF,MAAM;AACJ,QAAM,MAAM,QAAQ;AACpB,QAAM,EAAE,kBAAkB,cAAc,IAAI,cAAc;AAC1D,QAAM,CAAC,iBAAiB,kBAAkB,QAAI,wBAAqC,IAAI;AACvF,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAuB,IAAI;AAErD,+BAAU,MAAM;AACd,QAAI,YAAY;AAEhB,UAAM,aAAa,YAAY;AAC7B,UAAI,CAAC,oBAAoB,CAAC,eAAe;AACvC,2BAAmB,IAAI;AACvB;AAAA,MACF;AAEA,UAAI;AAEF,cAAM,SAAS,IAAI,cAAc,UAAU,kBAAkB,aAAa;AAE1E,YAAI,CAAC,QAAQ;AACX,gBAAM,IAAI;AAAA,YACR,WAAW,aAAa,6BAA6B,gBAAgB;AAAA,UACvE;AAAA,QACF;AAGA,cAAMC,UAAS,MAAM,OAAO;AAE5B,YAAI,CAAC,WAAW;AACd,6BAAmB,MAAMA,QAAO,OAAO;AACvC,mBAAS,IAAI;AAAA,QACf;AAAA,MACF,SAAS,KAAK;AACZ,YAAI,CAAC,WAAW;AACd,mBAAS,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;AAC5D,6BAAmB,IAAI;AAAA,QACzB;AAAA,MACF;AAAA,IACF;AAEA,eAAW;AAEX,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,kBAAkB,eAAe,IAAI,aAAa,CAAC;AAGvD,MAAI,OAAO;AACT,QAAI,eAAe;AACjB,UAAI,OAAO,kBAAkB,YAAY;AACvC,eAAO,6EAAG,wBAAc,KAAK,GAAE;AAAA,MACjC;AACA,aAAO,6EAAG,yBAAc;AAAA,IAC1B;AAEA,WACE,8CAAC,SAAI,WAAU,wBACb;AAAA,mDAAC,QAAG,kCAAoB;AAAA,MACxB,6CAAC,OAAG,gBAAM,SAAQ;AAAA,OACpB;AAAA,EAEJ;AAGA,MAAI,CAAC,iBAAiB;AACpB,WAAO,6EAAG,oBAAS;AAAA,EACrB;AAGA,SACE,6CAAC,0BAAS,UACR,uDAAC,mBAAgB,GACnB;AAEJ;;;ATvCA,IAAAC,oBAkJO;AAGP,IAAAA,oBAA6D;","names":["import_react","ReduxProvider","import_react_redux","import_react_redux","import_react","i18nRegistry","import_react","i18nRegistry","module","import_react","import_react","themes","import_react","import_jsx_runtime","module","import_framework"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/HAI3Provider.tsx","../src/HAI3Context.tsx","../src/hooks/useAppDispatch.ts","../src/hooks/useAppSelector.ts","../src/hooks/useTranslation.ts","../src/hooks/useScreenTranslations.ts","../src/hooks/useNavigation.ts","../src/contexts/RouteParamsContext.tsx","../src/hooks/useRouteParams.ts","../src/hooks/useTheme.ts","../src/components/AppRouter.tsx"],"sourcesContent":["/**\n * @hai3/react - React Bindings\n *\n * This package provides:\n * - HAI3Provider context provider\n * - Type-safe hooks for state and actions\n * - AppRouter for screen rendering\n *\n * Layer: L3 (Depends on @hai3/framework)\n */\n\n// ============================================================================\n// Provider\n// ============================================================================\n\nexport { HAI3Provider } from './HAI3Provider';\nexport { HAI3Context, useHAI3 } from './HAI3Context';\n\n// ============================================================================\n// Hooks\n// ============================================================================\n\nexport {\n useAppDispatch,\n useAppSelector,\n useTranslation,\n useScreenTranslations,\n useNavigation,\n useTheme,\n} from './hooks';\n\nexport { useRouteParams } from './hooks/useRouteParams';\n\n// ============================================================================\n// Components\n// ============================================================================\n\nexport { AppRouter } from './components';\n\n// ============================================================================\n// Contexts\n// ============================================================================\n\nexport { RouteParamsProvider, RouteParamsContext } from './contexts/RouteParamsContext';\nexport type { RouteParams, RouteParamsProviderProps } from './contexts/RouteParamsContext';\n\n// ============================================================================\n// Type Exports\n// ============================================================================\n\nexport type {\n HAI3ProviderProps,\n RouterType,\n RouterConfig,\n UseHAI3Return,\n UseAppSelector,\n UseAppDispatchReturn,\n UseTranslationReturn,\n UseScreenTranslationsReturn,\n UseLanguageReturn,\n UseThemeReturn,\n UseMenuReturn,\n UseScreenReturn,\n UseNavigationReturn,\n UseScreensetReturn,\n UsePopupReturn,\n UseOverlayReturn,\n AppRouterProps,\n HAI3ProviderComponent,\n AppRouterComponent,\n} from './types';\n\n// ============================================================================\n// Re-exports from @hai3/framework for convenience\n// ============================================================================\n\n// These re-exports allow users to import everything from @hai3/react\n// without needing to import from @hai3/framework directly\n\nexport {\n // Core\n createHAI3,\n createHAI3App,\n presets,\n\n // Backward compatibility singletons\n screensetRegistry,\n\n // Backward compatibility constants\n ACCOUNTS_DOMAIN,\n\n // I18nRegistry class (capital I for backward compat)\n I18nRegistry,\n\n // Plugins\n screensets,\n themes,\n layout,\n navigation,\n routing,\n i18n,\n effects,\n\n // Registries\n createScreensetRegistry,\n createThemeRegistry,\n createRouteRegistry,\n\n // Flux (Event bus + Store)\n // NOTE: eventBus is re-exported separately below with augmented EventPayloadMap type\n\n // Store\n createStore,\n getStore,\n registerSlice,\n hasSlice,\n createSlice,\n\n // Layout domain exports\n LayoutDomain,\n ScreensetCategory,\n layoutReducer,\n layoutDomainReducers,\n LAYOUT_SLICE_NAME,\n headerSlice,\n footerSlice,\n menuSlice,\n sidebarSlice,\n screenSlice,\n popupSlice,\n overlaySlice,\n headerActions,\n footerActions,\n menuActions,\n sidebarActions,\n screenActions,\n popupActions,\n overlayActions,\n // Individual reducer functions - header\n setUser,\n setHeaderLoading,\n clearUser,\n // Individual reducer functions - footer\n setFooterVisible,\n setFooterConfig,\n toggleMenu,\n setMenuCollapsed,\n setMenuItems,\n setMenuVisible,\n setMenuConfig,\n toggleSidebar,\n setSidebarCollapsed,\n setSidebarPosition,\n setSidebarTitle,\n setSidebarContent,\n setSidebarVisible,\n setSidebarWidth,\n setSidebarConfig,\n setActiveScreen,\n setScreenLoading,\n navigateTo,\n clearActiveScreen,\n openPopup,\n closePopup,\n closeTopPopup,\n closeAllPopups,\n showOverlay,\n hideOverlay,\n setOverlayVisible,\n\n // Tenant (app-level, not layout)\n TENANT_SLICE_NAME,\n tenantSlice,\n tenantActions,\n tenantReducer,\n setTenant,\n setTenantLoading,\n clearTenant,\n // Tenant effects and events\n initTenantEffects,\n changeTenant,\n clearTenantAction,\n setTenantLoadingState,\n TenantEvents,\n\n // Mock (app-level, not layout)\n mockSlice,\n mockActions,\n setMockEnabled,\n // Mock effects and events\n initMockEffects,\n toggleMockMode,\n MockEvents,\n\n // API\n apiRegistry,\n BaseApiService,\n RestProtocol,\n SseProtocol,\n // Protocol-specific mock plugins (replaces generic MockPlugin)\n RestMockPlugin,\n SseMockPlugin,\n MockEventSource,\n // Plugin base classes\n ApiPluginBase,\n ApiPlugin,\n ApiProtocol,\n RestPlugin,\n RestPluginWithConfig,\n SsePlugin,\n SsePluginWithConfig,\n // Type guards\n isShortCircuit,\n isRestShortCircuit,\n isSseShortCircuit,\n // Mock plugin identification\n MOCK_PLUGIN,\n isMockPlugin,\n\n // I18n\n i18nRegistry,\n I18nRegistryImpl,\n createI18nRegistry,\n SUPPORTED_LANGUAGES,\n getLanguageMetadata,\n} from '@hai3/framework';\n\n// Re-export i18n types from @hai3/framework (correct layer access)\nexport { Language, TextDirection, LanguageDisplayMode } from '@hai3/framework';\n\n// Re-export types from @hai3/framework\nexport type {\n // Config\n HAI3Config,\n HAI3Plugin,\n HAI3AppBuilder,\n HAI3App,\n PluginFactory,\n PluginProvides,\n PluginLifecycle,\n ScreensetRegistry,\n ThemeRegistry,\n ThemeConfig,\n RouteRegistry,\n Preset,\n Presets,\n ScreensetsConfig,\n NavigateToScreenPayload,\n NavigateToScreensetPayload,\n ShowPopupPayload,\n ChangeThemePayload,\n SetLanguagePayload,\n\n // Flux (Events + Store)\n EventHandler,\n Subscription,\n\n // Store\n RootState,\n AppDispatch,\n SliceObject,\n HAI3Store,\n\n // Layout\n ScreensetId,\n ScreenId,\n MenuItemConfig,\n ScreenLoader,\n ScreenConfig,\n MenuScreenItem,\n ScreensetDefinition,\n LayoutDomainState,\n HeaderUser,\n HeaderConfig,\n HeaderState,\n FooterConfig,\n FooterState,\n MenuItem,\n MenuState,\n SidebarPosition,\n SidebarState,\n ScreenState,\n PopupConfig,\n PopupState,\n PopupSliceState,\n OverlayConfig,\n OverlayState,\n LayoutState,\n RootStateWithLayout,\n LayoutDomainReducers,\n\n // Tenant types\n Tenant,\n TenantState,\n TenantChangedPayload,\n TenantClearedPayload,\n\n // Mock types\n MockState,\n MockTogglePayload,\n\n // API\n MockMap,\n ApiServiceConfig,\n JsonValue,\n JsonObject,\n JsonPrimitive,\n JsonCompatible,\n SseProtocolConfig,\n RestProtocolConfig,\n // Plugin context types (class-based plugin system)\n ApiRequestContext,\n ApiResponseContext,\n ShortCircuitResponse,\n PluginClass,\n ProtocolClass,\n ProtocolPluginType,\n BasePluginHooks,\n // Protocol-specific types\n RestPluginHooks,\n SsePluginHooks,\n RestRequestContext,\n RestResponseContext,\n ApiPluginErrorContext,\n SseConnectContext,\n EventSourceLike,\n RestShortCircuitResponse,\n SseShortCircuitResponse,\n RestMockConfig,\n SseMockConfig,\n SseMockEvent,\n\n // Backward compatibility type aliases\n ScreensetConfig,\n\n // Theme types\n ThemeApplyFn,\n UikitTheme,\n\n // I18n\n I18nConfig,\n TranslationLoader,\n TranslationMap,\n TranslationDictionary,\n LanguageMetadata,\n I18nRegistryType,\n} from '@hai3/framework';\n\n// ============================================================================\n// Module Augmentation Support - EventPayloadMap Re-declaration\n// ============================================================================\n\n/**\n * Re-declare EventPayloadMap to enable module augmentation on @hai3/react\n *\n * This creates a new declaration site in @hai3/react that TypeScript can augment.\n * App-layer code can now use `declare module '@hai3/react'` instead of importing\n * from L1 packages directly, maintaining proper layer architecture.\n *\n * ARCHITECTURE: This pattern allows L3+ code to augment event types without\n * violating layer boundaries by importing from L1 (@hai3/state).\n *\n * IMPORTANT: We must also re-export eventBus with the augmented type to ensure\n * type safety. The eventBus instance uses this augmented EventPayloadMap.\n *\n * @example\n * ```typescript\n * // In app-layer code (e.g., src/app/events/bootstrapEvents.ts)\n * import '@hai3/react';\n *\n * declare module '@hai3/react' {\n * interface EventPayloadMap {\n * 'app/user/fetch': void;\n * 'app/user/loaded': { user: ApiUser };\n * }\n * }\n * ```\n */\nimport type { EventPayloadMap as FrameworkEventPayloadMap } from '@hai3/framework';\nimport type { EventBus } from '@hai3/state';\nimport { eventBus as frameworkEventBus } from '@hai3/framework';\n\nexport interface EventPayloadMap extends FrameworkEventPayloadMap {}\n\n/**\n * Re-export eventBus with augmented EventPayloadMap type.\n * This ensures that code importing eventBus from @hai3/react gets\n * type-safe access to both framework events and app-layer augmented events.\n */\nexport const eventBus: EventBus<EventPayloadMap> = frameworkEventBus as EventBus<EventPayloadMap>;\n","/**\n * HAI3 Provider - Main provider component for HAI3 applications\n *\n * React Layer: L3 (Depends on @hai3/framework)\n */\n\nimport React, { useMemo, useEffect } from 'react';\nimport { Provider as ReduxProvider } from 'react-redux';\nimport { createHAI3App } from '@hai3/framework';\nimport type { HAI3App } from '@hai3/framework';\nimport { HAI3Context } from './HAI3Context';\nimport type { HAI3ProviderProps } from './types';\n\n/**\n * HAI3 Provider Component\n *\n * Provides the HAI3 application context to all child components.\n * Creates the HAI3 app instance with the full preset by default.\n *\n * @example\n * ```tsx\n * // Default - creates app with full preset\n * <HAI3Provider>\n * <App />\n * </HAI3Provider>\n *\n * // With configuration\n * <HAI3Provider config={{ devMode: true }}>\n * <App />\n * </HAI3Provider>\n *\n * // With pre-built app\n * const app = createHAI3().use(screensets()).build();\n * <HAI3Provider app={app}>\n * <App />\n * </HAI3Provider>\n * ```\n */\nexport const HAI3Provider: React.FC<HAI3ProviderProps> = ({\n children,\n config,\n app: providedApp,\n router,\n}) => {\n // Create or use provided app instance\n const app = useMemo<HAI3App>(() => {\n if (providedApp) {\n return providedApp;\n }\n\n // Merge router config into HAI3Config\n const mergedConfig = {\n ...config,\n routerMode: router?.type,\n autoNavigate: router?.autoNavigate ?? config?.autoNavigate,\n };\n\n return createHAI3App(mergedConfig);\n }, [providedApp, config, router]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n // Only destroy if we created the app (not provided)\n if (!providedApp) {\n app.destroy();\n }\n };\n }, [app, providedApp]);\n\n return (\n <HAI3Context.Provider value={app}>\n <ReduxProvider store={app.store as Parameters<typeof ReduxProvider>[0]['store']}>\n {children}\n </ReduxProvider>\n </HAI3Context.Provider>\n );\n};\n","/**\n * HAI3 Context - React context for HAI3 application\n *\n * React Layer: L3 (Depends on @hai3/framework)\n */\n\nimport { createContext, useContext } from 'react';\nimport type { HAI3App } from '@hai3/framework';\n\n// ============================================================================\n// Context Definition\n// ============================================================================\n\n/**\n * HAI3 Context\n * Holds the HAI3 app instance for the application.\n */\nexport const HAI3Context = createContext<HAI3App | null>(null);\n\n/**\n * Use the HAI3 context.\n * Throws if used outside of HAI3Provider.\n *\n * @returns The HAI3 app instance\n */\nexport function useHAI3(): HAI3App {\n const context = useContext(HAI3Context);\n\n if (!context) {\n throw new Error(\n 'useHAI3 must be used within a HAI3Provider. ' +\n 'Wrap your application with <HAI3Provider> to access HAI3 features.'\n );\n }\n\n return context;\n}\n","/**\n * useAppDispatch Hook - Type-safe dispatch hook\n *\n * React Layer: L3\n */\n\nimport { useDispatch } from 'react-redux';\nimport type { AppDispatch } from '@hai3/framework';\n\n/**\n * Type-safe dispatch hook.\n *\n * @returns The typed dispatch function\n *\n * @example\n * ```tsx\n * const dispatch = useAppDispatch();\n * dispatch(someAction());\n * ```\n */\nexport function useAppDispatch(): AppDispatch {\n // Use untyped useDispatch and cast the result\n // This avoids type constraint issues with react-redux's generic\n return useDispatch() as AppDispatch;\n}\n","/**\n * useAppSelector Hook - Type-safe selector hook\n *\n * React Layer: L3\n */\n\nimport { useSelector, type TypedUseSelectorHook } from 'react-redux';\nimport type { RootState } from '@hai3/framework';\n\n/**\n * Type-safe selector hook.\n *\n * @example\n * ```tsx\n * const activeScreen = useAppSelector(selectActiveScreen);\n * const menuCollapsed = useAppSelector(selectMenuCollapsed);\n * ```\n */\nexport const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;\n","/**\n * useTranslation Hook - Translation utilities\n *\n * React Layer: L3\n */\n\nimport { useMemo, useCallback, useSyncExternalStore } from 'react';\nimport type { Language } from '@hai3/framework';\nimport { useHAI3 } from '../HAI3Context';\nimport type { UseTranslationReturn } from '../types';\n\n/**\n * Hook for accessing translation utilities.\n *\n * @returns Translation utilities\n *\n * @example\n * ```tsx\n * const { t, language, setLanguage, isRTL } = useTranslation();\n *\n * return (\n * <div dir={isRTL ? 'rtl' : 'ltr'}>\n * <h1>{t('common:app.title')}</h1>\n * <p>{t('common:app.welcome', { name: 'John' })}</p>\n * </div>\n * );\n * ```\n */\nexport function useTranslation(): UseTranslationReturn {\n const app = useHAI3();\n const { i18nRegistry } = app;\n\n // Subscribe to translation changes using useSyncExternalStore\n // Uses version counter to trigger re-renders when translations change\n const version = useSyncExternalStore(\n useCallback(\n (callback: () => void) => {\n // Subscribe to translation changes (new translations registered)\n return i18nRegistry.subscribe(callback);\n },\n [i18nRegistry]\n ),\n () => i18nRegistry.getVersion(),\n () => i18nRegistry.getVersion()\n );\n\n // Get current language (memoized to avoid unnecessary recalculations)\n // version is used to trigger recalculation when translations change\n const language = useMemo(() => {\n void version; // Trigger recalculation when version changes\n return i18nRegistry.getLanguage();\n }, [i18nRegistry, version]);\n\n // Translation function\n const t = useCallback(\n (key: string, params?: Record<string, string | number | boolean>) => {\n return i18nRegistry.t(key, params);\n },\n [i18nRegistry]\n );\n\n // Set language function\n const setLanguage = useCallback(\n async (lang: Language) => {\n await i18nRegistry.setLanguage(lang);\n },\n [i18nRegistry]\n );\n\n // Check RTL - recomputes when language changes\n const isRTL = useMemo(() => {\n // Reference language to trigger recalculation on language change\n void language;\n return i18nRegistry.isRTL();\n }, [i18nRegistry, language]);\n\n return {\n t,\n language,\n setLanguage,\n isRTL,\n };\n}\n","/**\n * useScreenTranslations Hook - Screen-level translation loading\n *\n * React Layer: L3\n */\n\nimport { useState, useEffect, useMemo, useCallback, useSyncExternalStore } from 'react';\nimport type { TranslationMap, TranslationLoader } from '@hai3/framework';\nimport { useHAI3 } from '../HAI3Context';\nimport type { UseScreenTranslationsReturn } from '../types';\n\n// Re-export TranslationMap for consumers who need it\nexport type { TranslationMap };\n\n/**\n * Check if the input is a TranslationLoader function (from I18nRegistry.createLoader)\n * vs a TranslationMap object\n */\nfunction isTranslationLoader(\n input: TranslationMap | TranslationLoader\n): input is TranslationLoader {\n return typeof input === 'function';\n}\n\n/**\n * Hook for loading screen-level translations.\n * Use this in screen components to lazy-load translations.\n * Automatically reloads translations when language changes.\n *\n * @param screensetId - The screenset ID\n * @param screenId - The screen ID\n * @param translations - Either a TranslationMap object or a TranslationLoader function\n * (from I18nRegistry.createLoader)\n * @returns Loading state\n *\n * @example\n * ```tsx\n * // Option 1: Using I18nRegistry.createLoader (recommended)\n * const translations = I18nRegistry.createLoader({\n * en: () => import('./i18n/en.json'),\n * es: () => import('./i18n/es.json'),\n * });\n *\n * // Option 2: Using raw TranslationMap\n * const translations = {\n * en: () => import('./i18n/en.json'),\n * es: () => import('./i18n/es.json'),\n * };\n *\n * export const HomeScreen: React.FC = () => {\n * const { isLoaded, error } = useScreenTranslations(\n * 'demo',\n * 'home',\n * translations\n * );\n *\n * if (!isLoaded) return <LoadingSpinner />;\n * if (error) return <ErrorMessage error={error} />;\n *\n * return <div>...</div>;\n * };\n * ```\n */\nexport function useScreenTranslations(\n screensetId: string,\n screenId: string,\n translations: TranslationMap | TranslationLoader\n): UseScreenTranslationsReturn {\n const app = useHAI3();\n const { i18nRegistry } = app;\n\n // Track loading state per language to handle language changes\n const [loadedLanguage, setLoadedLanguage] = useState<string | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n // Subscribe to translation changes using useSyncExternalStore\n // This ensures we reload when language changes\n const version = useSyncExternalStore(\n useCallback(\n (callback: () => void) => i18nRegistry.subscribe(callback),\n [i18nRegistry]\n ),\n () => i18nRegistry.getVersion(),\n () => i18nRegistry.getVersion()\n );\n\n // Get current language (changes when version changes)\n // version is used to trigger recalculation when translations change\n const currentLanguage = useMemo(() => {\n void version; // Trigger recalculation when version changes\n return i18nRegistry.getLanguage();\n }, [i18nRegistry, version]);\n\n // Create a TranslationLoader function from the translation map or use directly if already a loader\n const loader: TranslationLoader = useMemo(() => {\n if (isTranslationLoader(translations)) {\n // Already a loader function (from I18nRegistry.createLoader)\n return translations;\n }\n\n // Convert TranslationMap to TranslationLoader\n return async (language: string) => {\n const importFn = translations[language as keyof typeof translations];\n if (!importFn) {\n // Return empty dictionary if language not in map\n return {};\n }\n const module = await importFn();\n return module.default;\n };\n }, [translations]);\n\n useEffect(() => {\n // Skip if no language or already loaded for this language\n if (!currentLanguage || currentLanguage === loadedLanguage) {\n return;\n }\n\n let cancelled = false;\n setIsLoading(true);\n\n const loadTranslations = async () => {\n try {\n const namespace = `screen.${screensetId}.${screenId}`;\n\n // Register the loader for future language changes\n i18nRegistry.registerLoader(namespace, loader);\n\n // Actually load the translations for current language\n const loadedTranslations = await loader(currentLanguage);\n i18nRegistry.register(namespace, currentLanguage, loadedTranslations);\n\n if (!cancelled) {\n setLoadedLanguage(currentLanguage);\n setIsLoading(false);\n setError(null);\n }\n } catch (err) {\n if (!cancelled) {\n setError(err instanceof Error ? err : new Error(String(err)));\n setIsLoading(false);\n }\n }\n };\n\n loadTranslations();\n\n return () => {\n cancelled = true;\n };\n }, [screensetId, screenId, loader, i18nRegistry, currentLanguage, loadedLanguage]);\n\n // Derive isLoaded from whether we've loaded translations for the current language\n const isLoaded = currentLanguage !== null && currentLanguage === loadedLanguage && !isLoading;\n\n return { isLoaded, error };\n}\n","/**\n * useNavigation Hook - Navigation utilities\n *\n * React Layer: L3\n */\n\nimport { useCallback } from 'react';\nimport { useHAI3 } from '../HAI3Context';\nimport { useAppSelector } from './useAppSelector';\nimport type { RootStateWithLayout } from '@hai3/framework';\nimport type { UseNavigationReturn } from '../types';\n\n/**\n * Hook for navigation utilities.\n *\n * @returns Navigation utilities\n *\n * @example\n * ```tsx\n * const { navigateToScreen, navigateToScreenset, currentScreen } = useNavigation();\n *\n * // Navigate to a simple screen\n * return (\n * <button onClick={() => navigateToScreen('demo', 'home')}>\n * Go to Home\n * </button>\n * );\n *\n * // Navigate to a parameterized screen\n * return (\n * <button onClick={() => navigateToScreen('demo', 'user-detail', { id: '123' })}>\n * View User 123\n * </button>\n * );\n * ```\n */\nexport function useNavigation(): UseNavigationReturn {\n const app = useHAI3();\n // Access state directly via useAppSelector - no selectors needed\n // Layout slices use flat keys like 'layout/screen', not nested 'layout.screen'\n const currentScreen = useAppSelector(\n (state) => {\n // Try flat key first (current SDK architecture)\n const flatKey = state as Record<string, { activeScreen?: string | null }>;\n if (flatKey['layout/screen']) {\n return flatKey['layout/screen'].activeScreen ?? null;\n }\n // Fallback to nested structure (for backward compatibility)\n const nested = state as unknown as RootStateWithLayout;\n return nested.layout?.screen?.activeScreen ?? null;\n }\n );\n\n // Navigate to a specific screen, optionally with route params\n const navigateToScreen = useCallback(\n (screensetId: string, screenId: string, params?: Record<string, string>) => {\n if (app.actions.navigateToScreen) {\n app.actions.navigateToScreen({ screensetId, screenId, params });\n }\n },\n [app.actions]\n );\n\n // Navigate to a screenset (uses default screen)\n const navigateToScreenset = useCallback(\n (screensetId: string) => {\n if (app.actions.navigateToScreenset) {\n app.actions.navigateToScreenset({ screensetId });\n }\n },\n [app.actions]\n );\n\n /**\n * Derived state: screenset looked up from currentScreen via routeRegistry.\n * Single source of truth (Redux), automatic reactivity.\n */\n const currentScreenset = currentScreen\n ? app.routeRegistry?.getScreensetForScreen(currentScreen) ?? null\n : null;\n\n return {\n navigateToScreen,\n navigateToScreenset,\n currentScreenset,\n currentScreen,\n };\n}\n","/**\n * Route Params Context\n *\n * Provides route parameters to screen components via React context.\n *\n * React Layer: L3\n */\n\nimport { createContext, useContext, type ReactNode } from 'react';\n\n/**\n * Route params type\n */\nexport type RouteParams = Record<string, string>;\n\n/**\n * Route params context\n */\nconst RouteParamsContext = createContext<RouteParams>({});\n\n/**\n * Route params provider props\n */\nexport interface RouteParamsProviderProps {\n params: RouteParams;\n children: ReactNode;\n}\n\n/**\n * Route params provider component\n */\nexport function RouteParamsProvider({ params, children }: RouteParamsProviderProps): JSX.Element {\n return (\n <RouteParamsContext.Provider value={params}>\n {children}\n </RouteParamsContext.Provider>\n );\n}\n\n/**\n * Hook to access route params from context\n */\nexport function useRouteParamsContext(): RouteParams {\n return useContext(RouteParamsContext);\n}\n\nexport { RouteParamsContext };\n","/**\n * useRouteParams Hook\n *\n * Provides access to route parameters from the current URL.\n * Supports type-safe route params via module augmentation.\n *\n * React Layer: L3\n *\n * @example\n * ```tsx\n * import { useRouteParams } from '@hai3/react';\n *\n * // Basic usage (no type safety)\n * const UserDetailScreen: React.FC = () => {\n * const params = useRouteParams();\n * // params: Record<string, string>\n *\n * return <div>User ID: {params.id}</div>;\n * };\n *\n * // Type-safe usage with module augmentation\n * // First, declare the route params in your app:\n * // declare module '@hai3/framework' {\n * // interface RouteParams {\n * // 'user-detail': { userId: string };\n * // }\n * // }\n *\n * const UserDetailScreen: React.FC = () => {\n * const params = useRouteParams<'user-detail'>();\n * // params: { userId: string } - fully typed!\n *\n * return <div>User ID: {params.userId}</div>;\n * };\n * ```\n */\n\nimport { useRouteParamsContext } from '../contexts/RouteParamsContext';\nimport type { RouteParams as FrameworkRouteParams } from '@hai3/framework';\n\n/**\n * Hook to access route parameters from the current URL.\n * \n * @template TScreenId - Optional screen ID for type-safe route params\n * @returns Route parameters, optionally typed based on screen ID\n */\nexport function useRouteParams<TScreenId extends keyof FrameworkRouteParams = string>(): TScreenId extends keyof FrameworkRouteParams \n ? FrameworkRouteParams[TScreenId] \n : Record<string, string> {\n return useRouteParamsContext() as TScreenId extends keyof FrameworkRouteParams \n ? FrameworkRouteParams[TScreenId] \n : Record<string, string>;\n}\n","/**\n * useTheme Hook - Theme utilities\n *\n * React Layer: L3\n */\n\nimport { useCallback, useMemo, useSyncExternalStore } from 'react';\nimport { useHAI3 } from '../HAI3Context';\nimport type { UseThemeReturn } from '../types';\n\n/**\n * Hook for theme utilities.\n *\n * @returns Theme utilities\n *\n * @example\n * ```tsx\n * const { currentTheme, themes, setTheme } = useTheme();\n *\n * return (\n * <select\n * value={currentTheme}\n * onChange={(e) => setTheme(e.target.value)}\n * >\n * {themes.map((theme) => (\n * <option key={theme.id} value={theme.id}>\n * {theme.name}\n * </option>\n * ))}\n * </select>\n * );\n * ```\n */\nexport function useTheme(): UseThemeReturn {\n const app = useHAI3();\n const { themeRegistry } = app;\n\n // Subscribe to theme changes using useSyncExternalStore\n // Uses version counter to trigger re-renders when theme changes\n const version = useSyncExternalStore(\n useCallback(\n (callback: () => void) => {\n return themeRegistry.subscribe(callback);\n },\n [themeRegistry]\n ),\n () => themeRegistry.getVersion(),\n () => themeRegistry.getVersion()\n );\n\n // Get current theme (memoized, recalculates on version change)\n const currentTheme = useMemo(() => {\n // Reference version to trigger recalculation on theme change\n void version;\n const theme = themeRegistry.getCurrent();\n return theme?.id;\n }, [themeRegistry, version]);\n\n // Get all themes\n const themes = useMemo(() => {\n return themeRegistry.getAll().map((theme) => ({\n id: theme.id,\n name: theme.name,\n }));\n }, [themeRegistry]);\n\n // Set theme\n const setTheme = useCallback(\n (themeId: string) => {\n if (app.actions.changeTheme) {\n app.actions.changeTheme({ themeId });\n }\n },\n [app.actions]\n );\n\n return {\n currentTheme,\n themes,\n setTheme,\n };\n}\n","/**\n * AppRouter Component - Renders the active screen\n *\n * React Layer: L3\n */\n\nimport React, { Suspense, useState, useEffect } from 'react';\nimport { useHAI3 } from '../HAI3Context';\nimport { useNavigation } from '../hooks/useNavigation';\nimport { RouteParamsProvider, type RouteParams } from '../contexts/RouteParamsContext';\nimport type { AppRouterProps } from '../types';\n\n/**\n * AppRouter Component\n *\n * Renders the currently active screen based on navigation state.\n * Handles lazy loading and error boundaries.\n *\n * @example\n * ```tsx\n * <HAI3Provider>\n * <Layout>\n * <AppRouter\n * fallback={<LoadingSpinner />}\n * errorFallback={(error) => <ErrorPage error={error} />}\n * />\n * </Layout>\n * </HAI3Provider>\n * ```\n */\nexport const AppRouter: React.FC<AppRouterProps> = ({\n fallback = null,\n errorFallback,\n}) => {\n const app = useHAI3();\n const { currentScreenset, currentScreen } = useNavigation();\n const [ScreenComponent, setScreenComponent] = useState<React.ComponentType | null>(null);\n const [error, setError] = useState<Error | null>(null);\n\n // Extract route params synchronously from current URL to avoid race condition\n // This ensures params are available on first render\n const [routeParams, setRouteParams] = useState<RouteParams>(() => {\n if (typeof window === 'undefined') {\n return {};\n }\n const pathname = window.location.pathname;\n const base = app.config.base || '';\n const internalPath = base && pathname.startsWith(base)\n ? pathname.slice(base.length) || '/'\n : pathname;\n const match = app.routeRegistry?.matchRoute(internalPath);\n return match?.params ?? {};\n });\n\n // Update route params when navigation changes (browser back/forward or programmatic navigation)\n useEffect(() => {\n if (typeof window === 'undefined') {\n return;\n }\n const pathname = window.location.pathname;\n const base = app.config.base || '';\n const internalPath = base && pathname.startsWith(base)\n ? pathname.slice(base.length) || '/'\n : pathname;\n const match = app.routeRegistry?.matchRoute(internalPath);\n setRouteParams(match?.params ?? {});\n }, [app.config.base, app.routeRegistry, currentScreen]);\n\n useEffect(() => {\n let cancelled = false;\n\n const loadScreen = async () => {\n if (!currentScreenset || !currentScreen) {\n setScreenComponent(null);\n return;\n }\n\n try {\n // Get screen loader from route registry\n const loader = app.routeRegistry.getScreen(currentScreenset, currentScreen);\n\n if (!loader) {\n throw new Error(\n `Screen \"${currentScreen}\" not found in screenset \"${currentScreenset}\".`\n );\n }\n\n // Load the screen component\n const module = await loader();\n\n if (!cancelled) {\n setScreenComponent(() => module.default);\n setError(null);\n }\n } catch (err) {\n if (!cancelled) {\n setError(err instanceof Error ? err : new Error(String(err)));\n setScreenComponent(null);\n }\n }\n };\n\n loadScreen();\n\n return () => {\n cancelled = true;\n };\n }, [currentScreenset, currentScreen, app.routeRegistry]);\n\n // Handle error state\n if (error) {\n if (errorFallback) {\n if (typeof errorFallback === 'function') {\n return <>{errorFallback(error)}</>;\n }\n return <>{errorFallback}</>;\n }\n // Default error display\n return (\n <div className=\"p-5 text-destructive\">\n <h2>Error loading screen</h2>\n <p>{error.message}</p>\n </div>\n );\n }\n\n // Handle loading state\n if (!ScreenComponent) {\n return <>{fallback}</>;\n }\n\n // Render the screen component wrapped with route params context\n return (\n <RouteParamsProvider params={routeParams}>\n <Suspense fallback={fallback}>\n <ScreenComponent />\n </Suspense>\n </RouteParamsProvider>\n );\n};\n"],"mappings":"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","names":["import_react","ReduxProvider","import_react_redux","import_react_redux","import_react","i18nRegistry","import_react","i18nRegistry","module","import_react","import_react","import_jsx_runtime","import_react","themes","import_react","import_jsx_runtime","module","import_framework","frameworkEventBus"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import React__default from 'react';
|
|
2
|
+
import React__default, { ReactNode } from 'react';
|
|
3
3
|
import { HAI3ProviderProps, UseTranslationReturn, UseScreenTranslationsReturn, UseNavigationReturn, UseThemeReturn, AppRouterProps } from './types.cjs';
|
|
4
|
-
export { AppRouterComponent, HAI3ProviderComponent, UseAppDispatchReturn, UseAppSelector, UseHAI3Return, UseLanguageReturn, UseMenuReturn, UseOverlayReturn, UsePopupReturn, UseScreenReturn, UseScreensetReturn } from './types.cjs';
|
|
5
|
-
import { HAI3App, AppDispatch, RootState, TranslationMap, TranslationLoader } from '@hai3/framework';
|
|
6
|
-
export { ACCOUNTS_DOMAIN, ApiPlugin, ApiPluginBase, ApiPluginErrorContext, ApiProtocol, ApiRequestContext, ApiResponseContext, ApiServiceConfig, AppDispatch, BaseApiService, BasePluginHooks, ChangeThemePayload, EventHandler,
|
|
4
|
+
export { AppRouterComponent, HAI3ProviderComponent, RouterConfig, RouterType, UseAppDispatchReturn, UseAppSelector, UseHAI3Return, UseLanguageReturn, UseMenuReturn, UseOverlayReturn, UsePopupReturn, UseScreenReturn, UseScreensetReturn } from './types.cjs';
|
|
5
|
+
import { HAI3App, AppDispatch, RootState, TranslationMap, TranslationLoader, RouteParams as RouteParams$1, EventPayloadMap as EventPayloadMap$1 } from '@hai3/framework';
|
|
6
|
+
export { ACCOUNTS_DOMAIN, ApiPlugin, ApiPluginBase, ApiPluginErrorContext, ApiProtocol, ApiRequestContext, ApiResponseContext, ApiServiceConfig, AppDispatch, BaseApiService, BasePluginHooks, ChangeThemePayload, EventHandler, EventSourceLike, FooterConfig, FooterState, HAI3App, HAI3AppBuilder, HAI3Config, HAI3Plugin, HAI3Store, HeaderConfig, HeaderState, HeaderUser, I18nConfig, I18nRegistry, I18nRegistryImpl, I18nRegistryType, JsonCompatible, JsonObject, JsonPrimitive, JsonValue, LAYOUT_SLICE_NAME, Language, LanguageDisplayMode, LanguageMetadata, LayoutDomain, LayoutDomainReducers, LayoutDomainState, LayoutState, MOCK_PLUGIN, MenuItem, MenuItemConfig, MenuScreenItem, MenuState, MockEventSource, MockEvents, MockMap, MockState, MockTogglePayload, NavigateToScreenPayload, NavigateToScreensetPayload, OverlayConfig, OverlayState, PluginClass, PluginFactory, PluginLifecycle, PluginProvides, PopupConfig, PopupSliceState, PopupState, Preset, Presets, ProtocolClass, ProtocolPluginType, RestMockConfig, RestMockPlugin, RestPlugin, RestPluginHooks, RestPluginWithConfig, RestProtocol, RestProtocolConfig, RestRequestContext, RestResponseContext, RestShortCircuitResponse, RootState, RootStateWithLayout, RouteRegistry, SUPPORTED_LANGUAGES, ScreenConfig, ScreenId, ScreenLoader, ScreenState, ScreensetCategory, ScreensetConfig, ScreensetDefinition, ScreensetId, ScreensetRegistry, ScreensetsConfig, SetLanguagePayload, ShortCircuitResponse, ShowPopupPayload, SidebarPosition, SidebarState, SliceObject, SseConnectContext, SseMockConfig, SseMockEvent, SseMockPlugin, SsePlugin, SsePluginHooks, SsePluginWithConfig, SseProtocol, SseProtocolConfig, SseShortCircuitResponse, Subscription, TENANT_SLICE_NAME, Tenant, TenantChangedPayload, TenantClearedPayload, TenantEvents, TenantState, TextDirection, ThemeApplyFn, ThemeConfig, ThemeRegistry, TranslationDictionary, TranslationLoader, TranslationMap, UikitTheme, apiRegistry, changeTenant, clearActiveScreen, clearTenant, clearTenantAction, clearUser, closeAllPopups, closePopup, closeTopPopup, createHAI3, createHAI3App, createI18nRegistry, createRouteRegistry, createScreensetRegistry, createSlice, createStore, createThemeRegistry, effects, footerActions, footerSlice, getLanguageMetadata, getStore, hasSlice, headerActions, headerSlice, hideOverlay, i18n, i18nRegistry, initMockEffects, initTenantEffects, isMockPlugin, isRestShortCircuit, isShortCircuit, isSseShortCircuit, layout, layoutDomainReducers, layoutReducer, menuActions, menuSlice, mockActions, mockSlice, navigateTo, navigation, openPopup, overlayActions, overlaySlice, popupActions, popupSlice, presets, registerSlice, routing, screenActions, screenSlice, screensetRegistry, screensets, setActiveScreen, setFooterConfig, setFooterVisible, setHeaderLoading, setMenuCollapsed, setMenuConfig, setMenuItems, setMenuVisible, setMockEnabled, setOverlayVisible, setScreenLoading, setSidebarCollapsed, setSidebarConfig, setSidebarContent, setSidebarPosition, setSidebarTitle, setSidebarVisible, setSidebarWidth, setTenant, setTenantLoading, setTenantLoadingState, setUser, showOverlay, sidebarActions, sidebarSlice, tenantActions, tenantReducer, tenantSlice, themes, toggleMenu, toggleMockMode, toggleSidebar } from '@hai3/framework';
|
|
7
7
|
import { TypedUseSelectorHook } from 'react-redux';
|
|
8
|
+
import { EventBus } from '@hai3/state';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* HAI3 Provider - Main provider component for HAI3 applications
|
|
@@ -175,15 +176,68 @@ declare function useScreenTranslations(screensetId: string, screenId: string, tr
|
|
|
175
176
|
* ```tsx
|
|
176
177
|
* const { navigateToScreen, navigateToScreenset, currentScreen } = useNavigation();
|
|
177
178
|
*
|
|
179
|
+
* // Navigate to a simple screen
|
|
178
180
|
* return (
|
|
179
181
|
* <button onClick={() => navigateToScreen('demo', 'home')}>
|
|
180
182
|
* Go to Home
|
|
181
183
|
* </button>
|
|
182
184
|
* );
|
|
185
|
+
*
|
|
186
|
+
* // Navigate to a parameterized screen
|
|
187
|
+
* return (
|
|
188
|
+
* <button onClick={() => navigateToScreen('demo', 'user-detail', { id: '123' })}>
|
|
189
|
+
* View User 123
|
|
190
|
+
* </button>
|
|
191
|
+
* );
|
|
183
192
|
* ```
|
|
184
193
|
*/
|
|
185
194
|
declare function useNavigation(): UseNavigationReturn;
|
|
186
195
|
|
|
196
|
+
/**
|
|
197
|
+
* useRouteParams Hook
|
|
198
|
+
*
|
|
199
|
+
* Provides access to route parameters from the current URL.
|
|
200
|
+
* Supports type-safe route params via module augmentation.
|
|
201
|
+
*
|
|
202
|
+
* React Layer: L3
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* ```tsx
|
|
206
|
+
* import { useRouteParams } from '@hai3/react';
|
|
207
|
+
*
|
|
208
|
+
* // Basic usage (no type safety)
|
|
209
|
+
* const UserDetailScreen: React.FC = () => {
|
|
210
|
+
* const params = useRouteParams();
|
|
211
|
+
* // params: Record<string, string>
|
|
212
|
+
*
|
|
213
|
+
* return <div>User ID: {params.id}</div>;
|
|
214
|
+
* };
|
|
215
|
+
*
|
|
216
|
+
* // Type-safe usage with module augmentation
|
|
217
|
+
* // First, declare the route params in your app:
|
|
218
|
+
* // declare module '@hai3/framework' {
|
|
219
|
+
* // interface RouteParams {
|
|
220
|
+
* // 'user-detail': { userId: string };
|
|
221
|
+
* // }
|
|
222
|
+
* // }
|
|
223
|
+
*
|
|
224
|
+
* const UserDetailScreen: React.FC = () => {
|
|
225
|
+
* const params = useRouteParams<'user-detail'>();
|
|
226
|
+
* // params: { userId: string } - fully typed!
|
|
227
|
+
*
|
|
228
|
+
* return <div>User ID: {params.userId}</div>;
|
|
229
|
+
* };
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Hook to access route parameters from the current URL.
|
|
235
|
+
*
|
|
236
|
+
* @template TScreenId - Optional screen ID for type-safe route params
|
|
237
|
+
* @returns Route parameters, optionally typed based on screen ID
|
|
238
|
+
*/
|
|
239
|
+
declare function useRouteParams<TScreenId extends keyof RouteParams$1 = string>(): TScreenId extends keyof RouteParams$1 ? RouteParams$1[TScreenId] : Record<string, string>;
|
|
240
|
+
|
|
187
241
|
/**
|
|
188
242
|
* useTheme Hook - Theme utilities
|
|
189
243
|
*
|
|
@@ -241,4 +295,44 @@ declare function useTheme(): UseThemeReturn;
|
|
|
241
295
|
*/
|
|
242
296
|
declare const AppRouter: React__default.FC<AppRouterProps>;
|
|
243
297
|
|
|
244
|
-
|
|
298
|
+
/**
|
|
299
|
+
* Route params type
|
|
300
|
+
*/
|
|
301
|
+
type RouteParams = Record<string, string>;
|
|
302
|
+
/**
|
|
303
|
+
* Route params context
|
|
304
|
+
*/
|
|
305
|
+
declare const RouteParamsContext: React.Context<RouteParams>;
|
|
306
|
+
/**
|
|
307
|
+
* Route params provider props
|
|
308
|
+
*/
|
|
309
|
+
interface RouteParamsProviderProps {
|
|
310
|
+
params: RouteParams;
|
|
311
|
+
children: ReactNode;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Route params provider component
|
|
315
|
+
*/
|
|
316
|
+
declare function RouteParamsProvider({ params, children }: RouteParamsProviderProps): JSX.Element;
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* @hai3/react - React Bindings
|
|
320
|
+
*
|
|
321
|
+
* This package provides:
|
|
322
|
+
* - HAI3Provider context provider
|
|
323
|
+
* - Type-safe hooks for state and actions
|
|
324
|
+
* - AppRouter for screen rendering
|
|
325
|
+
*
|
|
326
|
+
* Layer: L3 (Depends on @hai3/framework)
|
|
327
|
+
*/
|
|
328
|
+
|
|
329
|
+
interface EventPayloadMap extends EventPayloadMap$1 {
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Re-export eventBus with augmented EventPayloadMap type.
|
|
333
|
+
* This ensures that code importing eventBus from @hai3/react gets
|
|
334
|
+
* type-safe access to both framework events and app-layer augmented events.
|
|
335
|
+
*/
|
|
336
|
+
declare const eventBus: EventBus<EventPayloadMap>;
|
|
337
|
+
|
|
338
|
+
export { AppRouter, AppRouterProps, type EventPayloadMap, HAI3Context, HAI3Provider, HAI3ProviderProps, type RouteParams, RouteParamsContext, RouteParamsProvider, type RouteParamsProviderProps, UseNavigationReturn, UseScreenTranslationsReturn, UseThemeReturn, UseTranslationReturn, eventBus, useAppDispatch, useAppSelector, useHAI3, useNavigation, useRouteParams, useScreenTranslations, useTheme, useTranslation };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import React__default from 'react';
|
|
2
|
+
import React__default, { ReactNode } from 'react';
|
|
3
3
|
import { HAI3ProviderProps, UseTranslationReturn, UseScreenTranslationsReturn, UseNavigationReturn, UseThemeReturn, AppRouterProps } from './types.js';
|
|
4
|
-
export { AppRouterComponent, HAI3ProviderComponent, UseAppDispatchReturn, UseAppSelector, UseHAI3Return, UseLanguageReturn, UseMenuReturn, UseOverlayReturn, UsePopupReturn, UseScreenReturn, UseScreensetReturn } from './types.js';
|
|
5
|
-
import { HAI3App, AppDispatch, RootState, TranslationMap, TranslationLoader } from '@hai3/framework';
|
|
6
|
-
export { ACCOUNTS_DOMAIN, ApiPlugin, ApiPluginBase, ApiPluginErrorContext, ApiProtocol, ApiRequestContext, ApiResponseContext, ApiServiceConfig, AppDispatch, BaseApiService, BasePluginHooks, ChangeThemePayload, EventHandler,
|
|
4
|
+
export { AppRouterComponent, HAI3ProviderComponent, RouterConfig, RouterType, UseAppDispatchReturn, UseAppSelector, UseHAI3Return, UseLanguageReturn, UseMenuReturn, UseOverlayReturn, UsePopupReturn, UseScreenReturn, UseScreensetReturn } from './types.js';
|
|
5
|
+
import { HAI3App, AppDispatch, RootState, TranslationMap, TranslationLoader, RouteParams as RouteParams$1, EventPayloadMap as EventPayloadMap$1 } from '@hai3/framework';
|
|
6
|
+
export { ACCOUNTS_DOMAIN, ApiPlugin, ApiPluginBase, ApiPluginErrorContext, ApiProtocol, ApiRequestContext, ApiResponseContext, ApiServiceConfig, AppDispatch, BaseApiService, BasePluginHooks, ChangeThemePayload, EventHandler, EventSourceLike, FooterConfig, FooterState, HAI3App, HAI3AppBuilder, HAI3Config, HAI3Plugin, HAI3Store, HeaderConfig, HeaderState, HeaderUser, I18nConfig, I18nRegistry, I18nRegistryImpl, I18nRegistryType, JsonCompatible, JsonObject, JsonPrimitive, JsonValue, LAYOUT_SLICE_NAME, Language, LanguageDisplayMode, LanguageMetadata, LayoutDomain, LayoutDomainReducers, LayoutDomainState, LayoutState, MOCK_PLUGIN, MenuItem, MenuItemConfig, MenuScreenItem, MenuState, MockEventSource, MockEvents, MockMap, MockState, MockTogglePayload, NavigateToScreenPayload, NavigateToScreensetPayload, OverlayConfig, OverlayState, PluginClass, PluginFactory, PluginLifecycle, PluginProvides, PopupConfig, PopupSliceState, PopupState, Preset, Presets, ProtocolClass, ProtocolPluginType, RestMockConfig, RestMockPlugin, RestPlugin, RestPluginHooks, RestPluginWithConfig, RestProtocol, RestProtocolConfig, RestRequestContext, RestResponseContext, RestShortCircuitResponse, RootState, RootStateWithLayout, RouteRegistry, SUPPORTED_LANGUAGES, ScreenConfig, ScreenId, ScreenLoader, ScreenState, ScreensetCategory, ScreensetConfig, ScreensetDefinition, ScreensetId, ScreensetRegistry, ScreensetsConfig, SetLanguagePayload, ShortCircuitResponse, ShowPopupPayload, SidebarPosition, SidebarState, SliceObject, SseConnectContext, SseMockConfig, SseMockEvent, SseMockPlugin, SsePlugin, SsePluginHooks, SsePluginWithConfig, SseProtocol, SseProtocolConfig, SseShortCircuitResponse, Subscription, TENANT_SLICE_NAME, Tenant, TenantChangedPayload, TenantClearedPayload, TenantEvents, TenantState, TextDirection, ThemeApplyFn, ThemeConfig, ThemeRegistry, TranslationDictionary, TranslationLoader, TranslationMap, UikitTheme, apiRegistry, changeTenant, clearActiveScreen, clearTenant, clearTenantAction, clearUser, closeAllPopups, closePopup, closeTopPopup, createHAI3, createHAI3App, createI18nRegistry, createRouteRegistry, createScreensetRegistry, createSlice, createStore, createThemeRegistry, effects, footerActions, footerSlice, getLanguageMetadata, getStore, hasSlice, headerActions, headerSlice, hideOverlay, i18n, i18nRegistry, initMockEffects, initTenantEffects, isMockPlugin, isRestShortCircuit, isShortCircuit, isSseShortCircuit, layout, layoutDomainReducers, layoutReducer, menuActions, menuSlice, mockActions, mockSlice, navigateTo, navigation, openPopup, overlayActions, overlaySlice, popupActions, popupSlice, presets, registerSlice, routing, screenActions, screenSlice, screensetRegistry, screensets, setActiveScreen, setFooterConfig, setFooterVisible, setHeaderLoading, setMenuCollapsed, setMenuConfig, setMenuItems, setMenuVisible, setMockEnabled, setOverlayVisible, setScreenLoading, setSidebarCollapsed, setSidebarConfig, setSidebarContent, setSidebarPosition, setSidebarTitle, setSidebarVisible, setSidebarWidth, setTenant, setTenantLoading, setTenantLoadingState, setUser, showOverlay, sidebarActions, sidebarSlice, tenantActions, tenantReducer, tenantSlice, themes, toggleMenu, toggleMockMode, toggleSidebar } from '@hai3/framework';
|
|
7
7
|
import { TypedUseSelectorHook } from 'react-redux';
|
|
8
|
+
import { EventBus } from '@hai3/state';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* HAI3 Provider - Main provider component for HAI3 applications
|
|
@@ -175,15 +176,68 @@ declare function useScreenTranslations(screensetId: string, screenId: string, tr
|
|
|
175
176
|
* ```tsx
|
|
176
177
|
* const { navigateToScreen, navigateToScreenset, currentScreen } = useNavigation();
|
|
177
178
|
*
|
|
179
|
+
* // Navigate to a simple screen
|
|
178
180
|
* return (
|
|
179
181
|
* <button onClick={() => navigateToScreen('demo', 'home')}>
|
|
180
182
|
* Go to Home
|
|
181
183
|
* </button>
|
|
182
184
|
* );
|
|
185
|
+
*
|
|
186
|
+
* // Navigate to a parameterized screen
|
|
187
|
+
* return (
|
|
188
|
+
* <button onClick={() => navigateToScreen('demo', 'user-detail', { id: '123' })}>
|
|
189
|
+
* View User 123
|
|
190
|
+
* </button>
|
|
191
|
+
* );
|
|
183
192
|
* ```
|
|
184
193
|
*/
|
|
185
194
|
declare function useNavigation(): UseNavigationReturn;
|
|
186
195
|
|
|
196
|
+
/**
|
|
197
|
+
* useRouteParams Hook
|
|
198
|
+
*
|
|
199
|
+
* Provides access to route parameters from the current URL.
|
|
200
|
+
* Supports type-safe route params via module augmentation.
|
|
201
|
+
*
|
|
202
|
+
* React Layer: L3
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* ```tsx
|
|
206
|
+
* import { useRouteParams } from '@hai3/react';
|
|
207
|
+
*
|
|
208
|
+
* // Basic usage (no type safety)
|
|
209
|
+
* const UserDetailScreen: React.FC = () => {
|
|
210
|
+
* const params = useRouteParams();
|
|
211
|
+
* // params: Record<string, string>
|
|
212
|
+
*
|
|
213
|
+
* return <div>User ID: {params.id}</div>;
|
|
214
|
+
* };
|
|
215
|
+
*
|
|
216
|
+
* // Type-safe usage with module augmentation
|
|
217
|
+
* // First, declare the route params in your app:
|
|
218
|
+
* // declare module '@hai3/framework' {
|
|
219
|
+
* // interface RouteParams {
|
|
220
|
+
* // 'user-detail': { userId: string };
|
|
221
|
+
* // }
|
|
222
|
+
* // }
|
|
223
|
+
*
|
|
224
|
+
* const UserDetailScreen: React.FC = () => {
|
|
225
|
+
* const params = useRouteParams<'user-detail'>();
|
|
226
|
+
* // params: { userId: string } - fully typed!
|
|
227
|
+
*
|
|
228
|
+
* return <div>User ID: {params.userId}</div>;
|
|
229
|
+
* };
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Hook to access route parameters from the current URL.
|
|
235
|
+
*
|
|
236
|
+
* @template TScreenId - Optional screen ID for type-safe route params
|
|
237
|
+
* @returns Route parameters, optionally typed based on screen ID
|
|
238
|
+
*/
|
|
239
|
+
declare function useRouteParams<TScreenId extends keyof RouteParams$1 = string>(): TScreenId extends keyof RouteParams$1 ? RouteParams$1[TScreenId] : Record<string, string>;
|
|
240
|
+
|
|
187
241
|
/**
|
|
188
242
|
* useTheme Hook - Theme utilities
|
|
189
243
|
*
|
|
@@ -241,4 +295,44 @@ declare function useTheme(): UseThemeReturn;
|
|
|
241
295
|
*/
|
|
242
296
|
declare const AppRouter: React__default.FC<AppRouterProps>;
|
|
243
297
|
|
|
244
|
-
|
|
298
|
+
/**
|
|
299
|
+
* Route params type
|
|
300
|
+
*/
|
|
301
|
+
type RouteParams = Record<string, string>;
|
|
302
|
+
/**
|
|
303
|
+
* Route params context
|
|
304
|
+
*/
|
|
305
|
+
declare const RouteParamsContext: React.Context<RouteParams>;
|
|
306
|
+
/**
|
|
307
|
+
* Route params provider props
|
|
308
|
+
*/
|
|
309
|
+
interface RouteParamsProviderProps {
|
|
310
|
+
params: RouteParams;
|
|
311
|
+
children: ReactNode;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Route params provider component
|
|
315
|
+
*/
|
|
316
|
+
declare function RouteParamsProvider({ params, children }: RouteParamsProviderProps): JSX.Element;
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* @hai3/react - React Bindings
|
|
320
|
+
*
|
|
321
|
+
* This package provides:
|
|
322
|
+
* - HAI3Provider context provider
|
|
323
|
+
* - Type-safe hooks for state and actions
|
|
324
|
+
* - AppRouter for screen rendering
|
|
325
|
+
*
|
|
326
|
+
* Layer: L3 (Depends on @hai3/framework)
|
|
327
|
+
*/
|
|
328
|
+
|
|
329
|
+
interface EventPayloadMap extends EventPayloadMap$1 {
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Re-export eventBus with augmented EventPayloadMap type.
|
|
333
|
+
* This ensures that code importing eventBus from @hai3/react gets
|
|
334
|
+
* type-safe access to both framework events and app-layer augmented events.
|
|
335
|
+
*/
|
|
336
|
+
declare const eventBus: EventBus<EventPayloadMap>;
|
|
337
|
+
|
|
338
|
+
export { AppRouter, AppRouterProps, type EventPayloadMap, HAI3Context, HAI3Provider, HAI3ProviderProps, type RouteParams, RouteParamsContext, RouteParamsProvider, type RouteParamsProviderProps, UseNavigationReturn, UseScreenTranslationsReturn, UseThemeReturn, UseTranslationReturn, eventBus, useAppDispatch, useAppSelector, useHAI3, useNavigation, useRouteParams, useScreenTranslations, useTheme, useTranslation };
|
package/dist/index.js
CHANGED
|
@@ -21,14 +21,20 @@ import { jsx } from "react/jsx-runtime";
|
|
|
21
21
|
var HAI3Provider = ({
|
|
22
22
|
children,
|
|
23
23
|
config,
|
|
24
|
-
app: providedApp
|
|
24
|
+
app: providedApp,
|
|
25
|
+
router
|
|
25
26
|
}) => {
|
|
26
27
|
const app = useMemo(() => {
|
|
27
28
|
if (providedApp) {
|
|
28
29
|
return providedApp;
|
|
29
30
|
}
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
const mergedConfig = {
|
|
32
|
+
...config,
|
|
33
|
+
routerMode: router?.type,
|
|
34
|
+
autoNavigate: router?.autoNavigate ?? config?.autoNavigate
|
|
35
|
+
};
|
|
36
|
+
return createHAI3App(mergedConfig);
|
|
37
|
+
}, [providedApp, config, router]);
|
|
32
38
|
useEffect(() => {
|
|
33
39
|
return () => {
|
|
34
40
|
if (!providedApp) {
|
|
@@ -176,9 +182,9 @@ function useNavigation() {
|
|
|
176
182
|
}
|
|
177
183
|
);
|
|
178
184
|
const navigateToScreen = useCallback3(
|
|
179
|
-
(screensetId, screenId) => {
|
|
185
|
+
(screensetId, screenId, params) => {
|
|
180
186
|
if (app.actions.navigateToScreen) {
|
|
181
|
-
app.actions.navigateToScreen({ screensetId, screenId });
|
|
187
|
+
app.actions.navigateToScreen({ screensetId, screenId, params });
|
|
182
188
|
}
|
|
183
189
|
},
|
|
184
190
|
[app.actions]
|
|
@@ -200,6 +206,22 @@ function useNavigation() {
|
|
|
200
206
|
};
|
|
201
207
|
}
|
|
202
208
|
|
|
209
|
+
// src/contexts/RouteParamsContext.tsx
|
|
210
|
+
import { createContext as createContext2, useContext as useContext2 } from "react";
|
|
211
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
212
|
+
var RouteParamsContext = createContext2({});
|
|
213
|
+
function RouteParamsProvider({ params, children }) {
|
|
214
|
+
return /* @__PURE__ */ jsx2(RouteParamsContext.Provider, { value: params, children });
|
|
215
|
+
}
|
|
216
|
+
function useRouteParamsContext() {
|
|
217
|
+
return useContext2(RouteParamsContext);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// src/hooks/useRouteParams.ts
|
|
221
|
+
function useRouteParams() {
|
|
222
|
+
return useRouteParamsContext();
|
|
223
|
+
}
|
|
224
|
+
|
|
203
225
|
// src/hooks/useTheme.ts
|
|
204
226
|
import { useCallback as useCallback4, useMemo as useMemo4, useSyncExternalStore as useSyncExternalStore3 } from "react";
|
|
205
227
|
function useTheme() {
|
|
@@ -243,7 +265,7 @@ function useTheme() {
|
|
|
243
265
|
|
|
244
266
|
// src/components/AppRouter.tsx
|
|
245
267
|
import { Suspense, useState as useState2, useEffect as useEffect3 } from "react";
|
|
246
|
-
import { Fragment, jsx as
|
|
268
|
+
import { Fragment, jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
247
269
|
var AppRouter = ({
|
|
248
270
|
fallback = null,
|
|
249
271
|
errorFallback
|
|
@@ -252,6 +274,26 @@ var AppRouter = ({
|
|
|
252
274
|
const { currentScreenset, currentScreen } = useNavigation();
|
|
253
275
|
const [ScreenComponent, setScreenComponent] = useState2(null);
|
|
254
276
|
const [error, setError] = useState2(null);
|
|
277
|
+
const [routeParams, setRouteParams] = useState2(() => {
|
|
278
|
+
if (typeof window === "undefined") {
|
|
279
|
+
return {};
|
|
280
|
+
}
|
|
281
|
+
const pathname = window.location.pathname;
|
|
282
|
+
const base = app.config.base || "";
|
|
283
|
+
const internalPath = base && pathname.startsWith(base) ? pathname.slice(base.length) || "/" : pathname;
|
|
284
|
+
const match = app.routeRegistry?.matchRoute(internalPath);
|
|
285
|
+
return match?.params ?? {};
|
|
286
|
+
});
|
|
287
|
+
useEffect3(() => {
|
|
288
|
+
if (typeof window === "undefined") {
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
const pathname = window.location.pathname;
|
|
292
|
+
const base = app.config.base || "";
|
|
293
|
+
const internalPath = base && pathname.startsWith(base) ? pathname.slice(base.length) || "/" : pathname;
|
|
294
|
+
const match = app.routeRegistry?.matchRoute(internalPath);
|
|
295
|
+
setRouteParams(match?.params ?? {});
|
|
296
|
+
}, [app.config.base, app.routeRegistry, currentScreen]);
|
|
255
297
|
useEffect3(() => {
|
|
256
298
|
let cancelled = false;
|
|
257
299
|
const loadScreen = async () => {
|
|
@@ -286,19 +328,19 @@ var AppRouter = ({
|
|
|
286
328
|
if (error) {
|
|
287
329
|
if (errorFallback) {
|
|
288
330
|
if (typeof errorFallback === "function") {
|
|
289
|
-
return /* @__PURE__ */
|
|
331
|
+
return /* @__PURE__ */ jsx3(Fragment, { children: errorFallback(error) });
|
|
290
332
|
}
|
|
291
|
-
return /* @__PURE__ */
|
|
333
|
+
return /* @__PURE__ */ jsx3(Fragment, { children: errorFallback });
|
|
292
334
|
}
|
|
293
335
|
return /* @__PURE__ */ jsxs("div", { className: "p-5 text-destructive", children: [
|
|
294
|
-
/* @__PURE__ */
|
|
295
|
-
/* @__PURE__ */
|
|
336
|
+
/* @__PURE__ */ jsx3("h2", { children: "Error loading screen" }),
|
|
337
|
+
/* @__PURE__ */ jsx3("p", { children: error.message })
|
|
296
338
|
] });
|
|
297
339
|
}
|
|
298
340
|
if (!ScreenComponent) {
|
|
299
|
-
return /* @__PURE__ */
|
|
341
|
+
return /* @__PURE__ */ jsx3(Fragment, { children: fallback });
|
|
300
342
|
}
|
|
301
|
-
return /* @__PURE__ */
|
|
343
|
+
return /* @__PURE__ */ jsx3(RouteParamsProvider, { params: routeParams, children: /* @__PURE__ */ jsx3(Suspense, { fallback, children: /* @__PURE__ */ jsx3(ScreenComponent, {}) }) });
|
|
302
344
|
};
|
|
303
345
|
|
|
304
346
|
// src/index.ts
|
|
@@ -319,7 +361,6 @@ import {
|
|
|
319
361
|
createScreensetRegistry,
|
|
320
362
|
createThemeRegistry,
|
|
321
363
|
createRouteRegistry,
|
|
322
|
-
eventBus,
|
|
323
364
|
createStore,
|
|
324
365
|
getStore,
|
|
325
366
|
registerSlice,
|
|
@@ -417,6 +458,8 @@ import {
|
|
|
417
458
|
getLanguageMetadata
|
|
418
459
|
} from "@hai3/framework";
|
|
419
460
|
import { Language, TextDirection, LanguageDisplayMode } from "@hai3/framework";
|
|
461
|
+
import { eventBus as frameworkEventBus } from "@hai3/framework";
|
|
462
|
+
var eventBus = frameworkEventBus;
|
|
420
463
|
export {
|
|
421
464
|
ACCOUNTS_DOMAIN,
|
|
422
465
|
ApiPlugin,
|
|
@@ -439,6 +482,8 @@ export {
|
|
|
439
482
|
RestPlugin,
|
|
440
483
|
RestPluginWithConfig,
|
|
441
484
|
RestProtocol,
|
|
485
|
+
RouteParamsContext,
|
|
486
|
+
RouteParamsProvider,
|
|
442
487
|
SUPPORTED_LANGUAGES,
|
|
443
488
|
ScreensetCategory,
|
|
444
489
|
SseMockPlugin,
|
|
@@ -540,6 +585,7 @@ export {
|
|
|
540
585
|
useAppSelector,
|
|
541
586
|
useHAI3,
|
|
542
587
|
useNavigation,
|
|
588
|
+
useRouteParams,
|
|
543
589
|
useScreenTranslations,
|
|
544
590
|
useTheme,
|
|
545
591
|
useTranslation
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/HAI3Provider.tsx","../src/HAI3Context.tsx","../src/hooks/useAppDispatch.ts","../src/hooks/useAppSelector.ts","../src/hooks/useTranslation.ts","../src/hooks/useScreenTranslations.ts","../src/hooks/useNavigation.ts","../src/hooks/useTheme.ts","../src/components/AppRouter.tsx","../src/index.ts"],"sourcesContent":["/**\n * HAI3 Provider - Main provider component for HAI3 applications\n *\n * React Layer: L3 (Depends on @hai3/framework)\n */\n\nimport React, { useMemo, useEffect } from 'react';\nimport { Provider as ReduxProvider } from 'react-redux';\nimport { createHAI3App } from '@hai3/framework';\nimport type { HAI3App } from '@hai3/framework';\nimport { HAI3Context } from './HAI3Context';\nimport type { HAI3ProviderProps } from './types';\n\n/**\n * HAI3 Provider Component\n *\n * Provides the HAI3 application context to all child components.\n * Creates the HAI3 app instance with the full preset by default.\n *\n * @example\n * ```tsx\n * // Default - creates app with full preset\n * <HAI3Provider>\n * <App />\n * </HAI3Provider>\n *\n * // With configuration\n * <HAI3Provider config={{ devMode: true }}>\n * <App />\n * </HAI3Provider>\n *\n * // With pre-built app\n * const app = createHAI3().use(screensets()).build();\n * <HAI3Provider app={app}>\n * <App />\n * </HAI3Provider>\n * ```\n */\nexport const HAI3Provider: React.FC<HAI3ProviderProps> = ({\n children,\n config,\n app: providedApp,\n}) => {\n // Create or use provided app instance\n const app = useMemo<HAI3App>(() => {\n if (providedApp) {\n return providedApp;\n }\n\n return createHAI3App(config);\n }, [providedApp, config]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n // Only destroy if we created the app (not provided)\n if (!providedApp) {\n app.destroy();\n }\n };\n }, [app, providedApp]);\n\n return (\n <HAI3Context.Provider value={app}>\n <ReduxProvider store={app.store as Parameters<typeof ReduxProvider>[0]['store']}>\n {children}\n </ReduxProvider>\n </HAI3Context.Provider>\n );\n};\n","/**\n * HAI3 Context - React context for HAI3 application\n *\n * React Layer: L3 (Depends on @hai3/framework)\n */\n\nimport { createContext, useContext } from 'react';\nimport type { HAI3App } from '@hai3/framework';\n\n// ============================================================================\n// Context Definition\n// ============================================================================\n\n/**\n * HAI3 Context\n * Holds the HAI3 app instance for the application.\n */\nexport const HAI3Context = createContext<HAI3App | null>(null);\n\n/**\n * Use the HAI3 context.\n * Throws if used outside of HAI3Provider.\n *\n * @returns The HAI3 app instance\n */\nexport function useHAI3(): HAI3App {\n const context = useContext(HAI3Context);\n\n if (!context) {\n throw new Error(\n 'useHAI3 must be used within a HAI3Provider. ' +\n 'Wrap your application with <HAI3Provider> to access HAI3 features.'\n );\n }\n\n return context;\n}\n","/**\n * useAppDispatch Hook - Type-safe dispatch hook\n *\n * React Layer: L3\n */\n\nimport { useDispatch } from 'react-redux';\nimport type { AppDispatch } from '@hai3/framework';\n\n/**\n * Type-safe dispatch hook.\n *\n * @returns The typed dispatch function\n *\n * @example\n * ```tsx\n * const dispatch = useAppDispatch();\n * dispatch(someAction());\n * ```\n */\nexport function useAppDispatch(): AppDispatch {\n // Use untyped useDispatch and cast the result\n // This avoids type constraint issues with react-redux's generic\n return useDispatch() as AppDispatch;\n}\n","/**\n * useAppSelector Hook - Type-safe selector hook\n *\n * React Layer: L3\n */\n\nimport { useSelector, type TypedUseSelectorHook } from 'react-redux';\nimport type { RootState } from '@hai3/framework';\n\n/**\n * Type-safe selector hook.\n *\n * @example\n * ```tsx\n * const activeScreen = useAppSelector(selectActiveScreen);\n * const menuCollapsed = useAppSelector(selectMenuCollapsed);\n * ```\n */\nexport const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;\n","/**\n * useTranslation Hook - Translation utilities\n *\n * React Layer: L3\n */\n\nimport { useMemo, useCallback, useSyncExternalStore } from 'react';\nimport type { Language } from '@hai3/framework';\nimport { useHAI3 } from '../HAI3Context';\nimport type { UseTranslationReturn } from '../types';\n\n/**\n * Hook for accessing translation utilities.\n *\n * @returns Translation utilities\n *\n * @example\n * ```tsx\n * const { t, language, setLanguage, isRTL } = useTranslation();\n *\n * return (\n * <div dir={isRTL ? 'rtl' : 'ltr'}>\n * <h1>{t('common:app.title')}</h1>\n * <p>{t('common:app.welcome', { name: 'John' })}</p>\n * </div>\n * );\n * ```\n */\nexport function useTranslation(): UseTranslationReturn {\n const app = useHAI3();\n const { i18nRegistry } = app;\n\n // Subscribe to translation changes using useSyncExternalStore\n // Uses version counter to trigger re-renders when translations change\n const version = useSyncExternalStore(\n useCallback(\n (callback: () => void) => {\n // Subscribe to translation changes (new translations registered)\n return i18nRegistry.subscribe(callback);\n },\n [i18nRegistry]\n ),\n () => i18nRegistry.getVersion(),\n () => i18nRegistry.getVersion()\n );\n\n // Get current language (memoized to avoid unnecessary recalculations)\n // version is used to trigger recalculation when translations change\n const language = useMemo(() => {\n void version; // Trigger recalculation when version changes\n return i18nRegistry.getLanguage();\n }, [i18nRegistry, version]);\n\n // Translation function\n const t = useCallback(\n (key: string, params?: Record<string, string | number | boolean>) => {\n return i18nRegistry.t(key, params);\n },\n [i18nRegistry]\n );\n\n // Set language function\n const setLanguage = useCallback(\n async (lang: Language) => {\n await i18nRegistry.setLanguage(lang);\n },\n [i18nRegistry]\n );\n\n // Check RTL - recomputes when language changes\n const isRTL = useMemo(() => {\n // Reference language to trigger recalculation on language change\n void language;\n return i18nRegistry.isRTL();\n }, [i18nRegistry, language]);\n\n return {\n t,\n language,\n setLanguage,\n isRTL,\n };\n}\n","/**\n * useScreenTranslations Hook - Screen-level translation loading\n *\n * React Layer: L3\n */\n\nimport { useState, useEffect, useMemo, useCallback, useSyncExternalStore } from 'react';\nimport type { TranslationMap, TranslationLoader } from '@hai3/framework';\nimport { useHAI3 } from '../HAI3Context';\nimport type { UseScreenTranslationsReturn } from '../types';\n\n// Re-export TranslationMap for consumers who need it\nexport type { TranslationMap };\n\n/**\n * Check if the input is a TranslationLoader function (from I18nRegistry.createLoader)\n * vs a TranslationMap object\n */\nfunction isTranslationLoader(\n input: TranslationMap | TranslationLoader\n): input is TranslationLoader {\n return typeof input === 'function';\n}\n\n/**\n * Hook for loading screen-level translations.\n * Use this in screen components to lazy-load translations.\n * Automatically reloads translations when language changes.\n *\n * @param screensetId - The screenset ID\n * @param screenId - The screen ID\n * @param translations - Either a TranslationMap object or a TranslationLoader function\n * (from I18nRegistry.createLoader)\n * @returns Loading state\n *\n * @example\n * ```tsx\n * // Option 1: Using I18nRegistry.createLoader (recommended)\n * const translations = I18nRegistry.createLoader({\n * en: () => import('./i18n/en.json'),\n * es: () => import('./i18n/es.json'),\n * });\n *\n * // Option 2: Using raw TranslationMap\n * const translations = {\n * en: () => import('./i18n/en.json'),\n * es: () => import('./i18n/es.json'),\n * };\n *\n * export const HomeScreen: React.FC = () => {\n * const { isLoaded, error } = useScreenTranslations(\n * 'demo',\n * 'home',\n * translations\n * );\n *\n * if (!isLoaded) return <LoadingSpinner />;\n * if (error) return <ErrorMessage error={error} />;\n *\n * return <div>...</div>;\n * };\n * ```\n */\nexport function useScreenTranslations(\n screensetId: string,\n screenId: string,\n translations: TranslationMap | TranslationLoader\n): UseScreenTranslationsReturn {\n const app = useHAI3();\n const { i18nRegistry } = app;\n\n // Track loading state per language to handle language changes\n const [loadedLanguage, setLoadedLanguage] = useState<string | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n // Subscribe to translation changes using useSyncExternalStore\n // This ensures we reload when language changes\n const version = useSyncExternalStore(\n useCallback(\n (callback: () => void) => i18nRegistry.subscribe(callback),\n [i18nRegistry]\n ),\n () => i18nRegistry.getVersion(),\n () => i18nRegistry.getVersion()\n );\n\n // Get current language (changes when version changes)\n // version is used to trigger recalculation when translations change\n const currentLanguage = useMemo(() => {\n void version; // Trigger recalculation when version changes\n return i18nRegistry.getLanguage();\n }, [i18nRegistry, version]);\n\n // Create a TranslationLoader function from the translation map or use directly if already a loader\n const loader: TranslationLoader = useMemo(() => {\n if (isTranslationLoader(translations)) {\n // Already a loader function (from I18nRegistry.createLoader)\n return translations;\n }\n\n // Convert TranslationMap to TranslationLoader\n return async (language: string) => {\n const importFn = translations[language as keyof typeof translations];\n if (!importFn) {\n // Return empty dictionary if language not in map\n return {};\n }\n const module = await importFn();\n return module.default;\n };\n }, [translations]);\n\n useEffect(() => {\n // Skip if no language or already loaded for this language\n if (!currentLanguage || currentLanguage === loadedLanguage) {\n return;\n }\n\n let cancelled = false;\n setIsLoading(true);\n\n const loadTranslations = async () => {\n try {\n const namespace = `screen.${screensetId}.${screenId}`;\n\n // Register the loader for future language changes\n i18nRegistry.registerLoader(namespace, loader);\n\n // Actually load the translations for current language\n const loadedTranslations = await loader(currentLanguage);\n i18nRegistry.register(namespace, currentLanguage, loadedTranslations);\n\n if (!cancelled) {\n setLoadedLanguage(currentLanguage);\n setIsLoading(false);\n setError(null);\n }\n } catch (err) {\n if (!cancelled) {\n setError(err instanceof Error ? err : new Error(String(err)));\n setIsLoading(false);\n }\n }\n };\n\n loadTranslations();\n\n return () => {\n cancelled = true;\n };\n }, [screensetId, screenId, loader, i18nRegistry, currentLanguage, loadedLanguage]);\n\n // Derive isLoaded from whether we've loaded translations for the current language\n const isLoaded = currentLanguage !== null && currentLanguage === loadedLanguage && !isLoading;\n\n return { isLoaded, error };\n}\n","/**\n * useNavigation Hook - Navigation utilities\n *\n * React Layer: L3\n */\n\nimport { useCallback } from 'react';\nimport { useHAI3 } from '../HAI3Context';\nimport { useAppSelector } from './useAppSelector';\nimport type { RootStateWithLayout } from '@hai3/framework';\nimport type { UseNavigationReturn } from '../types';\n\n/**\n * Hook for navigation utilities.\n *\n * @returns Navigation utilities\n *\n * @example\n * ```tsx\n * const { navigateToScreen, navigateToScreenset, currentScreen } = useNavigation();\n *\n * return (\n * <button onClick={() => navigateToScreen('demo', 'home')}>\n * Go to Home\n * </button>\n * );\n * ```\n */\nexport function useNavigation(): UseNavigationReturn {\n const app = useHAI3();\n // Access state directly via useAppSelector - no selectors needed\n // Layout slices use flat keys like 'layout/screen', not nested 'layout.screen'\n const currentScreen = useAppSelector(\n (state) => {\n // Try flat key first (current SDK architecture)\n const flatKey = state as Record<string, { activeScreen?: string | null }>;\n if (flatKey['layout/screen']) {\n return flatKey['layout/screen'].activeScreen ?? null;\n }\n // Fallback to nested structure (for backward compatibility)\n const nested = state as unknown as RootStateWithLayout;\n return nested.layout?.screen?.activeScreen ?? null;\n }\n );\n\n // Navigate to a specific screen\n const navigateToScreen = useCallback(\n (screensetId: string, screenId: string) => {\n if (app.actions.navigateToScreen) {\n app.actions.navigateToScreen({ screensetId, screenId });\n }\n },\n [app.actions]\n );\n\n // Navigate to a screenset (uses default screen)\n const navigateToScreenset = useCallback(\n (screensetId: string) => {\n if (app.actions.navigateToScreenset) {\n app.actions.navigateToScreenset({ screensetId });\n }\n },\n [app.actions]\n );\n\n /**\n * Derived state: screenset looked up from currentScreen via routeRegistry.\n * Single source of truth (Redux), automatic reactivity.\n */\n const currentScreenset = currentScreen\n ? app.routeRegistry?.getScreensetForScreen(currentScreen) ?? null\n : null;\n\n return {\n navigateToScreen,\n navigateToScreenset,\n currentScreenset,\n currentScreen,\n };\n}\n","/**\n * useTheme Hook - Theme utilities\n *\n * React Layer: L3\n */\n\nimport { useCallback, useMemo, useSyncExternalStore } from 'react';\nimport { useHAI3 } from '../HAI3Context';\nimport type { UseThemeReturn } from '../types';\n\n/**\n * Hook for theme utilities.\n *\n * @returns Theme utilities\n *\n * @example\n * ```tsx\n * const { currentTheme, themes, setTheme } = useTheme();\n *\n * return (\n * <select\n * value={currentTheme}\n * onChange={(e) => setTheme(e.target.value)}\n * >\n * {themes.map((theme) => (\n * <option key={theme.id} value={theme.id}>\n * {theme.name}\n * </option>\n * ))}\n * </select>\n * );\n * ```\n */\nexport function useTheme(): UseThemeReturn {\n const app = useHAI3();\n const { themeRegistry } = app;\n\n // Subscribe to theme changes using useSyncExternalStore\n // Uses version counter to trigger re-renders when theme changes\n const version = useSyncExternalStore(\n useCallback(\n (callback: () => void) => {\n return themeRegistry.subscribe(callback);\n },\n [themeRegistry]\n ),\n () => themeRegistry.getVersion(),\n () => themeRegistry.getVersion()\n );\n\n // Get current theme (memoized, recalculates on version change)\n const currentTheme = useMemo(() => {\n // Reference version to trigger recalculation on theme change\n void version;\n const theme = themeRegistry.getCurrent();\n return theme?.id;\n }, [themeRegistry, version]);\n\n // Get all themes\n const themes = useMemo(() => {\n return themeRegistry.getAll().map((theme) => ({\n id: theme.id,\n name: theme.name,\n }));\n }, [themeRegistry]);\n\n // Set theme\n const setTheme = useCallback(\n (themeId: string) => {\n if (app.actions.changeTheme) {\n app.actions.changeTheme({ themeId });\n }\n },\n [app.actions]\n );\n\n return {\n currentTheme,\n themes,\n setTheme,\n };\n}\n","/**\n * AppRouter Component - Renders the active screen\n *\n * React Layer: L3\n */\n\nimport React, { Suspense, useState, useEffect } from 'react';\nimport { useHAI3 } from '../HAI3Context';\nimport { useNavigation } from '../hooks/useNavigation';\nimport type { AppRouterProps } from '../types';\n\n/**\n * AppRouter Component\n *\n * Renders the currently active screen based on navigation state.\n * Handles lazy loading and error boundaries.\n *\n * @example\n * ```tsx\n * <HAI3Provider>\n * <Layout>\n * <AppRouter\n * fallback={<LoadingSpinner />}\n * errorFallback={(error) => <ErrorPage error={error} />}\n * />\n * </Layout>\n * </HAI3Provider>\n * ```\n */\nexport const AppRouter: React.FC<AppRouterProps> = ({\n fallback = null,\n errorFallback,\n}) => {\n const app = useHAI3();\n const { currentScreenset, currentScreen } = useNavigation();\n const [ScreenComponent, setScreenComponent] = useState<React.ComponentType | null>(null);\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n\n const loadScreen = async () => {\n if (!currentScreenset || !currentScreen) {\n setScreenComponent(null);\n return;\n }\n\n try {\n // Get screen loader from route registry\n const loader = app.routeRegistry.getScreen(currentScreenset, currentScreen);\n\n if (!loader) {\n throw new Error(\n `Screen \"${currentScreen}\" not found in screenset \"${currentScreenset}\".`\n );\n }\n\n // Load the screen component\n const module = await loader();\n\n if (!cancelled) {\n setScreenComponent(() => module.default);\n setError(null);\n }\n } catch (err) {\n if (!cancelled) {\n setError(err instanceof Error ? err : new Error(String(err)));\n setScreenComponent(null);\n }\n }\n };\n\n loadScreen();\n\n return () => {\n cancelled = true;\n };\n }, [currentScreenset, currentScreen, app.routeRegistry]);\n\n // Handle error state\n if (error) {\n if (errorFallback) {\n if (typeof errorFallback === 'function') {\n return <>{errorFallback(error)}</>;\n }\n return <>{errorFallback}</>;\n }\n // Default error display\n return (\n <div className=\"p-5 text-destructive\">\n <h2>Error loading screen</h2>\n <p>{error.message}</p>\n </div>\n );\n }\n\n // Handle loading state\n if (!ScreenComponent) {\n return <>{fallback}</>;\n }\n\n // Render the screen component\n return (\n <Suspense fallback={fallback}>\n <ScreenComponent />\n </Suspense>\n );\n};\n","/**\n * @hai3/react - React Bindings\n *\n * This package provides:\n * - HAI3Provider context provider\n * - Type-safe hooks for state and actions\n * - AppRouter for screen rendering\n *\n * Layer: L3 (Depends on @hai3/framework)\n */\n\n// ============================================================================\n// Provider\n// ============================================================================\n\nexport { HAI3Provider } from './HAI3Provider';\nexport { HAI3Context, useHAI3 } from './HAI3Context';\n\n// ============================================================================\n// Hooks\n// ============================================================================\n\nexport {\n useAppDispatch,\n useAppSelector,\n useTranslation,\n useScreenTranslations,\n useNavigation,\n useTheme,\n} from './hooks';\n\n// ============================================================================\n// Components\n// ============================================================================\n\nexport { AppRouter } from './components';\n\n// ============================================================================\n// Type Exports\n// ============================================================================\n\nexport type {\n HAI3ProviderProps,\n UseHAI3Return,\n UseAppSelector,\n UseAppDispatchReturn,\n UseTranslationReturn,\n UseScreenTranslationsReturn,\n UseLanguageReturn,\n UseThemeReturn,\n UseMenuReturn,\n UseScreenReturn,\n UseNavigationReturn,\n UseScreensetReturn,\n UsePopupReturn,\n UseOverlayReturn,\n AppRouterProps,\n HAI3ProviderComponent,\n AppRouterComponent,\n} from './types';\n\n// ============================================================================\n// Re-exports from @hai3/framework for convenience\n// ============================================================================\n\n// These re-exports allow users to import everything from @hai3/react\n// without needing to import from @hai3/framework directly\n\nexport {\n // Core\n createHAI3,\n createHAI3App,\n presets,\n\n // Backward compatibility singletons\n screensetRegistry,\n\n // Backward compatibility constants\n ACCOUNTS_DOMAIN,\n\n // I18nRegistry class (capital I for backward compat)\n I18nRegistry,\n\n // Plugins\n screensets,\n themes,\n layout,\n navigation,\n routing,\n i18n,\n effects,\n\n // Registries\n createScreensetRegistry,\n createThemeRegistry,\n createRouteRegistry,\n\n // Flux (Event bus + Store)\n eventBus,\n\n // Store\n createStore,\n getStore,\n registerSlice,\n hasSlice,\n createSlice,\n\n // Layout domain exports\n LayoutDomain,\n ScreensetCategory,\n layoutReducer,\n layoutDomainReducers,\n LAYOUT_SLICE_NAME,\n headerSlice,\n footerSlice,\n menuSlice,\n sidebarSlice,\n screenSlice,\n popupSlice,\n overlaySlice,\n headerActions,\n footerActions,\n menuActions,\n sidebarActions,\n screenActions,\n popupActions,\n overlayActions,\n // Individual reducer functions - header\n setUser,\n setHeaderLoading,\n clearUser,\n // Individual reducer functions - footer\n setFooterVisible,\n setFooterConfig,\n toggleMenu,\n setMenuCollapsed,\n setMenuItems,\n setMenuVisible,\n setMenuConfig,\n toggleSidebar,\n setSidebarCollapsed,\n setSidebarPosition,\n setSidebarTitle,\n setSidebarContent,\n setSidebarVisible,\n setSidebarWidth,\n setSidebarConfig,\n setActiveScreen,\n setScreenLoading,\n navigateTo,\n clearActiveScreen,\n openPopup,\n closePopup,\n closeTopPopup,\n closeAllPopups,\n showOverlay,\n hideOverlay,\n setOverlayVisible,\n\n // Tenant (app-level, not layout)\n TENANT_SLICE_NAME,\n tenantSlice,\n tenantActions,\n tenantReducer,\n setTenant,\n setTenantLoading,\n clearTenant,\n // Tenant effects and events\n initTenantEffects,\n changeTenant,\n clearTenantAction,\n setTenantLoadingState,\n TenantEvents,\n\n // Mock (app-level, not layout)\n mockSlice,\n mockActions,\n setMockEnabled,\n // Mock effects and events\n initMockEffects,\n toggleMockMode,\n MockEvents,\n\n // API\n apiRegistry,\n BaseApiService,\n RestProtocol,\n SseProtocol,\n // Protocol-specific mock plugins (replaces generic MockPlugin)\n RestMockPlugin,\n SseMockPlugin,\n MockEventSource,\n // Plugin base classes\n ApiPluginBase,\n ApiPlugin,\n ApiProtocol,\n RestPlugin,\n RestPluginWithConfig,\n SsePlugin,\n SsePluginWithConfig,\n // Type guards\n isShortCircuit,\n isRestShortCircuit,\n isSseShortCircuit,\n // Mock plugin identification\n MOCK_PLUGIN,\n isMockPlugin,\n\n // I18n\n i18nRegistry,\n I18nRegistryImpl,\n createI18nRegistry,\n SUPPORTED_LANGUAGES,\n getLanguageMetadata,\n} from '@hai3/framework';\n\n// Re-export i18n types from @hai3/framework (correct layer access)\nexport { Language, TextDirection, LanguageDisplayMode } from '@hai3/framework';\n\n// Re-export types from @hai3/framework\nexport type {\n // Config\n HAI3Config,\n HAI3Plugin,\n HAI3AppBuilder,\n HAI3App,\n PluginFactory,\n PluginProvides,\n PluginLifecycle,\n ScreensetRegistry,\n ThemeRegistry,\n ThemeConfig,\n RouteRegistry,\n Preset,\n Presets,\n ScreensetsConfig,\n NavigateToScreenPayload,\n NavigateToScreensetPayload,\n ShowPopupPayload,\n ChangeThemePayload,\n SetLanguagePayload,\n\n // Flux (Events + Store)\n EventPayloadMap,\n EventHandler,\n Subscription,\n\n // Store\n RootState,\n AppDispatch,\n SliceObject,\n HAI3Store,\n\n // Layout\n ScreensetId,\n ScreenId,\n MenuItemConfig,\n ScreenLoader,\n ScreenConfig,\n MenuScreenItem,\n ScreensetDefinition,\n LayoutDomainState,\n HeaderUser,\n HeaderConfig,\n HeaderState,\n FooterConfig,\n FooterState,\n MenuItem,\n MenuState,\n SidebarPosition,\n SidebarState,\n ScreenState,\n PopupConfig,\n PopupState,\n PopupSliceState,\n OverlayConfig,\n OverlayState,\n LayoutState,\n RootStateWithLayout,\n LayoutDomainReducers,\n\n // Tenant types\n Tenant,\n TenantState,\n TenantChangedPayload,\n TenantClearedPayload,\n\n // Mock types\n MockState,\n MockTogglePayload,\n\n // API\n MockMap,\n ApiServiceConfig,\n JsonValue,\n JsonObject,\n JsonPrimitive,\n JsonCompatible,\n SseProtocolConfig,\n RestProtocolConfig,\n // Plugin context types (class-based plugin system)\n ApiRequestContext,\n ApiResponseContext,\n ShortCircuitResponse,\n PluginClass,\n ProtocolClass,\n ProtocolPluginType,\n BasePluginHooks,\n // Protocol-specific types\n RestPluginHooks,\n SsePluginHooks,\n RestRequestContext,\n RestResponseContext,\n ApiPluginErrorContext,\n SseConnectContext,\n EventSourceLike,\n RestShortCircuitResponse,\n SseShortCircuitResponse,\n RestMockConfig,\n SseMockConfig,\n SseMockEvent,\n\n // Backward compatibility type aliases\n ScreensetConfig,\n\n // Theme types\n ThemeApplyFn,\n UikitTheme,\n\n // I18n\n I18nConfig,\n TranslationLoader,\n TranslationMap,\n TranslationDictionary,\n LanguageMetadata,\n I18nRegistryType,\n} from '@hai3/framework';\n"],"mappings":"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","names":["useMemo","i18nRegistry","useMemo","useEffect","useMemo","useCallback","useSyncExternalStore","i18nRegistry","useSyncExternalStore","useCallback","useMemo","useEffect","useCallback","useCallback","useCallback","useMemo","useSyncExternalStore","useSyncExternalStore","useCallback","useMemo","themes","useState","useEffect","jsx","useState","useEffect","createHAI3App"]}
|
|
1
|
+
{"version":3,"sources":["../src/HAI3Provider.tsx","../src/HAI3Context.tsx","../src/hooks/useAppDispatch.ts","../src/hooks/useAppSelector.ts","../src/hooks/useTranslation.ts","../src/hooks/useScreenTranslations.ts","../src/hooks/useNavigation.ts","../src/contexts/RouteParamsContext.tsx","../src/hooks/useRouteParams.ts","../src/hooks/useTheme.ts","../src/components/AppRouter.tsx","../src/index.ts"],"sourcesContent":["/**\n * HAI3 Provider - Main provider component for HAI3 applications\n *\n * React Layer: L3 (Depends on @hai3/framework)\n */\n\nimport React, { useMemo, useEffect } from 'react';\nimport { Provider as ReduxProvider } from 'react-redux';\nimport { createHAI3App } from '@hai3/framework';\nimport type { HAI3App } from '@hai3/framework';\nimport { HAI3Context } from './HAI3Context';\nimport type { HAI3ProviderProps } from './types';\n\n/**\n * HAI3 Provider Component\n *\n * Provides the HAI3 application context to all child components.\n * Creates the HAI3 app instance with the full preset by default.\n *\n * @example\n * ```tsx\n * // Default - creates app with full preset\n * <HAI3Provider>\n * <App />\n * </HAI3Provider>\n *\n * // With configuration\n * <HAI3Provider config={{ devMode: true }}>\n * <App />\n * </HAI3Provider>\n *\n * // With pre-built app\n * const app = createHAI3().use(screensets()).build();\n * <HAI3Provider app={app}>\n * <App />\n * </HAI3Provider>\n * ```\n */\nexport const HAI3Provider: React.FC<HAI3ProviderProps> = ({\n children,\n config,\n app: providedApp,\n router,\n}) => {\n // Create or use provided app instance\n const app = useMemo<HAI3App>(() => {\n if (providedApp) {\n return providedApp;\n }\n\n // Merge router config into HAI3Config\n const mergedConfig = {\n ...config,\n routerMode: router?.type,\n autoNavigate: router?.autoNavigate ?? config?.autoNavigate,\n };\n\n return createHAI3App(mergedConfig);\n }, [providedApp, config, router]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n // Only destroy if we created the app (not provided)\n if (!providedApp) {\n app.destroy();\n }\n };\n }, [app, providedApp]);\n\n return (\n <HAI3Context.Provider value={app}>\n <ReduxProvider store={app.store as Parameters<typeof ReduxProvider>[0]['store']}>\n {children}\n </ReduxProvider>\n </HAI3Context.Provider>\n );\n};\n","/**\n * HAI3 Context - React context for HAI3 application\n *\n * React Layer: L3 (Depends on @hai3/framework)\n */\n\nimport { createContext, useContext } from 'react';\nimport type { HAI3App } from '@hai3/framework';\n\n// ============================================================================\n// Context Definition\n// ============================================================================\n\n/**\n * HAI3 Context\n * Holds the HAI3 app instance for the application.\n */\nexport const HAI3Context = createContext<HAI3App | null>(null);\n\n/**\n * Use the HAI3 context.\n * Throws if used outside of HAI3Provider.\n *\n * @returns The HAI3 app instance\n */\nexport function useHAI3(): HAI3App {\n const context = useContext(HAI3Context);\n\n if (!context) {\n throw new Error(\n 'useHAI3 must be used within a HAI3Provider. ' +\n 'Wrap your application with <HAI3Provider> to access HAI3 features.'\n );\n }\n\n return context;\n}\n","/**\n * useAppDispatch Hook - Type-safe dispatch hook\n *\n * React Layer: L3\n */\n\nimport { useDispatch } from 'react-redux';\nimport type { AppDispatch } from '@hai3/framework';\n\n/**\n * Type-safe dispatch hook.\n *\n * @returns The typed dispatch function\n *\n * @example\n * ```tsx\n * const dispatch = useAppDispatch();\n * dispatch(someAction());\n * ```\n */\nexport function useAppDispatch(): AppDispatch {\n // Use untyped useDispatch and cast the result\n // This avoids type constraint issues with react-redux's generic\n return useDispatch() as AppDispatch;\n}\n","/**\n * useAppSelector Hook - Type-safe selector hook\n *\n * React Layer: L3\n */\n\nimport { useSelector, type TypedUseSelectorHook } from 'react-redux';\nimport type { RootState } from '@hai3/framework';\n\n/**\n * Type-safe selector hook.\n *\n * @example\n * ```tsx\n * const activeScreen = useAppSelector(selectActiveScreen);\n * const menuCollapsed = useAppSelector(selectMenuCollapsed);\n * ```\n */\nexport const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;\n","/**\n * useTranslation Hook - Translation utilities\n *\n * React Layer: L3\n */\n\nimport { useMemo, useCallback, useSyncExternalStore } from 'react';\nimport type { Language } from '@hai3/framework';\nimport { useHAI3 } from '../HAI3Context';\nimport type { UseTranslationReturn } from '../types';\n\n/**\n * Hook for accessing translation utilities.\n *\n * @returns Translation utilities\n *\n * @example\n * ```tsx\n * const { t, language, setLanguage, isRTL } = useTranslation();\n *\n * return (\n * <div dir={isRTL ? 'rtl' : 'ltr'}>\n * <h1>{t('common:app.title')}</h1>\n * <p>{t('common:app.welcome', { name: 'John' })}</p>\n * </div>\n * );\n * ```\n */\nexport function useTranslation(): UseTranslationReturn {\n const app = useHAI3();\n const { i18nRegistry } = app;\n\n // Subscribe to translation changes using useSyncExternalStore\n // Uses version counter to trigger re-renders when translations change\n const version = useSyncExternalStore(\n useCallback(\n (callback: () => void) => {\n // Subscribe to translation changes (new translations registered)\n return i18nRegistry.subscribe(callback);\n },\n [i18nRegistry]\n ),\n () => i18nRegistry.getVersion(),\n () => i18nRegistry.getVersion()\n );\n\n // Get current language (memoized to avoid unnecessary recalculations)\n // version is used to trigger recalculation when translations change\n const language = useMemo(() => {\n void version; // Trigger recalculation when version changes\n return i18nRegistry.getLanguage();\n }, [i18nRegistry, version]);\n\n // Translation function\n const t = useCallback(\n (key: string, params?: Record<string, string | number | boolean>) => {\n return i18nRegistry.t(key, params);\n },\n [i18nRegistry]\n );\n\n // Set language function\n const setLanguage = useCallback(\n async (lang: Language) => {\n await i18nRegistry.setLanguage(lang);\n },\n [i18nRegistry]\n );\n\n // Check RTL - recomputes when language changes\n const isRTL = useMemo(() => {\n // Reference language to trigger recalculation on language change\n void language;\n return i18nRegistry.isRTL();\n }, [i18nRegistry, language]);\n\n return {\n t,\n language,\n setLanguage,\n isRTL,\n };\n}\n","/**\n * useScreenTranslations Hook - Screen-level translation loading\n *\n * React Layer: L3\n */\n\nimport { useState, useEffect, useMemo, useCallback, useSyncExternalStore } from 'react';\nimport type { TranslationMap, TranslationLoader } from '@hai3/framework';\nimport { useHAI3 } from '../HAI3Context';\nimport type { UseScreenTranslationsReturn } from '../types';\n\n// Re-export TranslationMap for consumers who need it\nexport type { TranslationMap };\n\n/**\n * Check if the input is a TranslationLoader function (from I18nRegistry.createLoader)\n * vs a TranslationMap object\n */\nfunction isTranslationLoader(\n input: TranslationMap | TranslationLoader\n): input is TranslationLoader {\n return typeof input === 'function';\n}\n\n/**\n * Hook for loading screen-level translations.\n * Use this in screen components to lazy-load translations.\n * Automatically reloads translations when language changes.\n *\n * @param screensetId - The screenset ID\n * @param screenId - The screen ID\n * @param translations - Either a TranslationMap object or a TranslationLoader function\n * (from I18nRegistry.createLoader)\n * @returns Loading state\n *\n * @example\n * ```tsx\n * // Option 1: Using I18nRegistry.createLoader (recommended)\n * const translations = I18nRegistry.createLoader({\n * en: () => import('./i18n/en.json'),\n * es: () => import('./i18n/es.json'),\n * });\n *\n * // Option 2: Using raw TranslationMap\n * const translations = {\n * en: () => import('./i18n/en.json'),\n * es: () => import('./i18n/es.json'),\n * };\n *\n * export const HomeScreen: React.FC = () => {\n * const { isLoaded, error } = useScreenTranslations(\n * 'demo',\n * 'home',\n * translations\n * );\n *\n * if (!isLoaded) return <LoadingSpinner />;\n * if (error) return <ErrorMessage error={error} />;\n *\n * return <div>...</div>;\n * };\n * ```\n */\nexport function useScreenTranslations(\n screensetId: string,\n screenId: string,\n translations: TranslationMap | TranslationLoader\n): UseScreenTranslationsReturn {\n const app = useHAI3();\n const { i18nRegistry } = app;\n\n // Track loading state per language to handle language changes\n const [loadedLanguage, setLoadedLanguage] = useState<string | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n // Subscribe to translation changes using useSyncExternalStore\n // This ensures we reload when language changes\n const version = useSyncExternalStore(\n useCallback(\n (callback: () => void) => i18nRegistry.subscribe(callback),\n [i18nRegistry]\n ),\n () => i18nRegistry.getVersion(),\n () => i18nRegistry.getVersion()\n );\n\n // Get current language (changes when version changes)\n // version is used to trigger recalculation when translations change\n const currentLanguage = useMemo(() => {\n void version; // Trigger recalculation when version changes\n return i18nRegistry.getLanguage();\n }, [i18nRegistry, version]);\n\n // Create a TranslationLoader function from the translation map or use directly if already a loader\n const loader: TranslationLoader = useMemo(() => {\n if (isTranslationLoader(translations)) {\n // Already a loader function (from I18nRegistry.createLoader)\n return translations;\n }\n\n // Convert TranslationMap to TranslationLoader\n return async (language: string) => {\n const importFn = translations[language as keyof typeof translations];\n if (!importFn) {\n // Return empty dictionary if language not in map\n return {};\n }\n const module = await importFn();\n return module.default;\n };\n }, [translations]);\n\n useEffect(() => {\n // Skip if no language or already loaded for this language\n if (!currentLanguage || currentLanguage === loadedLanguage) {\n return;\n }\n\n let cancelled = false;\n setIsLoading(true);\n\n const loadTranslations = async () => {\n try {\n const namespace = `screen.${screensetId}.${screenId}`;\n\n // Register the loader for future language changes\n i18nRegistry.registerLoader(namespace, loader);\n\n // Actually load the translations for current language\n const loadedTranslations = await loader(currentLanguage);\n i18nRegistry.register(namespace, currentLanguage, loadedTranslations);\n\n if (!cancelled) {\n setLoadedLanguage(currentLanguage);\n setIsLoading(false);\n setError(null);\n }\n } catch (err) {\n if (!cancelled) {\n setError(err instanceof Error ? err : new Error(String(err)));\n setIsLoading(false);\n }\n }\n };\n\n loadTranslations();\n\n return () => {\n cancelled = true;\n };\n }, [screensetId, screenId, loader, i18nRegistry, currentLanguage, loadedLanguage]);\n\n // Derive isLoaded from whether we've loaded translations for the current language\n const isLoaded = currentLanguage !== null && currentLanguage === loadedLanguage && !isLoading;\n\n return { isLoaded, error };\n}\n","/**\n * useNavigation Hook - Navigation utilities\n *\n * React Layer: L3\n */\n\nimport { useCallback } from 'react';\nimport { useHAI3 } from '../HAI3Context';\nimport { useAppSelector } from './useAppSelector';\nimport type { RootStateWithLayout } from '@hai3/framework';\nimport type { UseNavigationReturn } from '../types';\n\n/**\n * Hook for navigation utilities.\n *\n * @returns Navigation utilities\n *\n * @example\n * ```tsx\n * const { navigateToScreen, navigateToScreenset, currentScreen } = useNavigation();\n *\n * // Navigate to a simple screen\n * return (\n * <button onClick={() => navigateToScreen('demo', 'home')}>\n * Go to Home\n * </button>\n * );\n *\n * // Navigate to a parameterized screen\n * return (\n * <button onClick={() => navigateToScreen('demo', 'user-detail', { id: '123' })}>\n * View User 123\n * </button>\n * );\n * ```\n */\nexport function useNavigation(): UseNavigationReturn {\n const app = useHAI3();\n // Access state directly via useAppSelector - no selectors needed\n // Layout slices use flat keys like 'layout/screen', not nested 'layout.screen'\n const currentScreen = useAppSelector(\n (state) => {\n // Try flat key first (current SDK architecture)\n const flatKey = state as Record<string, { activeScreen?: string | null }>;\n if (flatKey['layout/screen']) {\n return flatKey['layout/screen'].activeScreen ?? null;\n }\n // Fallback to nested structure (for backward compatibility)\n const nested = state as unknown as RootStateWithLayout;\n return nested.layout?.screen?.activeScreen ?? null;\n }\n );\n\n // Navigate to a specific screen, optionally with route params\n const navigateToScreen = useCallback(\n (screensetId: string, screenId: string, params?: Record<string, string>) => {\n if (app.actions.navigateToScreen) {\n app.actions.navigateToScreen({ screensetId, screenId, params });\n }\n },\n [app.actions]\n );\n\n // Navigate to a screenset (uses default screen)\n const navigateToScreenset = useCallback(\n (screensetId: string) => {\n if (app.actions.navigateToScreenset) {\n app.actions.navigateToScreenset({ screensetId });\n }\n },\n [app.actions]\n );\n\n /**\n * Derived state: screenset looked up from currentScreen via routeRegistry.\n * Single source of truth (Redux), automatic reactivity.\n */\n const currentScreenset = currentScreen\n ? app.routeRegistry?.getScreensetForScreen(currentScreen) ?? null\n : null;\n\n return {\n navigateToScreen,\n navigateToScreenset,\n currentScreenset,\n currentScreen,\n };\n}\n","/**\n * Route Params Context\n *\n * Provides route parameters to screen components via React context.\n *\n * React Layer: L3\n */\n\nimport { createContext, useContext, type ReactNode } from 'react';\n\n/**\n * Route params type\n */\nexport type RouteParams = Record<string, string>;\n\n/**\n * Route params context\n */\nconst RouteParamsContext = createContext<RouteParams>({});\n\n/**\n * Route params provider props\n */\nexport interface RouteParamsProviderProps {\n params: RouteParams;\n children: ReactNode;\n}\n\n/**\n * Route params provider component\n */\nexport function RouteParamsProvider({ params, children }: RouteParamsProviderProps): JSX.Element {\n return (\n <RouteParamsContext.Provider value={params}>\n {children}\n </RouteParamsContext.Provider>\n );\n}\n\n/**\n * Hook to access route params from context\n */\nexport function useRouteParamsContext(): RouteParams {\n return useContext(RouteParamsContext);\n}\n\nexport { RouteParamsContext };\n","/**\n * useRouteParams Hook\n *\n * Provides access to route parameters from the current URL.\n * Supports type-safe route params via module augmentation.\n *\n * React Layer: L3\n *\n * @example\n * ```tsx\n * import { useRouteParams } from '@hai3/react';\n *\n * // Basic usage (no type safety)\n * const UserDetailScreen: React.FC = () => {\n * const params = useRouteParams();\n * // params: Record<string, string>\n *\n * return <div>User ID: {params.id}</div>;\n * };\n *\n * // Type-safe usage with module augmentation\n * // First, declare the route params in your app:\n * // declare module '@hai3/framework' {\n * // interface RouteParams {\n * // 'user-detail': { userId: string };\n * // }\n * // }\n *\n * const UserDetailScreen: React.FC = () => {\n * const params = useRouteParams<'user-detail'>();\n * // params: { userId: string } - fully typed!\n *\n * return <div>User ID: {params.userId}</div>;\n * };\n * ```\n */\n\nimport { useRouteParamsContext } from '../contexts/RouteParamsContext';\nimport type { RouteParams as FrameworkRouteParams } from '@hai3/framework';\n\n/**\n * Hook to access route parameters from the current URL.\n * \n * @template TScreenId - Optional screen ID for type-safe route params\n * @returns Route parameters, optionally typed based on screen ID\n */\nexport function useRouteParams<TScreenId extends keyof FrameworkRouteParams = string>(): TScreenId extends keyof FrameworkRouteParams \n ? FrameworkRouteParams[TScreenId] \n : Record<string, string> {\n return useRouteParamsContext() as TScreenId extends keyof FrameworkRouteParams \n ? FrameworkRouteParams[TScreenId] \n : Record<string, string>;\n}\n","/**\n * useTheme Hook - Theme utilities\n *\n * React Layer: L3\n */\n\nimport { useCallback, useMemo, useSyncExternalStore } from 'react';\nimport { useHAI3 } from '../HAI3Context';\nimport type { UseThemeReturn } from '../types';\n\n/**\n * Hook for theme utilities.\n *\n * @returns Theme utilities\n *\n * @example\n * ```tsx\n * const { currentTheme, themes, setTheme } = useTheme();\n *\n * return (\n * <select\n * value={currentTheme}\n * onChange={(e) => setTheme(e.target.value)}\n * >\n * {themes.map((theme) => (\n * <option key={theme.id} value={theme.id}>\n * {theme.name}\n * </option>\n * ))}\n * </select>\n * );\n * ```\n */\nexport function useTheme(): UseThemeReturn {\n const app = useHAI3();\n const { themeRegistry } = app;\n\n // Subscribe to theme changes using useSyncExternalStore\n // Uses version counter to trigger re-renders when theme changes\n const version = useSyncExternalStore(\n useCallback(\n (callback: () => void) => {\n return themeRegistry.subscribe(callback);\n },\n [themeRegistry]\n ),\n () => themeRegistry.getVersion(),\n () => themeRegistry.getVersion()\n );\n\n // Get current theme (memoized, recalculates on version change)\n const currentTheme = useMemo(() => {\n // Reference version to trigger recalculation on theme change\n void version;\n const theme = themeRegistry.getCurrent();\n return theme?.id;\n }, [themeRegistry, version]);\n\n // Get all themes\n const themes = useMemo(() => {\n return themeRegistry.getAll().map((theme) => ({\n id: theme.id,\n name: theme.name,\n }));\n }, [themeRegistry]);\n\n // Set theme\n const setTheme = useCallback(\n (themeId: string) => {\n if (app.actions.changeTheme) {\n app.actions.changeTheme({ themeId });\n }\n },\n [app.actions]\n );\n\n return {\n currentTheme,\n themes,\n setTheme,\n };\n}\n","/**\n * AppRouter Component - Renders the active screen\n *\n * React Layer: L3\n */\n\nimport React, { Suspense, useState, useEffect } from 'react';\nimport { useHAI3 } from '../HAI3Context';\nimport { useNavigation } from '../hooks/useNavigation';\nimport { RouteParamsProvider, type RouteParams } from '../contexts/RouteParamsContext';\nimport type { AppRouterProps } from '../types';\n\n/**\n * AppRouter Component\n *\n * Renders the currently active screen based on navigation state.\n * Handles lazy loading and error boundaries.\n *\n * @example\n * ```tsx\n * <HAI3Provider>\n * <Layout>\n * <AppRouter\n * fallback={<LoadingSpinner />}\n * errorFallback={(error) => <ErrorPage error={error} />}\n * />\n * </Layout>\n * </HAI3Provider>\n * ```\n */\nexport const AppRouter: React.FC<AppRouterProps> = ({\n fallback = null,\n errorFallback,\n}) => {\n const app = useHAI3();\n const { currentScreenset, currentScreen } = useNavigation();\n const [ScreenComponent, setScreenComponent] = useState<React.ComponentType | null>(null);\n const [error, setError] = useState<Error | null>(null);\n\n // Extract route params synchronously from current URL to avoid race condition\n // This ensures params are available on first render\n const [routeParams, setRouteParams] = useState<RouteParams>(() => {\n if (typeof window === 'undefined') {\n return {};\n }\n const pathname = window.location.pathname;\n const base = app.config.base || '';\n const internalPath = base && pathname.startsWith(base)\n ? pathname.slice(base.length) || '/'\n : pathname;\n const match = app.routeRegistry?.matchRoute(internalPath);\n return match?.params ?? {};\n });\n\n // Update route params when navigation changes (browser back/forward or programmatic navigation)\n useEffect(() => {\n if (typeof window === 'undefined') {\n return;\n }\n const pathname = window.location.pathname;\n const base = app.config.base || '';\n const internalPath = base && pathname.startsWith(base)\n ? pathname.slice(base.length) || '/'\n : pathname;\n const match = app.routeRegistry?.matchRoute(internalPath);\n setRouteParams(match?.params ?? {});\n }, [app.config.base, app.routeRegistry, currentScreen]);\n\n useEffect(() => {\n let cancelled = false;\n\n const loadScreen = async () => {\n if (!currentScreenset || !currentScreen) {\n setScreenComponent(null);\n return;\n }\n\n try {\n // Get screen loader from route registry\n const loader = app.routeRegistry.getScreen(currentScreenset, currentScreen);\n\n if (!loader) {\n throw new Error(\n `Screen \"${currentScreen}\" not found in screenset \"${currentScreenset}\".`\n );\n }\n\n // Load the screen component\n const module = await loader();\n\n if (!cancelled) {\n setScreenComponent(() => module.default);\n setError(null);\n }\n } catch (err) {\n if (!cancelled) {\n setError(err instanceof Error ? err : new Error(String(err)));\n setScreenComponent(null);\n }\n }\n };\n\n loadScreen();\n\n return () => {\n cancelled = true;\n };\n }, [currentScreenset, currentScreen, app.routeRegistry]);\n\n // Handle error state\n if (error) {\n if (errorFallback) {\n if (typeof errorFallback === 'function') {\n return <>{errorFallback(error)}</>;\n }\n return <>{errorFallback}</>;\n }\n // Default error display\n return (\n <div className=\"p-5 text-destructive\">\n <h2>Error loading screen</h2>\n <p>{error.message}</p>\n </div>\n );\n }\n\n // Handle loading state\n if (!ScreenComponent) {\n return <>{fallback}</>;\n }\n\n // Render the screen component wrapped with route params context\n return (\n <RouteParamsProvider params={routeParams}>\n <Suspense fallback={fallback}>\n <ScreenComponent />\n </Suspense>\n </RouteParamsProvider>\n );\n};\n","/**\n * @hai3/react - React Bindings\n *\n * This package provides:\n * - HAI3Provider context provider\n * - Type-safe hooks for state and actions\n * - AppRouter for screen rendering\n *\n * Layer: L3 (Depends on @hai3/framework)\n */\n\n// ============================================================================\n// Provider\n// ============================================================================\n\nexport { HAI3Provider } from './HAI3Provider';\nexport { HAI3Context, useHAI3 } from './HAI3Context';\n\n// ============================================================================\n// Hooks\n// ============================================================================\n\nexport {\n useAppDispatch,\n useAppSelector,\n useTranslation,\n useScreenTranslations,\n useNavigation,\n useTheme,\n} from './hooks';\n\nexport { useRouteParams } from './hooks/useRouteParams';\n\n// ============================================================================\n// Components\n// ============================================================================\n\nexport { AppRouter } from './components';\n\n// ============================================================================\n// Contexts\n// ============================================================================\n\nexport { RouteParamsProvider, RouteParamsContext } from './contexts/RouteParamsContext';\nexport type { RouteParams, RouteParamsProviderProps } from './contexts/RouteParamsContext';\n\n// ============================================================================\n// Type Exports\n// ============================================================================\n\nexport type {\n HAI3ProviderProps,\n RouterType,\n RouterConfig,\n UseHAI3Return,\n UseAppSelector,\n UseAppDispatchReturn,\n UseTranslationReturn,\n UseScreenTranslationsReturn,\n UseLanguageReturn,\n UseThemeReturn,\n UseMenuReturn,\n UseScreenReturn,\n UseNavigationReturn,\n UseScreensetReturn,\n UsePopupReturn,\n UseOverlayReturn,\n AppRouterProps,\n HAI3ProviderComponent,\n AppRouterComponent,\n} from './types';\n\n// ============================================================================\n// Re-exports from @hai3/framework for convenience\n// ============================================================================\n\n// These re-exports allow users to import everything from @hai3/react\n// without needing to import from @hai3/framework directly\n\nexport {\n // Core\n createHAI3,\n createHAI3App,\n presets,\n\n // Backward compatibility singletons\n screensetRegistry,\n\n // Backward compatibility constants\n ACCOUNTS_DOMAIN,\n\n // I18nRegistry class (capital I for backward compat)\n I18nRegistry,\n\n // Plugins\n screensets,\n themes,\n layout,\n navigation,\n routing,\n i18n,\n effects,\n\n // Registries\n createScreensetRegistry,\n createThemeRegistry,\n createRouteRegistry,\n\n // Flux (Event bus + Store)\n // NOTE: eventBus is re-exported separately below with augmented EventPayloadMap type\n\n // Store\n createStore,\n getStore,\n registerSlice,\n hasSlice,\n createSlice,\n\n // Layout domain exports\n LayoutDomain,\n ScreensetCategory,\n layoutReducer,\n layoutDomainReducers,\n LAYOUT_SLICE_NAME,\n headerSlice,\n footerSlice,\n menuSlice,\n sidebarSlice,\n screenSlice,\n popupSlice,\n overlaySlice,\n headerActions,\n footerActions,\n menuActions,\n sidebarActions,\n screenActions,\n popupActions,\n overlayActions,\n // Individual reducer functions - header\n setUser,\n setHeaderLoading,\n clearUser,\n // Individual reducer functions - footer\n setFooterVisible,\n setFooterConfig,\n toggleMenu,\n setMenuCollapsed,\n setMenuItems,\n setMenuVisible,\n setMenuConfig,\n toggleSidebar,\n setSidebarCollapsed,\n setSidebarPosition,\n setSidebarTitle,\n setSidebarContent,\n setSidebarVisible,\n setSidebarWidth,\n setSidebarConfig,\n setActiveScreen,\n setScreenLoading,\n navigateTo,\n clearActiveScreen,\n openPopup,\n closePopup,\n closeTopPopup,\n closeAllPopups,\n showOverlay,\n hideOverlay,\n setOverlayVisible,\n\n // Tenant (app-level, not layout)\n TENANT_SLICE_NAME,\n tenantSlice,\n tenantActions,\n tenantReducer,\n setTenant,\n setTenantLoading,\n clearTenant,\n // Tenant effects and events\n initTenantEffects,\n changeTenant,\n clearTenantAction,\n setTenantLoadingState,\n TenantEvents,\n\n // Mock (app-level, not layout)\n mockSlice,\n mockActions,\n setMockEnabled,\n // Mock effects and events\n initMockEffects,\n toggleMockMode,\n MockEvents,\n\n // API\n apiRegistry,\n BaseApiService,\n RestProtocol,\n SseProtocol,\n // Protocol-specific mock plugins (replaces generic MockPlugin)\n RestMockPlugin,\n SseMockPlugin,\n MockEventSource,\n // Plugin base classes\n ApiPluginBase,\n ApiPlugin,\n ApiProtocol,\n RestPlugin,\n RestPluginWithConfig,\n SsePlugin,\n SsePluginWithConfig,\n // Type guards\n isShortCircuit,\n isRestShortCircuit,\n isSseShortCircuit,\n // Mock plugin identification\n MOCK_PLUGIN,\n isMockPlugin,\n\n // I18n\n i18nRegistry,\n I18nRegistryImpl,\n createI18nRegistry,\n SUPPORTED_LANGUAGES,\n getLanguageMetadata,\n} from '@hai3/framework';\n\n// Re-export i18n types from @hai3/framework (correct layer access)\nexport { Language, TextDirection, LanguageDisplayMode } from '@hai3/framework';\n\n// Re-export types from @hai3/framework\nexport type {\n // Config\n HAI3Config,\n HAI3Plugin,\n HAI3AppBuilder,\n HAI3App,\n PluginFactory,\n PluginProvides,\n PluginLifecycle,\n ScreensetRegistry,\n ThemeRegistry,\n ThemeConfig,\n RouteRegistry,\n Preset,\n Presets,\n ScreensetsConfig,\n NavigateToScreenPayload,\n NavigateToScreensetPayload,\n ShowPopupPayload,\n ChangeThemePayload,\n SetLanguagePayload,\n\n // Flux (Events + Store)\n EventHandler,\n Subscription,\n\n // Store\n RootState,\n AppDispatch,\n SliceObject,\n HAI3Store,\n\n // Layout\n ScreensetId,\n ScreenId,\n MenuItemConfig,\n ScreenLoader,\n ScreenConfig,\n MenuScreenItem,\n ScreensetDefinition,\n LayoutDomainState,\n HeaderUser,\n HeaderConfig,\n HeaderState,\n FooterConfig,\n FooterState,\n MenuItem,\n MenuState,\n SidebarPosition,\n SidebarState,\n ScreenState,\n PopupConfig,\n PopupState,\n PopupSliceState,\n OverlayConfig,\n OverlayState,\n LayoutState,\n RootStateWithLayout,\n LayoutDomainReducers,\n\n // Tenant types\n Tenant,\n TenantState,\n TenantChangedPayload,\n TenantClearedPayload,\n\n // Mock types\n MockState,\n MockTogglePayload,\n\n // API\n MockMap,\n ApiServiceConfig,\n JsonValue,\n JsonObject,\n JsonPrimitive,\n JsonCompatible,\n SseProtocolConfig,\n RestProtocolConfig,\n // Plugin context types (class-based plugin system)\n ApiRequestContext,\n ApiResponseContext,\n ShortCircuitResponse,\n PluginClass,\n ProtocolClass,\n ProtocolPluginType,\n BasePluginHooks,\n // Protocol-specific types\n RestPluginHooks,\n SsePluginHooks,\n RestRequestContext,\n RestResponseContext,\n ApiPluginErrorContext,\n SseConnectContext,\n EventSourceLike,\n RestShortCircuitResponse,\n SseShortCircuitResponse,\n RestMockConfig,\n SseMockConfig,\n SseMockEvent,\n\n // Backward compatibility type aliases\n ScreensetConfig,\n\n // Theme types\n ThemeApplyFn,\n UikitTheme,\n\n // I18n\n I18nConfig,\n TranslationLoader,\n TranslationMap,\n TranslationDictionary,\n LanguageMetadata,\n I18nRegistryType,\n} from '@hai3/framework';\n\n// ============================================================================\n// Module Augmentation Support - EventPayloadMap Re-declaration\n// ============================================================================\n\n/**\n * Re-declare EventPayloadMap to enable module augmentation on @hai3/react\n *\n * This creates a new declaration site in @hai3/react that TypeScript can augment.\n * App-layer code can now use `declare module '@hai3/react'` instead of importing\n * from L1 packages directly, maintaining proper layer architecture.\n *\n * ARCHITECTURE: This pattern allows L3+ code to augment event types without\n * violating layer boundaries by importing from L1 (@hai3/state).\n *\n * IMPORTANT: We must also re-export eventBus with the augmented type to ensure\n * type safety. The eventBus instance uses this augmented EventPayloadMap.\n *\n * @example\n * ```typescript\n * // In app-layer code (e.g., src/app/events/bootstrapEvents.ts)\n * import '@hai3/react';\n *\n * declare module '@hai3/react' {\n * interface EventPayloadMap {\n * 'app/user/fetch': void;\n * 'app/user/loaded': { user: ApiUser };\n * }\n * }\n * ```\n */\nimport type { EventPayloadMap as FrameworkEventPayloadMap } from '@hai3/framework';\nimport type { EventBus } from '@hai3/state';\nimport { eventBus as frameworkEventBus } from '@hai3/framework';\n\nexport interface EventPayloadMap extends FrameworkEventPayloadMap {}\n\n/**\n * Re-export eventBus with augmented EventPayloadMap type.\n * This ensures that code importing eventBus from @hai3/react gets\n * type-safe access to both framework events and app-layer augmented events.\n */\nexport const eventBus: EventBus<EventPayloadMap> = frameworkEventBus as EventBus<EventPayloadMap>;\n"],"mappings":"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","names":["useMemo","i18nRegistry","useMemo","useEffect","useMemo","useCallback","useSyncExternalStore","i18nRegistry","useSyncExternalStore","useCallback","useMemo","useEffect","useCallback","useCallback","createContext","useContext","jsx","useCallback","useMemo","useSyncExternalStore","useSyncExternalStore","useCallback","useMemo","themes","useState","useEffect","jsx","useState","useEffect","createHAI3App"]}
|
package/dist/types.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["/**\n * @hai3/react - Type Definitions\n *\n * Core types for HAI3 React bindings.\n * Provides type-safe hooks and components.\n *\n * Now using real imports from @hai3/framework since packages are built together.\n */\n\nimport type { ReactNode } from 'react';\nimport type {\n HAI3Config,\n HAI3App,\n RootState,\n Language,\n LanguageMetadata,\n MenuItemConfig,\n ScreensetDefinition,\n ScreensetCategory,\n} from '@hai3/framework';\n\n// Re-export imported types for convenience\nexport type { HAI3Config, HAI3App, MenuItemConfig, ScreensetDefinition, ScreensetCategory };\n\n// ============================================================================\n// Type Aliases\n// ============================================================================\n\n// From @hai3/store\ntype Selector<TResult, TState = RootState> = (state: TState) => TResult;\n\n// Language is imported from @hai3/framework\ntype TranslationParams = Record<string, string | number | boolean>;\n\n// ============================================================================\n// HAI3 Provider Props\n// ============================================================================\n\n/**\n * HAI3 Provider Props\n * Props for the main HAI3Provider component.\n *\n * @example\n * ```tsx\n * <HAI3Provider config={{ devMode: true }}>\n * <App />\n * </HAI3Provider>\n * ```\n */\nexport interface HAI3ProviderProps {\n /** Child components */\n children: ReactNode;\n /** HAI3 configuration */\n config?: HAI3Config;\n /** Pre-built HAI3 app instance (optional) */\n app?: HAI3App;\n}\n\n// ============================================================================\n// Hook Return Types\n// ============================================================================\n\n/**\n * useHAI3 Hook Return Type\n * Returns the HAI3 app instance from context.\n */\nexport type UseHAI3Return = HAI3App;\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) => Promise<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 * useLanguage Hook Return Type\n * Language selection utilities.\n */\nexport interface UseLanguageReturn {\n /** Current language */\n current: Language | null;\n /** All supported languages */\n supported: LanguageMetadata[];\n /** Change language */\n setLanguage: (language: Language) => Promise<void>;\n /** Check if current language is RTL */\n isRTL: boolean;\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 * useMenu Hook Return Type\n * Menu state and actions.\n */\nexport interface UseMenuReturn {\n /** Menu items */\n items: MenuItemConfig[];\n /** Whether menu is collapsed */\n collapsed: boolean;\n /** Whether menu is visible */\n visible: boolean;\n /** Toggle menu collapse */\n toggle: () => void;\n /** Set collapsed state */\n setCollapsed: (collapsed: boolean) => void;\n}\n\n/**\n * useScreen Hook Return Type\n * Current screen state.\n */\nexport interface UseScreenReturn {\n /** Active screen ID */\n activeScreen: string | null;\n /** Whether screen is loading */\n isLoading: boolean;\n}\n\n/**\n * useNavigation Hook Return Type\n * Navigation utilities.\n */\nexport interface UseNavigationReturn {\n /** Navigate to a screen */\n navigateToScreen: (screensetId: string, screenId: string) => void;\n /** Navigate to a screenset (uses default screen) */\n navigateToScreenset: (screensetId: string) => void;\n /** Current screenset ID */\n currentScreenset: string | null;\n /** Current screen ID */\n currentScreen: string | null;\n}\n\n/**\n * useScreenset Hook Return Type\n * Current screenset state.\n */\nexport interface UseScreensetReturn {\n /** Current screenset */\n screenset: ScreensetDefinition | undefined;\n /** Current screenset ID */\n screensetId: string | null;\n /** Current category */\n category: ScreensetCategory | null;\n}\n\n/**\n * usePopup Hook Return Type\n * Popup utilities.\n */\nexport interface UsePopupReturn {\n /** Show a popup */\n show: (config: { id: string; title?: string; content?: () => Promise<{ default: React.ComponentType }> }) => void;\n /** Hide current popup */\n hide: () => void;\n /** Hide all popups */\n hideAll: () => void;\n /** Whether any popup is open */\n isOpen: boolean;\n /** Current popup stack */\n stack: Array<{ id: string; title?: string }>;\n}\n\n/**\n * useOverlay Hook Return Type\n * Overlay utilities.\n */\nexport interface UseOverlayReturn {\n /** Show an overlay */\n show: (config: { id: string; content?: () => Promise<{ default: React.ComponentType }> }) => void;\n /** Hide current overlay */\n hide: () => void;\n /** Whether any overlay is open */\n isOpen: boolean;\n}\n\n// ============================================================================\n// App Router Props\n// ============================================================================\n\n/**\n * App Router Props\n * Props for the AppRouter component.\n */\nexport interface AppRouterProps {\n /** Fallback component while loading */\n fallback?: ReactNode;\n /** Error boundary fallback */\n errorFallback?: ReactNode | ((error: Error) => ReactNode);\n}\n\n// ============================================================================\n// Component Types\n// ============================================================================\n\n/**\n * HAI3Provider Component Type\n */\nexport type HAI3ProviderComponent = React.FC<HAI3ProviderProps>;\n\n/**\n * AppRouter Component Type\n */\nexport type AppRouterComponent = React.FC<AppRouterProps>;\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["/**\n * @hai3/react - Type Definitions\n *\n * Core types for HAI3 React bindings.\n * Provides type-safe hooks and components.\n *\n * Now using real imports from @hai3/framework since packages are built together.\n */\n\nimport type { ReactNode } from 'react';\nimport type {\n HAI3Config,\n HAI3App,\n RootState,\n Language,\n LanguageMetadata,\n MenuItemConfig,\n ScreensetDefinition,\n ScreensetCategory,\n} from '@hai3/framework';\n\n// Re-export imported types for convenience\nexport type { HAI3Config, HAI3App, MenuItemConfig, ScreensetDefinition, ScreensetCategory };\n\n// ============================================================================\n// Type Aliases\n// ============================================================================\n\n// From @hai3/store\ntype Selector<TResult, TState = RootState> = (state: TState) => TResult;\n\n// Language is imported from @hai3/framework\ntype TranslationParams = Record<string, string | number | boolean>;\n\n// ============================================================================\n// HAI3 Provider Props\n// ============================================================================\n\n/**\n * Router configuration type\n */\nexport type RouterType = 'browser' | 'hash' | 'memory';\n\n/**\n * Router configuration\n */\nexport interface RouterConfig {\n /** Router type - browser (default), hash, or memory */\n type?: RouterType;\n /** Auto-navigate to first screen on load (default: true) */\n autoNavigate?: boolean;\n}\n\n/**\n * HAI3 Provider Props\n * Props for the main HAI3Provider component.\n *\n * @example\n * ```tsx\n * <HAI3Provider config={{ devMode: true }}>\n * <App />\n * </HAI3Provider>\n *\n * // With router configuration\n * <HAI3Provider router={{ type: 'hash' }}>\n * <App />\n * </HAI3Provider>\n * ```\n */\nexport interface HAI3ProviderProps {\n /** Child components */\n children: ReactNode;\n /** HAI3 configuration */\n config?: HAI3Config;\n /** Pre-built HAI3 app instance (optional) */\n app?: HAI3App;\n /** Router configuration */\n router?: RouterConfig;\n}\n\n// ============================================================================\n// Hook Return Types\n// ============================================================================\n\n/**\n * useHAI3 Hook Return Type\n * Returns the HAI3 app instance from context.\n */\nexport type UseHAI3Return = HAI3App;\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) => Promise<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 * useLanguage Hook Return Type\n * Language selection utilities.\n */\nexport interface UseLanguageReturn {\n /** Current language */\n current: Language | null;\n /** All supported languages */\n supported: LanguageMetadata[];\n /** Change language */\n setLanguage: (language: Language) => Promise<void>;\n /** Check if current language is RTL */\n isRTL: boolean;\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 * useMenu Hook Return Type\n * Menu state and actions.\n */\nexport interface UseMenuReturn {\n /** Menu items */\n items: MenuItemConfig[];\n /** Whether menu is collapsed */\n collapsed: boolean;\n /** Whether menu is visible */\n visible: boolean;\n /** Toggle menu collapse */\n toggle: () => void;\n /** Set collapsed state */\n setCollapsed: (collapsed: boolean) => void;\n}\n\n/**\n * useScreen Hook Return Type\n * Current screen state.\n */\nexport interface UseScreenReturn {\n /** Active screen ID */\n activeScreen: string | null;\n /** Whether screen is loading */\n isLoading: boolean;\n}\n\n/**\n * useNavigation Hook Return Type\n * Navigation utilities.\n */\nexport interface UseNavigationReturn {\n /** Navigate to a screen, optionally with route params */\n navigateToScreen: (screensetId: string, screenId: string, params?: Record<string, string>) => void;\n /** Navigate to a screenset (uses default screen) */\n navigateToScreenset: (screensetId: string) => void;\n /** Current screenset ID */\n currentScreenset: string | null;\n /** Current screen ID */\n currentScreen: string | null;\n}\n\n/**\n * useScreenset Hook Return Type\n * Current screenset state.\n */\nexport interface UseScreensetReturn {\n /** Current screenset */\n screenset: ScreensetDefinition | undefined;\n /** Current screenset ID */\n screensetId: string | null;\n /** Current category */\n category: ScreensetCategory | null;\n}\n\n/**\n * usePopup Hook Return Type\n * Popup utilities.\n */\nexport interface UsePopupReturn {\n /** Show a popup */\n show: (config: { id: string; title?: string; content?: () => Promise<{ default: React.ComponentType }> }) => void;\n /** Hide current popup */\n hide: () => void;\n /** Hide all popups */\n hideAll: () => void;\n /** Whether any popup is open */\n isOpen: boolean;\n /** Current popup stack */\n stack: Array<{ id: string; title?: string }>;\n}\n\n/**\n * useOverlay Hook Return Type\n * Overlay utilities.\n */\nexport interface UseOverlayReturn {\n /** Show an overlay */\n show: (config: { id: string; content?: () => Promise<{ default: React.ComponentType }> }) => void;\n /** Hide current overlay */\n hide: () => void;\n /** Whether any overlay is open */\n isOpen: boolean;\n}\n\n// ============================================================================\n// App Router Props\n// ============================================================================\n\n/**\n * App Router Props\n * Props for the AppRouter component.\n */\nexport interface AppRouterProps {\n /** Fallback component while loading */\n fallback?: ReactNode;\n /** Error boundary fallback */\n errorFallback?: ReactNode | ((error: Error) => ReactNode);\n}\n\n// ============================================================================\n// Component Types\n// ============================================================================\n\n/**\n * HAI3Provider Component Type\n */\nexport type HAI3ProviderComponent = React.FC<HAI3ProviderProps>;\n\n/**\n * AppRouter Component Type\n */\nexport type AppRouterComponent = React.FC<AppRouterProps>;\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
|
package/dist/types.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
|
-
import { HAI3Config, HAI3App,
|
|
2
|
+
import { HAI3Config, HAI3App, RootState, Language, LanguageMetadata, MenuItemConfig, ScreensetDefinition, ScreensetCategory } from '@hai3/framework';
|
|
3
3
|
export { HAI3App, HAI3Config, MenuItemConfig, ScreensetCategory, ScreensetDefinition } from '@hai3/framework';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -13,6 +13,19 @@ export { HAI3App, HAI3Config, MenuItemConfig, ScreensetCategory, ScreensetDefini
|
|
|
13
13
|
|
|
14
14
|
type Selector<TResult, TState = RootState> = (state: TState) => TResult;
|
|
15
15
|
type TranslationParams = Record<string, string | number | boolean>;
|
|
16
|
+
/**
|
|
17
|
+
* Router configuration type
|
|
18
|
+
*/
|
|
19
|
+
type RouterType = 'browser' | 'hash' | 'memory';
|
|
20
|
+
/**
|
|
21
|
+
* Router configuration
|
|
22
|
+
*/
|
|
23
|
+
interface RouterConfig {
|
|
24
|
+
/** Router type - browser (default), hash, or memory */
|
|
25
|
+
type?: RouterType;
|
|
26
|
+
/** Auto-navigate to first screen on load (default: true) */
|
|
27
|
+
autoNavigate?: boolean;
|
|
28
|
+
}
|
|
16
29
|
/**
|
|
17
30
|
* HAI3 Provider Props
|
|
18
31
|
* Props for the main HAI3Provider component.
|
|
@@ -22,6 +35,11 @@ type TranslationParams = Record<string, string | number | boolean>;
|
|
|
22
35
|
* <HAI3Provider config={{ devMode: true }}>
|
|
23
36
|
* <App />
|
|
24
37
|
* </HAI3Provider>
|
|
38
|
+
*
|
|
39
|
+
* // With router configuration
|
|
40
|
+
* <HAI3Provider router={{ type: 'hash' }}>
|
|
41
|
+
* <App />
|
|
42
|
+
* </HAI3Provider>
|
|
25
43
|
* ```
|
|
26
44
|
*/
|
|
27
45
|
interface HAI3ProviderProps {
|
|
@@ -31,6 +49,8 @@ interface HAI3ProviderProps {
|
|
|
31
49
|
config?: HAI3Config;
|
|
32
50
|
/** Pre-built HAI3 app instance (optional) */
|
|
33
51
|
app?: HAI3App;
|
|
52
|
+
/** Router configuration */
|
|
53
|
+
router?: RouterConfig;
|
|
34
54
|
}
|
|
35
55
|
/**
|
|
36
56
|
* useHAI3 Hook Return Type
|
|
@@ -133,8 +153,8 @@ interface UseScreenReturn {
|
|
|
133
153
|
* Navigation utilities.
|
|
134
154
|
*/
|
|
135
155
|
interface UseNavigationReturn {
|
|
136
|
-
/** Navigate to a screen */
|
|
137
|
-
navigateToScreen: (screensetId: string, screenId: string) => void;
|
|
156
|
+
/** Navigate to a screen, optionally with route params */
|
|
157
|
+
navigateToScreen: (screensetId: string, screenId: string, params?: Record<string, string>) => void;
|
|
138
158
|
/** Navigate to a screenset (uses default screen) */
|
|
139
159
|
navigateToScreenset: (screensetId: string) => void;
|
|
140
160
|
/** Current screenset ID */
|
|
@@ -215,4 +235,4 @@ type HAI3ProviderComponent = React.FC<HAI3ProviderProps>;
|
|
|
215
235
|
*/
|
|
216
236
|
type AppRouterComponent = React.FC<AppRouterProps>;
|
|
217
237
|
|
|
218
|
-
export type { AppRouterComponent, AppRouterProps, HAI3ProviderComponent, HAI3ProviderProps, UseAppDispatchReturn, UseAppSelector, UseHAI3Return, UseLanguageReturn, UseMenuReturn, UseNavigationReturn, UseOverlayReturn, UsePopupReturn, UseScreenReturn, UseScreenTranslationsReturn, UseScreensetReturn, UseThemeReturn, UseTranslationReturn };
|
|
238
|
+
export type { AppRouterComponent, AppRouterProps, HAI3ProviderComponent, HAI3ProviderProps, RouterConfig, RouterType, UseAppDispatchReturn, UseAppSelector, UseHAI3Return, UseLanguageReturn, UseMenuReturn, UseNavigationReturn, UseOverlayReturn, UsePopupReturn, UseScreenReturn, UseScreenTranslationsReturn, UseScreensetReturn, UseThemeReturn, UseTranslationReturn };
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
|
-
import { HAI3Config, HAI3App,
|
|
2
|
+
import { HAI3Config, HAI3App, RootState, Language, LanguageMetadata, MenuItemConfig, ScreensetDefinition, ScreensetCategory } from '@hai3/framework';
|
|
3
3
|
export { HAI3App, HAI3Config, MenuItemConfig, ScreensetCategory, ScreensetDefinition } from '@hai3/framework';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -13,6 +13,19 @@ export { HAI3App, HAI3Config, MenuItemConfig, ScreensetCategory, ScreensetDefini
|
|
|
13
13
|
|
|
14
14
|
type Selector<TResult, TState = RootState> = (state: TState) => TResult;
|
|
15
15
|
type TranslationParams = Record<string, string | number | boolean>;
|
|
16
|
+
/**
|
|
17
|
+
* Router configuration type
|
|
18
|
+
*/
|
|
19
|
+
type RouterType = 'browser' | 'hash' | 'memory';
|
|
20
|
+
/**
|
|
21
|
+
* Router configuration
|
|
22
|
+
*/
|
|
23
|
+
interface RouterConfig {
|
|
24
|
+
/** Router type - browser (default), hash, or memory */
|
|
25
|
+
type?: RouterType;
|
|
26
|
+
/** Auto-navigate to first screen on load (default: true) */
|
|
27
|
+
autoNavigate?: boolean;
|
|
28
|
+
}
|
|
16
29
|
/**
|
|
17
30
|
* HAI3 Provider Props
|
|
18
31
|
* Props for the main HAI3Provider component.
|
|
@@ -22,6 +35,11 @@ type TranslationParams = Record<string, string | number | boolean>;
|
|
|
22
35
|
* <HAI3Provider config={{ devMode: true }}>
|
|
23
36
|
* <App />
|
|
24
37
|
* </HAI3Provider>
|
|
38
|
+
*
|
|
39
|
+
* // With router configuration
|
|
40
|
+
* <HAI3Provider router={{ type: 'hash' }}>
|
|
41
|
+
* <App />
|
|
42
|
+
* </HAI3Provider>
|
|
25
43
|
* ```
|
|
26
44
|
*/
|
|
27
45
|
interface HAI3ProviderProps {
|
|
@@ -31,6 +49,8 @@ interface HAI3ProviderProps {
|
|
|
31
49
|
config?: HAI3Config;
|
|
32
50
|
/** Pre-built HAI3 app instance (optional) */
|
|
33
51
|
app?: HAI3App;
|
|
52
|
+
/** Router configuration */
|
|
53
|
+
router?: RouterConfig;
|
|
34
54
|
}
|
|
35
55
|
/**
|
|
36
56
|
* useHAI3 Hook Return Type
|
|
@@ -133,8 +153,8 @@ interface UseScreenReturn {
|
|
|
133
153
|
* Navigation utilities.
|
|
134
154
|
*/
|
|
135
155
|
interface UseNavigationReturn {
|
|
136
|
-
/** Navigate to a screen */
|
|
137
|
-
navigateToScreen: (screensetId: string, screenId: string) => void;
|
|
156
|
+
/** Navigate to a screen, optionally with route params */
|
|
157
|
+
navigateToScreen: (screensetId: string, screenId: string, params?: Record<string, string>) => void;
|
|
138
158
|
/** Navigate to a screenset (uses default screen) */
|
|
139
159
|
navigateToScreenset: (screensetId: string) => void;
|
|
140
160
|
/** Current screenset ID */
|
|
@@ -215,4 +235,4 @@ type HAI3ProviderComponent = React.FC<HAI3ProviderProps>;
|
|
|
215
235
|
*/
|
|
216
236
|
type AppRouterComponent = React.FC<AppRouterProps>;
|
|
217
237
|
|
|
218
|
-
export type { AppRouterComponent, AppRouterProps, HAI3ProviderComponent, HAI3ProviderProps, UseAppDispatchReturn, UseAppSelector, UseHAI3Return, UseLanguageReturn, UseMenuReturn, UseNavigationReturn, UseOverlayReturn, UsePopupReturn, UseScreenReturn, UseScreenTranslationsReturn, UseScreensetReturn, UseThemeReturn, UseTranslationReturn };
|
|
238
|
+
export type { AppRouterComponent, AppRouterProps, HAI3ProviderComponent, HAI3ProviderProps, RouterConfig, RouterType, UseAppDispatchReturn, UseAppSelector, UseHAI3Return, UseLanguageReturn, UseMenuReturn, UseNavigationReturn, UseOverlayReturn, UsePopupReturn, UseScreenReturn, UseScreenTranslationsReturn, UseScreensetReturn, UseThemeReturn, UseTranslationReturn };
|