@onecx/react-utils
Overview
@onecx/react-utils provides runtime helpers used by React micro-frontends inside OneCX. It focuses on style scoping, dynamic theme variable injection, and portal-aware wiring needed for PrimeReact and remote component isolation.
Public Exports
The package exports the following public API:
-
withApp,withRemotefrom@onecx/react-utils/styling(HOCs for wiring providers and style isolation) -
applyThemeVariablesfrom@onecx/react-utils/theme -
PortalPagefrom@onecx/react-utils -
registerPortalPageTranslations,getTranslationPathFromMetafrom@onecx/react-utils(translation helpers) -
guards hooks (
useGuardCheck,useGuardDeactivation,useGuardsGatherer,useWrappedGuards) from@onecx/react-utils/guards -
TranslationBridge,withBaseProviders,withAppGlobals,composeProviders,styleAttributesfrom@onecx/react-utils/utils -
primeBaseTheme.scssfrom@onecx/react-utils/primeBaseTheme.scss(PrimeReact theme base styles)
Public entrypoints:
-
@onecx/react-utils -
@onecx/react-utils/guards -
@onecx/react-utils/styling -
@onecx/react-utils/theme -
@onecx/react-utils/utils -
@onecx/react-utils/primeBaseTheme.scss
Style Scoping
The style scoping and PrimeReact isolation are wired automatically by withApp and withRemote. Use the HOCs to ensure the scoper is attached and scoped containers are provided for your microfrontend.
Theme Variable Injection
Theme variables can be injected at runtime by calling applyThemeVariables, which updates the @layer tokens block inside scoped style tags.
import { applyThemeVariables } from '@onecx/react-utils/theme';
applyThemeVariables(theme, 'example|example-ui');
Dynamic Scoping (Portals)
To ensure styles remain scoped for portal-rendered PrimeReact components, the package intercepts portal creation and appends intermediate style data for isolation (enabled automatically by the HOCs).
PortalPage
PortalPage is a layout helper that publishes page metadata to the shell (via CurrentPageTopic) and optionally guards content based on permissions. It also exposes a standard container (.portal-page) and prints translated unauthorized messages when access is denied.
import { PortalPage } from '@onecx/react-utils';
export const Detail = () => (
<PortalPage
pageName="Detail"
helpArticleId="detail-page"
permission="TEST#DETAIL"
>
<DetailContent />
</PortalPage>
);
TranslationBridge
TranslationBridge syncs the OneCX user language (from UserService.lang$) with react-i18next by calling i18n.changeLanguage. It is automatically mounted by withApp and withRemote through withBaseProviders.
import { TranslationBridge } from '@onecx/react-utils/utils';
Translation Resource Registration
Use the helpers below to wire portal translations into your i18next backend configuration (for example inside an i18n setup file):
import i18n from 'i18next';
import { registerPortalPageTranslations } from '@onecx/react-utils';
registerPortalPageTranslations(i18n, import.meta.url);
If you need to resolve a different base path, use getTranslationPathFromMeta directly:
import { getTranslationPathFromMeta } from '@onecx/react-utils';
const basePath = getTranslationPathFromMeta(import.meta.url, 'assets/i18n/');
Style Attributes
The styleAttributes exports provide the standard data-attributes used for style scoping. Use them when you need to render custom containers or dynamic content outside the default HOCs:
import {
dataStyleIdAttribute,
dataStyleIsolationAttribute,
dataNoPortalLayoutStylesAttribute,
} from '@onecx/react-utils/utils';
export const ScopedContainer = ({ scopeId, children }) => (
<div
{...{
[dataStyleIdAttribute]: scopeId,
[dataStyleIsolationAttribute]: '',
[dataNoPortalLayoutStylesAttribute]: '',
}}
>
{children}
</div>
);
withApp / withRemote
withApp is used for main app shells, while withRemote is used for remote micro-frontends. Both:
-
wire base providers (app state, configuration, user)
-
attach translation syncing via
TranslationBridge -
set up PrimeReact style scoping and theme registry
Use them as follows:
import { withApp, withRemote } from '@onecx/react-utils';
export default withApp(AppRouter, {
PRODUCT_NAME: 'example',
REMOTES_NAME: 'example-remotes'
});
export default withRemote(RemoteWidget, {
PRODUCT_NAME: 'example',
REMOTES_NAME: 'example-remotes'
});
PrimeReact Theme Base Import
To apply PrimeReact theming consistently, you must import the base theme stylesheet from this package in your app styles:
@import "@onecx/react-utils/primeBaseTheme.scss";
Guards
The guards utilities help you execute canActivate, canDeactivate, canMatch, and canActivateChild checks in React Router flows (React Router v6/v7). They are exported from the dedicated entry point:
import {
useGuardCheck,
useGuardDeactivation,
useGuardsGatherer,
useWrappedGuards,
} from '@onecx/react-utils/guards';
Example usage (simplified):
const Guards = () => {
const { guardCheck } = useGuardCheck();
const runGuards = async () => {
const result = await guardCheck('/orders', {
canActivate: [() => true],
canMatch: [() => true],
});
if (!result) {
// handle blocked navigation
}
};
return <button onClick={runGuards}>Check guards</button>;
};
For coordinated navigation flows across multiple remotes, you can wire the lower-level helpers:
-
GuardsNavigationStateControllerto track guard state modes -
GuardsGathererto collect guard results before committing navigation