@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, withRemote from @onecx/react-utils/styling (HOCs for wiring providers and style isolation)

  • applyThemeVariables from @onecx/react-utils/theme

  • PortalPage from @onecx/react-utils

  • registerPortalPageTranslations, getTranslationPathFromMeta from @onecx/react-utils (translation helpers)

  • guards hooks (useGuardCheck, useGuardDeactivation, useGuardsGatherer, useWrappedGuards) from @onecx/react-utils/guards

  • TranslationBridge, withBaseProviders, withAppGlobals, composeProviders, styleAttributes from @onecx/react-utils/utils

  • primeBaseTheme.scss from @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:

  • GuardsNavigationStateController to track guard state modes

  • GuardsGatherer to collect guard results before committing navigation

Application Wiring

The withApp HOC composes common providers (app state, configuration, user, theme) and sets up the style scoping helpers for micro-frontends.