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

robobyte-front-builder

v1.0.35-beta.12

Published

RoboByte low-code UI builder, Report builder, and navigation extension system

Readme

robobyte-front-builder

A low-code UI Builder, Report Builder, Print Layout Designer, and Navigation Extension API for Next.js applications.

npm version license github


📚 Documentation

| Document | Audience | What it covers | |---|---|---| | README.md (this file) | Everyone | Public surface, provider props, every component's inspector schema, action-scope tables, troubleshooting, changelog. The exhaustive reference. | | INTEGRATION.md | Host-app developers | next.config.js setup, peer deps, page wrapper pattern, provider bridge, print layout integration steps. | | docs/ReportViewer.md | Host-app developers | Embedding <ReportViewer> in regular React (cancellation, memo'd filters, viewerActions, master/detail patterns). | | docs/fetchReportData.md | Host-app developers | Calling fetchReportDataByPageId directly from host code (hooks, KPI counters, XLSX export, paginated cursors). | | docs/printLayout.md | Host-app developers | Triggering print layouts via PrintDialog ref API, recommended PrintProvider + usePrintLayout() pattern. | | training/00-index.md | AI sessions / schema authors | Component catalog index — categories and one-page refs for every component the builder ships. | | training/35-reportViewer.md | AI sessions / schema authors | Full AI manual for the reportViewer component (Calculation scope, action arrays, filter shape, recipes). | | training/48-fetchReportData.md | AI sessions / schema authors | In-builder Calculation reference for the auto-injected fetchReportData helper. | | training/49-printLayout.md | AI sessions / schema authors | In-builder Calculation reference for openPrintLayout / closePrintLayout. | | RoboByteBuilder_User_Manual.docx | End users | Visual user manual for the builder UI. Ships inside the package. |

Pair convention. Most features have two manuals: a docs/ one for host-app React code (consumer of the package) and a training/ one for AI sessions emitting builder schemas / Calculation code. They cross-link each other; pick the audience that matches your task.


Table of Contents

  1. What's included
  2. Requirements
  3. Installation
  4. Peer dependencies
  5. next.config.js setup
  6. Provider setup
  7. Builder pages
  8. Navigation Extension API
  9. Provider props reference
  10. AG Grid theme
  11. MUI theme
  12. fetchReportDataByPageId
  13. ReportViewer as a component
  14. Data Grid component
  15. Dialog component
  16. Popover component
  17. Excel Upload component
  18. Wizard component
  19. Repeater component
  20. Menu component
  21. View Renderer component
  22. Layout Grid component
  23. Breadcrumb component
  24. Print Layout Builder
  25. Calculation Scope Reference
  26. KPI Component Actions
  27. Global Data Store
  28. Dark / Light theme
  29. Syncing local changes
  30. Troubleshooting
  31. Publishing
  32. Changelog

What's included

  • UI Builder — drag-and-drop canvas for building data-driven views with 50+ components
  • Report Builder — design and preview paginated reports with AG Grid
  • Print Layout Designer — multi-zone print templates (header / body pages / footer)
  • Navigator Builder — configure sidebar navigation
  • Viewer — production read-only renderer for saved UI Builder views
  • Navigation Extension API — inject nav items from the host app without forking the package
  • KPI Components — 12 ready-to-use metric visualisations (gauge, trend, bullet chart, rating, countdown, …)
  • Timer Engine — configurable auto-refresh timers per view
  • Undo / Redo / Copy / Paste — full clipboard and history support in the builder
  • Global Data Store — cross-route reactive state that survives client-side navigations

Requirements

| Dependency | Version | |---|---| | Node.js | ≥ 18 | | React / React DOM | ≥ 18 | | Next.js | ≥ 13 | | @mui/material | ≥ 7 | | AG Grid | ≥ 33 |


Installation

npm install robobyte-front-builder

Peer dependencies

Only the libraries that must be shared as a single instance are declared as peerDependencies — React, MUI, Emotion, and AG Grid. Everything else ships inside the package so the host app doesn't need to install them manually.

npm install \
  react react-dom next \
  @mui/material @mui/icons-material @mui/lab @mui/system \
  @mui/x-data-grid @mui/x-date-pickers @mui/x-internals @mui/x-virtualizer \
  @emotion/react @emotion/styled \
  ag-grid-community ag-grid-enterprise ag-grid-react \
  xlsx react-hot-toast

Why only these? React and MUI use context and module registries that break if two copies exist in the same app (hooks errors, theme not applied, AG Grid license warnings). xlsx is required by the Excel Upload component and is resolved from the host app's node_modules because the builder source is transpiled in the host's webpack context. Everything else — dayjs, lodash, recharts, etc. — can safely run from the package's own node_modules copy with no side effects.


next.config.js setup

Two things are required: transpile the package and set up the context-aware bare-alias webpack plugin so that bare imports like services/*, context/*, etc. resolve to the correct source tree.

const path = require('path')
const withTM = require('next-transpile-modules')(['robobyte-front-builder'])

const hostSrc    = path.resolve(__dirname, 'src')
const builderSrc = path.resolve(__dirname, 'node_modules/robobyte-front-builder/src')

module.exports = withTM({
  webpack(config, { isServer }) {
    if (isServer) {
      config.resolve.conditionNames = ['require', 'node', 'default']
    }

    const { NormalModuleReplacementPlugin } = require('webpack')

    // Package-owned services — always resolved from the package
    const packageOwnedServices = [
      'services/reportData/fetchReportData',
    ]
    packageOwnedServices.forEach(mod => {
      config.plugins.push(
        new NormalModuleReplacementPlugin(
          new RegExp(`^${mod.replace(/\//g, '\\/')}(\\.js)?$`),
          resource => { resource.request = path.join(builderSrc, mod) }
        )
      )
    })

    // Context-aware bare alias routing
    config.plugins.push(
      new NormalModuleReplacementPlugin(
        /^(services|views|context|src|pages)(\/|$)/,
        resource => {
          const isBuilder =
            resource.context.includes('robobyte-front-builder') ||
            resource.context.includes('RoboByteFrontBuilder')
          const root = isBuilder ? builderSrc : hostSrc
          resource.request = resource.request.replace(
            /^(services|views|context|src|pages)(\/|$)/,
            (_, prefix, sep) =>
              prefix === 'src'
                ? root + sep
                : path.join(root, prefix) + sep
          )
        }
      )
    )

    return config
  },
})

Restart the dev server whenever next.config.js changes — hot-reload does not apply to webpack plugin changes.


Provider setup (_app.js)

Wrap the component tree with RoboByteFrontBuilderProvider. Bridge your host auth context into it so the package attaches auth headers to every API call.

import { RoboByteFrontBuilderProvider } from 'robobyte-front-builder'

function RoboByteBridge({ children }) {
  const auth = useContext(YourAuthContext)
  return (
    <RoboByteFrontBuilderProvider
      baseURL={process.env.NEXT_PUBLIC_API_BASE_URL}
      apiURL={process.env.NEXT_PUBLIC_API_URL}
      user={auth.user}
      accessToken={auth.accessToken}
      agGridLicenseKey={process.env.NEXT_PUBLIC_AG_GRID_LICENSE_KEY}
      // Optional: Quartz theme overrides applied to every <AgGridReact>
      // in the package. Merged on top of the package defaults — see the
      // "AG Grid theme" section for the full list of params and the
      // programmatic API. Omit to use the package defaults.
      agGridTheme={{ accentColor: '#3b82f6' }}
      // Optional: MUI theme overrides applied to every MUI component the
      // package renders. Deep-merged on top of DEFAULT_MUI_THEME_OPTIONS.
      // See the "MUI theme" section for the full token list. Omit to use
      // the package defaults (Inter font, 8px radius, soft shadows, etc.).
      muiTheme={{
        palette: { primary: { main: '#3b82f6' } },
        shape:   { borderRadius: 10 },
      }}
    >
      {children}
    </RoboByteFrontBuilderProvider>
  )
}

export default function App({ Component, pageProps }) {
  const getLayout = Component.getLayout ?? (page => page)
  return (
    <YourAuthProvider>
      <RoboByteBridge>
        {getLayout(<Component {...pageProps} />)}
      </RoboByteBridge>
    </YourAuthProvider>
  )
}

Builder pages

All builder routes live under the /builders/ prefix. Create a thin wrapper page in your host app for each route.

| Route | Package export | |---|---| | /builders/ui | UIBuilderPage | | /builders/ui/views | ViewsList | | /builders/report | ReportBuilderPage | | /builders/report/list | ReportsList | | /builders/report/viewer | ReportViewer | | /builders/report/reportsPermissions | ReportsCard | | /builders/navigator | NavigatorBuilderPage | | /viewer/[id] | ViewerPage | | /printBuilder | PrintBuilderPage | | /printBuilder/layouts | PrintLayoutsList |

Page wrapper pattern

Use explicit import + static property assignment. A bare export { X as default } does not reliably carry getLayout, acl, authGuard across package boundaries in Next.js.

// pages/builders/report/viewer/index.jsx
import { ReportViewer } from 'robobyte-front-builder'
import BlankLayout from 'src/@core/layouts/BlankLayout'
import PermissionsSubjects from 'src/configs/Permissions/PermissionsSubjects.json'

ReportViewer.getLayout  = page => <BlankLayout>{page}</BlankLayout>
ReportViewer.acl        = { action: 'view', subject: PermissionsSubjects.Free }
ReportViewer.authGuard  = true
ReportViewer.guestGuard = false
export default ReportViewer

Viewer page (/viewer/[id])

import { useContext } from 'react'
import { ViewerPage, SystemContext } from 'robobyte-front-builder'
import { YourNavContext } from 'src/context/YourNavContext'

function SystemContextBridge({ children }) {
  const { nav } = useContext(YourNavContext)
  return (
    <SystemContext.Provider value={{ nav }}>
      {children}
    </SystemContext.Provider>
  )
}

export default function ViewerRoute() {
  return (
    <SystemContextBridge>
      <ViewerPage />
    </SystemContextBridge>
  )
}

ViewerRoute.authGuard  = true
ViewerRoute.guestGuard = false

Navigation Extension API

Option A — Static items via the Provider

<RoboByteFrontBuilderProvider
  navExtensions={[
    {
      id: 'host-analytics',
      title: 'Analytics',
      icon: 'ChartBar',
      type: 'static',
      path: '/analytics',
      insertAt: 'end',
    },
  ]}
>
  ...
</RoboByteFrontBuilderProvider>

Option B — Dynamic items via useNavExtension hook

import { useNavExtension } from 'robobyte-front-builder'

function MyFeaturePlugin() {
  useNavExtension(
    [{ id: 'my-feature', title: 'My Feature', icon: 'StarOutline', type: 'static', path: '/my-feature', insertAt: 'start' }],
    'my-feature-plugin'
  )
  return null
}

Nav item shape

| Field | Type | Required | Description | |---|---|---|---| | id | string | yes | Stable unique identifier | | title | string | yes | Display label | | icon | string | no | mdi-material-ui icon name | | type | 'static' | 'dynamic' | 'external' | yes | Route type | | path | string | for static | Absolute path | | viewId | number | for dynamic | Registered view ID | | externalUrl | string | for external | Full URL, opens in new tab | | insertAt | 'start' | 'end' | number | { afterId } | { beforeId } | no | Placement (default 'end') | | children | NavItem[] | no | Collapsible group | | action / subject | string | no | CASL ACL visibility |


Provider props reference

| Prop | Type | Description | |---|---|---| | baseURL | string | Root API server URL | | apiURL | string | /api prefix URL | | user | object | Current user object from your auth context | | accessToken | string | Bearer token attached to every service call | | agGridLicenseKey | string | AG Grid Enterprise license key — the provider calls LicenseManager.setLicenseKey() and registers all enterprise modules internally | | agGridTheme | object | Quartz theme overrides applied to every <AgGridReact> in the package. Merged on top of DEFAULT_AG_THEME_PARAMS. Example: { accentColor: '#3b82f6', headerHeight: 32 }. See AG Grid theme. | | muiTheme | object | Theme | MUI theme overrides (options object) deep-merged on top of DEFAULT_MUI_THEME_OPTIONS, OR a pre-built MUI Theme used as-is. Example: { palette: { primary: { main: '#6366f1' } }, shape: { borderRadius: 12 } }. See MUI theme. | | disableMuiTheme | boolean | When true, the provider skips its inner <ThemeProvider> entirely — use this if the host app already wraps everything in its own MUI ThemeProvider and wants it to apply inside the builder pages without merging. Default false. | | navExtensions | array | Static nav items to inject into the sidebar | | endpoints | object | Full-URL overrides per endpoint group + name |

AG Grid note: Do not call LicenseManager or ModuleRegistry in the host app — the provider handles it entirely.


AG Grid theme

Every <AgGridReact> in the package — reportViewer, dataGrid, the role-permission editor, the navigator picker — reads its theme from a single context. The default lives in code at src/lib/agGridTheme.js and can be overridden in two places:

1. Host-app override via the provider

Pass an object of Quartz params to agGridTheme. The object is merged on top of the package defaults — keys you set win, everything else falls back.

<RoboByteFrontBuilderProvider
  agGridTheme={{
    accentColor:  '#3b82f6',
    headerHeight: 32,
    fontFamily:   'inherit',
  }}
  /* …other props… */
>
  <App />
</RoboByteFrontBuilderProvider>

See the AG Grid Quartz theming reference for the full list of params.

2. Package-wide default

Open src/lib/agGridTheme.js and edit DEFAULT_AG_THEME_PARAMS. Affects every consumer of robobyte-front-builder that doesn't supply its own agGridTheme.

Programmatic use

import {
  DEFAULT_AG_THEME_PARAMS,   // frozen params object
  DEFAULT_AG_THEME,          // pre-built Quartz theme
  buildAgGridTheme,          // (overrides) => Quartz theme
  AgGridThemeProvider,       // standalone provider (no other dependencies)
  useAgGridTheme,            // hook returning the resolved theme
} from 'robobyte-front-builder'

// In a host component that renders its own AG Grid:
import { AgGridReact } from 'ag-grid-react'
function MyGrid() {
  const theme = useAgGridTheme()
  return <AgGridReact theme={theme} columnDefs={[...]} />
}

The hook falls back to DEFAULT_AG_THEME when called outside RoboByteFrontBuilderProvider, so isolated grids still render correctly.

Future plan. A "system settings" path will eventually layer between DEFAULT_AG_THEME_PARAMS and the host's agGridTheme prop, letting admins customize the theme without a code change. The provider API will stay the same.


MUI theme

Every Material-UI component the package renders (Button, TextField, Dialog, Tooltip, Chip, Card, Tabs, …) reads its theme from a single MUI <ThemeProvider> mounted by RoboByteFrontBuilderProvider. The default theme lives at src/lib/muiTheme.js and is designed to look distinctly not like stock MUI — Inter typography, 8px radius, soft shadows, flat buttons, no ripple, faster tooltips, dark mode pair.

Key default tokens

| Token | Value | Rationale | |---|---|---| | typography.fontFamily | Inter, SF Pro Display, system-ui, … | Modern UI font with graceful system fallbacks. | | shape.borderRadius | 8 | Soft corners across the surface (vs MUI's default 4). | | palette.primary.main | #3b82f6 | Tailwind blue-500, professional neutral primary. | | palette.secondary.main | #FF1185 | Matches DEFAULT_AG_THEME_PARAMS.accentColor — brand color shared with AG Grid surfaces. | | shadows[1..8] | soft, large-radius | Tailwind-like elevation instead of Material's hard shadows. | | MuiButton.disableElevation | true | Flat buttons by default. | | MuiButton.disableRipple | true | Desktop-first. | | MuiTextField.size | 'small' | Builder UI is data-dense. | | MuiTooltip.arrow / enterDelay | true / 200ms | Less hover-spam, more obvious anchoring. |

Host-app override via the provider

<RoboByteFrontBuilderProvider
  muiTheme={{
    palette: {
      primary: { main: '#6366f1' },     // indigo-500
    },
    shape: { borderRadius: 12 },
    typography: { fontFamily: '"Plus Jakarta Sans", sans-serif' },
  }}
>
  <App />
</RoboByteFrontBuilderProvider>

The override is deep-merged on top of the package defaults — keys you set win, everything else falls back.

Three ways to pass muiTheme

| Pass | What happens | |---|---| | Nothing | Uses DEFAULT_MUI_THEME. | | Theme options object ({ palette, shape, typography, components, … }) | Deep-merged with defaults; package builds the final Theme. | | A pre-built MUI Theme (from your own createTheme) | Used as-is. Escape hatch for full control. |

Disable the inner ThemeProvider

If the host has its own <ThemeProvider> wrapping the entire app and wants it to apply inside the builder pages without merging, pass disableMuiTheme={true}:

<ThemeProvider theme={yourGlobalTheme}>
  <RoboByteFrontBuilderProvider disableMuiTheme>
    <App />
  </RoboByteFrontBuilderProvider>
</ThemeProvider>

Programmatic use

import {
  DEFAULT_MUI_THEME_OPTIONS,   // raw default options (frozen)
  DARK_MUI_THEME_OPTIONS,      // dark counterpart
  DEFAULT_MUI_THEME,           // pre-built light Theme
  DEFAULT_MUI_THEME_DARK,      // pre-built dark Theme
  buildMuiTheme,               // (overrides, { mode? }) => Theme
  isResolvedMuiTheme,          // (value) => boolean — detect options vs Theme
} from 'robobyte-front-builder'

Coordinating with AG Grid + brand identity

The MUI palette.secondary.main (#FF1185) and the AG Grid accentColor are intentionally the same string. Change one, change the other, or wait for the future unified theme prop that will derive both from a shared token bag.

Future plan. A single unified theme prop will derive MUI, AG Grid, and chart themes from one set of design tokens. Until then, muiTheme and agGridTheme are the two sources to coordinate.


fetchReportDataByPageId

Fetches report data by pageId without any AG Grid dependency. Always imported from the package path — the NormalModuleReplacementPlugin in next.config.js routes it to the package's canonical implementation.

import fetchReportDataByPageId from 'services/reportData/fetchReportData'

const result = await fetchReportDataByPageId({
  pageId,          // required
  filter,          // { Tfilter, TFilter, customFilterCode, ... }
  isDataOnly,      // return raw rows only (default false)
  dataAsObject,    // key rows by unique id (default false)
  isPagination,    // server-side pagination (default true)
  isSingle,        // return first row only (default false)
  globalParams,    // override selectionParams by index
  page,            // page number (default 1)
  pageSize,        // page size (default 50)
  authContext,
  context,
})

if (result.success) {
  console.log(result.rows)
  console.log(result.total)
}

customFilterCode

const filter = {
  customFilterCode: `
    if (authContext?.user?.shopId) {
      customFilter.push({ field: 'ShopId', value: authContext.user.shopId, operation: 'Equal' })
    }
  `
}

ReportViewer as a component

ReportViewer can be rendered inline anywhere — not only as a full page:

import { ReportViewer } from 'robobyte-front-builder'

<ReportViewer
  pageId="your-page-id"
  minimized={true}
  noHeader={true}
  filter={{ Tfilter: [...] }}
  height="400px"
/>

| Prop | Type | Description | |---|---|---| | id | string | Report ID | | pageId | string | Report page ID | | filter | object | External filter | | minimized | bool | Removes padding and box shadow | | noHeader | bool | Hides the report title and studio button | | height | string | Grid height (default 85vh) | | isSingle | bool | Return only the first row | | dataAsObject | bool | Key rows by unique id | | setData | function | Callback receiving the loaded rows | | setOutGridApi | function | Callback receiving the AG Grid API instance | | refresh | any | Change this value to force a data reload | | actions | array | Custom row action buttons | | columnsConfig | array | Column overrides | | globalParams | array | Override selectionParams by index | | sessionId | string | Load filter payload from localStorage | | updateRef | ref | Ref for programmatic updates |


Data Grid component

The Data Grid wraps AG Grid Enterprise and is configurable entirely from the builder inspector.

Inspector — Main tab

| Field | Description | |---|---| | Key | Reference key for reportRefs access | | Data Key | Key to read/write row data in page data | | Columns | Expression returning an AG Grid colDef[] array | | Extra Columns | Visual editor for adding new columns on top of data-driven ones | | Columns Config | Visual editor for overriding existing column properties by field name | | Row Actions | Visual editor for per-row action buttons | | Add Button Label | Label for the add-row button (default "Add") | | New Row Template | Code returning the default object for a new row | | Read Only | Expression — when truthy, disables all editing | | Show Add Button | Toggle the add-row button | | Show Delete Col | Toggle the delete-row column | | Height | Grid height expression (e.g. '400px', '60vh') | | Row Selection | none / single / multiple | | Pagination | Enable client-side pagination | | Page Size | Rows per page |

reportRefs API

const grid = reportRefs['myGridKey']
grid.getRows()              // current row data array
grid.setRows(arr)           // replace all rows
grid.addRow(obj)            // append a row
grid.updateRow(index, obj)  // update a row by index
grid.deleteRow(index)       // delete a row by index
grid.getGridApi()           // raw AG Grid API instance

Dialog component

Renders a hidden MUI Dialog opened programmatically via openDialog(key) / closeDialog(key).

Inspector — Main tab

| Field | Description | |---|---| | Key | Identifier used to open/close — must be unique on the page | | View ID | When set, renders a full embedded view inside the dialog body | | Title | Dialog title bar text (expression) | | Hide Title Bar | Hides the entire title bar | | Max Width | xs / sm / md / lg / xl | | Full Width | Stretch to max width breakpoint | | Full Screen | Full-screen mode | | Show Close Button | Shows the × icon | | Close on Backdrop | Closes when user clicks outside | | Action Buttons | Footer buttons, each with its own Calculation code |

Usage

// Open with optional seed data
openDialog('confirmDelete')
openDialog('editUser', { userId: row.id, name: row.name })

// Close
closeDialog('confirmDelete')

Isolated data store

Each dialog gets its own data / setData scope. To read or write the parent page state from inside a dialog use pageData and pageSetData:

// Inside a dialog action:
pageSetData(prev => ({ ...prev, lastEdited: data.userId }))

Popover component

A self-contained trigger (button, icon button, or text) that opens a floating panel. No openDialog call needed.

Inspector — Main tab

| Field | Description | |---|---| | Trigger Type | button / icon-button / text | | Trigger Label | Label text | | Placement | bottom-start, bottom, bottom-end, top-start, etc. | | Trigger On | click (default) or hover | | Controlled Open | Expression — overrides the internal open/close state | | Close On Content Click | Closes when any child inside is clicked |


Excel Upload component

Lets users upload .xlsx, .xls, or .csv files, map columns to field names, and access the result in actions.

Display variants

| Variant | Description | |---|---| | dropzone | Large dashed drop zone with drag & drop | | button | Compact outlined button | | icon | Icon-only button |

Actions

| Event | newValue | Notes | |---|---|---| | onUpload | { fileName, headers, rowCount } | Fires after parsing, before the mapping dialog | | onMapped | Array<object> | Fires before data is saved — return a modified array to override | | onClear | [] | Fires when the user clears the data |

reportRefs API

const uploader = reportRefs['myUploaderKey']
uploader.rows          // current mapped rows
uploader.setRows(arr)  // replace stored rows
uploader.clear()       // clear all stored rows

Wizard component

A MUI Stepper with optional validation, async lifecycle hooks, and controlled or uncontrolled step state.

Inspector props — Wizard

| Prop | Type | Default | Description | |---|---|---|---| | orientation | 'horizontal' | 'vertical' | 'horizontal' | Stepper orientation | | linear | boolean | true | Prevent skipping ahead | | hideNavigation | boolean | false | Hide Back / Next / Finish buttons | | key | string | 'wizardStep' | data key written with the current step index | | activeStep | number | expression | — | When set, wizard is controlled by data[key] | | onStepChange | JS action | — | Receives { from, to, direction, goToStep, nextStep, prevStep } | | onFinish | JS action | — | Runs when user clicks Finish on the last step |

Inspector props — Wizard Step

| Prop | Type | Description | |---|---|---| | label | string | Step label in the stepper header | | optional | boolean | Marks the step as optional | | onEnter | JS action | Fires when this step becomes active | | onNext | JS action | Return false to block navigation (validation) |

Navigation helpers

goToStep(n)   // jump to step n (0-based)
nextStep()    // advance one step
prevStep()    // go back one step

Repeater component

Renders a list of identical template items from a static array, a dynamic count, or a fetched API endpoint.

| Mode | How to configure | |---|---| | Static items | Set items to a static or expression array | | Count | Set count to a number; optionally dataKey to store values | | Endpoint | Set endpoint + serviceId or widgetId |

Expressions inside a Repeater

| Variable | Value | |---|---| | dataItem | The current array element | | itemIndex | Zero-based item index | | form[key] | The current item's scoped form value |


Menu component

Renders a MUI Tabs bar in two modes: navigation mode (items-based, each tab is a link/action) and tab-panel mode (tabs-based, each tab owns a drop zone).

| Prop | Type | Description | |---|---|---| | items | array | Navigation items { title, icon?, href? } — enables navigation mode | | tabs | array | Tab panel items { label, icon? } — enables tab-panel mode | | vertical | boolean | Render tabs vertically | | justified | boolean | Stretch tabs to fill full width |


View Renderer component

Embeds a saved builder view inline inside another view, with isolated or shared state.

| Prop | Type | Description | |---|---|---| | viewId | string | Required. ID of the saved view to embed | | isolated | boolean | true = own data/form/refs, false = shares parent state | | initialData | expression | Seed data passed on mount (isolated mode only) | | externalData | expression | Additional data merged on every parent re-render | | heightMode | 'auto' | 'fixed' | 'fixed' enables a pixel height with scroll | | height | number | Pixel height when heightMode is 'fixed' |


Layout Grid component

A CSS Grid container whose column count, gap, and per-cell styling are configured in the builder inspector.

| Prop | Type | Default | Description | |---|---|---|---| | cols | number | 2 | Number of equal-width columns | | gap | number px | 8 | Column gap | | rowGap | number px | same as gap | Row gap | | cellMinHeight | number/string | — | Default min-height for every cell | | cellPadding | number/string | — | Inner padding for every cell | | cellBackgroundColor | color | — | Background color for every cell | | cellBorder | string | — | CSS border shorthand for every cell | | cellBorderRadius | number/string | — | Border radius for every cell | | cellBoxShadow | string | — | Box-shadow for every cell | | cellJustifyContent | string | — | Flexbox justify-content inside every cell | | cellAlignItems | string | — | Flexbox align-items inside every cell |


Breadcrumb component

Renders a MUI Breadcrumbs navigation trail.

{
  "type": "breadcrumb",
  "props": {
    "main": {
      "items": {
        "valueType": "value",
        "value": [
          { "label": "Home",    "href": "/" },
          { "label": "Reports", "href": "/reports" },
          { "label": "Q1 2025" }
        ]
      }
    }
  }
}

Print Layout Builder

⚠️ Preview — needs more testing. Functional but not production-ready.

Design reusable print layouts with configurable headers, footers, multi-page bodies, watermarks, and page numbering.

Backend API endpoints required

| Method | URL | Description | |---|---|---| | POST | UiBuilderModule/PrintLayout | Create a new layout | | PUT | UiBuilderModule/PrintLayout | Update an existing layout | | GET | UiBuilderModule/PrintLayout/GetAll | List all layouts | | GET | UiBuilderModule/PrintLayout/GetById?id=<id> | Fetch by ID | | DELETE | UiBuilderModule/PrintLayout?id=<id> | Delete a layout |

Triggering print from a view

openPrintLayout('your-layout-id', {
  invoiceNumber: data.invoiceNumber,
  customerName:  data.customer.name,
  lines:         data.lines,
})

Page numbering format

Use {page} and {pages} tokens in the Format field:

Page {page} of {pages}   →  Page 1 of 4

Calculation Scope Reference

Every Calculation function receives the same set of variables:

Core state

| Variable | Description | |---|---| | form | Form field values (read-only snapshot) | | data | Reactive page state | | setData | Write page state — setData(prev => ({ ...prev, key: value })) | | dataRef | Mutable non-reactive store | | reportRefs | Map of { [key]: ref } for every Data Grid / Excel Upload on the page |

Dialog / layout

| Variable | Description | |---|---| | openDialog(key, data?) | Open a dialog, optionally seeding its isolated state | | closeDialog(key) | Close a dialog | | openPrintLayout(layoutId, data?) | Open the print preview | | closePrintLayout() | Close the active print preview |

Navigation & routing

| Variable | Description | |---|---| | router | Next.js router — router.push('/path'), router.query, etc. | | urlParams | { query, pathname, asPath } snapshot |

Global store

| Variable | Description | |---|---| | globalData | Cross-route global state (read) | | setGlobalData(updater) | Write global state — shallow-merges by default |

Services

| Variable | Description | |---|---| | GetService | Authenticated GET | | PostService | Authenticated POST | | UpdateService | Authenticated PUT | | PatchService | Authenticated PATCH | | DeleteService | Authenticated DELETE | | fetchReportData | Fetch report data by pageId (or by an inline builderModel). | | getReportSource(localId) | Resolve an inline-authored report from the view schema's reportSources registry. Returns the builderModel or null. Pass to fetchReportData({ builderModel }) to skip the server fetch. |

Helpers

| Variable | Description | |---|---| | showToast(message, type?) | 'success' | 'error' | 'warning' | 'info' | 'loading' |

Parent page scope (inside dialogs / embedded views)

| Variable | Description | |---|---| | page.data | Parent page's reactive state | | page.setData | Write to the parent page's state | | page.dataRef | Parent page's non-reactive store | | page.reportRefs | Parent page's grid refs |

Repeater-only

| Variable | Description | |---|---| | dataItem | The current repeated item | | itemIndex | Zero-based iteration index |


KPI Component Actions

KPI components support interaction events configured in the inspector Main tab → Actions section.

| Component | Event | Click-context variables | |---|---|---| | Metric | onClick | clickedValue | | Rating | onChange | newValue, clickedValue | | Chart | onDataClick | clickedItem, clickedValue, clickedField, clickedLabel, clickedIndex | | HeatmapGrid | onCellClick | clickedItem, clickedValue, clickedRow, clickedCol, clickedRowIndex, clickedColIndex | | Timeline | onItemClick | clickedItem, clickedIndex, clickedLabel, clickedStatus, clickedValue | | StepStage | onStepClick | clickedItem, clickedIndex, clickedId, clickedLabel, clickedStatus | | TagList | onTagClick | clickedItem, clickedTag, clickedLabel, clickedValue, clickedIndex |


Global Data Store

A module-level reactive singleton that survives client-side navigations.

In Calculation functions

// Read
console.log(globalData.selectedUser)

// Write
setGlobalData(prev => ({ ...prev, selectedUser: clickedItem }))

// Navigate — globalData persists to the next page
router.push('/user-detail')

In React components

import { useGlobalStore } from 'robobyte-front-builder'

function MyComponent() {
  const { globalData, setGlobalData } = useGlobalStore()
  return <p>Selected: {globalData.selectedUser?.name}</p>
}

Resetting on logout

import { resetGlobalData } from 'robobyte-front-builder'

function handleLogout() {
  resetGlobalData()
  // ... your auth logout
}

API

| Export | Description | |---|---| | useGlobalStore() | React hook — { globalData, setGlobalData } | | getGlobalData() | Synchronous read from non-React code | | setGlobalData(updater) | Write from anywhere | | subscribeGlobal(fn) | Subscribe to changes — returns unsubscribe function | | resetGlobalData() | Reset to {} and notify all subscribers |


Dark / Light theme

Both the UI Builder and Print Layout Builder support dark and light modes (default: dark). A toggle button (☀️ / 🌙) is available in each builder's toolbar. The choice is persisted in localStorage under rbb:builderThemeMode. The theme is scoped to the builder pages only and does not affect the rest of the host application.


Syncing local changes

When using file: path, node_modules/robobyte-front-builder is a copy, not a symlink. After editing source files, sync manually:

SRC=RoboByteFrontBuilder/src
PKG=YourApp/node_modules/robobyte-front-builder/src

cp $SRC/lib/index.js $PKG/lib/index.js
cp $SRC/lib/providers/RoboByteFrontBuilderProvider.jsx $PKG/lib/providers/RoboByteFrontBuilderProvider.jsx
cp $SRC/services/reportData/fetchReportData.js $PKG/services/reportData/fetchReportData.js
# ... add other files as needed

Hot-reload picks up all file changes automatically. Only next.config.js changes require a dev server restart.


Troubleshooting

"Module not found: Can't resolve 'xlsx'"
→ Install xlsx in the host app: npm install xlsx --legacy-peer-deps

"Cannot find module 'services/...'"
→ Ensure the NormalModuleReplacementPlugin is configured in next.config.js

AG Grid table not showing / license warning
→ Pass agGridLicenseKey to RoboByteFrontBuilderProvider. Do not call LicenseManager or ModuleRegistry in the host app.

AG Grid error #200 — IntegratedChartsModule not registered
→ The provider registers IntegratedChartsModule.with(AgChartsEnterpriseModule) automatically. Ensure ag-charts-enterprise is installed in the package.

AG Grid theme override not applying
→ Pass it via <RoboByteFrontBuilderProvider agGridTheme={{ … }}>, not as a theme={…} prop on individual <AgGridReact> instances rendered by the package. Internal grids ignore per-instance themes; the provider's context is the single source of truth. See the AG Grid theme section.

ReportViewer renders at half width
→ The outer Box in reportViewer/index.js must use display: 'block', not display: 'flex'.

Static props (getLayout, acl) not picked up from package exports
→ Use the explicit import + assignment pattern. Bare export { X as default } does not carry static properties across package boundaries.

Duplicate React / MUI hook errors
→ Pin react, react-dom, and @mui/material to the host app's copies via config.resolve.alias in next.config.js.

Old routes returning 404
→ Check that host-app pages exist under /builders/... and that old paths have getServerSideProps = () => ({ notFound: true }) stubs.


Publishing

npm login          # one-time setup

npm version patch  # 1.0.x — bug fixes
npm version minor  # 1.x.0 — new features
npm version major  # x.0.0 — breaking changes

npm publish

Dry run (verify what will be published without actually publishing):

npm publish --dry-run

Changelog

1.0.29

  • Inline report sources. The view schema gains a top-level reportSources map — a registry of inline-authored builderModels addressable by short localId. The <reportViewer> inspector gets a new "Source" picker that toggles between Saved (existing pageId / id) and Inline (registry-backed) modes. Authors create / edit sources via a fullscreen Report Builder Dialog that embeds the real /builders/report page with mode='dialog' + onSaveInline / onSaveServer callbacks. Resolution priority across the system: inline builderModel > reportSourceId > pageId > id. All existing schemas continue to work unchanged.
  • fetchReportDataByPageId({ builderModel }). New optional parameter that skips the GetReportDetails fetch when an inline model is in hand. Used by the new viewer pipeline and exposed in Calculation code via the auto-injected getReportSource(localId) helper, which reads from a module-level reportSourcesRegistry singleton (BuilderProvider / ProductionViewer keep it in sync — same pattern as routerRef).
  • ReportSourcesManager. Small dialog (opened from the inspector or the sidebar's View tab) for renaming / duplicating / deleting registry entries, with in-use detection (counts every node referencing each source).
  • View tab → Report Sources section. Sources can also be authored from the sidebar's View tab, not only from a reportViewer inspector. Useful for views whose only consumers are autocomplete-with-data fields or hand-coded calculations — you don't need a reportViewer on the canvas to manage the registry.
  • New context API on useBuilder(). reportSources, generateReportSourceId(), setReportSource(localId, src), removeReportSource(localId), getReportSource(localId) — full registry CRUD that participates in undo/redo through setSchema.

1.0.25

  • Centralized AG Grid theme. Every <AgGridReact> in the package (reportViewer, dataGrid, role-permission editor, navigator picker) now reads its Quartz theme from a single context. Host apps can override package-wide theme params (accent color, header height, fonts, border radius, etc.) via the new agGridTheme prop on RoboByteFrontBuilderProvider. Defaults live in src/lib/agGridTheme.js. New exports: DEFAULT_AG_THEME_PARAMS, DEFAULT_AG_THEME, buildAgGridTheme, AgGridThemeProvider, useAgGridTheme.
  • <ReportViewer> redesigned toolbar. Single-row toolbar: title + caption on the left; collapsible search, Filter (outlined button), Refresh (outlined button), and configurable viewer actions on the right. Auto-refresh interval, "Load all data" toggle, and Excel export moved into the side tool panel under Display Settings. Search popover navigable by keyboard (↑ ↓ Home End Enter Esc).
  • <ReportViewer> new inspector fields. title, caption, viewerActions (array of page-level action buttons appended after Filter/Refresh), debug (renders a floating bug icon with a popover showing resolved pageId/id/builder model id/etc. — hidden in production by default).
  • Print Layout integration. Host apps can now trigger print layouts directly via the imperative PrintDialog ref API — see docs/printLayout.md for the recommended PrintProvider pattern with usePrintLayout().
  • Public exports expanded. fetchReportDataByPageId now exported from the package surface (import { fetchReportDataByPageId } from 'robobyte-front-builder'); the legacy bare-alias path still works.
  • Unsaved changes guard. Builder pages now warn on tab close / refresh / in-app navigation when the schema has unsaved edits. BuilderProvider exposes loadSchema(schema) (clears history baseline), markClean() (post-save reset), and isDirty.
  • Session log + AI fine-tune pipeline. Every successful save (UI Builder + Print Builder) is auto-logged to localStorage with the full schema. New Session Logs toolbar dialog lets developers add training prompts to entries and export a Together AI-ready JSONL. Together is now a first-class AI provider in /api/ai.

1.0.21

  • Added Timer Engine — configurable auto-refresh timers per view
  • Added full Undo / Redo history with keyboard shortcuts (Ctrl+Z / Ctrl+Y)
  • Added Cut / Copy / Paste with system clipboard support (Ctrl+X / Ctrl+C / Ctrl+V)
  • Added Undo / Redo buttons to the viewer toolbar
  • Expanded KPI suite: Gauge, BulletChart, ColorScale, Rating, Countdown, AvatarGroup, StepStage
  • Print Layout designer: multi-zone canvas, @page CSS, print dialog

1.0.20

  • KPI components: Metric, Trend, Badge, StatusDot, IconBox, Sparkline, MiniBarChart, Donut, Funnel, HeatmapGrid, TagList, Timeline, ComparisonBars
  • Threshold engine and number formatting utilities
  • Dark / light theme toggle in UI builder and Print Layout builder

1.0.x

  • UI Builder, Report Builder, Navigator Builder, Print Builder initial releases
  • Navigation Extension API
  • AG Grid and MUI data grid integration
  • Drag-and-drop canvas with 50+ components
  • Global Data Store

License & third-party components

robobyte-front-builder itself is released under the MIT License — the source code in this repository is free to use, modify, and distribute, including in commercial products.

Important: this package depends on third-party libraries with their own licenses. The MIT license applies only to this package's source code; it does not relicense or waive obligations under those third-party licenses.

AG Grid Enterprise — commercial license required for production

The report and grid components use AG Grid Enterprise features (server-side row model, side tool panel, status bar, integrated charts, master/detail). The ag-grid-enterprise package is a commercial product owned by AG Grid Ltd:

  • Development: AG Grid Enterprise works without a license key, but renders a watermark and prints a console warning. Fine for local dev and evaluation.
  • Production deployment: requires a paid AG Grid Enterprise license. See ag-grid.com/license-pricing for the current terms.

Pass your license key via the provider — the package calls LicenseManager.setLicenseKey() and registers AllEnterpriseModule + IntegratedChartsModule.with(AgChartsEnterpriseModule) internally:

<RoboByteFrontBuilderProvider
  agGridLicenseKey={process.env.NEXT_PUBLIC_AG_GRID_LICENSE_KEY}
  // …other props…
>
  …
</RoboByteFrontBuilderProvider>

MUI X — free vs. Pro / Premium tiers

@mui/x-data-grid, @mui/x-date-pickers, and related packages have a free MIT tier and paid Pro / Premium tiers. This package uses only the free tier. If you swap in @mui/x-data-grid-pro or @mui/x-date-pickers-pro in your host app, comply with MUI's commercial license: mui.com/pricing.

Everything else

All other runtime and peer dependencies are open-source under permissive licenses (MIT, Apache 2.0, ISC, BSD). Run npm ls --omit dev for the full dependency graph and a tool like license-checker for a license enumeration.

A condensed version of this notice lives in the LICENSE file shipped with the package.


Full user manual: RoboByteBuilder_User_Manual.docx (included in the package)