Globals


Instance Methods

App()

Application root: mounts the router behind the app-wide providers (tab management) and disables the context menu in production. The analytics SDK (services/analytics/analytics.js) self-initializes on import in index.jsx, so it needs no provider here.

Router()

History-API router variant - use when the deploy path is known (basename from VITE_BASE_URL). App.jsx picks one of the two (HashRouter.jsx is the current default, this one is commented out there).

Content + screensaver providers around the routes, pages guarded by the ErrorBoundary, same as HashRouter.jsx - but unlike HashRouter.jsx, this variant does NOT wrap the routes in Stage (the whole-app scale wrapper) and has no separate /print-map route. It has drifted out of sync with HashRouter.jsx's later additions; picking this variant today would run the kiosk unscaled and without the print-map dev tool.

Router()

Hash-based router variant - works regardless of the deploy path, so it's the default (see App.jsx). Stage (the whole-app scale wrapper, see Stage.jsx) sits inside rather than around it in App.jsx, because it reads its config via useConfig() -> useSearchParams(), which requires router context. Content + screensaver providers around the routes, pages guarded by the ErrorBoundary; the Screensaver stays mounted as a sibling so its fade works in both directions.

/print-map is a dev-only export tool (see PrintMap.jsx), not part of the visitor-facing kiosk - it's branched out here, before Stage/ContentProvider/ ScreensaverProvider, so it gets none of the kiosk chrome (fixed-resolution scaling, idle screensaver) and fetches its own content directly instead of going through ContentProvider's route-based file resolution (presentationModes.js has no entry for it).

Pages()

Route table of the exhibit: "/" is the app selection, each presentation mode has its own path, and GeneralPageTracking reports every route change. Value Advisory Services and Rad Enablement are linear SlidePage decks (optional :viewId slide segment); Value Partnership is a bespoke interactive sub-app with its own nested routes (see ValuePartnership.jsx).

resolveCountryColors( countryDisplay?: Object, fallbackColor: string, ): Object

Resolves value-partnership-globe-countries.json's continent-keyed and per-country config into the ccn3-keyed color map InteractiveGlobe's polygon layer needs. continents is applied first (colors every country in that continent), then countries (pre-populated with every ISO country, {cca3, name, state} - only cca3/state are read here, name is an editor-facing label) on top as per-country overrides - so e.g. continents.Europe="highlight" plus a DEU entry with state "hide" highlights all of Europe except Germany.

"normal" entries are treated as "no explicit choice" and skipped in both loops rather than written into the map - countries is pre-populated with all ~250 countries at "normal" by default (so an editor only has to change the ones they care about), and since "normal" is also the ultimate fallback color (defaultCountryColor), those untouched entries would otherwise silently overwrite a continent-level highlight/hide for every country in it.

Shared between the 3D globe (GlobePage.jsx) and the print map (PrintMap.jsx) so both render the exact same country colors from the same content.

Parameters

  • countryDisplay (Object, optional) — content.valuePartnership.countryDisplay.
  • fallbackColor (string) — Used as defaultCountryColor when countryDisplay.colors.normal isn't set (config-schema.js's globeFallbackCountryColor).

Returns

  • Object

countryMetaByCcn3(ccn3: string): Object | undefined

Country metadata for a given ISO numeric code, e.g. countryPolygons.js decorating each world-atlas feature.

Parameters

  • ccn3 (string) — ISO numeric country code, e.g. "276" for Germany.

Returns

  • Object | undefined

countryMetaByCca3(cca3: string): Object | undefined

Country metadata for a given ISO alpha-3 code, e.g. resolving countryDisplay's countries entries (see countryColors.js).

Parameters

  • cca3 (string) — ISO alpha-3 country code, e.g. "DEU" for Germany.

Returns

  • Object | undefined

countryMetaByName(rawName: string): Object | undefined

Country metadata by common name, case-insensitively and resolving COUNTRY_NAME_ALIASES first (e.g. content authored with a country's short/colloquial name instead of world-countries' commonName). Currently unused elsewhere in src - kept alongside the other by-* lookups.

Parameters

  • rawName (string) — Country name as authored in content.

Returns

  • Object | undefined

countriesByContinent( continent: string, ): Array.<{ccn3: string, cca3: string, commonName: string, continent: string}>

All countries in a given continent/region - value-partnership-globe- countries.json's continents entries are resolved through this (see countryColors.js).

Parameters

  • continent (string) — world-countries' region field: "Africa", "Americas", "Antarctic", "Asia", "Europe", "Oceania".

Returns

  • Array.<{ccn3: string, cca3: string, commonName: string, continent: string}>

loadCountryPolygons(): Array.<Object>

Converts the world-atlas topology into GeoJSON country features (once, then cached in-module), decorated with the metadata (name/cca3/continent) countryMeta.js knows for each ccn3 - consumed by InteractiveGlobe's polygon layer. Also splits out French Guiana (from France's MultiPolygon) and Alaska (from the USA's) into their own features, see the inline comments below, so they can be colored independently via countryColors.js.

Returns

  • Array.<Object> — GeoJSON Feature objects, each with properties: {ccn3, name, cca3, continent}.

RadHeader(props: Object)

Page header shown on every RadEnablement slide (title/subline from content.header); the story icon on the right follows whichever story the current view belongs to.

Parameters

  • props (Object)
    • props.viewId (string) — Currently shown view id.

Other

CacheableVideo

Drop-in replacement for <video src="..."> that's cacheable by the service worker. Renders "Loading video..." until the fetch has completed.

Parameters

  • src (string) — URL of the video file to fetch and play.
  • playing (boolean, optional) — When given, drives playback: true plays, false pauses and rewinds. Lets an always-mounted but hidden video (e.g. the screensaver behind opacity: 0) stop decoding while it's not visible.
  • fallback (React.ReactNode, optional) — Rendered while the blob is being fetched, instead of the default "Loading video..." text.
  • props (*) — Passed through to the underlying <video> element (autoPlay, loop, muted, playsInline, ...).

ComponentRenderer

Renders a single content block of a view. Looks the block's type up in the element registry (elements/registry.js) and reshapes the raw block into the component's props via the element's own adapter. Unknown types render a debug hint in dev mode and nothing in production.

Parameters

  • props (Object)
    • props.block (Object) — A content block from a view's elements array, e.g. { type: "headline", text: "..." }.
    • props.selectedTargetViewId (string | null) — Currently armed target view (story-hub selection), passed through to selectWidget.
    • props.onSelectTarget (function) — Arms/clears the target view selection.
    • props.onNavigate (function) — Navigates to a view id (used by buttonList/buttonGrid).

IntroLoopVideo

Plays intro once, then switches to loop playing forever. Both videos are mounted from the start - the loop is fetched, decoded and paused at its first frame in the background while the intro plays, so the switch is just an opacity swap instead of a src change that would force a fresh fetch/decode at the exact moment of the handoff (visible as a stutter).

Parameters

  • intro (string) — URL of the video played once at the start.
  • loop (string) — URL of the video played on loop afterwards.
  • props (*) — Passed through to both underlying <video> elements.

Screensaver

Full-screen overlay shown while the app is idle (see useScreensaver). Stays mounted at all times so the opacity transition plays both when fading in and when fading out; visibility is toggled via CSS class. Dismissing it needs no handler here - any interaction is already picked up by the global listeners in useIdle and flips isIdle back to false.

The video shown depends on defaultMode (config-schema.js): each presentation mode's own content file (see PRESENTATION_MODES in presentationModes.js, loaded per-route by ContentProvider) defines its own screensaver under "screensavers", keyed by that mode's key. In multi-app/ navbar mode (defaultMode "all") or for an unrecognized defaultMode value, no entry matches and no video is shown.

SlideNavigation

Fixed bottom navigation of the slide pages, with three modes:

  • closed: menu button + prev/next arrows (hidden entirely while the view has no adjacency, e.g. before content has loaded)
  • menu: full-width bar with Home / Screensaver / Apps / Slides / close, plus an "Open Link" button when the current view has a link/visibleLink (opened in a new tab via useTabs)
  • slides: same bar plus the full-screen SlidesOverlay

Parameters

  • props (Object)
    • props.prevViewId (string | null) — Target of the "back" arrow, disables it when null.
    • props.nextViewId (string | null) — Target of the "next" arrow, disables it when null.
    • props.homeViewId (string) — View the menu's Home button navigates to.
    • props.currentViewId (string) — Currently shown view (highlighted in the slides overlay).
    • props.onNavigate (function) — Navigates within the current app, keeping config params.

SlidePage

Shared skeleton of the slide-based presentation pages (ValueAdvisoryServices, RadEnablement): viewId routing, slide navigation, element-bucket layout and the content error/redirect states. The pages themselves only supply their constants, their CSS (via classPrefix) and an optional header.

Parameters

  • basePath (string) — route prefix, e.g. "/rad-enablement"
  • startViewId (string) — view shown at the bare route, e.g. "rad-intro"
  • storyHubViewId (string) — the selectWidget hub view (e.g. "rad-select-story"), see getAdjacentRootViews
  • homeViewId (string, optional, default: "storyHubViewId") — menu's Home button target; defaults to storyHubViewId but can point elsewhere (e.g. an intro slide) when Home shouldn't land on the story picker
  • classPrefix (string) — CSS class prefix, e.g. "rad" -> "rad-page", "rad-slide-content"
  • renderHeader (function, optional) — optional per-page header, returning a React node
  • disableAnimations (boolean, optional, default: false) — mirrored onto the page div as data-disable-animations so a page's own CSS can opt into reacting to it (e.g. RadEnablement.scss dropping its background image) - SlidePage itself has no opinion on what it should disable, see config-schema.js

SlidesOverlay

Full-screen overlay listing every slide of the loaded content file as a clickable thumbnail (from the view's optional thumbnail field, with a text placeholder as fallback), grouped by story. A toggle switch selects "All Slides" or a single story (the "intro" story is excluded from the switch entirely - its slides only show up under "All Slides"); it opens on the current view's story, or "All Slides" when that story isn't offered as its own tab. Rendered by SlideNavigation in its "slides" mode.

Parameters

  • props (Object)
    • props.currentViewId (string) — View to highlight and to derive the initial story tab from.
    • props.onSelectSlide (function) — Called with the clicked slide's view id.

Stage

Whole-app scale wrapper. Renders children inside a fixed-size box and scales that box down to fit whatever real screen it ends up on via CSS transform: scale().

Replaces the previous per-page calc(1rem / X) + html-root-font-size scaling scheme: instead of keeping dozens of components' em/rem units in sync with two independent, uncoordinated breakpoint systems (the app's own root font-size AND @ui-marcom/shared's internal viewport-width breakpoints), every pixel authored anywhere in children scales together as one image - which system decided a given size no longer matters once it's inside this box.

Each sales app has one fixed, content-driven orientation (confirmed with the content team: everything is landscape except Rad Enablement, which is portrait-only - see PRESENTATION_MODES' orientation field, matched against the current route via resolveModeForPath()). "/" (app selection) matches no mode and defaults to landscape.

The reference box has two independent axes, not one:

  • WHICH physical kiosk this is (stageDevice config value: "4k" or "ipad") picks that device's own landscape width/height pair. A 4K panel and an iPad need separate pairs (not a shared one) because an iPad is a 2x Retina display - its CSS point resolution is roughly half its physical pixel count, very different from a 4K panel's 1:1 mapping.
  • Orientation then swaps THAT device's own pair for portrait routes - "a physically rotated panel" is only true within one device's pair, not across devices. Treating portrait as a single cross-device resolution was tried first and broke both ends: Rad Enablement letterboxed on the iPad (wrong aspect ratio), and would have upscaled/blurred on a rotated 4K panel (wrong magnitude) - see README.md's "Scaling (Stage)" section.

The scale factor is never allowed above 1 in practice: the reference resolution is deliberately the largest target device in its orientation, so real screens only ever scale down. Upscaling would blur the WebGL globe (InteractiveGlobe.jsx), whose canvas render resolution three.js derives from layout size, not from a CSS transform applied to an ancestor.

stage-inner also carries data-stage-device so per-device CSS overrides (e.g. RadEnablement.scss's iPad content-density correction, since the same em-authored content necessarily renders larger on the iPad's ~2x-smaller reference box) can target a device without their own JS.

Must be mounted inside the router (see HashRouter.jsx), not in App.jsx - it reads its config (stageDevice and the stageRefWidth/Height / stageIpadRefWidth/Height pairs) via useConfig() and the current route via useLocation(), both of which need router context and would silently fail (or throw) outside a .

AiObs

Before/after-style AI observation showcase ("aIObs" element type): a picture plus screenshot (optionally alongside a screens device frame image, which switches to a stacked "computer + data" layout instead of the default side-by-side one), with an optional badge row and add-on caption.

Parameters

  • props (Object)
    • props.picture (string) — Primary image URL.
    • props.pictureAddOn (string, optional) — Optional caption/second image rendered next to picture.
    • props.screenshot (string) — Secondary image URL.
    • props.screens (string, optional) — Optional device-frame image URL; when set, switches to the stacked layout.
    • props.badges (Array.<{iconLink: string, text: string}>) — Badges rendered via BadgeList.

Avatar

Round avatar image, used for the portrait next to a Quote.

Parameters

  • props (Object)
    • props.src (string) — Image URL.
    • props.alt (string) — Alt text.

Badge

Single icon-plus-label pill ("badge" element type), also used standalone inside BadgeList. icon (a ui-marcom-icon name) takes precedence over iconLink (an arbitrary image URL) when both are given.

Parameters

  • props (Object)
    • props.iconLink (string, optional) — Fallback icon image URL, used when icon is not set.
    • props.icon (string, optional) — ui-marcom-icon name; takes precedence over iconLink.
    • props.text (string, optional) — Label text.

BadgeList

Row of Badges. Not a registry element itself - rendered internally by AiObs.

Parameters

  • props (Object)
    • props.badges (Array.<{iconLink: string, text: string}>) — One entry per badge.

BodyText

Plain paragraph of body-sized text ("bodyText" element type) - an intro or description paragraph below a headline. Distinct from disclaimer (small, absolutely bottom-pinned legal print) and from headline (display-sized).

Parameters

  • props (Object)
    • props.text (string) — Paragraph text. Supports <mark>...</mark> highlight spans, but only when level is "1".
    • props.level (string, optional) — Size variant; "1" renders the larger, mark-aware boxed style, anything else the plain body-text--{level} paragraph.

ButtonGrid

Grid of logo tiles ("buttonGrid" element type), e.g. partner institutions. Like ButtonList, clicking reports the target view id to the page instead of navigating directly.

Parameters

  • props (Object)
    • props.items (Array.<{content: {logo: string}, targetViewId: string}>) — One entry per tile.
    • props.onNavigate (function) — Called with the clicked tile's target view id.

ButtonList

Vertical list of navigation buttons ("buttonList" element type). Buttons don't navigate themselves - they report the chosen view id to the page.

Parameters

  • props (Object)
    • props.items (Array.<{content: {label: string}, targetViewId: string, icon: string}>) — One entry per button. icon is optional and rendered when present, but the registry adapter (index.js) never populates it from content today, so it's effectively unused via the normal content-authoring path.
    • props.onNavigate (function) — Called with the clicked item's target view id.

Card

Simple text card with optional headline, body and footer line. Used as the detail popup of a Circle in the CircleInfographic.

Parameters

  • props (Object)
    • props.headline (string, optional) — Card headline.
    • props.text (string, optional) — Card body text.
    • props.underline (string, optional) — Small footer line below the body.

CardGrid

Stat tiles plus an optional highlight card ("cardGrid" element type), e.g. "20% perceived time savings" alongside a customer statement.

Parameters

  • props (Object)
    • props.stats (Array.<{value: string, label: string}>) — Stat tiles (value + caption).
    • props.highlight (Object | null) — Optional emphasized card.

ChartGrid

One or two chart/diagram images side by side, each with an optional caption above it ("chartGrid" element type). Portrait: stacks to 1 column.

Parameters

  • props (Object)
    • props.items (Array.<{title: (string|null), image: string}>) — 1-2 chart entries.

CircleChain

N labeled circles overlapping in a horizontal row ("circleChain" element type), brand-gradient colored left to right.

Parameters

  • props (Object)
    • props.items (Array.<{text: string}>) — Circles, left to right.
    • props.orientation ("landscape" | "portrait", optional, default: "\"landscape\"") — Sizes each circle as a fraction of the measured ring diameter, per the Figma spec's portrait/landscape ratios.

Circle

One selectable circle of the CircleInfographic. Toggles its detail Card on tap and closes on tap-outside.

Parameters

  • props (Object)
    • props.text (string) — Label inside the circle.
    • props.color ("black" | "blue" | "white" | "orange") — Color/position variant class.
    • props.card (Object) — Detail card content.
    • props.icons (Array.<{small: string, big: string}>) — Orbiting IconBubbles definitions.
    • props.handleCircleSelect (function) — Notifies the parent to blur the other circles.
    • props.close (function) — Notifies the parent to lift the blur again.

ARROW_BLACK

Interactive four-circle service infographic ("circleInfographic" element type): tapping a circle opens its detail Card and blurs the rest. Expects exactly four entries; render order is fixed to match the layout.

Parameters

  • props (Object)
    • props.circle (Array.<{text: string, icons: Array.<{small: string, big: string}>, card: {headline: (string|null), text: (string|null), underline: (string|null)}}>) — The four circle definitions.
    • props.headline (string) — Label shown in the center of the ring.

Disclaimer

Small-print legal/disclaimer line of a slide ("disclaimer" element type).

Parameters

  • props (Object)
    • props.text (string) — Disclaimer text.

Headline

Semantic heading with app-wide typography classes. Renders the content JSON's "headline" (level 2) and "subheadline" (level 3) element types, and is used directly for page headers.

Parameters

  • props (Object)
    • props.text (string) — Heading text.
    • props.level (number, optional, default: 1) — Heading level 1-6, controls both tag (h1-h6) and size class.
    • props.color ("white" | "orange", optional, default: "\"white\"") — Color variant class.

IconBubbles

Decorative pair of icon bubbles (one big, one small) orbiting a Circle in the CircleInfographic.

Parameters

  • props (Object)
    • props.action (function) — Called on click of either bubble; forwarded to the parent Circle as its select/close handler.
    • props.num (number) — Index among the Circle's icon bubbles, used for per-bubble positioning (num--{n} class).
    • props.big (string) — Icon URL for the big bubble.
    • props.small (string) — Icon URL for the small bubble.

IconBulletPoints

Vertical list of icon-plus-text bullet points ("iconBulletPoints" element type).

Parameters

  • props (Object)
    • props.points (Array.<{icon: string, text: string}>) — One entry per bullet point.

IconWheel

N icon nodes with text labels evenly spaced around a decorative ring ("iconWheel" element type) - unlike CircleInfographic/SelectWidget, purely decorative and non-interactive.

Parameters

  • props (Object)
    • props.items (Array.<{icon: string, label: string}>) — Ring nodes.

ImageBtnWidget

Full-width image with an optional ButtonGrid below it ("imageBtnWidget" element type).

Parameters

  • props (Object)
    • props.image (string) — Image URL.
    • props.buttonGrid (Object, optional) — Adapted ButtonGrid props (see ButtonGrid/index.js), rendered when items is present.

ImageCard

Card with an image and/or caption text. Rendered by ImageCardGrid.

Parameters

  • props (Object)
    • props.image (string, optional) — Image URL.
    • props.text (string, optional) — Caption text.

ImageCardGrid

Grid of ImageCards ("imageCardGrid" element type), e.g. product screenshots with captions.

Parameters

  • props (Object)
    • props.items (Array.<{image: (string|null), text: (string|null)}>) — One entry per card.

InfoGridWidget

Labelled text box (or image) next to a grid of short labels ("infoGridWidget" element type), e.g. a nodule example paired with its measurable attributes. When textboxImage is set, it replaces the head/text box entirely.

Parameters

  • props (Object)
    • props.select (string, optional) — Small caption above the text/image box (e.g. "Example").
    • props.textboxHead (string, optional) — Headline inside the text box; ignored when textboxImage is set.
    • props.textboxImage (string, optional) — Image URL shown instead of the text box.
    • props.textboxText (Array.<{item: string}>) — Body lines inside the text box; ignored when textboxImage is set.
    • props.grid (Array.<{item: string}>) — Grid tiles, one headline each.

InstitutionBadge

Country flag + institution logo pair ("institutionBadge" element type), shown on the "Discover real-world impact" slides.

Parameters

  • props (Object)
    • props.flag (string) — Flag image URL.
    • props.logo (string) — Institution logo URL.

LinkBtn

Standalone "open external link" control button, styled like the SlideNavigation menu button. Not a registry element (no index.js/schema.js) and currently not imported anywhere in src - kept here for the pattern used inline by SlideNavigation's own link/visibleLink buttons.

Parameters

  • props (Object)
    • props.link (string) — URL opened in a new tab via useTabs.

PeerList

Grid of peer/benchmark cards ("peerList" element type), each with a logo, optional flag, optional stat tiles and an optional highlighted quote.

Parameters

  • props (Object)
    • props.peers (Array.<{flag: ?string, logo: string, stats: Array.<{value: string, label: string}>, highlight: ?{headline: string, text: string}}>) — One entry per peer card.

ProcessFlow

N flat step images (photo/mockup with title+bullets already baked in) connected by arrows ("processFlow" element type).

Parameters

  • props (Object)
    • props.items (Array.<{image: string, card: {headline: string, points: Array.<string>}}>) — Steps, left to right; 3 bullet points switch the card to the narrower --2 layout, anything else uses --1.

Quote

Single quote row: avatar plus headline and quote text. Rendered by QuoteList.

Parameters

  • props (Object)
    • props.item (Object) — Quote content.

QuoteList

Stack of customer quotes ("quoteList" element type).

Parameters

  • props (Object)
    • props.items (Array.<{content: {headline: string, icon: string, text: string, source: string}}>) — One entry per quote; source is optional.
    • props.level (number, optional) — Size/spacing variant class (quote-list--level{n}); defaults to 0 via the registry adapter.

SelectWidget

Circular story picker ("selectWidget" element type): options are spread evenly around a ring; selecting one shows its title in the center and arms the page's "next" navigation (it does not navigate by itself).

Parameters

  • props (Object)
    • props.options (Array.<{id: string, text: string, icon: string}>, optional) — Selectable options; id is a view id.
    • props.orientation ("portrait" | "landscape", optional, default: "\"portrait\"") — Ring/item sizing preset (from the content JSON).
    • props.selectedId (string | null) — Currently selected option id.
    • props.onSelect (function) — Called with the tapped option's id, or with no argument on an outside click (deselects).

StepTracker

Horizontal dot progress indicator ("stepTracker" element type): one circle per step, connected by a line, the current step filled solid.

Parameters

  • props (Object)
    • props.total (number) — Total number of steps.
    • props.current (number) — Current step, 1-based.

StoryTitle

Full-bleed story opener ("storyTitle" element type): big title over an optional background artwork. When videoIntro/videoLoop are set and disableAnimations isn't, an animated background plays on top of the static background image instead of it.

Parameters

  • props (Object)
    • props.title (string) — Story title text.
    • props.background (string, optional) — Background image URL, also the fallback shown when the video is disabled/missing/still loading.
    • props.videoIntro (string, optional) — Background video played once.
    • props.videoLoop (string, optional) — Background video played after, on loop.

TextMediaWidget

Media block with an accompanying text box ("textMediaWidget" element type). Shows an image or a (service-worker-cacheable) video, plus optional text.

Parameters

  • props (Object)
    • props.image (string | null) — Image URL; mutually exclusive with video in practice.
    • props.video (string | null) — Video URL, played via CacheableVideo.
    • props.text (string | null) — Text shown below the media.
    • props.level (number | null, optional) — When 1, wraps image in an ImageCard instead of a plain <img>.

useElementSize

Parameters

  • initialSize (Object, optional) — Value returned before the observer's first callback fires. Defaults to {0,0}; pass a best-guess (e.g. window.innerWidth/innerHeight) when the element is expected to roughly fill the viewport, to avoid a one-frame flash at size 0.

Returns

  • Array — A [ref, size] tuple: a callback ref to attach to the observed element, and its current {width, height} content-box size in CSS px.

useIdle

Parameters

  • idleTime (number) — Time in ms of inactivity after which isIdle becomes true.

Returns

  • Object — trigger is the event type that ended the last idle period ("init" on first mount), and is reset to null once idle again - useful for debugging what woke the app up. forceIdle shows the idle state immediately, without waiting for the timeout.

AppSelectionPage

Landing screen at "/": one tile per presentation mode (see PRESENTATION_MODES). Also the target of the idle session reset and of the menu's "Apps" button.

PrintMapPage

Dev-only export tool: renders the same country polygons and location points the 3D globe (InteractiveGlobe.jsx) uses, but as a flat, unclipped d3-geo projection instead of a 3D perspective - see the print-map decision doc referenced from the project chat. Not part of the visitor-facing kiosk; reachable directly at #/print-map (see HashRouter.jsx), outside the Stage/ContentProvider/Screensaver chain, so it fetches its own content instead of going through ContentProvider's route-based file resolution.

RadEnablementPage

"RadEnablement Services" presentation app - the shared SlidePage plus a persistent RadHeader (content: public/data/rad-content.json).

ValueAdvisoryServicesPage

"Value Advisory Services" presentation app - the shared SlidePage plus a persistent per-story icon badge (content: public/data/vas-content.json).

VasHeader

Persistent per-story icon badge shown top-right on every VAS slide of a story except its own storyTitle cover (which already fills the screen). Unlike RAD, VAS views author their own headline text per view (there is no app/story-wide title to repeat) - only the story icon is a constant, from stories..header.icon in vas-content.json.

Parameters

  • props (Object)
    • props.viewId (string) — Currently shown view id.

GlobeBottomNav

Fixed bar for stepping through the currently visible globe markers without having to hunt for pins on the globe - Home/Prev/Next + a "N of total" jump-to-index select, plus the previous/current/next marker by name. Only rendered while a marker is selected (preview or full details open), at the same screen position as ValuePartnershipNav's own bottom bar - it overlays/replaces that bar for the duration of the selection rather than stacking alongside it.

Parameters

  • props (Object)
    • props.locations (Array.<GlobeLocation>)
    • props.selectedId (string | number | null)
    • props.labels (Object) — content.valuePartnership.labels.
    • props.onSelect (function) — Called with the newly selected location.
    • props.onHome (function) — Clears the selection (closes the detail card).

GlobeDetailCard

Detail overlay for a clicked globe marker, ported from value-globe.js's card__big/card__details. Two views:

  • "preview" (default): compact popup with a short blurb and a "Show details" button, shown right after clicking a marker.
  • "details": the full card - a single "Overview" tab (headline/image/ keyfacts/partnership/quote) for outcome points; one tab per impact category for impact points instead, no separate "Overview" tab there - each category tab renders its own outcomes/impacts, key facts & team setup, and customer key-challenges/goals sections, see value-globe.js:900-983 for the ported-from markup.

Parameters

  • props (Object)
    • props.point (Object) — The clicked location's full content entry.
    • props.labels (Object) — content.valuePartnership.labels.
    • props.onClose (function)

GlobePage

"Globe" tab of Value Partnership: the 3D InteractiveGlobe (lazy- loaded, see below) with its ValueCheckboxPanel filter/search drawer, GlobeBottomNav home/prev/next bar and, once a marker is selected, its GlobeDetailCard. isPointVisible (ported from the old app's value-globe.js) decides which of content.valuePartnership.points are shown, combining the checkbox panel's filters and search field.

ValueCheckboxPanel

Slide-in filter panel for the globe's markers, ported from the old value-checkbox-panel Lit component. Controlled component for filtering: filters is owned by GlobePage (see its isPointVisible-equivalent useMemo), this just renders it and reports changes via onChange. The open/collapsed state of the drawer itself is local UI state - it doesn't affect which markers are visible, so it has no reason to live in GlobePage.

Parameters

  • props (Object)
    • props.filters (Object) — { search, impactCasesActive, outcomeCasesActive, checkedImpactCases, checkedOutcomeCases, checkedStrategyCases }.
    • props.onChange (function) — Called with the next filters object.

CategoryMenu

"Choose a category" slide-in side panel, ported from value-partnerships-page.js's .value-categories block: a Departments/Roles switch plus the matching list of clickable category buttons (content.partnerships.buttons or .roles). Same collapsible-drawer pattern as GlobePage's ValueCheckboxPanel - see that component for why the open/collapsed state is local UI state rather than a prop.

Parameters

  • props (Object)
    • props.selectedView ("departments" | "roles")
    • props.onViewChange (function)
    • props.categories (Array.<{id: string, title: string}>) — Buttons or roles for the current view.
    • props.onSelectCategory (function)
    • props.labels (Object)

CategoryOverlay

PPT-deck overlay for one department/role, ported from value-partnerships-page.js's renderOverlay/renderCard. Shows every content.valuePartnership.partnerships.ppt item whose location/roles match the selected category as a clickable preview card.

Parameters

  • props (Object)
    • props.category (Object)
    • props.selectedView ("departments" | "roles")
    • props.ppt (Array.<Object>) — Full presentation-deck list.
    • props.onSelectPpt (function)
    • props.onClose (function)

PartnershipsPage

Value Partnerships page: hospital-department/role browser + presentation deck viewer, ported from value-partnerships-page.js. See CategoryMenu, CategoryOverlay, PresentationBrowser and SlideView for the individual pieces this composes.

Parameters

  • props (Object)
    • props.onActionsChange (function, optional) — Registers this page's "Show key slides"/"Show all presentations" buttons into ValuePartnershipNav's children slot (see ValuePartnership.jsx).

PresentationBrowser

Full-screen browse overlay, ported from value-slideview-filter.js (the old "SlideViewFilter" - a misleading name, it has nothing to do with filtering a single deck's slides). Two modes:

  • "all": every presentation deck, grouped per content.valuePartnership's partnershipsFilterUS/partnershipsFilter link groups (hideUS picks which).
  • "keySlides": a thumbnail grid of content.valuePartnership.partnerships .keySlides.overview, each opening its matching mini-deck from keySlides.ppt.

Parameters

  • props (Object)
    • props.mode ("all" | "keySlides")
    • props.hideUS (boolean) — Accepted (per PartnershipsPage's linkGroups selection) but its own toggle switch is currently commented out below, so this is presently unused inside the component.
    • props.onToggleHideUS (function) — See hideUS - currently unused inside the component.
    • props.linkGroups (Array) — content.valuePartnership.partnershipsFilterUS|Filter.groups.
    • props.ppt (Array) — Full presentation-deck list (to resolve a link's ppt.id).
    • props.keySlidesOverview (Array)
    • props.keySlidesPpt (Array)
    • props.onSelectPpt (function)
    • props.onClose (function)
    • props.onSwitchMode (function) — Jumps to the other mode ("all" <-> "keySlides").

QrCodeCanvas

Renders url as a QR code onto a canvas via the qrcode package (ported from value-slideview(-filter).js's showQRCode).

Parameters

  • props (Object)
    • props.url (string) — URL/text to encode.
    • props.size (number, optional, default: 220) — Canvas width/height in px.

COPYRIGHT_NOTICE

Fullscreen presentation-deck viewer, ported from value-slideview.js (minus the QR/congress-app "save highlights" checkbox mode, which lives in PresentationBrowser, and the manual <link rel=preload> injection, replaced by the browser's own image decoding/caching). Mount with key={ppt.id} so opening a different deck resets page cleanly instead of syncing it via effect.

Parameters

  • props (Object)
    • props.ppt (Object)
    • props.initialPage (number, optional, default: 1)
    • props.labels (Object)
    • props.onClose (function)

Normalizes the webLink field found on partnership/ppt/filter-option entries (value-partnership-partnerships.json) into a URL the QR code can encode. webLink is stored inconsistently as either a plain string or a one-element array, and is sometimes an empty string when no link exists.

Parameters

  • webLink (string | Array.<string>)

Returns

  • string | null — The resolved URL, or null if none is set.

ValueDriverNav

Compact vertical quick-nav for the 6 drivers, shown in ValueExcellencePage's detail-view aside so the user can jump straight between driver pages instead of returning to the Venn-diagram overview each time.

Parameters

  • props (Object)
    • props.drivers (Array.<{id: string, title: string}>) — content.valuePartnership.drivers
    • props.selectedId (string) — id of the currently active driver
    • props.onSelect (function)
    • props.onBack (function)
    • props.labels (Object)

ValueExcellencePage

Value & Excellence Drivers page, ported from value-excellence-page.js: an overview (clickable Venn infographic) that switches to a driver detail view. The old page also duplicated the detail solutions as a mobile-only accordion (hidden above its "xl" breakpoint via CSS) - this kiosk always runs at one large landscape resolution (see presentationModes.js), so only the grid variant is ported; the DOM-measurement height hack for the grid titles is replaced by CSS Grid's own row-stretching.

ValueInfographic

Clickable Venn-diagram infographic of the 6 value/excellence drivers, ported from the old value-infografic Lit component. The SVG itself is a large static asset (see venn-diagram-svg.js) rendered via dangerouslySetInnerHTML - safe here since the markup is our own trusted, static file, not user input. Clicks are handled by delegation (each segment carries a data-driver-id attribute) instead of converting ~14 inline Lit event bindings into individual JSX handlers.

Parameters

  • props (Object)
    • props.onSelect (function) — Called with the clicked driver's id.

ValuePartnershipPage

"Value Partnership" presentation app. Unlike ValueAdvisoryServices/ RadEnablement (linear SlidePage decks), this is a bespoke sub-app with 3 independent interactive sections (globe, excellence drivers, partnerships/ slideshow) sharing one nav bar and one content file - so it owns its own nested route table instead of going through SlidePage.

GlobePage is deliberately kept outside that route table and always rendered (just hidden via CSS - see .value-partnership-page__globe--hidden

  • while another tab is active) instead of being mounted/unmounted per route like Excellence/Partnerships are. It owns a full Three.js/WebGL scene (react-globe.gl); tearing that down and rebuilding it on every tab switch is both slow and a known memory-leak risk class for this kind of library on repeated unmount. GlobePage's own active prop drives pausing its render loop while hidden instead (see InteractiveGlobe.jsx).

ValuePartnershipNav

Fixed nav bar shared by all 3 Value Partnership sections: section switcher (labels from content) + a burger toggle on the right that reveals the "Switch App" button back to the app selection (kept collapsed by default per Figma, unlike the sibling nav bars - ValueDriverNav/CategoryMenu/ ValueCheckboxPanel - which show it unconditionally). The section-switcher labels/logo area also carries the long-press-to-reload kiosk gesture (see Reload).

children, when passed, renders as a second button group alongside the section switcher - the lifted-state slot a routed sub-page (e.g. PartnershipsPage) uses to put its own page-scoped actions in this shared bar, mirroring how suppressNav/onSelectionChange let a sub-page affect this bar from below (see ValuePartnership.jsx).

Parameters

  • props (Object)
    • props.children (*, optional) — React node(s) for the second button group.

useAnalytics

Returns the analytics singleton's tracking functions. Not a real React hook (no state/context involved) - kept as a hook-shaped function so existing call sites read the same as the old useTracking().

CONFIG_SCHEMA: Array.<{key: string, source: string, name: string, type: string, default: *, min: number, description: string}>

Declares every kiosk/device config value the app understands. Values come from URL params (source "param", read live by useConfig in config.jsx and kept alive across navigation), each with type, default and a German description shown in admin/debug contexts.

useConfig

React hook that resolves every entry in CONFIG_SCHEMA (config-schema.js) against the current URL search params / import.meta.env and returns them as a flat, typed { key: value } object.

Returns

  • Object — Config values keyed by their CONFIG_SCHEMA key.

ContentContext

Context carrying { content, views, stories, error, getView, getAdjacentRootViews } - consume via useContent.

useContent

React hook to access the loaded content object. Returns {} until the content.json fetch in ContentProvider has resolved.

RETRY_DELAY_MS

Resolves the content file(s) for the current route, fetches them (once per file-list combination - already-fetched combinations are served from an in-memory cache so switching between apps doesn't refetch) and makes the merged result available to all descendants via ContentContext. On fetch failure, content stays {}, the failure is exposed as error (pages show a visible message instead of a blank screen) and the fetch is retried until it succeeds.

PRESENTATION_MODES: Array.<PresentationMode>

Single source of truth for the 3 presentation modes/sales apps. key doubles as the valid defaultMode config value (config-schema.js) and as the route path segment (see Routes.jsx, AppSelection.jsx). contentFile is the JSON this mode's route loads via ContentProvider (services/content.jsx); null means the page doesn't fetch any content (yet). A mode can use contentFiles (array) instead of contentFile (single string) when its content is split across several smaller files - ContentProvider fetches all of them and merges the results into one content object, so consumers still read e.g. content.valuePartnership.points regardless of which file it came from.

orientation is each app's fixed, content-driven physical orientation (confirmed with the content team, not device-dependent - Rad Enablement is portrait-only, everything else landscape) - consumed by Stage.jsx to pick a landscape vs. portrait reference resolution for the whole-app scale wrapper. resolveModeForPath() below is the one place that maps a route to its mode - reused by Stage and GeneralPageTracking so they can never disagree about which mode a given path belongs to.

resolveModeForPath

Resolves which PRESENTATION_MODES entry a route belongs to, or null for a path that isn't any mode's route (currently just "/", the app selection screen - always landscape, see Stage.jsx).

Parameters

  • pathname (string)

Returns

ScreensaverProvider

Tracks idle state and exposes it via ScreensaverContext.

useScreensaver

React hook to access { isIdle, trigger, screensaverFadeDuration, showNow }. Must be used within a <ScreensaverProvider>.

TabProvider

Provides openTab/closeTab (see useTabs) to the component tree, tracking open external tabs/windows per URL.

useTabs

React hook to access openTab/closeTab. Must be used within a <TabProvider>.

GeneralPageTracking

Invisible helper mounted next to the routes (see Routes.jsx): keeps document.title in sync with the current route. Page-view tracking itself is handled implicitly by the analytics SDK's History API listener (see services/analytics/AnalyticsSDK.js) - no explicit tracking call needed here.

parseConfigValue

Parses and validates a single raw config value against its schema definition.

Parameters

  • rawValue (string | null | undefined) — The raw value as read from searchParams.get(...) or import.meta.env[...]. Always a string when set.
  • definition (Object) — The matching entry from CONFIG_SCHEMA.
    • definition.type ("boolean" | "number" | "string") — How to interpret rawValue.
    • definition.default (*) — Value to use when rawValue is missing/invalid.
    • definition.min (number, optional) — Only for type "number": reject values below this.
    • definition.max (number, optional) — Only for type "number": reject values above this.
    • definition.key (string) — Config key name, used only for warning messages.

Returns

  • * — The parsed value, or definition.default if rawValue was empty or failed validation.

Navigates with a native View Transition cross-fade. react-router's own viewTransition navigate option only works with the data router (createHashRouter/RouterProvider) - this app uses the plain declarative /, so the native API is driven manually. flushSync forces the DOM update to happen synchronously inside the callback, which the API requires.

Callers are responsible for keeping the current query string alive (kiosk/device config, see config-schema.js) by including it in path.

Parameters

  • navigate (function) — react-router's navigate function (from useNavigate()).
  • path (string) — Target path, including query string.