@ethisyscore/plugin-ui 1.44.0 → 1.46.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,7 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode, ReactElement } from 'react';
3
+ import { A as ActionDescriptor, B as Breadcrumb, P as PageHeaderDerivedProps, a as PluginDetailContextItem, R as RouteMeta, H as HeaderMenuItem, b as HeaderDetailContext, c as PageHeaderState } from '../../pageHeaderTypes-PWZpiwp6.js';
4
+ export { d as ActionSlot, e as HeaderAction, f as HeaderActionVariant, g as PluginDetailContext, h as RouteMetaEntry } from '../../pageHeaderTypes-PWZpiwp6.js';
3
5
 
4
6
  /**
5
7
  * Static Tailwind basis classes for {@link FillGridItem}.
@@ -46,156 +48,6 @@ interface FillGridItemProps {
46
48
  }
47
49
  declare function FillGridItem({ span, className, children }: FillGridItemProps): react.JSX.Element;
48
50
 
49
- /**
50
- * `@ethisyscore/plugin-ui/components/layout` — page-header contracts.
51
- *
52
- * Promoted from the monolith's `src/components/layout/types.ts` +
53
- * `src/hooks/menu/menuConfig.ts` so every plugin shares ONE header layer instead
54
- * of copying `PageHeader` + `usePageHeader` + these types per plugin. The shapes
55
- * are the subset the header machinery actually reads — decoupled from the
56
- * monolith's shell-only `SubMenuProps`/`MenuActionConfig`, which drag in RBAC,
57
- * notification, and layout state a plugin never has.
58
- */
59
- /**
60
- * Header-placement hint for an action.
61
- *
62
- * - "primary" surfaces as the page-header primary CTA.
63
- * - "secondary" surfaces as the page-header secondary dropdown (at most one per page).
64
- * - "overflow" surfaces in the page-header ⋯ More menu.
65
- * - "sidebar-only" not header-visible (default).
66
- */
67
- type ActionSlot = "primary" | "secondary" | "overflow" | "sidebar-only";
68
- /**
69
- * Visual variant of a header action. `"danger"` renders the destructive style;
70
- * `"primary"`/`"secondary"` are sidebar-pill hints.
71
- */
72
- type HeaderActionVariant = "primary" | "secondary" | "danger";
73
- /**
74
- * Header-facing descriptor of an action. Built by `usePageHeader` from a menu
75
- * item / detail context; consumed by `PageHeader`.
76
- */
77
- interface ActionDescriptor {
78
- id: string;
79
- label: string;
80
- icon?: string;
81
- /** Anchor href. Mutually exclusive with `onClick`. */
82
- href?: string;
83
- /** Imperative click handler. Mutually exclusive with `href`. */
84
- onClick?: () => void;
85
- /** Render with danger style (Delete / Cancel). */
86
- danger?: boolean;
87
- /** Secondary-slot dropdown children (Lifecycle ▾ etc.). */
88
- children?: ActionDescriptor[];
89
- /** Optional disabled state (e.g. Lifecycle option not legal in current state). */
90
- disabled?: boolean;
91
- /** Optional tooltip / aria-label for icon-only buttons. */
92
- description?: ReactNode;
93
- }
94
- /**
95
- * A raw header source action, as authored in a plugin's menu config or supplied
96
- * by a detail context. The union superset of the monolith's `MenuActionConfig`
97
- * and `SidebarDetailContextNavItem` — only the fields the header reads.
98
- */
99
- interface HeaderAction {
100
- id: string;
101
- label: string;
102
- icon?: string;
103
- /** Navigates when clicked. Mutually exclusive with `actionId`/`onClick`. */
104
- href?: string;
105
- /** Dispatches via the sidebar-action channel instead of navigating. */
106
- actionId?: string;
107
- /** Explicit click handler (detail-context actions can carry one directly). */
108
- onClick?: () => void;
109
- /** Visual variant — see {@link HeaderActionVariant}. */
110
- variant?: HeaderActionVariant;
111
- /** Page-header placement. Defaults to `"sidebar-only"` (not header-visible). */
112
- slot?: ActionSlot;
113
- disabled?: boolean;
114
- /** Secondary-slot dropdown children. */
115
- children?: HeaderAction[];
116
- }
117
- /**
118
- * A menu item the `PageHeaderProvider` matches against the current route. When
119
- * the active route is this item's `href`, its `actions` feed the header. Plugins
120
- * author these as a faithful slice of the monolith's `menuConfig.ts`.
121
- */
122
- interface HeaderMenuItem {
123
- id: string;
124
- label: string;
125
- href?: string;
126
- group?: string;
127
- actions?: HeaderAction[];
128
- children?: HeaderMenuItem[];
129
- }
130
- /**
131
- * Detail-page header context — the actions/title a detail or edit page surfaces
132
- * without a menu item of its own. A page hook publishes this (or, more commonly,
133
- * spreads its own `headerProps`); parity with the monolith's `detailContext`.
134
- */
135
- interface HeaderDetailContext {
136
- title?: string;
137
- /**
138
- * Optional subtitle (e.g. the entity name) shown under the title. Read by
139
- * `usePageHeader` so a wrapper-rendered header (see
140
- * {@link PageHeaderProviderProps.useDetailContext}) can surface it without the
141
- * page spreading its own `headerProps`.
142
- */
143
- subtitle?: ReactNode;
144
- actions?: HeaderAction[];
145
- }
146
- /** One node in the header breadcrumb trail (`Home / Finance / <page>`). */
147
- interface Breadcrumb {
148
- label: string;
149
- /** Navigates when clicked; omit for the current (leaf) crumb. */
150
- href?: string;
151
- }
152
- /**
153
- * Breadcrumb metadata for one route — a faithful shift of the monolith's
154
- * `routeMeta.ts` entry: a full path `pattern` (`:`-segments are params) with a
155
- * `label` and the `parent` route's `pattern`. `buildBreadcrumbs` matches the
156
- * current path against the patterns (most-specific wins), walks the `parent`
157
- * chain, prepends Home, and resolves each ancestor's pattern with the captured
158
- * params — identical to the monolith's breadcrumb builder.
159
- *
160
- * `pageId` is the one plugin-only addition (the monolith has no page-bundle ids):
161
- * it links a pattern to its platform-react page so the manifest generator can emit
162
- * the page's `route`. The SDK breadcrumb builder ignores it.
163
- */
164
- interface RouteMetaEntry {
165
- /** Full path pattern, e.g. `/extensions/finance/invoices/:id/edit`. */
166
- pattern: string;
167
- label: string;
168
- /** Parent route's `pattern`; omit for a top-level route. */
169
- parent?: string;
170
- /** Platform-react page id this pattern maps to (plugin manifest link; SDK ignores). */
171
- pageId?: string;
172
- }
173
- /** The migrated `routeMeta` slice — a flat array, same shape as the monolith. */
174
- type RouteMeta = RouteMetaEntry[];
175
- /**
176
- * What `PageHeaderContext` publishes — the subset of the monolith's `SubMenuProps`
177
- * that `usePageHeader` reads. `null` when no provider is mounted (a page rendered
178
- * standalone, e.g. a test) → the hook derives empty header props.
179
- */
180
- interface PageHeaderState {
181
- activeMenuItem?: HeaderMenuItem | null;
182
- detailContext?: HeaderDetailContext | null;
183
- title?: string;
184
- subtitle?: ReactNode;
185
- /** Root breadcrumb trail (e.g. `Home / Finance`); `PageHeader` appends the title. */
186
- breadcrumbs?: Breadcrumb[];
187
- }
188
- /** The prop bundle `usePageHeader` returns, ready to spread onto `<PageHeader>`. */
189
- interface PageHeaderDerivedProps {
190
- title: string;
191
- subtitle?: ReactNode;
192
- primaryAction?: ActionDescriptor;
193
- secondaryAction?: ActionDescriptor;
194
- overflowActions?: ActionDescriptor[];
195
- /** Root breadcrumb trail; `PageHeader` appends the current `title` as the leaf. */
196
- breadcrumbs?: Breadcrumb[];
197
- }
198
-
199
51
  /**
200
52
  * `@ethisyscore/plugin-ui/components/layout` — the page-header, promoted from the
201
53
  * monolith so plugins share one component instead of copying it. In a plugin this
@@ -230,6 +82,22 @@ declare function PageHeader({ title, subtitle, primaryAction, secondaryAction, o
230
82
  */
231
83
  declare function usePageHeader(): PageHeaderDerivedProps;
232
84
 
85
+ /**
86
+ * Merge a plugin detail-context's `actions` into the header props a SELF-RENDERING
87
+ * detail page spreads onto `<PageHeader>`.
88
+ *
89
+ * Use this when a detail page renders its own `<PageHeader {...headerProps}/>` and
90
+ * sources its CTAs from a `*DetailContext` hook (rather than from a `menuConfig`
91
+ * entry, which detail routes can't have — their path is dynamic). Applies the same
92
+ * slot split (`primary`/`secondary`/`overflow`; `sidebar-only` is not shown in the
93
+ * header) and `actionId → useTriggerSidebarAction` dispatch the SDK applies to
94
+ * menu-item actions, so a detail-context action fires the page's `useSidebarActions`
95
+ * handler exactly like a list-page CTA. `href` actions navigate.
96
+ *
97
+ * The companion for the OTHER surface is `toHostSidebarInput` (host sidebar).
98
+ */
99
+ declare function useDetailHeaderActions(base: PageHeaderDerivedProps, actions: PluginDetailContextItem[]): PageHeaderDerivedProps;
100
+
233
101
  /**
234
102
  * Builds the `Home / … / <page>` breadcrumb trail — a faithful port of the
235
103
  * monolith's `buildBreadcrumbs`. Matches the current path against the `routeMeta`
@@ -355,4 +223,4 @@ declare function useActiveSidebarActions(): ReadonlySet<string>;
355
223
  */
356
224
  declare function useReportSidebarActionActive(actionId: string, isActive: boolean): void;
357
225
 
358
- export { type ActionDescriptor, type ActionHandler, type ActionSlot, type Breadcrumb, type FillGap, FillGrid, FillGridItem, type FillSpan, type HeaderAction, type HeaderActionVariant, type HeaderDetailContext, type HeaderMenuItem, PageHeader, PageHeaderContext, type PageHeaderDerivedProps, type PageHeaderProps, PageHeaderProvider, type PageHeaderProviderProps, type PageHeaderState, type RouteMeta, type RouteMetaEntry, SidebarActionContext, type SidebarActionContextValue, SidebarActionProvider, type Twelfths, buildBreadcrumbs, useActiveSidebarActions, usePageHeader, usePageHeaderContext, useReportSidebarActionActive, useSidebarAction, useSidebarActions, useTriggerSidebarAction, withPageHeader };
226
+ export { ActionDescriptor, type ActionHandler, Breadcrumb, type FillGap, FillGrid, FillGridItem, type FillSpan, HeaderDetailContext, HeaderMenuItem, PageHeader, PageHeaderContext, PageHeaderDerivedProps, type PageHeaderProps, PageHeaderProvider, type PageHeaderProviderProps, PageHeaderState, PluginDetailContextItem, RouteMeta, SidebarActionContext, type SidebarActionContextValue, SidebarActionProvider, type Twelfths, buildBreadcrumbs, useActiveSidebarActions, useDetailHeaderActions, usePageHeader, usePageHeaderContext, useReportSidebarActionActive, useSidebarAction, useSidebarActions, useTriggerSidebarAction, withPageHeader };
@@ -429,6 +429,52 @@ function toDescriptor(raw, triggerAction) {
429
429
  children: raw.children ? raw.children.map((c) => toDescriptor(c, triggerAction)) : void 0
430
430
  };
431
431
  }
432
+ function useDetailHeaderActions(base, actions) {
433
+ const triggerAction = useTriggerSidebarAction();
434
+ return useMemo(() => {
435
+ if (actions.length === 0) {
436
+ return base;
437
+ }
438
+ let primary = base.primaryAction;
439
+ let secondary = base.secondaryAction;
440
+ const overflow = [...base.overflowActions ?? []];
441
+ for (const action of actions) {
442
+ const descriptor = toDescriptor2(action, triggerAction);
443
+ switch (action.slot ?? "sidebar-only") {
444
+ case "primary":
445
+ if (primary == null) primary = descriptor;
446
+ else overflow.push(descriptor);
447
+ break;
448
+ case "secondary":
449
+ if (secondary == null) secondary = descriptor;
450
+ else overflow.push(descriptor);
451
+ break;
452
+ case "overflow":
453
+ overflow.push(descriptor);
454
+ break;
455
+ }
456
+ }
457
+ return {
458
+ ...base,
459
+ primaryAction: primary,
460
+ secondaryAction: secondary,
461
+ overflowActions: overflow.length > 0 ? overflow : void 0
462
+ };
463
+ }, [base, actions, triggerAction]);
464
+ }
465
+ function toDescriptor2(raw, triggerAction) {
466
+ const onClick = raw.href != null ? void 0 : raw.onClick ?? (raw.actionId ? () => triggerAction(raw.actionId) : void 0);
467
+ return {
468
+ id: raw.id,
469
+ label: raw.label,
470
+ icon: raw.icon,
471
+ href: raw.href,
472
+ onClick,
473
+ disabled: raw.disabled,
474
+ danger: raw.variant === "danger",
475
+ children: raw.children?.map((child) => toDescriptor2(child, triggerAction))
476
+ };
477
+ }
432
478
 
433
479
  // src/components/layout/breadcrumbs.ts
434
480
  var HOME_CRUMB = { label: "Home", href: "/" };
@@ -548,6 +594,6 @@ function findByHref(items, pathname) {
548
594
  return null;
549
595
  }
550
596
 
551
- export { FillGrid, FillGridItem, PageHeader, PageHeaderContext, PageHeaderProvider, SidebarActionContext, SidebarActionProvider, buildBreadcrumbs, useActiveSidebarActions, usePageHeader, usePageHeaderContext, useReportSidebarActionActive, useSidebarAction, useSidebarActions, useTriggerSidebarAction, withPageHeader };
597
+ export { FillGrid, FillGridItem, PageHeader, PageHeaderContext, PageHeaderProvider, SidebarActionContext, SidebarActionProvider, buildBreadcrumbs, useActiveSidebarActions, useDetailHeaderActions, usePageHeader, usePageHeaderContext, useReportSidebarActionActive, useSidebarAction, useSidebarActions, useTriggerSidebarAction, withPageHeader };
552
598
  //# sourceMappingURL=index.js.map
553
599
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/layout/fillGridClasses.ts","../../../src/components/layout/FillGrid.tsx","../../../src/components/layout/PageHeader.tsx","../../../src/components/layout/pageHeaderContext.ts","../../../src/components/layout/sidebarAction.tsx","../../../src/components/layout/usePageHeader.ts","../../../src/components/layout/breadcrumbs.ts","../../../src/components/layout/PageHeaderProvider.tsx"],"names":["jsx","Breadcrumbs","Box","Link","createContext","useContext","useRef","useState","useMemo","jsxs"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Static Tailwind basis classes for {@link FillGridItem}.\n *\n * Tailwind's content scanner extracts class candidates from raw source text and\n * cannot follow string concatenation — `\"sm:\" + \"basis-[...]\"` is invisible to\n * it. So every fully-prefixed class is spelled out as a literal below, indexed\n * by breakpoint → gap → span. `fillItemClass` only ever *looks up* a literal; it\n * never builds one. This is what guarantees the responsive classes survive a\n * production purge (no fragile safelist comment to keep in sync).\n *\n * NOTE: because these literals live in the SDK, a CONSUMER's Tailwind build must\n * scan this package's dist (add it to `content`) or the classes won't generate.\n *\n * basis(n, g) = calc(n/12 * 100% - g * (1 - n/12)), g = gap in rem.\n * gap-5 => g = 1.25rem; gap-2.5 => g = 0.625rem. Span 12 => basis-full.\n */\nexport type Twelfths = 2.4 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12;\nexport type FillGap = 2.5 | 5;\ntype Breakpoint = \"xs\" | \"sm\" | \"md\" | \"lg\";\nexport type FillSpan = Partial<Record<Breakpoint, Twelfths>>;\n\n/**\n * Full literal class per breakpoint × gap × span. `xs` is unprefixed; `sm`/`md`/\n * `lg` carry the Tailwind prefix. Every string here is a real, scannable literal.\n */\nconst CLASSES: Record<Breakpoint, Record<FillGap, Record<Twelfths, string>>> = {\n xs: {\n 5: {\n 2.4: \"basis-[calc(20%-1rem)]\",\n 3: \"basis-[calc(25%-0.9375rem)]\",\n 4: \"basis-[calc(33.333%-0.8333rem)]\",\n 5: \"basis-[calc(41.667%-0.7292rem)]\",\n 6: \"basis-[calc(50%-0.625rem)]\",\n 7: \"basis-[calc(58.333%-0.5208rem)]\",\n 8: \"basis-[calc(66.667%-0.4167rem)]\",\n 9: \"basis-[calc(75%-0.3125rem)]\",\n 12: \"basis-full\",\n },\n 2.5: {\n 2.4: \"basis-[calc(20%-0.5rem)]\",\n 3: \"basis-[calc(25%-0.46875rem)]\",\n 4: \"basis-[calc(33.333%-0.41667rem)]\",\n 5: \"basis-[calc(41.667%-0.36458rem)]\",\n 6: \"basis-[calc(50%-0.3125rem)]\",\n 7: \"basis-[calc(58.333%-0.26042rem)]\",\n 8: \"basis-[calc(66.667%-0.20833rem)]\",\n 9: \"basis-[calc(75%-0.15625rem)]\",\n 12: \"basis-full\",\n },\n },\n sm: {\n 5: {\n 2.4: \"sm:basis-[calc(20%-1rem)]\",\n 3: \"sm:basis-[calc(25%-0.9375rem)]\",\n 4: \"sm:basis-[calc(33.333%-0.8333rem)]\",\n 5: \"sm:basis-[calc(41.667%-0.7292rem)]\",\n 6: \"sm:basis-[calc(50%-0.625rem)]\",\n 7: \"sm:basis-[calc(58.333%-0.5208rem)]\",\n 8: \"sm:basis-[calc(66.667%-0.4167rem)]\",\n 9: \"sm:basis-[calc(75%-0.3125rem)]\",\n 12: \"sm:basis-full\",\n },\n 2.5: {\n 2.4: \"sm:basis-[calc(20%-0.5rem)]\",\n 3: \"sm:basis-[calc(25%-0.46875rem)]\",\n 4: \"sm:basis-[calc(33.333%-0.41667rem)]\",\n 5: \"sm:basis-[calc(41.667%-0.36458rem)]\",\n 6: \"sm:basis-[calc(50%-0.3125rem)]\",\n 7: \"sm:basis-[calc(58.333%-0.26042rem)]\",\n 8: \"sm:basis-[calc(66.667%-0.20833rem)]\",\n 9: \"sm:basis-[calc(75%-0.15625rem)]\",\n 12: \"sm:basis-full\",\n },\n },\n md: {\n 5: {\n 2.4: \"md:basis-[calc(20%-1rem)]\",\n 3: \"md:basis-[calc(25%-0.9375rem)]\",\n 4: \"md:basis-[calc(33.333%-0.8333rem)]\",\n 5: \"md:basis-[calc(41.667%-0.7292rem)]\",\n 6: \"md:basis-[calc(50%-0.625rem)]\",\n 7: \"md:basis-[calc(58.333%-0.5208rem)]\",\n 8: \"md:basis-[calc(66.667%-0.4167rem)]\",\n 9: \"md:basis-[calc(75%-0.3125rem)]\",\n 12: \"md:basis-full\",\n },\n 2.5: {\n 2.4: \"md:basis-[calc(20%-0.5rem)]\",\n 3: \"md:basis-[calc(25%-0.46875rem)]\",\n 4: \"md:basis-[calc(33.333%-0.41667rem)]\",\n 5: \"md:basis-[calc(41.667%-0.36458rem)]\",\n 6: \"md:basis-[calc(50%-0.3125rem)]\",\n 7: \"md:basis-[calc(58.333%-0.26042rem)]\",\n 8: \"md:basis-[calc(66.667%-0.20833rem)]\",\n 9: \"md:basis-[calc(75%-0.15625rem)]\",\n 12: \"md:basis-full\",\n },\n },\n lg: {\n 5: {\n 2.4: \"lg:basis-[calc(20%-1rem)]\",\n 3: \"lg:basis-[calc(25%-0.9375rem)]\",\n 4: \"lg:basis-[calc(33.333%-0.8333rem)]\",\n 5: \"lg:basis-[calc(41.667%-0.7292rem)]\",\n 6: \"lg:basis-[calc(50%-0.625rem)]\",\n 7: \"lg:basis-[calc(58.333%-0.5208rem)]\",\n 8: \"lg:basis-[calc(66.667%-0.4167rem)]\",\n 9: \"lg:basis-[calc(75%-0.3125rem)]\",\n 12: \"lg:basis-full\",\n },\n 2.5: {\n 2.4: \"lg:basis-[calc(20%-0.5rem)]\",\n 3: \"lg:basis-[calc(25%-0.46875rem)]\",\n 4: \"lg:basis-[calc(33.333%-0.41667rem)]\",\n 5: \"lg:basis-[calc(41.667%-0.36458rem)]\",\n 6: \"lg:basis-[calc(50%-0.3125rem)]\",\n 7: \"lg:basis-[calc(58.333%-0.26042rem)]\",\n 8: \"lg:basis-[calc(66.667%-0.20833rem)]\",\n 9: \"lg:basis-[calc(75%-0.15625rem)]\",\n 12: \"lg:basis-full\",\n },\n },\n};\n\nconst BREAKPOINTS: readonly Breakpoint[] = [\"xs\", \"sm\", \"md\", \"lg\"];\n\n/**\n * Full class string for one item: always `min-w-0 grow`, plus the literal basis\n * class for each supplied breakpoint (looked up, never concatenated).\n */\nexport function fillItemClass(span: FillSpan, gap: FillGap): string {\n const parts = [\"min-w-0\", \"grow\"];\n for (const bp of BREAKPOINTS) {\n const n = span[bp];\n if (n !== undefined) parts.push(CLASSES[bp][gap][n]);\n }\n return parts.join(\" \");\n}\n","import { createContext, useContext } from \"react\";\nimport { Box } from \"@mui/material\";\nimport { fillItemClass, type FillGap, type FillSpan } from \"./fillGridClasses\";\n\nconst FillGapContext = createContext<FillGap>(5);\n\ninterface FillGridProps {\n /** Gutter width. 5 = 20px (default), 2.5 = 10px. Matches MUI spacing values. */\n gap?: FillGap;\n className?: string;\n children: React.ReactNode;\n}\n\n/**\n * A flex-wrap row whose items `grow` to fill a partially-filled last row — the\n * dashboard/overview convention. NOT for forms, tables, or single full-width cards.\n *\n * Renders `w-full` so it always spans its container: a `FillGrid` is itself often\n * a flex item of a parent MUI `<Grid container>` / flex row, where without an\n * explicit width it would shrink-wrap to its content instead of filling the row\n * (the behaviour a `<Grid container size={12}>` used to give).\n */\nexport function FillGrid({ gap = 5, className, children }: FillGridProps) {\n const gapClass = gap === 2.5 ? \"gap-2.5\" : \"gap-5\";\n return (\n <FillGapContext.Provider value={gap}>\n <Box className={[\"flex w-full flex-wrap\", gapClass, className].filter(Boolean).join(\" \")}>\n {children}\n </Box>\n </FillGapContext.Provider>\n );\n}\n\ninterface FillGridItemProps {\n /** 12-column span per breakpoint, mirroring MUI Grid's `size`. Default { xs: 12 }. */\n span?: FillSpan;\n className?: string;\n children: React.ReactNode;\n}\n\nexport function FillGridItem({ span = { xs: 12 }, className, children }: FillGridItemProps) {\n const gap = useContext(FillGapContext);\n return (\n <Box className={[fillItemClass(span, gap), className].filter(Boolean).join(\" \")}>\n {children}\n </Box>\n );\n}\n","import { useState, useRef, type ReactNode } from \"react\";\nimport { Link } from \"react-router-dom\";\nimport {\n Box,\n Breadcrumbs as MuiBreadcrumbs,\n Stack,\n Typography,\n Link as MuiLink,\n Button,\n IconButton,\n Menu,\n MenuItem,\n} from \"../ui\";\nimport type { ActionDescriptor, Breadcrumb } from \"./pageHeaderTypes\";\n\n/**\n * `@ethisyscore/plugin-ui/components/layout` — the page-header, promoted from the\n * monolith so plugins share one component instead of copying it. In a plugin this\n * IS the page header: the host suppresses its own chrome for platform-react\n * surfaces, so this renders the breadcrumb trail, the title, and the CTAs.\n *\n * `breadcrumbs` is the ROOT trail (e.g. `Home / Finance`); the current `title` is\n * appended as the non-link leaf crumb. MUI primitives come from the sibling\n * `../ui` barrel (host externals, never bundled); `Link` is react-router's so\n * links keep middle-click / open-in-new-tab / a11y.\n */\nexport interface PageHeaderProps {\n title: string;\n subtitle?: ReactNode;\n primaryAction?: ActionDescriptor;\n secondaryAction?: ActionDescriptor;\n overflowActions?: ActionDescriptor[];\n /** Root breadcrumb trail; the `title` is appended as the current-page leaf. */\n breadcrumbs?: Breadcrumb[];\n}\n\nexport function PageHeader({\n title,\n subtitle,\n primaryAction,\n secondaryAction,\n overflowActions,\n breadcrumbs,\n}: PageHeaderProps) {\n const hasActions =\n primaryAction != null ||\n secondaryAction != null ||\n (overflowActions != null && overflowActions.length > 0);\n\n return (\n <Stack direction=\"column\" spacing={0.5} className=\"mb-4\">\n {breadcrumbs != null && breadcrumbs.length > 0 && <Breadcrumbs trail={breadcrumbs} />}\n <Stack direction=\"row\" justifyContent=\"space-between\" alignItems=\"flex-start\" spacing={2}>\n <Box>\n {/* Title is optional: in a plugin the host renders the surface title,\n so list pages pass an empty title and only their CTA shows. Pages\n that want an in-body title (detail/create/edit) set it explicitly. */}\n {title !== \"\" && (\n <Typography variant=\"h4\" component=\"h1\">\n {title}\n </Typography>\n )}\n {subtitle != null && (\n <Typography variant=\"body2\" color=\"text.secondary\" className=\"mt-1\">\n {subtitle}\n </Typography>\n )}\n </Box>\n {hasActions && (\n <Stack\n direction=\"row\"\n spacing={1}\n alignItems=\"center\"\n data-testid=\"page-header-actions\"\n >\n {overflowActions != null && overflowActions.length > 0 && (\n <OverflowMenu actions={overflowActions} />\n )}\n {secondaryAction != null && <SecondaryDropdown action={secondaryAction} />}\n {primaryAction != null && <PrimaryButton action={primaryAction} />}\n </Stack>\n )}\n </Stack>\n </Stack>\n );\n}\n\n/**\n * Breadcrumb trail — mirrors the host's `gogo-ui` `PageBreadcrumbs` exactly (MUI\n * `Breadcrumbs` with the same markup/props) so the plugin surface looks identical\n * to host-rendered chrome: `text.secondary` links (`underline=\"hover\"`) up to the\n * current page, a `text.primary` leaf, `variant=\"body2\"`, `mb-2 px-1`.\n */\nfunction Breadcrumbs({ trail }: { trail: Breadcrumb[] }) {\n if (trail.length < 2) return null;\n return (\n <MuiBreadcrumbs aria-label=\"breadcrumb\" className=\"mb-2 px-1\">\n {trail.map((crumb, index) =>\n index < trail.length - 1 ? (\n <MuiLink\n key={crumb.href ?? crumb.label}\n component={Link}\n to={crumb.href ?? \"/\"}\n underline=\"hover\"\n color=\"text.secondary\"\n variant=\"body2\"\n >\n {crumb.label}\n </MuiLink>\n ) : (\n <Typography key={crumb.label} color=\"text.primary\" variant=\"body2\">\n {crumb.label}\n </Typography>\n ),\n )}\n </MuiBreadcrumbs>\n );\n}\n\nfunction PrimaryButton({ action }: { action: ActionDescriptor }) {\n const common = {\n \"data-danger\": action.danger ? \"true\" : undefined,\n disabled: action.disabled,\n } as const;\n if (action.href != null) {\n return (\n <Button\n component={Link}\n to={action.href}\n variant=\"contained\"\n color={action.danger ? \"error\" : \"primary\"}\n {...common}\n >\n {action.label}\n </Button>\n );\n }\n return (\n <Button\n onClick={action.onClick}\n variant=\"contained\"\n color={action.danger ? \"error\" : \"primary\"}\n {...common}\n >\n {action.label}\n </Button>\n );\n}\n\nfunction useMenuState() {\n const [open, setOpen] = useState(false);\n const anchorRef = useRef<HTMLButtonElement | null>(null);\n return {\n open,\n anchorRef,\n toggle: () => setOpen((v) => !v),\n close: () => setOpen(false),\n };\n}\n\nfunction SecondaryDropdown({ action }: { action: ActionDescriptor }) {\n const { open, anchorRef, toggle, close } = useMenuState();\n const children = action.children ?? [];\n\n return (\n <>\n <Button\n ref={anchorRef}\n variant=\"outlined\"\n onClick={toggle}\n disabled={action.disabled || children.length === 0}\n aria-haspopup=\"menu\"\n aria-expanded={open || undefined}\n aria-label={action.label}\n >\n {action.label} ▾\n </Button>\n <Menu anchorEl={anchorRef.current} open={open} onClose={close}>\n {children.map((child) => (\n // href children render as anchors (component={Link}) to keep\n // middle-click / open-in-new-tab / a11y. `href` and `onClick` are\n // mutually exclusive on ActionDescriptor, so one MenuItem covers both.\n <MenuItem\n key={child.id}\n {...(child.href != null ? { component: Link, to: child.href } : {})}\n onClick={() => {\n close();\n child.onClick?.();\n }}\n disabled={child.disabled}\n >\n {child.label}\n </MenuItem>\n ))}\n </Menu>\n </>\n );\n}\n\nfunction OverflowMenu({ actions }: { actions: ActionDescriptor[] }) {\n const { open, anchorRef, toggle, close } = useMenuState();\n return (\n <>\n <IconButton\n ref={anchorRef}\n size=\"small\"\n aria-label=\"More actions\"\n onClick={toggle}\n >\n {\"⋯\"}\n </IconButton>\n <Menu anchorEl={anchorRef.current} open={open} onClose={close}>\n {actions.map((a) => (\n // href items render as anchors (component={Link}) — like\n // PrimaryButton — to keep middle-click / open-in-new-tab / a11y.\n // `href` and `onClick` are mutually exclusive on ActionDescriptor,\n // so one MenuItem covers both.\n <MenuItem\n key={a.id}\n {...(a.href != null ? { component: Link, to: a.href } : {})}\n onClick={() => {\n close();\n a.onClick?.();\n }}\n disabled={a.disabled}\n sx={a.danger ? { color: \"error.main\" } : undefined}\n >\n {a.label}\n </MenuItem>\n ))}\n </Menu>\n </>\n );\n}\n","import { createContext, useContext } from \"react\";\nimport type { PageHeaderState } from \"./pageHeaderTypes\";\n\n/**\n * Carries the active menu item / detail context so `usePageHeader` can derive\n * header props. The plugin analogue of the monolith shell's\n * `SubMenuPropsContext`: mounted once by `PageHeaderProvider`, read per page.\n *\n * `null` when no provider is mounted (a page rendered standalone, e.g. a test) —\n * consumers treat `null` as \"no header context\" and derive empty props.\n */\nexport const PageHeaderContext = createContext<PageHeaderState | null>(null);\n\n/** Returns the provider-published header state, or `null` when none is mounted. */\nexport function usePageHeaderContext(): PageHeaderState | null {\n return useContext(PageHeaderContext);\n}\n","import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from \"react\";\n\n/**\n * Sidebar-action dispatch channel — promoted from the monolith's\n * `SidebarActionContext`. Header buttons carrying an `actionId` (rather than an\n * `href`) dispatch through here; a page registers a handler via\n * `useSidebarAction` to open its own dialog. This is what makes `actionId` CTAs\n * (\"New Supplier Invoice\", \"New Cost Code\", …) fire when clicked.\n */\n\nexport type ActionHandler = (actionId: string) => void;\n\nexport interface SidebarActionContextValue {\n /** Dispatch an action to all registered page handlers. */\n triggerAction: (actionId: string) => void;\n /** Register a handler that receives sidebar actions. Returns an unregister function. */\n registerHandler: (handler: ActionHandler) => () => void;\n /** Set of actionIds whose owning UI surface (e.g. a dialog) is currently open. */\n activeActions: ReadonlySet<string>;\n /** Reports whether the owning UI surface for `actionId` is currently open. */\n setActionActive: (actionId: string, isActive: boolean) => void;\n}\n\nexport const SidebarActionContext = createContext<SidebarActionContextValue>({\n triggerAction: () => {},\n registerHandler: () => () => {},\n activeActions: new Set(),\n setActionActive: () => {},\n});\n\nexport function SidebarActionProvider({ children }: { children: ReactNode }) {\n const handlersRef = useRef(new Set<ActionHandler>());\n const [activeActions, setActiveActions] = useState<ReadonlySet<string>>(() => new Set());\n\n const triggerAction = useCallback((actionId: string) => {\n for (const handler of handlersRef.current) {\n handler(actionId);\n }\n }, []);\n\n const registerHandler = useCallback((handler: ActionHandler) => {\n handlersRef.current.add(handler);\n return () => {\n handlersRef.current.delete(handler);\n };\n }, []);\n\n const setActionActive = useCallback((actionId: string, isActive: boolean) => {\n setActiveActions((prev) => {\n const has = prev.has(actionId);\n if (isActive === has) return prev;\n const next = new Set(prev);\n if (isActive) next.add(actionId);\n else next.delete(actionId);\n return next;\n });\n }, []);\n\n const value = useMemo(\n () => ({ triggerAction, registerHandler, activeActions, setActionActive }),\n [triggerAction, registerHandler, activeActions, setActionActive],\n );\n\n return <SidebarActionContext.Provider value={value}>{children}</SidebarActionContext.Provider>;\n}\n\n/** Used by the header to dispatch actions to pages. */\nexport function useTriggerSidebarAction(): (actionId: string) => void {\n return useContext(SidebarActionContext).triggerAction;\n}\n\n/** Used by pages to register a handler for sidebar actions. Auto-cleans up on unmount. */\nexport function useSidebarAction(handler: ActionHandler): void {\n const { registerHandler } = useContext(SidebarActionContext);\n useEffect(() => registerHandler(handler), [registerHandler, handler]);\n}\n\n/**\n * Registers a map of sidebar-action handlers keyed by action id, dispatching the\n * matching entry when an action fires (unknown ids are ignored). The handler map\n * may change every render — a ref keeps the dispatcher stable so the registration\n * doesn't churn.\n */\nexport function useSidebarActions(handlers: Record<string, (() => void) | undefined>): void {\n const handlersRef = useRef(handlers);\n handlersRef.current = handlers;\n useSidebarAction(\n useCallback((actionId: string) => {\n handlersRef.current[actionId]?.();\n }, []),\n );\n}\n\n/** Reads the set of dispatch-action ids whose owning UI surface is currently open. */\nexport function useActiveSidebarActions(): ReadonlySet<string> {\n return useContext(SidebarActionContext).activeActions;\n}\n\n/**\n * Reports to the channel whether the owning UI surface for `actionId` is open.\n * Pages call this from a hook scope, mirroring their dialog/drawer open state.\n */\nexport function useReportSidebarActionActive(actionId: string, isActive: boolean): void {\n const { setActionActive } = useContext(SidebarActionContext);\n useEffect(() => {\n setActionActive(actionId, isActive);\n return () => {\n setActionActive(actionId, false);\n };\n }, [actionId, isActive, setActionActive]);\n}\n","import { useMemo } from \"react\";\nimport { usePageHeaderContext } from \"./pageHeaderContext\";\nimport { useTriggerSidebarAction } from \"./sidebarAction\";\nimport type {\n ActionDescriptor,\n ActionSlot,\n HeaderAction,\n PageHeaderDerivedProps,\n} from \"./pageHeaderTypes\";\n\n/**\n * Derives `<PageHeader>` props from the active menu item or detail context —\n * promoted verbatim from the monolith's `usePageHeader`, reading the plugin's\n * `PageHeaderContext` instead of the shell's `SubMenuPropsContext`.\n *\n * Outside a mounted `PageHeaderProvider` (or in a test rendering a page\n * standalone) the context is `null` and the hook derives empty header props —\n * same shape, no work. Page hooks spread the result and may override\n * title/subtitle/actions.\n */\nexport function usePageHeader(): PageHeaderDerivedProps {\n const state = usePageHeaderContext();\n const { activeMenuItem, detailContext, title, subtitle, breadcrumbs } = state ?? {};\n // Dispatcher for actionId-only actions — the same channel a page registers\n // against via `useSidebarAction`. Threading it into `toDescriptor` is what\n // makes header buttons like `+ New Supplier Invoice` (which carry an\n // `actionId` and no `href`) open the page-owned dialog when clicked.\n const triggerAction = useTriggerSidebarAction();\n\n return useMemo(() => {\n const sourceActions: HeaderAction[] =\n detailContext?.actions ?? activeMenuItem?.actions ?? [];\n\n let primary: ActionDescriptor | undefined;\n let secondary: ActionDescriptor | undefined;\n const overflow: ActionDescriptor[] = [];\n\n for (const action of sourceActions) {\n const descriptor = toDescriptor(action, triggerAction);\n const slot: ActionSlot = action.slot ?? \"sidebar-only\";\n switch (slot) {\n case \"primary\":\n if (primary == null) {\n primary = descriptor;\n } else {\n console.warn(\n \"usePageHeader: multiple primary slots on this page; demoting later ones to overflow\",\n { keptId: primary.id, demotedId: descriptor.id },\n );\n overflow.push(descriptor);\n }\n break;\n case \"secondary\":\n if (secondary == null) {\n secondary = descriptor;\n } else {\n console.warn(\n \"usePageHeader: multiple secondary slots on this page; demoting later ones to overflow\",\n { keptId: secondary.id, demotedId: descriptor.id },\n );\n overflow.push(descriptor);\n }\n break;\n case \"overflow\":\n overflow.push(descriptor);\n break;\n case \"sidebar-only\":\n default:\n // Not header-visible.\n break;\n }\n }\n\n return {\n // The plugin's `PageHeader` is the sole header (the host suppresses its own\n // chrome for platform-react surfaces), so it owns the title: a list page\n // shows its menu label; detail/create/edit pages override with their own.\n title: title ?? detailContext?.title ?? activeMenuItem?.label ?? \"\",\n // Fall back to the detail context's subtitle so a wrapper-rendered header\n // (no page spreading its own `headerProps`) still surfaces the entity name.\n subtitle: subtitle ?? detailContext?.subtitle,\n primaryAction: primary,\n secondaryAction: secondary,\n overflowActions: overflow.length > 0 ? overflow : undefined,\n breadcrumbs,\n };\n }, [activeMenuItem, detailContext, title, subtitle, breadcrumbs, triggerAction]);\n}\n\n/**\n * Map a raw header source action to `PageHeader`'s `ActionDescriptor`.\n *\n * Resolution order for `onClick`:\n * 1. Explicit `raw.onClick` (detail-context actions can carry one directly).\n * 2. `raw.actionId` → dispatch via the sidebar-action channel. This is what\n * makes menu-config actions like `actionId: \"create-cost-code\"` (no `href`,\n * no `onClick`) fire when the header button is clicked — the page registers\n * a handler via `useSidebarAction`.\n * 3. Neither — the button still renders, but is a no-op (typically paired with\n * `href` so the primary button renders a Link instead).\n *\n * The trigger is threaded down explicitly rather than via a hook because this\n * runs inside `useMemo` and can recurse (for secondary-dropdown children).\n */\nfunction toDescriptor(\n raw: HeaderAction,\n triggerAction: (actionId: string) => void,\n): ActionDescriptor {\n const explicitOnClick = raw.onClick;\n const dispatchActionId = raw.actionId;\n // `href` and `onClick` are mutually exclusive on ActionDescriptor. A navigating\n // action (`href`) must NOT also carry an `onClick`, or the Link-rendering menu\n // items (SecondaryDropdown / OverflowMenu always call `child.onClick`) would fire\n // a sidebar dispatch IN ADDITION to navigating. If a raw action is misconfigured\n // with both `href` and `onClick`/`actionId`, `href` wins and `onClick` is dropped.\n const onClick =\n raw.href != null\n ? undefined\n : explicitOnClick ?? (dispatchActionId ? () => triggerAction(dispatchActionId) : undefined);\n return {\n id: raw.id,\n label: raw.label,\n icon: raw.icon,\n href: raw.href,\n onClick,\n disabled: raw.disabled,\n danger: raw.variant === \"danger\",\n children: raw.children ? raw.children.map((c) => toDescriptor(c, triggerAction)) : undefined,\n };\n}\n","import type { Breadcrumb, RouteMeta, RouteMetaEntry } from \"./pageHeaderTypes\";\n\n/** Synthesised root crumb — mirrors the monolith's virtual `{ pattern: \"/\", label: \"Home\" }`. */\nconst HOME_CRUMB: Breadcrumb = { label: \"Home\", href: \"/\" };\n\nfunction stripTrailingSlash(value: string): string {\n return value.length > 1 && value.endsWith(\"/\") ? value.slice(0, -1) : value;\n}\n\n/**\n * Orders routes most-specific first: more segments win, then at equal depth prefer\n * literal segments over `:param` ones — identical to the monolith's `SORTED_ROUTE_META`.\n */\nfunction sortBySpecificity(routeMeta: RouteMeta): RouteMetaEntry[] {\n return [...routeMeta].sort((a, b) => {\n const aDepth = a.pattern.split(\"/\").length;\n const bDepth = b.pattern.split(\"/\").length;\n if (bDepth !== aDepth) {\n return bDepth - aDepth;\n }\n const aDynamic = (a.pattern.match(/:/g) ?? []).length;\n const bDynamic = (b.pattern.match(/:/g) ?? []).length;\n return aDynamic - bDynamic;\n });\n}\n\n/**\n * Matches a pathname against the sorted routes segment-by-segment, capturing\n * `:param` values. Returns the first (most-specific) match, or `null`. Port of the\n * monolith's `matchRoute`.\n */\nfunction matchRoute(\n pathname: string,\n sorted: RouteMetaEntry[],\n): { entry: RouteMetaEntry; params: Record<string, string> } | null {\n const pathSegments = stripTrailingSlash(pathname).split(\"/\");\n for (const entry of sorted) {\n const patternSegments = entry.pattern.split(\"/\");\n if (patternSegments.length !== pathSegments.length) {\n continue;\n }\n const params: Record<string, string> = {};\n let matched = true;\n for (let i = 0; i < patternSegments.length; i++) {\n const pSeg = patternSegments[i];\n const vSeg = pathSegments[i];\n if (pSeg.startsWith(\":\")) {\n params[pSeg.slice(1)] = vSeg;\n } else if (pSeg !== vSeg) {\n matched = false;\n break;\n }\n }\n if (matched) {\n return { entry, params };\n }\n }\n return null;\n}\n\n/**\n * Replaces `:param` segments in a pattern with captured values. Port of\n * `resolvePattern`. The param-name class matches the identifiers `matchRoute`\n * captures (letters/digits/underscore, e.g. `:user_id`, `:id2`); when a value is\n * missing the original `:param` token is preserved rather than dropping the colon.\n */\nfunction resolvePattern(pattern: string, params: Record<string, string>): string {\n return pattern.replace(/:([A-Za-z0-9_]+)/g, (_, name: string) => params[name] ?? `:${name}`);\n}\n\n/**\n * Builds the `Home / … / <page>` breadcrumb trail — a faithful port of the\n * monolith's `buildBreadcrumbs`. Matches the current path against the `routeMeta`\n * patterns (most-specific wins), walks the `parent` chain, prepends Home, and maps\n * each ancestor to its resolved-pattern href (the current page gets no href). The\n * app/module crumb (e.g. \"Finance\") is just the top-level `routeMeta` entry — no\n * separate config, exactly like the monolith's `/finance` root entry.\n */\nexport function buildBreadcrumbs(pathname: string, routeMeta: RouteMeta): Breadcrumb[] {\n const match = matchRoute(pathname, sortBySpecificity(routeMeta));\n if (match == null) {\n return [HOME_CRUMB];\n }\n\n const { entry: current, params } = match;\n\n // Walk the parent chain (leaf → root), guarding against cycles.\n const chain: RouteMetaEntry[] = [current];\n const seen = new Set<string>([current.pattern]);\n let node = current;\n while (node.parent != null) {\n const parent = routeMeta.find((e) => e.pattern === node.parent);\n if (parent == null || seen.has(parent.pattern)) {\n break;\n }\n seen.add(parent.pattern);\n chain.unshift(parent);\n node = parent;\n }\n\n const crumbs: Breadcrumb[] = [HOME_CRUMB];\n chain.forEach((entry, index) => {\n const isLast = index === chain.length - 1;\n crumbs.push(isLast ? { label: entry.label } : { label: entry.label, href: resolvePattern(entry.pattern, params) });\n });\n return crumbs;\n}\n","import { useMemo, type ReactElement, type ReactNode } from \"react\";\nimport { useLocation } from \"react-router-dom\";\nimport { PageHeaderContext } from \"./pageHeaderContext\";\nimport { SidebarActionProvider } from \"./sidebarAction\";\nimport { buildBreadcrumbs } from \"./breadcrumbs\";\nimport { PageHeader } from \"./PageHeader\";\nimport { usePageHeader } from \"./usePageHeader\";\nimport type {\n HeaderDetailContext,\n HeaderMenuItem,\n PageHeaderState,\n RouteMeta,\n} from \"./pageHeaderTypes\";\n\n/**\n * Default detail-context resolver: no detail context. Kept as a stable named hook\n * so `PageHeaderProvider` can call the resolver UNCONDITIONALLY (a hook can't be\n * called behind a runtime branch), whether or not a plugin supplied one.\n */\nfunction useNoDetailContext(): HeaderDetailContext | null {\n return null;\n}\n\n/**\n * The wrapper-rendered header. Mounted by `PageHeaderProvider` ONLY when the\n * plugin's `useDetailContext` resolver returns a context for the active route.\n *\n * This is the plugin equivalent of a monolith NESTED-LAYOUT ROUTE — a layout that\n * renders one shared `<PageHeader>` above the `<Outlet>` for a set of content-only\n * sub-pages (e.g. a project/ticket detail subtree). A PlatformReact plugin has no\n * router outlet (each page is its own bundle), so the page-definer wrapper is the\n * only shared seam: the resolver says \"these routes have no self-rendered header,\n * here's their shared header context\" and this renders it. Reads the same\n * `usePageHeader` a self-rendering page would, so title/subtitle/CTAs are derived\n * identically; the resolver's context is already folded into the provider state.\n */\nfunction ChromeHeader(): ReactElement {\n return <PageHeader {...usePageHeader()} />;\n}\n\nexport interface PageHeaderProviderProps {\n /**\n * The plugin's menu-item config — a faithful slice of the monolith's\n * `menuConfig.ts`. The provider matches the active route against each item's\n * `href` (pre-order, so a parent list item wins over its own overview child)\n * and publishes the match so `usePageHeader` can surface its `actions`.\n */\n config: HeaderMenuItem[];\n /**\n * The plugin's breadcrumb metadata — a faithful slice of the monolith's\n * `routeMeta.ts` (`{ pattern, label, parent }[]`, re-rooted). The provider derives\n * the full `Home / … / <Page>` trail per route via `buildBreadcrumbs`, exactly like\n * the monolith. The app/module crumb (e.g. \"Finance\") is just its top-level entry.\n * Omit for no breadcrumbs.\n */\n routeMeta?: RouteMeta;\n /** Optional detail-context override for detail/edit routes with no menu item. */\n detailContext?: HeaderDetailContext | null;\n /**\n * Optional per-route detail-context RESOLVER hook. Called every render; when it\n * returns a context, the provider (a) folds it into the header state AND (b)\n * renders the header ITSELF (`<ChromeHeader>`) above the page — for detail\n * routes whose migrated page renders no `<PageHeader>` of its own. Returns\n * `null` for routes the page already headers (list/create/edit self-render), so\n * chrome never double-renders. Takes precedence over the static `detailContext`.\n */\n useDetailContext?: () => HeaderDetailContext | null;\n children: ReactNode;\n}\n\n/**\n * Plugin analogue of the monolith shell's `SubMenuPropsContext` provider: mounted\n * once at the plugin's router root, it resolves the active menu item from the\n * current route (feeding `usePageHeader`'s title + CTAs) and derives the breadcrumb\n * trail from `routeMeta`. Also mounts the `SidebarActionProvider` so `actionId`\n * header CTAs can dispatch to page-registered handlers.\n *\n * In a plugin this feeds the in-body `PageHeader` that migrated pages render —\n * which IS the surface header (the host suppresses its own chrome for\n * platform-react surfaces).\n */\nexport function PageHeaderProvider({\n config,\n routeMeta,\n detailContext,\n useDetailContext = useNoDetailContext,\n children,\n}: PageHeaderProviderProps) {\n const { pathname } = useLocation();\n // Resolve the active detail context. The resolver hook is ALWAYS called (the\n // default is a stable no-op) so hook order stays stable. When a resolver was\n // actually supplied it is AUTHORITATIVE: its result wins — including `null`,\n // which means \"suppress chrome for this route\" and must NOT fall back to the\n // static prop. The static `detailContext` is only the fallback when no resolver\n // was passed (the legacy direct-provider API).\n const resolvedFromResolver = useDetailContext();\n const resolvedDetailContext =\n useDetailContext === useNoDetailContext ? detailContext ?? null : resolvedFromResolver;\n\n const state = useMemo<PageHeaderState>(() => {\n const activeMenuItem = findByHref(config, normalise(pathname));\n const breadcrumbs = routeMeta != null ? buildBreadcrumbs(pathname, routeMeta) : undefined;\n // Default the in-body title to the breadcrumb LEAF label (the current route's\n // `routeMeta` label) so EVERY routed page shows a title — not just the ones that\n // happen to carry a menu item (list pages with CTAs). Only a real trail (Home +\n // ≥1 crumb) yields a leaf; a bare `[Home]` (no route match) leaves title unset so\n // the header stays chrome-only. A page hook can still override via its own\n // headerProps (e.g. a detail page swapping in the entity name).\n const title =\n breadcrumbs != null && breadcrumbs.length >= 2\n ? breadcrumbs[breadcrumbs.length - 1].label\n : undefined;\n return { activeMenuItem, detailContext: resolvedDetailContext, breadcrumbs, title };\n }, [config, routeMeta, pathname, resolvedDetailContext]);\n\n return (\n <SidebarActionProvider>\n <PageHeaderContext.Provider value={state}>\n {resolvedDetailContext != null ? <ChromeHeader /> : null}\n {children}\n </PageHeaderContext.Provider>\n </SidebarActionProvider>\n );\n}\n\n/**\n * Ready-made page wrapper for the PlatformReact page-definer's `wrapPage` option:\n * `withPageHeader(config, routeMeta, useDetailContext?)` returns\n * `(page) => <PageHeaderProvider …>{page}</PageHeaderProvider>`.\n *\n * Pass the optional `useDetailContext` resolver to have the provider render a\n * shared header for detail routes whose page renders none of its own (see\n * {@link PageHeaderProviderProps.useDetailContext}); omit it for the original\n * behaviour (provider supplies context only, each page self-renders `<PageHeader>`).\n *\n * Kept here — the same module as `PageHeaderProvider` and `usePageHeader` — on\n * purpose: the provider and the hook must resolve to ONE `PageHeaderContext`\n * instance, which only holds when both come from this `components/layout` entry.\n * (A bundler inlines a separate context copy into each entry, so wrapping from the\n * `platform-react` entry would give the provider a different context than the\n * hook — the header would render empty.) A plugin passes\n * `wrapPage: withPageHeader(<feature>MenuConfig, <feature>RouteMeta)`\n * (optionally a third resolver arg) to `createPluginPageDefiner`.\n */\nexport function withPageHeader(\n config: HeaderMenuItem[],\n routeMeta?: RouteMeta,\n useDetailContext?: () => HeaderDetailContext | null,\n): (page: ReactElement) => ReactElement {\n return (page) => (\n <PageHeaderProvider config={config} routeMeta={routeMeta} useDetailContext={useDetailContext}>\n {page}\n </PageHeaderProvider>\n );\n}\n\n/** Strip a trailing slash (except root) so `/x/` and `/x` match the same item. */\nfunction normalise(pathname: string): string {\n return pathname.length > 1 && pathname.endsWith(\"/\") ? pathname.slice(0, -1) : pathname;\n}\n\n/**\n * Pre-order search for the item whose `href` exactly matches `pathname`. Pre-order\n * means a parent list item (which carries the `actions`) is returned before its\n * own same-href overview child, so the CTA surfaces on the list route.\n */\nfunction findByHref(items: HeaderMenuItem[], pathname: string): HeaderMenuItem | null {\n for (const item of items) {\n if (item.href != null && normalise(item.href) === pathname) {\n return item;\n }\n if (item.children) {\n const nested = findByHref(item.children, pathname);\n if (nested) {\n return nested;\n }\n }\n }\n return null;\n}\n"]}
1
+ {"version":3,"sources":["../../../src/components/layout/fillGridClasses.ts","../../../src/components/layout/FillGrid.tsx","../../../src/components/layout/PageHeader.tsx","../../../src/components/layout/pageHeaderContext.ts","../../../src/components/layout/sidebarAction.tsx","../../../src/components/layout/usePageHeader.ts","../../../src/components/layout/useDetailHeaderActions.ts","../../../src/components/layout/breadcrumbs.ts","../../../src/components/layout/PageHeaderProvider.tsx"],"names":["jsx","Breadcrumbs","Box","Link","createContext","useContext","useRef","useState","useMemo","toDescriptor","jsxs"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Static Tailwind basis classes for {@link FillGridItem}.\n *\n * Tailwind's content scanner extracts class candidates from raw source text and\n * cannot follow string concatenation — `\"sm:\" + \"basis-[...]\"` is invisible to\n * it. So every fully-prefixed class is spelled out as a literal below, indexed\n * by breakpoint → gap → span. `fillItemClass` only ever *looks up* a literal; it\n * never builds one. This is what guarantees the responsive classes survive a\n * production purge (no fragile safelist comment to keep in sync).\n *\n * NOTE: because these literals live in the SDK, a CONSUMER's Tailwind build must\n * scan this package's dist (add it to `content`) or the classes won't generate.\n *\n * basis(n, g) = calc(n/12 * 100% - g * (1 - n/12)), g = gap in rem.\n * gap-5 => g = 1.25rem; gap-2.5 => g = 0.625rem. Span 12 => basis-full.\n */\nexport type Twelfths = 2.4 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12;\nexport type FillGap = 2.5 | 5;\ntype Breakpoint = \"xs\" | \"sm\" | \"md\" | \"lg\";\nexport type FillSpan = Partial<Record<Breakpoint, Twelfths>>;\n\n/**\n * Full literal class per breakpoint × gap × span. `xs` is unprefixed; `sm`/`md`/\n * `lg` carry the Tailwind prefix. Every string here is a real, scannable literal.\n */\nconst CLASSES: Record<Breakpoint, Record<FillGap, Record<Twelfths, string>>> = {\n xs: {\n 5: {\n 2.4: \"basis-[calc(20%-1rem)]\",\n 3: \"basis-[calc(25%-0.9375rem)]\",\n 4: \"basis-[calc(33.333%-0.8333rem)]\",\n 5: \"basis-[calc(41.667%-0.7292rem)]\",\n 6: \"basis-[calc(50%-0.625rem)]\",\n 7: \"basis-[calc(58.333%-0.5208rem)]\",\n 8: \"basis-[calc(66.667%-0.4167rem)]\",\n 9: \"basis-[calc(75%-0.3125rem)]\",\n 12: \"basis-full\",\n },\n 2.5: {\n 2.4: \"basis-[calc(20%-0.5rem)]\",\n 3: \"basis-[calc(25%-0.46875rem)]\",\n 4: \"basis-[calc(33.333%-0.41667rem)]\",\n 5: \"basis-[calc(41.667%-0.36458rem)]\",\n 6: \"basis-[calc(50%-0.3125rem)]\",\n 7: \"basis-[calc(58.333%-0.26042rem)]\",\n 8: \"basis-[calc(66.667%-0.20833rem)]\",\n 9: \"basis-[calc(75%-0.15625rem)]\",\n 12: \"basis-full\",\n },\n },\n sm: {\n 5: {\n 2.4: \"sm:basis-[calc(20%-1rem)]\",\n 3: \"sm:basis-[calc(25%-0.9375rem)]\",\n 4: \"sm:basis-[calc(33.333%-0.8333rem)]\",\n 5: \"sm:basis-[calc(41.667%-0.7292rem)]\",\n 6: \"sm:basis-[calc(50%-0.625rem)]\",\n 7: \"sm:basis-[calc(58.333%-0.5208rem)]\",\n 8: \"sm:basis-[calc(66.667%-0.4167rem)]\",\n 9: \"sm:basis-[calc(75%-0.3125rem)]\",\n 12: \"sm:basis-full\",\n },\n 2.5: {\n 2.4: \"sm:basis-[calc(20%-0.5rem)]\",\n 3: \"sm:basis-[calc(25%-0.46875rem)]\",\n 4: \"sm:basis-[calc(33.333%-0.41667rem)]\",\n 5: \"sm:basis-[calc(41.667%-0.36458rem)]\",\n 6: \"sm:basis-[calc(50%-0.3125rem)]\",\n 7: \"sm:basis-[calc(58.333%-0.26042rem)]\",\n 8: \"sm:basis-[calc(66.667%-0.20833rem)]\",\n 9: \"sm:basis-[calc(75%-0.15625rem)]\",\n 12: \"sm:basis-full\",\n },\n },\n md: {\n 5: {\n 2.4: \"md:basis-[calc(20%-1rem)]\",\n 3: \"md:basis-[calc(25%-0.9375rem)]\",\n 4: \"md:basis-[calc(33.333%-0.8333rem)]\",\n 5: \"md:basis-[calc(41.667%-0.7292rem)]\",\n 6: \"md:basis-[calc(50%-0.625rem)]\",\n 7: \"md:basis-[calc(58.333%-0.5208rem)]\",\n 8: \"md:basis-[calc(66.667%-0.4167rem)]\",\n 9: \"md:basis-[calc(75%-0.3125rem)]\",\n 12: \"md:basis-full\",\n },\n 2.5: {\n 2.4: \"md:basis-[calc(20%-0.5rem)]\",\n 3: \"md:basis-[calc(25%-0.46875rem)]\",\n 4: \"md:basis-[calc(33.333%-0.41667rem)]\",\n 5: \"md:basis-[calc(41.667%-0.36458rem)]\",\n 6: \"md:basis-[calc(50%-0.3125rem)]\",\n 7: \"md:basis-[calc(58.333%-0.26042rem)]\",\n 8: \"md:basis-[calc(66.667%-0.20833rem)]\",\n 9: \"md:basis-[calc(75%-0.15625rem)]\",\n 12: \"md:basis-full\",\n },\n },\n lg: {\n 5: {\n 2.4: \"lg:basis-[calc(20%-1rem)]\",\n 3: \"lg:basis-[calc(25%-0.9375rem)]\",\n 4: \"lg:basis-[calc(33.333%-0.8333rem)]\",\n 5: \"lg:basis-[calc(41.667%-0.7292rem)]\",\n 6: \"lg:basis-[calc(50%-0.625rem)]\",\n 7: \"lg:basis-[calc(58.333%-0.5208rem)]\",\n 8: \"lg:basis-[calc(66.667%-0.4167rem)]\",\n 9: \"lg:basis-[calc(75%-0.3125rem)]\",\n 12: \"lg:basis-full\",\n },\n 2.5: {\n 2.4: \"lg:basis-[calc(20%-0.5rem)]\",\n 3: \"lg:basis-[calc(25%-0.46875rem)]\",\n 4: \"lg:basis-[calc(33.333%-0.41667rem)]\",\n 5: \"lg:basis-[calc(41.667%-0.36458rem)]\",\n 6: \"lg:basis-[calc(50%-0.3125rem)]\",\n 7: \"lg:basis-[calc(58.333%-0.26042rem)]\",\n 8: \"lg:basis-[calc(66.667%-0.20833rem)]\",\n 9: \"lg:basis-[calc(75%-0.15625rem)]\",\n 12: \"lg:basis-full\",\n },\n },\n};\n\nconst BREAKPOINTS: readonly Breakpoint[] = [\"xs\", \"sm\", \"md\", \"lg\"];\n\n/**\n * Full class string for one item: always `min-w-0 grow`, plus the literal basis\n * class for each supplied breakpoint (looked up, never concatenated).\n */\nexport function fillItemClass(span: FillSpan, gap: FillGap): string {\n const parts = [\"min-w-0\", \"grow\"];\n for (const bp of BREAKPOINTS) {\n const n = span[bp];\n if (n !== undefined) parts.push(CLASSES[bp][gap][n]);\n }\n return parts.join(\" \");\n}\n","import { createContext, useContext } from \"react\";\nimport { Box } from \"@mui/material\";\nimport { fillItemClass, type FillGap, type FillSpan } from \"./fillGridClasses\";\n\nconst FillGapContext = createContext<FillGap>(5);\n\ninterface FillGridProps {\n /** Gutter width. 5 = 20px (default), 2.5 = 10px. Matches MUI spacing values. */\n gap?: FillGap;\n className?: string;\n children: React.ReactNode;\n}\n\n/**\n * A flex-wrap row whose items `grow` to fill a partially-filled last row — the\n * dashboard/overview convention. NOT for forms, tables, or single full-width cards.\n *\n * Renders `w-full` so it always spans its container: a `FillGrid` is itself often\n * a flex item of a parent MUI `<Grid container>` / flex row, where without an\n * explicit width it would shrink-wrap to its content instead of filling the row\n * (the behaviour a `<Grid container size={12}>` used to give).\n */\nexport function FillGrid({ gap = 5, className, children }: FillGridProps) {\n const gapClass = gap === 2.5 ? \"gap-2.5\" : \"gap-5\";\n return (\n <FillGapContext.Provider value={gap}>\n <Box className={[\"flex w-full flex-wrap\", gapClass, className].filter(Boolean).join(\" \")}>\n {children}\n </Box>\n </FillGapContext.Provider>\n );\n}\n\ninterface FillGridItemProps {\n /** 12-column span per breakpoint, mirroring MUI Grid's `size`. Default { xs: 12 }. */\n span?: FillSpan;\n className?: string;\n children: React.ReactNode;\n}\n\nexport function FillGridItem({ span = { xs: 12 }, className, children }: FillGridItemProps) {\n const gap = useContext(FillGapContext);\n return (\n <Box className={[fillItemClass(span, gap), className].filter(Boolean).join(\" \")}>\n {children}\n </Box>\n );\n}\n","import { useState, useRef, type ReactNode } from \"react\";\nimport { Link } from \"react-router-dom\";\nimport {\n Box,\n Breadcrumbs as MuiBreadcrumbs,\n Stack,\n Typography,\n Link as MuiLink,\n Button,\n IconButton,\n Menu,\n MenuItem,\n} from \"../ui\";\nimport type { ActionDescriptor, Breadcrumb } from \"./pageHeaderTypes\";\n\n/**\n * `@ethisyscore/plugin-ui/components/layout` — the page-header, promoted from the\n * monolith so plugins share one component instead of copying it. In a plugin this\n * IS the page header: the host suppresses its own chrome for platform-react\n * surfaces, so this renders the breadcrumb trail, the title, and the CTAs.\n *\n * `breadcrumbs` is the ROOT trail (e.g. `Home / Finance`); the current `title` is\n * appended as the non-link leaf crumb. MUI primitives come from the sibling\n * `../ui` barrel (host externals, never bundled); `Link` is react-router's so\n * links keep middle-click / open-in-new-tab / a11y.\n */\nexport interface PageHeaderProps {\n title: string;\n subtitle?: ReactNode;\n primaryAction?: ActionDescriptor;\n secondaryAction?: ActionDescriptor;\n overflowActions?: ActionDescriptor[];\n /** Root breadcrumb trail; the `title` is appended as the current-page leaf. */\n breadcrumbs?: Breadcrumb[];\n}\n\nexport function PageHeader({\n title,\n subtitle,\n primaryAction,\n secondaryAction,\n overflowActions,\n breadcrumbs,\n}: PageHeaderProps) {\n const hasActions =\n primaryAction != null ||\n secondaryAction != null ||\n (overflowActions != null && overflowActions.length > 0);\n\n return (\n <Stack direction=\"column\" spacing={0.5} className=\"mb-4\">\n {breadcrumbs != null && breadcrumbs.length > 0 && <Breadcrumbs trail={breadcrumbs} />}\n <Stack direction=\"row\" justifyContent=\"space-between\" alignItems=\"flex-start\" spacing={2}>\n <Box>\n {/* Title is optional: in a plugin the host renders the surface title,\n so list pages pass an empty title and only their CTA shows. Pages\n that want an in-body title (detail/create/edit) set it explicitly. */}\n {title !== \"\" && (\n <Typography variant=\"h4\" component=\"h1\">\n {title}\n </Typography>\n )}\n {subtitle != null && (\n <Typography variant=\"body2\" color=\"text.secondary\" className=\"mt-1\">\n {subtitle}\n </Typography>\n )}\n </Box>\n {hasActions && (\n <Stack\n direction=\"row\"\n spacing={1}\n alignItems=\"center\"\n data-testid=\"page-header-actions\"\n >\n {overflowActions != null && overflowActions.length > 0 && (\n <OverflowMenu actions={overflowActions} />\n )}\n {secondaryAction != null && <SecondaryDropdown action={secondaryAction} />}\n {primaryAction != null && <PrimaryButton action={primaryAction} />}\n </Stack>\n )}\n </Stack>\n </Stack>\n );\n}\n\n/**\n * Breadcrumb trail — mirrors the host's `gogo-ui` `PageBreadcrumbs` exactly (MUI\n * `Breadcrumbs` with the same markup/props) so the plugin surface looks identical\n * to host-rendered chrome: `text.secondary` links (`underline=\"hover\"`) up to the\n * current page, a `text.primary` leaf, `variant=\"body2\"`, `mb-2 px-1`.\n */\nfunction Breadcrumbs({ trail }: { trail: Breadcrumb[] }) {\n if (trail.length < 2) return null;\n return (\n <MuiBreadcrumbs aria-label=\"breadcrumb\" className=\"mb-2 px-1\">\n {trail.map((crumb, index) =>\n index < trail.length - 1 ? (\n <MuiLink\n key={crumb.href ?? crumb.label}\n component={Link}\n to={crumb.href ?? \"/\"}\n underline=\"hover\"\n color=\"text.secondary\"\n variant=\"body2\"\n >\n {crumb.label}\n </MuiLink>\n ) : (\n <Typography key={crumb.label} color=\"text.primary\" variant=\"body2\">\n {crumb.label}\n </Typography>\n ),\n )}\n </MuiBreadcrumbs>\n );\n}\n\nfunction PrimaryButton({ action }: { action: ActionDescriptor }) {\n const common = {\n \"data-danger\": action.danger ? \"true\" : undefined,\n disabled: action.disabled,\n } as const;\n if (action.href != null) {\n return (\n <Button\n component={Link}\n to={action.href}\n variant=\"contained\"\n color={action.danger ? \"error\" : \"primary\"}\n {...common}\n >\n {action.label}\n </Button>\n );\n }\n return (\n <Button\n onClick={action.onClick}\n variant=\"contained\"\n color={action.danger ? \"error\" : \"primary\"}\n {...common}\n >\n {action.label}\n </Button>\n );\n}\n\nfunction useMenuState() {\n const [open, setOpen] = useState(false);\n const anchorRef = useRef<HTMLButtonElement | null>(null);\n return {\n open,\n anchorRef,\n toggle: () => setOpen((v) => !v),\n close: () => setOpen(false),\n };\n}\n\nfunction SecondaryDropdown({ action }: { action: ActionDescriptor }) {\n const { open, anchorRef, toggle, close } = useMenuState();\n const children = action.children ?? [];\n\n return (\n <>\n <Button\n ref={anchorRef}\n variant=\"outlined\"\n onClick={toggle}\n disabled={action.disabled || children.length === 0}\n aria-haspopup=\"menu\"\n aria-expanded={open || undefined}\n aria-label={action.label}\n >\n {action.label} ▾\n </Button>\n <Menu anchorEl={anchorRef.current} open={open} onClose={close}>\n {children.map((child) => (\n // href children render as anchors (component={Link}) to keep\n // middle-click / open-in-new-tab / a11y. `href` and `onClick` are\n // mutually exclusive on ActionDescriptor, so one MenuItem covers both.\n <MenuItem\n key={child.id}\n {...(child.href != null ? { component: Link, to: child.href } : {})}\n onClick={() => {\n close();\n child.onClick?.();\n }}\n disabled={child.disabled}\n >\n {child.label}\n </MenuItem>\n ))}\n </Menu>\n </>\n );\n}\n\nfunction OverflowMenu({ actions }: { actions: ActionDescriptor[] }) {\n const { open, anchorRef, toggle, close } = useMenuState();\n return (\n <>\n <IconButton\n ref={anchorRef}\n size=\"small\"\n aria-label=\"More actions\"\n onClick={toggle}\n >\n {\"⋯\"}\n </IconButton>\n <Menu anchorEl={anchorRef.current} open={open} onClose={close}>\n {actions.map((a) => (\n // href items render as anchors (component={Link}) — like\n // PrimaryButton — to keep middle-click / open-in-new-tab / a11y.\n // `href` and `onClick` are mutually exclusive on ActionDescriptor,\n // so one MenuItem covers both.\n <MenuItem\n key={a.id}\n {...(a.href != null ? { component: Link, to: a.href } : {})}\n onClick={() => {\n close();\n a.onClick?.();\n }}\n disabled={a.disabled}\n sx={a.danger ? { color: \"error.main\" } : undefined}\n >\n {a.label}\n </MenuItem>\n ))}\n </Menu>\n </>\n );\n}\n","import { createContext, useContext } from \"react\";\nimport type { PageHeaderState } from \"./pageHeaderTypes\";\n\n/**\n * Carries the active menu item / detail context so `usePageHeader` can derive\n * header props. The plugin analogue of the monolith shell's\n * `SubMenuPropsContext`: mounted once by `PageHeaderProvider`, read per page.\n *\n * `null` when no provider is mounted (a page rendered standalone, e.g. a test) —\n * consumers treat `null` as \"no header context\" and derive empty props.\n */\nexport const PageHeaderContext = createContext<PageHeaderState | null>(null);\n\n/** Returns the provider-published header state, or `null` when none is mounted. */\nexport function usePageHeaderContext(): PageHeaderState | null {\n return useContext(PageHeaderContext);\n}\n","import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from \"react\";\n\n/**\n * Sidebar-action dispatch channel — promoted from the monolith's\n * `SidebarActionContext`. Header buttons carrying an `actionId` (rather than an\n * `href`) dispatch through here; a page registers a handler via\n * `useSidebarAction` to open its own dialog. This is what makes `actionId` CTAs\n * (\"New Supplier Invoice\", \"New Cost Code\", …) fire when clicked.\n */\n\nexport type ActionHandler = (actionId: string) => void;\n\nexport interface SidebarActionContextValue {\n /** Dispatch an action to all registered page handlers. */\n triggerAction: (actionId: string) => void;\n /** Register a handler that receives sidebar actions. Returns an unregister function. */\n registerHandler: (handler: ActionHandler) => () => void;\n /** Set of actionIds whose owning UI surface (e.g. a dialog) is currently open. */\n activeActions: ReadonlySet<string>;\n /** Reports whether the owning UI surface for `actionId` is currently open. */\n setActionActive: (actionId: string, isActive: boolean) => void;\n}\n\nexport const SidebarActionContext = createContext<SidebarActionContextValue>({\n triggerAction: () => {},\n registerHandler: () => () => {},\n activeActions: new Set(),\n setActionActive: () => {},\n});\n\nexport function SidebarActionProvider({ children }: { children: ReactNode }) {\n const handlersRef = useRef(new Set<ActionHandler>());\n const [activeActions, setActiveActions] = useState<ReadonlySet<string>>(() => new Set());\n\n const triggerAction = useCallback((actionId: string) => {\n for (const handler of handlersRef.current) {\n handler(actionId);\n }\n }, []);\n\n const registerHandler = useCallback((handler: ActionHandler) => {\n handlersRef.current.add(handler);\n return () => {\n handlersRef.current.delete(handler);\n };\n }, []);\n\n const setActionActive = useCallback((actionId: string, isActive: boolean) => {\n setActiveActions((prev) => {\n const has = prev.has(actionId);\n if (isActive === has) return prev;\n const next = new Set(prev);\n if (isActive) next.add(actionId);\n else next.delete(actionId);\n return next;\n });\n }, []);\n\n const value = useMemo(\n () => ({ triggerAction, registerHandler, activeActions, setActionActive }),\n [triggerAction, registerHandler, activeActions, setActionActive],\n );\n\n return <SidebarActionContext.Provider value={value}>{children}</SidebarActionContext.Provider>;\n}\n\n/** Used by the header to dispatch actions to pages. */\nexport function useTriggerSidebarAction(): (actionId: string) => void {\n return useContext(SidebarActionContext).triggerAction;\n}\n\n/** Used by pages to register a handler for sidebar actions. Auto-cleans up on unmount. */\nexport function useSidebarAction(handler: ActionHandler): void {\n const { registerHandler } = useContext(SidebarActionContext);\n useEffect(() => registerHandler(handler), [registerHandler, handler]);\n}\n\n/**\n * Registers a map of sidebar-action handlers keyed by action id, dispatching the\n * matching entry when an action fires (unknown ids are ignored). The handler map\n * may change every render — a ref keeps the dispatcher stable so the registration\n * doesn't churn.\n */\nexport function useSidebarActions(handlers: Record<string, (() => void) | undefined>): void {\n const handlersRef = useRef(handlers);\n handlersRef.current = handlers;\n useSidebarAction(\n useCallback((actionId: string) => {\n handlersRef.current[actionId]?.();\n }, []),\n );\n}\n\n/** Reads the set of dispatch-action ids whose owning UI surface is currently open. */\nexport function useActiveSidebarActions(): ReadonlySet<string> {\n return useContext(SidebarActionContext).activeActions;\n}\n\n/**\n * Reports to the channel whether the owning UI surface for `actionId` is open.\n * Pages call this from a hook scope, mirroring their dialog/drawer open state.\n */\nexport function useReportSidebarActionActive(actionId: string, isActive: boolean): void {\n const { setActionActive } = useContext(SidebarActionContext);\n useEffect(() => {\n setActionActive(actionId, isActive);\n return () => {\n setActionActive(actionId, false);\n };\n }, [actionId, isActive, setActionActive]);\n}\n","import { useMemo } from \"react\";\nimport { usePageHeaderContext } from \"./pageHeaderContext\";\nimport { useTriggerSidebarAction } from \"./sidebarAction\";\nimport type {\n ActionDescriptor,\n ActionSlot,\n HeaderAction,\n PageHeaderDerivedProps,\n} from \"./pageHeaderTypes\";\n\n/**\n * Derives `<PageHeader>` props from the active menu item or detail context —\n * promoted verbatim from the monolith's `usePageHeader`, reading the plugin's\n * `PageHeaderContext` instead of the shell's `SubMenuPropsContext`.\n *\n * Outside a mounted `PageHeaderProvider` (or in a test rendering a page\n * standalone) the context is `null` and the hook derives empty header props —\n * same shape, no work. Page hooks spread the result and may override\n * title/subtitle/actions.\n */\nexport function usePageHeader(): PageHeaderDerivedProps {\n const state = usePageHeaderContext();\n const { activeMenuItem, detailContext, title, subtitle, breadcrumbs } = state ?? {};\n // Dispatcher for actionId-only actions — the same channel a page registers\n // against via `useSidebarAction`. Threading it into `toDescriptor` is what\n // makes header buttons like `+ New Supplier Invoice` (which carry an\n // `actionId` and no `href`) open the page-owned dialog when clicked.\n const triggerAction = useTriggerSidebarAction();\n\n return useMemo(() => {\n const sourceActions: HeaderAction[] =\n detailContext?.actions ?? activeMenuItem?.actions ?? [];\n\n let primary: ActionDescriptor | undefined;\n let secondary: ActionDescriptor | undefined;\n const overflow: ActionDescriptor[] = [];\n\n for (const action of sourceActions) {\n const descriptor = toDescriptor(action, triggerAction);\n const slot: ActionSlot = action.slot ?? \"sidebar-only\";\n switch (slot) {\n case \"primary\":\n if (primary == null) {\n primary = descriptor;\n } else {\n console.warn(\n \"usePageHeader: multiple primary slots on this page; demoting later ones to overflow\",\n { keptId: primary.id, demotedId: descriptor.id },\n );\n overflow.push(descriptor);\n }\n break;\n case \"secondary\":\n if (secondary == null) {\n secondary = descriptor;\n } else {\n console.warn(\n \"usePageHeader: multiple secondary slots on this page; demoting later ones to overflow\",\n { keptId: secondary.id, demotedId: descriptor.id },\n );\n overflow.push(descriptor);\n }\n break;\n case \"overflow\":\n overflow.push(descriptor);\n break;\n case \"sidebar-only\":\n default:\n // Not header-visible.\n break;\n }\n }\n\n return {\n // The plugin's `PageHeader` is the sole header (the host suppresses its own\n // chrome for platform-react surfaces), so it owns the title: a list page\n // shows its menu label; detail/create/edit pages override with their own.\n title: title ?? detailContext?.title ?? activeMenuItem?.label ?? \"\",\n // Fall back to the detail context's subtitle so a wrapper-rendered header\n // (no page spreading its own `headerProps`) still surfaces the entity name.\n subtitle: subtitle ?? detailContext?.subtitle,\n primaryAction: primary,\n secondaryAction: secondary,\n overflowActions: overflow.length > 0 ? overflow : undefined,\n breadcrumbs,\n };\n }, [activeMenuItem, detailContext, title, subtitle, breadcrumbs, triggerAction]);\n}\n\n/**\n * Map a raw header source action to `PageHeader`'s `ActionDescriptor`.\n *\n * Resolution order for `onClick`:\n * 1. Explicit `raw.onClick` (detail-context actions can carry one directly).\n * 2. `raw.actionId` → dispatch via the sidebar-action channel. This is what\n * makes menu-config actions like `actionId: \"create-cost-code\"` (no `href`,\n * no `onClick`) fire when the header button is clicked — the page registers\n * a handler via `useSidebarAction`.\n * 3. Neither — the button still renders, but is a no-op (typically paired with\n * `href` so the primary button renders a Link instead).\n *\n * The trigger is threaded down explicitly rather than via a hook because this\n * runs inside `useMemo` and can recurse (for secondary-dropdown children).\n */\nfunction toDescriptor(\n raw: HeaderAction,\n triggerAction: (actionId: string) => void,\n): ActionDescriptor {\n const explicitOnClick = raw.onClick;\n const dispatchActionId = raw.actionId;\n // `href` and `onClick` are mutually exclusive on ActionDescriptor. A navigating\n // action (`href`) must NOT also carry an `onClick`, or the Link-rendering menu\n // items (SecondaryDropdown / OverflowMenu always call `child.onClick`) would fire\n // a sidebar dispatch IN ADDITION to navigating. If a raw action is misconfigured\n // with both `href` and `onClick`/`actionId`, `href` wins and `onClick` is dropped.\n const onClick =\n raw.href != null\n ? undefined\n : explicitOnClick ?? (dispatchActionId ? () => triggerAction(dispatchActionId) : undefined);\n return {\n id: raw.id,\n label: raw.label,\n icon: raw.icon,\n href: raw.href,\n onClick,\n disabled: raw.disabled,\n danger: raw.variant === \"danger\",\n children: raw.children ? raw.children.map((c) => toDescriptor(c, triggerAction)) : undefined,\n };\n}\n","import { useMemo } from \"react\";\nimport { useTriggerSidebarAction } from \"./sidebarAction\";\nimport type { ActionDescriptor, PageHeaderDerivedProps, PluginDetailContextItem } from \"./pageHeaderTypes\";\n\n/**\n * Merge a plugin detail-context's `actions` into the header props a SELF-RENDERING\n * detail page spreads onto `<PageHeader>`.\n *\n * Use this when a detail page renders its own `<PageHeader {...headerProps}/>` and\n * sources its CTAs from a `*DetailContext` hook (rather than from a `menuConfig`\n * entry, which detail routes can't have — their path is dynamic). Applies the same\n * slot split (`primary`/`secondary`/`overflow`; `sidebar-only` is not shown in the\n * header) and `actionId → useTriggerSidebarAction` dispatch the SDK applies to\n * menu-item actions, so a detail-context action fires the page's `useSidebarActions`\n * handler exactly like a list-page CTA. `href` actions navigate.\n *\n * The companion for the OTHER surface is `toHostSidebarInput` (host sidebar).\n */\nexport function useDetailHeaderActions(\n base: PageHeaderDerivedProps,\n actions: PluginDetailContextItem[],\n): PageHeaderDerivedProps {\n const triggerAction = useTriggerSidebarAction();\n return useMemo(() => {\n if (actions.length === 0) {\n return base;\n }\n let primary = base.primaryAction;\n let secondary = base.secondaryAction;\n const overflow: ActionDescriptor[] = [...(base.overflowActions ?? [])];\n for (const action of actions) {\n const descriptor = toDescriptor(action, triggerAction);\n switch (action.slot ?? \"sidebar-only\") {\n case \"primary\":\n if (primary == null) primary = descriptor;\n else overflow.push(descriptor);\n break;\n case \"secondary\":\n if (secondary == null) secondary = descriptor;\n else overflow.push(descriptor);\n break;\n case \"overflow\":\n overflow.push(descriptor);\n break;\n // \"sidebar-only\" is not surfaced in the header.\n }\n }\n return {\n ...base,\n primaryAction: primary,\n secondaryAction: secondary,\n overflowActions: overflow.length > 0 ? overflow : undefined,\n };\n }, [base, actions, triggerAction]);\n}\n\nfunction toDescriptor(\n raw: PluginDetailContextItem,\n triggerAction: (actionId: string) => void,\n): ActionDescriptor {\n const onClick =\n raw.href != null\n ? undefined\n : raw.onClick ?? (raw.actionId ? () => triggerAction(raw.actionId!) : undefined);\n return {\n id: raw.id,\n label: raw.label,\n icon: raw.icon,\n href: raw.href,\n onClick,\n disabled: raw.disabled,\n danger: raw.variant === \"danger\",\n children: raw.children?.map((child) => toDescriptor(child, triggerAction)),\n };\n}\n","import type { Breadcrumb, RouteMeta, RouteMetaEntry } from \"./pageHeaderTypes\";\n\n/** Synthesised root crumb — mirrors the monolith's virtual `{ pattern: \"/\", label: \"Home\" }`. */\nconst HOME_CRUMB: Breadcrumb = { label: \"Home\", href: \"/\" };\n\nfunction stripTrailingSlash(value: string): string {\n return value.length > 1 && value.endsWith(\"/\") ? value.slice(0, -1) : value;\n}\n\n/**\n * Orders routes most-specific first: more segments win, then at equal depth prefer\n * literal segments over `:param` ones — identical to the monolith's `SORTED_ROUTE_META`.\n */\nfunction sortBySpecificity(routeMeta: RouteMeta): RouteMetaEntry[] {\n return [...routeMeta].sort((a, b) => {\n const aDepth = a.pattern.split(\"/\").length;\n const bDepth = b.pattern.split(\"/\").length;\n if (bDepth !== aDepth) {\n return bDepth - aDepth;\n }\n const aDynamic = (a.pattern.match(/:/g) ?? []).length;\n const bDynamic = (b.pattern.match(/:/g) ?? []).length;\n return aDynamic - bDynamic;\n });\n}\n\n/**\n * Matches a pathname against the sorted routes segment-by-segment, capturing\n * `:param` values. Returns the first (most-specific) match, or `null`. Port of the\n * monolith's `matchRoute`.\n */\nfunction matchRoute(\n pathname: string,\n sorted: RouteMetaEntry[],\n): { entry: RouteMetaEntry; params: Record<string, string> } | null {\n const pathSegments = stripTrailingSlash(pathname).split(\"/\");\n for (const entry of sorted) {\n const patternSegments = entry.pattern.split(\"/\");\n if (patternSegments.length !== pathSegments.length) {\n continue;\n }\n const params: Record<string, string> = {};\n let matched = true;\n for (let i = 0; i < patternSegments.length; i++) {\n const pSeg = patternSegments[i];\n const vSeg = pathSegments[i];\n if (pSeg.startsWith(\":\")) {\n params[pSeg.slice(1)] = vSeg;\n } else if (pSeg !== vSeg) {\n matched = false;\n break;\n }\n }\n if (matched) {\n return { entry, params };\n }\n }\n return null;\n}\n\n/**\n * Replaces `:param` segments in a pattern with captured values. Port of\n * `resolvePattern`. The param-name class matches the identifiers `matchRoute`\n * captures (letters/digits/underscore, e.g. `:user_id`, `:id2`); when a value is\n * missing the original `:param` token is preserved rather than dropping the colon.\n */\nfunction resolvePattern(pattern: string, params: Record<string, string>): string {\n return pattern.replace(/:([A-Za-z0-9_]+)/g, (_, name: string) => params[name] ?? `:${name}`);\n}\n\n/**\n * Builds the `Home / … / <page>` breadcrumb trail — a faithful port of the\n * monolith's `buildBreadcrumbs`. Matches the current path against the `routeMeta`\n * patterns (most-specific wins), walks the `parent` chain, prepends Home, and maps\n * each ancestor to its resolved-pattern href (the current page gets no href). The\n * app/module crumb (e.g. \"Finance\") is just the top-level `routeMeta` entry — no\n * separate config, exactly like the monolith's `/finance` root entry.\n */\nexport function buildBreadcrumbs(pathname: string, routeMeta: RouteMeta): Breadcrumb[] {\n const match = matchRoute(pathname, sortBySpecificity(routeMeta));\n if (match == null) {\n return [HOME_CRUMB];\n }\n\n const { entry: current, params } = match;\n\n // Walk the parent chain (leaf → root), guarding against cycles.\n const chain: RouteMetaEntry[] = [current];\n const seen = new Set<string>([current.pattern]);\n let node = current;\n while (node.parent != null) {\n const parent = routeMeta.find((e) => e.pattern === node.parent);\n if (parent == null || seen.has(parent.pattern)) {\n break;\n }\n seen.add(parent.pattern);\n chain.unshift(parent);\n node = parent;\n }\n\n const crumbs: Breadcrumb[] = [HOME_CRUMB];\n chain.forEach((entry, index) => {\n const isLast = index === chain.length - 1;\n crumbs.push(isLast ? { label: entry.label } : { label: entry.label, href: resolvePattern(entry.pattern, params) });\n });\n return crumbs;\n}\n","import { useMemo, type ReactElement, type ReactNode } from \"react\";\nimport { useLocation } from \"react-router-dom\";\nimport { PageHeaderContext } from \"./pageHeaderContext\";\nimport { SidebarActionProvider } from \"./sidebarAction\";\nimport { buildBreadcrumbs } from \"./breadcrumbs\";\nimport { PageHeader } from \"./PageHeader\";\nimport { usePageHeader } from \"./usePageHeader\";\nimport type {\n HeaderDetailContext,\n HeaderMenuItem,\n PageHeaderState,\n RouteMeta,\n} from \"./pageHeaderTypes\";\n\n/**\n * Default detail-context resolver: no detail context. Kept as a stable named hook\n * so `PageHeaderProvider` can call the resolver UNCONDITIONALLY (a hook can't be\n * called behind a runtime branch), whether or not a plugin supplied one.\n */\nfunction useNoDetailContext(): HeaderDetailContext | null {\n return null;\n}\n\n/**\n * The wrapper-rendered header. Mounted by `PageHeaderProvider` ONLY when the\n * plugin's `useDetailContext` resolver returns a context for the active route.\n *\n * This is the plugin equivalent of a monolith NESTED-LAYOUT ROUTE — a layout that\n * renders one shared `<PageHeader>` above the `<Outlet>` for a set of content-only\n * sub-pages (e.g. a project/ticket detail subtree). A PlatformReact plugin has no\n * router outlet (each page is its own bundle), so the page-definer wrapper is the\n * only shared seam: the resolver says \"these routes have no self-rendered header,\n * here's their shared header context\" and this renders it. Reads the same\n * `usePageHeader` a self-rendering page would, so title/subtitle/CTAs are derived\n * identically; the resolver's context is already folded into the provider state.\n */\nfunction ChromeHeader(): ReactElement {\n return <PageHeader {...usePageHeader()} />;\n}\n\nexport interface PageHeaderProviderProps {\n /**\n * The plugin's menu-item config — a faithful slice of the monolith's\n * `menuConfig.ts`. The provider matches the active route against each item's\n * `href` (pre-order, so a parent list item wins over its own overview child)\n * and publishes the match so `usePageHeader` can surface its `actions`.\n */\n config: HeaderMenuItem[];\n /**\n * The plugin's breadcrumb metadata — a faithful slice of the monolith's\n * `routeMeta.ts` (`{ pattern, label, parent }[]`, re-rooted). The provider derives\n * the full `Home / … / <Page>` trail per route via `buildBreadcrumbs`, exactly like\n * the monolith. The app/module crumb (e.g. \"Finance\") is just its top-level entry.\n * Omit for no breadcrumbs.\n */\n routeMeta?: RouteMeta;\n /** Optional detail-context override for detail/edit routes with no menu item. */\n detailContext?: HeaderDetailContext | null;\n /**\n * Optional per-route detail-context RESOLVER hook. Called every render; when it\n * returns a context, the provider (a) folds it into the header state AND (b)\n * renders the header ITSELF (`<ChromeHeader>`) above the page — for detail\n * routes whose migrated page renders no `<PageHeader>` of its own. Returns\n * `null` for routes the page already headers (list/create/edit self-render), so\n * chrome never double-renders. Takes precedence over the static `detailContext`.\n */\n useDetailContext?: () => HeaderDetailContext | null;\n children: ReactNode;\n}\n\n/**\n * Plugin analogue of the monolith shell's `SubMenuPropsContext` provider: mounted\n * once at the plugin's router root, it resolves the active menu item from the\n * current route (feeding `usePageHeader`'s title + CTAs) and derives the breadcrumb\n * trail from `routeMeta`. Also mounts the `SidebarActionProvider` so `actionId`\n * header CTAs can dispatch to page-registered handlers.\n *\n * In a plugin this feeds the in-body `PageHeader` that migrated pages render —\n * which IS the surface header (the host suppresses its own chrome for\n * platform-react surfaces).\n */\nexport function PageHeaderProvider({\n config,\n routeMeta,\n detailContext,\n useDetailContext = useNoDetailContext,\n children,\n}: PageHeaderProviderProps) {\n const { pathname } = useLocation();\n // Resolve the active detail context. The resolver hook is ALWAYS called (the\n // default is a stable no-op) so hook order stays stable. When a resolver was\n // actually supplied it is AUTHORITATIVE: its result wins — including `null`,\n // which means \"suppress chrome for this route\" and must NOT fall back to the\n // static prop. The static `detailContext` is only the fallback when no resolver\n // was passed (the legacy direct-provider API).\n const resolvedFromResolver = useDetailContext();\n const resolvedDetailContext =\n useDetailContext === useNoDetailContext ? detailContext ?? null : resolvedFromResolver;\n\n const state = useMemo<PageHeaderState>(() => {\n const activeMenuItem = findByHref(config, normalise(pathname));\n const breadcrumbs = routeMeta != null ? buildBreadcrumbs(pathname, routeMeta) : undefined;\n // Default the in-body title to the breadcrumb LEAF label (the current route's\n // `routeMeta` label) so EVERY routed page shows a title — not just the ones that\n // happen to carry a menu item (list pages with CTAs). Only a real trail (Home +\n // ≥1 crumb) yields a leaf; a bare `[Home]` (no route match) leaves title unset so\n // the header stays chrome-only. A page hook can still override via its own\n // headerProps (e.g. a detail page swapping in the entity name).\n const title =\n breadcrumbs != null && breadcrumbs.length >= 2\n ? breadcrumbs[breadcrumbs.length - 1].label\n : undefined;\n return { activeMenuItem, detailContext: resolvedDetailContext, breadcrumbs, title };\n }, [config, routeMeta, pathname, resolvedDetailContext]);\n\n return (\n <SidebarActionProvider>\n <PageHeaderContext.Provider value={state}>\n {resolvedDetailContext != null ? <ChromeHeader /> : null}\n {children}\n </PageHeaderContext.Provider>\n </SidebarActionProvider>\n );\n}\n\n/**\n * Ready-made page wrapper for the PlatformReact page-definer's `wrapPage` option:\n * `withPageHeader(config, routeMeta, useDetailContext?)` returns\n * `(page) => <PageHeaderProvider …>{page}</PageHeaderProvider>`.\n *\n * Pass the optional `useDetailContext` resolver to have the provider render a\n * shared header for detail routes whose page renders none of its own (see\n * {@link PageHeaderProviderProps.useDetailContext}); omit it for the original\n * behaviour (provider supplies context only, each page self-renders `<PageHeader>`).\n *\n * Kept here — the same module as `PageHeaderProvider` and `usePageHeader` — on\n * purpose: the provider and the hook must resolve to ONE `PageHeaderContext`\n * instance, which only holds when both come from this `components/layout` entry.\n * (A bundler inlines a separate context copy into each entry, so wrapping from the\n * `platform-react` entry would give the provider a different context than the\n * hook — the header would render empty.) A plugin passes\n * `wrapPage: withPageHeader(<feature>MenuConfig, <feature>RouteMeta)`\n * (optionally a third resolver arg) to `createPluginPageDefiner`.\n */\nexport function withPageHeader(\n config: HeaderMenuItem[],\n routeMeta?: RouteMeta,\n useDetailContext?: () => HeaderDetailContext | null,\n): (page: ReactElement) => ReactElement {\n return (page) => (\n <PageHeaderProvider config={config} routeMeta={routeMeta} useDetailContext={useDetailContext}>\n {page}\n </PageHeaderProvider>\n );\n}\n\n/** Strip a trailing slash (except root) so `/x/` and `/x` match the same item. */\nfunction normalise(pathname: string): string {\n return pathname.length > 1 && pathname.endsWith(\"/\") ? pathname.slice(0, -1) : pathname;\n}\n\n/**\n * Pre-order search for the item whose `href` exactly matches `pathname`. Pre-order\n * means a parent list item (which carries the `actions`) is returned before its\n * own same-href overview child, so the CTA surfaces on the list route.\n */\nfunction findByHref(items: HeaderMenuItem[], pathname: string): HeaderMenuItem | null {\n for (const item of items) {\n if (item.href != null && normalise(item.href) === pathname) {\n return item;\n }\n if (item.children) {\n const nested = findByHref(item.children, pathname);\n if (nested) {\n return nested;\n }\n }\n }\n return null;\n}\n"]}