@lumeweb/portal-framework-ui 0.1.2 → 0.1.3
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.
|
@@ -33,7 +33,6 @@ function AppComponent({ loadNavigation = true, loadRoutes = true, name = "app" }
|
|
|
33
33
|
});
|
|
34
34
|
}
|
|
35
35
|
function AppContent({ loadNavigation = true, loadRoutes = true }) {
|
|
36
|
-
useIdentifyUser();
|
|
37
36
|
const { error: frameworkError, framework, isLoading: isFrameworkLoading } = useFramework();
|
|
38
37
|
const addMenuItems = useAppStore((state) => state.addMenuItems);
|
|
39
38
|
const error = useAppStore((state) => state.error);
|
|
@@ -95,6 +94,24 @@ function AppContent({ loadNavigation = true, loadRoutes = true }) {
|
|
|
95
94
|
setPluginConfigs,
|
|
96
95
|
addMenuItems
|
|
97
96
|
]);
|
|
97
|
+
return /* @__PURE__ */ jsx(Refine, {
|
|
98
|
+
...pluginConfigs,
|
|
99
|
+
options: getDefaultRefineOptions(),
|
|
100
|
+
routerProvider,
|
|
101
|
+
children: /* @__PURE__ */ jsx(AppContentInner, {
|
|
102
|
+
error,
|
|
103
|
+
framework,
|
|
104
|
+
frameworkError,
|
|
105
|
+
isFrameworkLoading,
|
|
106
|
+
isLoading,
|
|
107
|
+
loadNavigation,
|
|
108
|
+
loadRoutes,
|
|
109
|
+
routes
|
|
110
|
+
})
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
function AppContentInner({ error, framework, frameworkError, isFrameworkLoading, isLoading, loadNavigation, loadRoutes, routes }) {
|
|
114
|
+
useIdentifyUser();
|
|
98
115
|
if (isFrameworkLoading || isLoading) return /* @__PURE__ */ jsx(LoadingSpinner, {});
|
|
99
116
|
if (frameworkError) return /* @__PURE__ */ jsx(ErrorDisplay, {
|
|
100
117
|
error: frameworkError,
|
|
@@ -105,7 +122,6 @@ function AppContent({ loadNavigation = true, loadRoutes = true }) {
|
|
|
105
122
|
onRetry: () => window.location.reload()
|
|
106
123
|
});
|
|
107
124
|
if (!routes) return null;
|
|
108
|
-
const combinedPluginConfig = Object.assign({}, ...pluginConfigs);
|
|
109
125
|
const routerRoutes = createRoutesFromElements(Array.isArray(routes) ? routes.map((route) => createRouteElement(route, framework)) : []);
|
|
110
126
|
function createRouteElement(route, framework, child = false) {
|
|
111
127
|
const LazyComponent = getLazyComponent(route.component ?? "", route.pluginId ?? createNamespacedId("core", "fallback"), framework, route.id);
|
|
@@ -118,16 +134,11 @@ function AppContent({ loadNavigation = true, loadRoutes = true }) {
|
|
|
118
134
|
index: route.index,
|
|
119
135
|
path: route.path,
|
|
120
136
|
children: childRoutes
|
|
121
|
-
}
|
|
137
|
+
});
|
|
122
138
|
}
|
|
123
139
|
let router;
|
|
124
140
|
if (routerRoutes.length > 0) router = createBrowserRouter(routerRoutes);
|
|
125
|
-
return /* @__PURE__ */ jsxs(
|
|
126
|
-
...combinedPluginConfig,
|
|
127
|
-
options: getDefaultRefineOptions(),
|
|
128
|
-
routerProvider,
|
|
129
|
-
children: [/* @__PURE__ */ jsxs(DialogProvider, { children: [router && /* @__PURE__ */ jsx(RouterProvider, { router }), !router && /* @__PURE__ */ jsx(DialogRenderer, {})] }), /* @__PURE__ */ jsx(Toaster, {})]
|
|
130
|
-
});
|
|
141
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(DialogProvider, { children: [router && /* @__PURE__ */ jsx(RouterProvider, { router }), !router && /* @__PURE__ */ jsx(DialogRenderer, {})] }), /* @__PURE__ */ jsx(Toaster, {})] });
|
|
131
142
|
}
|
|
132
143
|
function getLazyComponent(componentString, pluginId, framework, routeId) {
|
|
133
144
|
if (!componentString || !pluginId) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppComponent.js","names":[],"sources":["../../../../src/components/app/AppComponent.tsx"],"sourcesContent":["import {\n Builder,\n createNamespacedId,\n createRemoteComponentLoader,\n defaultRemoteOptions,\n ErrorDisplay,\n Framework,\n FrameworkProvider,\n getDefaultRefineOptions,\n NamespacedId,\n NavigationFeature,\n NavigationItem,\n parseNamespacedId,\n RefineConfigCapability,\n type RouteDefinition,\n RouteErrorBoundary,\n RouteErrorBoundaryFallback,\n useFramework,\n} from \"@lumeweb/portal-framework-core\";\nimport { Toaster } from \"@lumeweb/portal-framework-ui-core\";\nimport { Refine, RefineProps } from \"@refinedev/core\";\nimport routerProvider from \"@refinedev/react-router\";\nimport React, { type ComponentType, useCallback, useEffect } from \"react\";\nimport {\n createBrowserRouter,\n createRoutesFromElements,\n Route,\n RouterProvider,\n} from \"react-router\";\n\nimport { useIdentifyUser } from \"@lumeweb/portal-analytics\";\nimport { registerAllActionItems } from \"@/components/actions\";\nimport { registerAllFormComponents } from \"@/components/form\";\nimport { Loading } from \"@/components/Loading\";\nimport { useAppStore } from \"@/store/appStore\";\nimport { useFrameworkSync } from \"@/store/portalStore\";\n\nimport { DialogProvider, DialogRenderer } from \"@/components\";\n\n// Register all form components at module load time\nregisterAllFormComponents();\nregisterAllActionItems();\n\nexport interface AppComponentProps {\n /** Whether to load navigation structure (default: true) */\n loadNavigation?: boolean;\n /** Whether to load route configurations (default: true) */\n loadRoutes?: boolean;\n /** Application name that will be used in the framework (default: \"app\") */\n name?: string;\n}\n\ntype AppContentProps = AppComponentProps;\n\nfunction AppComponent({\n loadNavigation = true,\n loadRoutes = true,\n name = \"app\",\n}: AppComponentProps) {\n // Memoize the configure function to prevent unnecessary re-renders\n const configureBuilder = useCallback((builder: Builder) => {\n return builder;\n }, []);\n\n return (\n <FrameworkProvider appName={name} configure={configureBuilder}>\n <AppContent loadNavigation={loadNavigation} loadRoutes={loadRoutes} />\n </FrameworkProvider>\n );\n}\n\nfunction AppContent({\n loadNavigation = true,\n loadRoutes = true,\n}: AppContentProps) {\n useIdentifyUser();\n const {\n error: frameworkError,\n framework,\n isLoading: isFrameworkLoading,\n } = useFramework();\n const addMenuItems = useAppStore((state) => state.addMenuItems);\n const error = useAppStore((state) => state.error);\n const isLoading = useAppStore((state) => state.isLoading);\n const pluginConfigs = useAppStore((state) => state.pluginConfigs);\n const routes = useAppStore((state) => state.routes);\n const setError = useAppStore((state) => state.setError);\n const setIsLoading = useAppStore((state) => state.setIsLoading);\n const setPluginConfigs = useAppStore((state) => state.setPluginConfigs);\n const setRoutes = useAppStore((state) => state.setRoutes);\n useFrameworkSync();\n // Load navigation data and plugin configs when framework is ready\n useEffect(() => {\n if (!framework || isFrameworkLoading) {\n return;\n }\n\n let mounted = true;\n\n async function loadData() {\n setIsLoading(true);\n setError(null);\n\n try {\n // Load navigation feature and capabilities in parallel\n let navigationFeature: NavigationFeature | undefined;\n let capabilities: RefineConfigCapability[] = [];\n let routes: RouteDefinition[] = [];\n let navigation: NavigationItem[] = [];\n\n if (loadNavigation) {\n navigationFeature = await framework!.getFeature<NavigationFeature>(\n createNamespacedId(\"core\", \"navigation\"),\n );\n }\n\n if (loadRoutes) {\n capabilities =\n await framework!.getCapabilitiesByType<RefineConfigCapability>(\n \"core:refine-config\",\n );\n }\n\n // Load routes and navigation if feature is enabled\n if (navigationFeature) {\n [routes, navigation] = await Promise.all([\n navigationFeature.getRoutes(),\n navigationFeature.getNavigation(),\n ]);\n }\n\n // Get configs from capabilities if routes are enabled\n const configs = loadRoutes\n ? (() => {\n let lastConfig: Partial<RefineProps> = [] as Partial<RefineProps>;\n return capabilities.map((cap) => {\n const latestConfig = cap.getConfig(lastConfig);\n\n lastConfig = Object.assign({}, lastConfig, latestConfig);\n\n return lastConfig;\n });\n })()\n : [];\n\n if (mounted) {\n setRoutes(routes);\n addMenuItems(navigation);\n setPluginConfigs(configs);\n setIsLoading(false);\n }\n } catch (err) {\n if (mounted) {\n setError(\n err instanceof Error\n ? err\n : new Error(\"Failed to load navigation data\"),\n );\n setIsLoading(false);\n }\n }\n }\n\n loadData();\n\n return () => {\n mounted = false;\n };\n }, [\n framework,\n isFrameworkLoading,\n loadNavigation,\n loadRoutes,\n setError,\n setIsLoading,\n setRoutes,\n setPluginConfigs,\n addMenuItems,\n ]);\n\n // Show loading state while framework is loading or we're loading navigation\n if (isFrameworkLoading || isLoading) {\n return <LoadingSpinner />;\n }\n\n // Show framework errors first\n if (frameworkError) {\n return (\n <ErrorDisplay\n error={frameworkError}\n onRetry={() => window.location.reload()}\n />\n );\n }\n\n // Show errors only if features are enabled\n if (error && (loadNavigation || loadRoutes)) {\n return (\n <ErrorDisplay error={error} onRetry={() => window.location.reload()} />\n );\n }\n\n // Wait for navigation data before rendering routes\n if (!routes) {\n return null;\n }\n\n // Spread plugin configs into a single object for Refine\n const combinedPluginConfig = Object.assign({}, ...pluginConfigs);\n\n const routerRoutes = createRoutesFromElements(\n Array.isArray(routes)\n ? routes.map((route: RouteDefinition) =>\n createRouteElement(route, framework!),\n )\n : [],\n );\n\n function createRouteElement(\n route: RouteDefinition,\n framework: Framework,\n child = false,\n ): React.ReactNode {\n const LazyComponent = getLazyComponent(\n route.component ?? \"\",\n route.pluginId ?? createNamespacedId(\"core\", \"fallback\"),\n framework,\n route.id!,\n );\n\n const jsxElement = LazyComponent ? <LazyComponent /> : null;\n const finalElement = jsxElement ? (\n withRouteContainer(jsxElement, !child)()\n ) : (\n // Use RouteErrorBoundaryFallback directly when component loading fails\n <RouteErrorBoundaryFallback\n error={new Error(`Failed to load element for route ${route.id}`)}\n />\n );\n\n const childRoutes = route.children?.map((childRoute: RouteDefinition) =>\n createRouteElement(childRoute, framework, true),\n );\n\n return (\n // @ts-ignore\n <Route\n element={finalElement}\n errorElement={<RouteErrorBoundary />}\n index={route.index}\n key={route.id}\n path={route.path}>\n {childRoutes}\n </Route>\n );\n }\n\n let router;\n\n if (routerRoutes.length > 0) {\n router = createBrowserRouter(routerRoutes);\n }\n\n const options = {\n ...combinedPluginConfig,\n options: getDefaultRefineOptions(),\n routerProvider,\n } satisfies Partial<RefineProps>;\n\n return (\n <Refine {...options}>\n <DialogProvider>\n {router && <RouterProvider router={router} />}\n {!router && <DialogRenderer />}\n </DialogProvider>\n <Toaster />\n </Refine>\n );\n}\n\nfunction getLazyComponent(\n componentString: string | undefined,\n pluginId: NamespacedId | undefined,\n framework: Framework, // Pass framework instance\n routeId: NamespacedId | string, // For logging\n): ComponentType<any> | null {\n if (!componentString || !pluginId) {\n console.error(\n `Route Error: Missing component string or pluginId for route id ${routeId}`,\n );\n return () => (\n <RouteErrorBoundaryFallback\n error={new Error(`Missing component/pluginId for route ${routeId}`)}\n />\n );\n }\n\n let componentName: string;\n try {\n if (componentString.includes(\":\")) {\n componentName = parseNamespacedId(componentString as NamespacedId).name;\n } else {\n componentName = componentString;\n }\n } catch (e) {\n console.error(\n `Route Error: Failed to parse component string \"${componentString}\" for route id ${routeId}`,\n e,\n );\n return () => (\n <RouteErrorBoundaryFallback\n error={new Error(`Invalid component string format: ${componentString}`)}\n />\n );\n }\n\n if (!componentName) {\n console.error(\n `Route Error: Could not extract componentName from \"${componentString}\" for route id ${routeId}`,\n );\n return () => (\n <RouteErrorBoundaryFallback\n error={new Error(`Invalid component name from: ${componentString}`)}\n />\n );\n }\n\n try {\n //@ts-ignore\n return createRemoteComponentLoader(\n { componentPath: componentName, pluginId: pluginId },\n framework,\n {\n ...defaultRemoteOptions,\n LoadingComponent: Loading,\n }, // Assuming defaultRemoteOptions is accessible or passed\n );\n } catch (e) {\n console.error(\n `Route Error: Failed createRemoteComponentLoader for ${pluginId}:${componentName}`,\n e,\n );\n return () => (\n <RouteErrorBoundaryFallback\n error={\n new Error(`Failed to create loader for ${pluginId}:${componentName}`)\n }\n />\n );\n }\n}\n\nfunction LoadingSpinner() {\n return (\n <div>\n <div className=\"animate-pulse\">\n <div className=\"h-4 w-3/4 rounded bg-gray-200\"></div>\n <div className=\"mt-4 space-y-3\">\n <div className=\"h-4 rounded bg-gray-200\"></div>\n <div className=\"h-4 rounded bg-gray-200\"></div>\n </div>\n </div>\n </div>\n );\n}\n\nfunction withRouteContainer(element: React.ReactNode, renderDialog: boolean) {\n return function RouteContainerHOC() {\n return (\n <>\n {renderDialog && <DialogRenderer />}\n {element}\n </>\n );\n };\n}\nexport { AppComponent };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AppComponent.js","names":[],"sources":["../../../../src/components/app/AppComponent.tsx"],"sourcesContent":["import {\n Builder,\n createNamespacedId,\n createRemoteComponentLoader,\n defaultRemoteOptions,\n ErrorDisplay,\n Framework,\n FrameworkProvider,\n getDefaultRefineOptions,\n NamespacedId,\n NavigationFeature,\n NavigationItem,\n parseNamespacedId,\n RefineConfigCapability,\n type RouteDefinition,\n RouteErrorBoundary,\n RouteErrorBoundaryFallback,\n useFramework,\n} from \"@lumeweb/portal-framework-core\";\nimport { Toaster } from \"@lumeweb/portal-framework-ui-core\";\nimport { Refine, RefineProps } from \"@refinedev/core\";\nimport routerProvider from \"@refinedev/react-router\";\nimport React, { type ComponentType, useCallback, useEffect } from \"react\";\nimport {\n createBrowserRouter,\n createRoutesFromElements,\n Route,\n RouterProvider,\n} from \"react-router\";\n\nimport { useIdentifyUser } from \"@lumeweb/portal-analytics\";\nimport { registerAllActionItems } from \"@/components/actions\";\nimport { registerAllFormComponents } from \"@/components/form\";\nimport { Loading } from \"@/components/Loading\";\nimport { useAppStore } from \"@/store/appStore\";\nimport { useFrameworkSync } from \"@/store/portalStore\";\n\nimport { DialogProvider, DialogRenderer } from \"@/components\";\n\n// Register all form components at module load time\nregisterAllFormComponents();\nregisterAllActionItems();\n\nexport interface AppComponentProps {\n /** Whether to load navigation structure (default: true) */\n loadNavigation?: boolean;\n /** Whether to load route configurations (default: true) */\n loadRoutes?: boolean;\n /** Application name that will be used in the framework (default: \"app\") */\n name?: string;\n}\n\ntype AppContentProps = AppComponentProps;\n\nfunction AppComponent({\n loadNavigation = true,\n loadRoutes = true,\n name = \"app\",\n}: AppComponentProps) {\n // Memoize the configure function to prevent unnecessary re-renders\n const configureBuilder = useCallback((builder: Builder) => {\n return builder;\n }, []);\n\n return (\n <FrameworkProvider appName={name} configure={configureBuilder}>\n <AppContent loadNavigation={loadNavigation} loadRoutes={loadRoutes} />\n </FrameworkProvider>\n );\n}\n\nfunction AppContent({\n loadNavigation = true,\n loadRoutes = true,\n}: AppContentProps) {\n const {\n error: frameworkError,\n framework,\n isLoading: isFrameworkLoading,\n } = useFramework();\n const addMenuItems = useAppStore((state) => state.addMenuItems);\n const error = useAppStore((state) => state.error);\n const isLoading = useAppStore((state) => state.isLoading);\n const pluginConfigs = useAppStore((state) => state.pluginConfigs);\n const routes = useAppStore((state) => state.routes);\n const setError = useAppStore((state) => state.setError);\n const setIsLoading = useAppStore((state) => state.setIsLoading);\n const setPluginConfigs = useAppStore((state) => state.setPluginConfigs);\n const setRoutes = useAppStore((state) => state.setRoutes);\n useFrameworkSync();\n // Load navigation data and plugin configs when framework is ready\n useEffect(() => {\n if (!framework || isFrameworkLoading) {\n return;\n }\n\n let mounted = true;\n\n async function loadData() {\n setIsLoading(true);\n setError(null);\n\n try {\n // Load navigation feature and capabilities in parallel\n let navigationFeature: NavigationFeature | undefined;\n let capabilities: RefineConfigCapability[] = [];\n let routes: RouteDefinition[] = [];\n let navigation: NavigationItem[] = [];\n\n if (loadNavigation) {\n navigationFeature = await framework!.getFeature<NavigationFeature>(\n createNamespacedId(\"core\", \"navigation\"),\n );\n }\n\n if (loadRoutes) {\n capabilities =\n await framework!.getCapabilitiesByType<RefineConfigCapability>(\n \"core:refine-config\",\n );\n }\n\n // Load routes and navigation if feature is enabled\n if (navigationFeature) {\n [routes, navigation] = await Promise.all([\n navigationFeature.getRoutes(),\n navigationFeature.getNavigation(),\n ]);\n }\n\n // Get configs from capabilities if routes are enabled\n const configs = loadRoutes\n ? (() => {\n let lastConfig: Partial<RefineProps> = [] as Partial<RefineProps>;\n return capabilities.map((cap) => {\n const latestConfig = cap.getConfig(lastConfig);\n\n lastConfig = Object.assign({}, lastConfig, latestConfig);\n\n return lastConfig;\n });\n })()\n : [];\n\n if (mounted) {\n setRoutes(routes);\n addMenuItems(navigation);\n setPluginConfigs(configs);\n setIsLoading(false);\n }\n } catch (err) {\n if (mounted) {\n setError(\n err instanceof Error\n ? err\n : new Error(\"Failed to load navigation data\"),\n );\n setIsLoading(false);\n }\n }\n }\n\n loadData();\n\n return () => {\n mounted = false;\n };\n }, [\n framework,\n isFrameworkLoading,\n loadNavigation,\n loadRoutes,\n setError,\n setIsLoading,\n setRoutes,\n setPluginConfigs,\n addMenuItems,\n ]);\n\n const options = {\n ...pluginConfigs,\n options: getDefaultRefineOptions(),\n routerProvider,\n } satisfies Partial<RefineProps>;\n\n return (\n <Refine {...options}>\n <AppContentInner\n error={error}\n framework={framework}\n frameworkError={frameworkError}\n isFrameworkLoading={isFrameworkLoading}\n isLoading={isLoading}\n loadNavigation={loadNavigation}\n loadRoutes={loadRoutes}\n routes={routes}\n />\n </Refine>\n );\n}\n\nfunction AppContentInner({\n error,\n framework,\n frameworkError,\n isFrameworkLoading,\n isLoading,\n loadNavigation,\n loadRoutes,\n routes,\n}: {\n error: Error | null;\n framework: Framework | null;\n frameworkError: Error | null;\n isFrameworkLoading: boolean;\n isLoading: boolean;\n loadNavigation: boolean;\n loadRoutes: boolean;\n routes: null | RouteDefinition[];\n}) {\n useIdentifyUser();\n\n // Show loading state while framework is loading or we're loading navigation\n if (isFrameworkLoading || isLoading) {\n return <LoadingSpinner />;\n }\n\n // Show framework errors first\n if (frameworkError) {\n return (\n <ErrorDisplay\n error={frameworkError}\n onRetry={() => window.location.reload()}\n />\n );\n }\n\n // Show errors only if features are enabled\n if (error && (loadNavigation || loadRoutes)) {\n return (\n <ErrorDisplay error={error} onRetry={() => window.location.reload()} />\n );\n }\n\n // Wait for navigation data before rendering routes\n if (!routes) {\n return null;\n }\n\n const routerRoutes = createRoutesFromElements(\n Array.isArray(routes)\n ? routes.map((route: RouteDefinition) =>\n createRouteElement(route, framework!),\n )\n : [],\n );\n\n function createRouteElement(\n route: RouteDefinition,\n framework: Framework,\n child = false,\n ): React.ReactNode {\n const LazyComponent = getLazyComponent(\n route.component ?? \"\",\n route.pluginId ?? createNamespacedId(\"core\", \"fallback\"),\n framework,\n route.id!,\n );\n\n const jsxElement = LazyComponent ? <LazyComponent /> : null;\n const finalElement = jsxElement ? (\n withRouteContainer(jsxElement, !child)()\n ) : (\n // Use RouteErrorBoundaryFallback directly when component loading fails\n <RouteErrorBoundaryFallback\n error={new Error(`Failed to load element for route ${route.id}`)}\n />\n );\n\n const childRoutes = route.children?.map((childRoute: RouteDefinition) =>\n createRouteElement(childRoute, framework, true),\n );\n\n return (\n <Route\n element={finalElement}\n errorElement={<RouteErrorBoundary />}\n index={route.index}\n path={route.path}>\n {childRoutes}\n </Route>\n );\n }\n\n let router;\n\n if (routerRoutes.length > 0) {\n router = createBrowserRouter(routerRoutes);\n }\n\n return (\n <>\n <DialogProvider>\n {router && <RouterProvider router={router} />}\n {!router && <DialogRenderer />}\n </DialogProvider>\n <Toaster />\n </>\n );\n}\n\nfunction getLazyComponent(\n componentString: string | undefined,\n pluginId: NamespacedId | undefined,\n framework: Framework, // Pass framework instance\n routeId: NamespacedId | string, // For logging\n): ComponentType<unknown> | null {\n if (!componentString || !pluginId) {\n console.error(\n `Route Error: Missing component string or pluginId for route id ${routeId}`,\n );\n return () => (\n <RouteErrorBoundaryFallback\n error={new Error(`Missing component/pluginId for route ${routeId}`)}\n />\n );\n }\n\n let componentName: string;\n try {\n if (componentString.includes(\":\")) {\n componentName = parseNamespacedId(componentString as NamespacedId).name;\n } else {\n componentName = componentString;\n }\n } catch (e) {\n console.error(\n `Route Error: Failed to parse component string \"${componentString}\" for route id ${routeId}`,\n e,\n );\n return () => (\n <RouteErrorBoundaryFallback\n error={new Error(`Invalid component string format: ${componentString}`)}\n />\n );\n }\n\n if (!componentName) {\n console.error(\n `Route Error: Could not extract componentName from \"${componentString}\" for route id ${routeId}`,\n );\n return () => (\n <RouteErrorBoundaryFallback\n error={new Error(`Invalid component name from: ${componentString}`)}\n />\n );\n }\n\n try {\n //@ts-expect-error -- createRemoteComponentLoader return type mismatch\n return createRemoteComponentLoader(\n { componentPath: componentName, pluginId: pluginId },\n framework,\n {\n ...defaultRemoteOptions,\n LoadingComponent: Loading,\n }, // Assuming defaultRemoteOptions is accessible or passed\n );\n } catch (e) {\n console.error(\n `Route Error: Failed createRemoteComponentLoader for ${pluginId}:${componentName}`,\n e,\n );\n return () => (\n <RouteErrorBoundaryFallback\n error={\n new Error(`Failed to create loader for ${pluginId}:${componentName}`)\n }\n />\n );\n }\n}\n\nfunction LoadingSpinner() {\n return (\n <div>\n <div className=\"animate-pulse\">\n <div className=\"h-4 w-3/4 rounded bg-gray-200\"></div>\n <div className=\"mt-4 space-y-3\">\n <div className=\"h-4 rounded bg-gray-200\"></div>\n <div className=\"h-4 rounded bg-gray-200\"></div>\n </div>\n </div>\n </div>\n );\n}\n\nfunction withRouteContainer(element: React.ReactNode, renderDialog: boolean) {\n return function RouteContainerHOC() {\n return (\n <>\n {renderDialog && <DialogRenderer />}\n {element}\n </>\n );\n };\n}\nexport { AppComponent };\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lumeweb/portal-framework-ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"react-is": "^19.2.6",
|
|
26
26
|
"use-debounce": "^10.1.1",
|
|
27
27
|
"@lumeweb/portal-analytics": "0.1.0",
|
|
28
|
-
"@lumeweb/portal-
|
|
29
|
-
"@lumeweb/portal-
|
|
28
|
+
"@lumeweb/portal-sdk": "0.1.5",
|
|
29
|
+
"@lumeweb/portal-framework-ui-core": "0.1.2"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@rollup/plugin-image": "^3.0.3",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"react-router": "^7.15.0",
|
|
65
65
|
"zod": "^4.4.3",
|
|
66
66
|
"zustand": "^5.0.9",
|
|
67
|
-
"@lumeweb/portal-framework-core": "^0.1.
|
|
67
|
+
"@lumeweb/portal-framework-core": "^0.1.2"
|
|
68
68
|
},
|
|
69
69
|
"repository": {
|
|
70
70
|
"type": "git",
|