npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

prolonreactcomponents

v3.2.0

Published

Reusable components for prolon BMSnet solution

Downloads

1,811

Readme

prolonreactcomponents

Shared React components, models and helpers for the BMSnet applications (BMSnetAdmin, the identity provider client, the alarm UI). This file is the one description of how an application consumes the library; the applications are expected to follow it, so that they all look and behave the same and a change lands in one place.

What you get

  • App shell: AuthorizationProvider, Topbar, MenuDrawer, ApplicationMenu and the menu resolver, createProlonTheme.
  • Screens: ActionBar, ProlonDataGrid / DataGridBase, SidesheetBase with SidesheetSection, PropertyList, Tabs, SplitView, Breadcrumb.
  • Inputs: InputField, SearchField, Select, Autocomplete, CheckBox, CoordField, DateRangePicker, YearPicker, the tag editors, FormulaEditor, TimeValueCreator.
  • Models and helpers: EntityViewModel, EntityTreeModel, Tenant, Tag and the tag kinds, User, fetchState, CustomError, isValidGuid, samePageLinkNavigation.

Everything is exported from the package root. dist/index.d.ts is the authoritative list.

Requirements

  • ESM only (since 3.0.0). The library is published as ES modules, which every Vite application consumes natively. There is no CommonJS build and there will not be one: a CommonJS library resolves to the CommonJS copy of dual-build packages such as react-oidc-context while an ESM application resolves to the ESM copy, and React contexts do not cross that line. That is why the shared AuthorizationProvider could not be used before 3.0.0.
  • Peer dependencies: React 19, @mui/material 7, @mui/icons-material 7, MUI X 8 (@mui/x-data-grid-pro, @mui/x-date-pickers-pro, @mui/x-license), react-router-dom 7, react-oidc-context 3, oidc-client-ts 3, @emotion/react and @emotion/styled, date-fns 4, dayjs, moment. Keep the application on the same majors; npm install refuses otherwise, and --legacy-peer-deps is not the answer, since it silences every future mismatch too.

Install

npm install prolonreactcomponents@^3

Importing

Import from the package root:

import { ActionBar, SidesheetBase, SidesheetSection, fetchState } from 'prolonreactcomponents';

The build is ESM with sideEffects: false, so bundlers drop what you do not use. The deep-path form (prolonreactcomponents/dist/Sidesheet/SidesheetBase) still resolves and older code need not change, but there is no longer a reason to write it.

Do the same with MUI: @mui/icons-material/Add rather than the icons barrel, since MUI's icon barrel is not tree-shaken in development.

The app shell

Every BMSnet application is built the same way. Top to bottom:

<AppSettingsProvider>                         {/* the app's own: fetches /api/settings?clientId=… */}
  <BrowserRouter basename={basePath}>
    <AuthorizationProvider …>                 {/* library */}
      <ThemeProvider theme={createProlonTheme(daDK, dataGridDaDK)} defaultMode="system">
        <CssBaseline enableColorScheme />
        <Topbar … />                          {/* library, mode from useColorScheme */}
        <MenuDrawer … />                      {/* library */}
        <Outlet />
      </ThemeProvider>
    </AuthorizationProvider>
  </BrowserRouter>
</AppSettingsProvider>

Settings

Settings come from the settings service, anonymously, before sign-in: GET {origin}/api/settings?clientId=<client> returns the authority, the API base URLs, the theme colour, the sibling application paths and the application menu. Fetch it once at the top of the tree and expose it through a context. The library does not do this for you, because each application has its own client id and settings shape, but it expects the fields below to be present.

Authorization

import { AuthorizationProvider } from 'prolonreactcomponents';
import { AuthProviderProps } from 'react-oidc-context';

const oidcConfig: AuthProviderProps = {
    authority: settings.authority,
    client_id: clientId,
    scope: "bmsnetdataapi offline_access openid bmsnetiot",
    redirect_uri: `${window.location.origin}${basePath}/authentication/callback`,
    silent_redirect_uri: `${window.location.origin}${basePath}/authentication/signin-callback`,
    post_logout_redirect_uri: `${window.location.origin}${basePath}`,
    response_type: "code",
    automaticSilentRenew: true,
    loadUserInfo: true,
    // Return to where the user was before the sign-in round trip. The handler stores it.
    onSigninCallback: () => {
        const stored = window.sessionStorage.getItem("location");
        if (stored) navigate(JSON.parse(stored), { replace: true });
    },
};

<AuthorizationProvider clientId={clientId} authority={settings} oidcConfig={oidcConfig} basePath={basePath}>
    {children}
</AuthorizationProvider>

The provider wraps react-oidc-context's AuthProvider and a handler that shows a spinner while loading, sends an unauthenticated user to sign-in once per page load after remembering where they were, and on an authentication error shows the message with a retry button rather than redirecting again (an automatic redirect on error loops against a failing identity server). Pass labels to translate the error texts; the defaults are Danish. Code outside React (an axios interceptor, a SignalR token factory) can read the current token through useAuth() in a small component that publishes it, or through the exported auth object. Anywhere below it, useAuth() from react-oidc-context gives the user and the access token. Until settings.authority has arrived, render children without the provider; the identity provider is not known yet.

The OAuth client's redirect URIs name the exact origin, so a dev server must run on a fixed port.

Theme and colour mode

createProlonTheme(...localization) returns the BMSnet theme with both colour schemes and the component overrides (square controls, dense grids, list and tab sizing). Pass the MUI and MUI X locale objects for the language.

Colour mode is owned by MUI: render ThemeProvider with defaultMode="system" and drive the Topbar's Lys / System / Mørk switch from useColorScheme(), in a component rendered inside the provider:

function ThemedTopbar(props: Omit<TopbarProps, 'mode' | 'setMode'>) {
    const { mode, setMode } = useColorScheme();
    return <Topbar {...props} mode={mode ?? 'system'} setMode={setMode} />;
}

Do not keep a light/dark state of your own: with colour schemes declared, the provider ignores palette.mode, and MUI persists the user's choice for you.

Topbar, drawer and application switcher

  • Topbar takes the title, an optional logo slot (the application switcher button goes here), the user block (name, company, email, signOut, userClick) and the mode props above.
  • MenuDrawer takes buttons: NavButton[] and userAccess. A NavButton with divider starts a group; requiresAnyOf hides an entry from users without one of the named permissions.
  • The switcher between BMSnet applications is served by the settings service as menu, a JSON-encoded string. Always go through parseMenu, never a length check, then resolveMenu with a hasPermission callback backed by the access token's role claims, then render with ApplicationMenu. Navigate with location.assign, not replace, so Back returns to the application. defaultMenu exists only as a fallback for the service being unreachable.

Sidesheets

SidesheetBase is the panel: title, subtitle, action bar, alerts, bottom buttons, unsaved-changes dialog. Group its content with variant="grouped" and SidesheetSection:

<SidesheetBase title={entity.dis} variant="grouped" …>
    <SidesheetSection title="Tenant">…</SidesheetSection>
    <SidesheetSection title="Værdi tags" collapsible>…</SidesheetSection>
</SidesheetBase>

A collapsible section gets a heading and a chevron; a plain one gets a small label. PropertyList / PropertyRow render read-only facts as label left, value right, with an optional copy button. The variant is opt-in, so a sheet without it looks as it always did.

Data grid selection

MUI X 8's rowSelectionModel is { type: 'include' | 'exclude', ids: Set }. Never read .ids as the selection: an exclude model, which the header checkbox produces, lists what is not selected. Keep application state as an id array and convert at the grid boundary.

Versioning and publishing

  • Semantic versioning. Additive changes are a minor bump, a change that alters what existing consumers get is a major bump. 3.0.0 is the ESM switch.
  • Publishing is automatic: every push to master builds src/components and publishes it to npm. Bump src/components/package.json in the same push as the change it releases. A push without a bump fails the publish harmlessly; a bump pushed before the change publishes the old code under the new number.
  • Never npm publish by hand.
  • Record the change in CHANGELOG.md next to this file.

Upgrading from 2.x to 3.0.0

  1. npm install prolonreactcomponents@^3.
  2. Nothing to change for imports; deep paths keep working.
  3. If the application kept a local copy of AuthorizationProvider to work around the context duplication, replace it with the library's as shown above and delete the copy.
  4. If the application drove the Topbar's mode switch from its own state, move it to useColorScheme as shown above.