@burojs/ui-shadcn 0.8.0 → 0.10.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.
Files changed (126) hide show
  1. package/dist/{bulk-summary-2HLgz7Il.cjs → bulk-summary-Chc61Pyw.cjs} +9 -7
  2. package/dist/bulk-summary-Chc61Pyw.cjs.map +1 -0
  3. package/dist/{bulk-summary-D6A0ua21.js → bulk-summary-DpSQD2Fq.js} +9 -7
  4. package/dist/bulk-summary-DpSQD2Fq.js.map +1 -0
  5. package/dist/{candidates-relation-picker-CGXItMN0.js → candidates-relation-picker-DRsHKe6N.js} +3 -3
  6. package/dist/{candidates-relation-picker-CGXItMN0.js.map → candidates-relation-picker-DRsHKe6N.js.map} +1 -1
  7. package/dist/{candidates-relation-picker-C47mF260.cjs → candidates-relation-picker-GIxsp7D_.cjs} +3 -3
  8. package/dist/{candidates-relation-picker-C47mF260.cjs.map → candidates-relation-picker-GIxsp7D_.cjs.map} +1 -1
  9. package/dist/{check-confirm-dialog-BT04Mieo.cjs → check-confirm-dialog-BMSb7wFv.cjs} +76 -9
  10. package/dist/check-confirm-dialog-BMSb7wFv.cjs.map +1 -0
  11. package/dist/{check-confirm-dialog-CtiRzOAt.js → check-confirm-dialog-B_u3YVHS.js} +72 -11
  12. package/dist/{check-confirm-dialog-CtiRzOAt.js.map → check-confirm-dialog-B_u3YVHS.js.map} +1 -1
  13. package/dist/{filter-builder-z3Axzf9Y.js → filter-builder-DX-xC3Yd.js} +14 -6
  14. package/dist/filter-builder-DX-xC3Yd.js.map +1 -0
  15. package/dist/{filter-builder-ByGhxLf_.cjs → filter-builder-Dt5E8PSX.cjs} +14 -6
  16. package/dist/filter-builder-Dt5E8PSX.cjs.map +1 -0
  17. package/dist/{flow-runtime-BVFjMU5-.cjs → flow-runtime-CQ4wf8co.cjs} +3 -3
  18. package/dist/{flow-runtime-BVFjMU5-.cjs.map → flow-runtime-CQ4wf8co.cjs.map} +1 -1
  19. package/dist/{flow-runtime-DrUWyTS0.js → flow-runtime-Q2vD7R3c.js} +3 -3
  20. package/dist/{flow-runtime-DrUWyTS0.js.map → flow-runtime-Q2vD7R3c.js.map} +1 -1
  21. package/dist/{flow-screen-3fk6J33y.js → flow-screen-B1y2yizP.js} +68 -29
  22. package/dist/flow-screen-B1y2yizP.js.map +1 -0
  23. package/dist/{flow-screen-6y5E_HT6.cjs → flow-screen-sw2cP70t.cjs} +67 -28
  24. package/dist/flow-screen-sw2cP70t.cjs.map +1 -0
  25. package/dist/index.cjs +2304 -247
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.cts +119 -12
  28. package/dist/index.d.ts +119 -12
  29. package/dist/index.js +2225 -172
  30. package/dist/index.js.map +1 -1
  31. package/dist/{inline-flow-host-C4KmZIYE.cjs → inline-flow-host-CkhoA69R.cjs} +3 -3
  32. package/dist/{inline-flow-host-C4KmZIYE.cjs.map → inline-flow-host-CkhoA69R.cjs.map} +1 -1
  33. package/dist/{inline-flow-host-YnnvWjdU.js → inline-flow-host-DqbXqcPS.js} +3 -3
  34. package/dist/{inline-flow-host-YnnvWjdU.js.map → inline-flow-host-DqbXqcPS.js.map} +1 -1
  35. package/dist/{lazy-relation-picker-dialog-DN4bvQfg.js → lazy-relation-picker-dialog-BaIEWLbF.js} +3 -52
  36. package/dist/lazy-relation-picker-dialog-BaIEWLbF.js.map +1 -0
  37. package/dist/{lazy-relation-picker-dialog-BAKBRn3V.cjs → lazy-relation-picker-dialog-CeRzOAi0.cjs} +3 -52
  38. package/dist/lazy-relation-picker-dialog-CeRzOAi0.cjs.map +1 -0
  39. package/dist/{page-flow-route-CtEfqAvU.js → page-flow-route-CP7cS7FY.js} +7 -7
  40. package/dist/page-flow-route-CP7cS7FY.js.map +1 -0
  41. package/dist/{page-flow-route-DEjAxHe3.cjs → page-flow-route-UDx8qvdM.cjs} +10 -10
  42. package/dist/page-flow-route-UDx8qvdM.cjs.map +1 -0
  43. package/dist/{place-node-Bhl8B3fF.cjs → place-node-C5ZmuHaN.cjs} +208 -55
  44. package/dist/place-node-C5ZmuHaN.cjs.map +1 -0
  45. package/dist/{place-node-BdxT-30h.js → place-node-DwWAigv0.js} +205 -58
  46. package/dist/place-node-DwWAigv0.js.map +1 -0
  47. package/dist/record-trail-store-Cjo9vtod.cjs +126 -0
  48. package/dist/record-trail-store-Cjo9vtod.cjs.map +1 -0
  49. package/dist/record-trail-store-Dn6bVry4.js +91 -0
  50. package/dist/record-trail-store-Dn6bVry4.js.map +1 -0
  51. package/dist/{related-list-cards-Bc_vfCE_.cjs → related-list-cards-BypKfm9t.cjs} +3 -3
  52. package/dist/{related-list-cards-Bc_vfCE_.cjs.map → related-list-cards-BypKfm9t.cjs.map} +1 -1
  53. package/dist/{related-list-cards-BvkD5OcC.js → related-list-cards-Dcmruy09.js} +3 -3
  54. package/dist/{related-list-cards-BvkD5OcC.js.map → related-list-cards-Dcmruy09.js.map} +1 -1
  55. package/dist/{related-list-timeline-k0DtnxTs.cjs → related-list-timeline-D-KClgKb.cjs} +4 -4
  56. package/dist/related-list-timeline-D-KClgKb.cjs.map +1 -0
  57. package/dist/{related-list-timeline-DCrwN9oO.js → related-list-timeline-DZON_qSc.js} +4 -4
  58. package/dist/related-list-timeline-DZON_qSc.js.map +1 -0
  59. package/dist/{related-rows-BW9Jr07T.cjs → related-rows-DgF05ssi.cjs} +4 -4
  60. package/dist/{related-rows-BW9Jr07T.cjs.map → related-rows-DgF05ssi.cjs.map} +1 -1
  61. package/dist/{related-rows-CPE-9FFr.js → related-rows-ETZl5CB9.js} +4 -4
  62. package/dist/{related-rows-CPE-9FFr.js.map → related-rows-ETZl5CB9.js.map} +1 -1
  63. package/dist/{relation-create-DDEYcKfw.cjs → relation-create-B8zngAcA.cjs} +82 -13
  64. package/dist/relation-create-B8zngAcA.cjs.map +1 -0
  65. package/dist/{relation-create-C43cdPQt.js → relation-create-CeCWyxIb.js} +79 -16
  66. package/dist/relation-create-CeCWyxIb.js.map +1 -0
  67. package/dist/{relation-many-picker-BlrGRwMV.js → relation-many-picker-CT7nKfE2.js} +12 -10
  68. package/dist/relation-many-picker-CT7nKfE2.js.map +1 -0
  69. package/dist/{relation-many-picker-Br-zBHxT.cjs → relation-many-picker-Cq0EHY5I.cjs} +12 -10
  70. package/dist/relation-many-picker-Cq0EHY5I.cjs.map +1 -0
  71. package/dist/{relation-picker-x7P5HKie.js → relation-picker-CCyuMeGq.js} +13 -10
  72. package/dist/relation-picker-CCyuMeGq.js.map +1 -0
  73. package/dist/{relation-picker-ADjxI_TI.cjs → relation-picker-DmwTzgsd.cjs} +13 -10
  74. package/dist/relation-picker-DmwTzgsd.cjs.map +1 -0
  75. package/dist/{relation-picker-dialog-CyKliBkN.js → relation-picker-dialog-CoWKjNv8.js} +5 -5
  76. package/dist/relation-picker-dialog-CoWKjNv8.js.map +1 -0
  77. package/dist/{relation-picker-dialog-DimVQF9Y.cjs → relation-picker-dialog-mbwyNK43.cjs} +5 -5
  78. package/dist/relation-picker-dialog-mbwyNK43.cjs.map +1 -0
  79. package/dist/{relation-select-Cr3CfNLy.cjs → relation-select-CguIo2M5.cjs} +2 -2
  80. package/dist/{relation-select-Cr3CfNLy.cjs.map → relation-select-CguIo2M5.cjs.map} +1 -1
  81. package/dist/{relation-select-B8Fq4o-t.js → relation-select-nAYxhopN.js} +2 -2
  82. package/dist/{relation-select-B8Fq4o-t.js.map → relation-select-nAYxhopN.js.map} +1 -1
  83. package/dist/{success-notices-Dl3M1fZP.cjs → success-notices-Cl4b6MLQ.cjs} +3 -2
  84. package/dist/success-notices-Cl4b6MLQ.cjs.map +1 -0
  85. package/dist/{success-notices-LDEgEkc4.js → success-notices-CrcWOGSo.js} +3 -2
  86. package/dist/success-notices-CrcWOGSo.js.map +1 -0
  87. package/dist/{use-dialog-filter-state-tNvqAAjh.cjs → use-dialog-filter-state-CpWblz3C.cjs} +2 -2
  88. package/dist/{use-dialog-filter-state-tNvqAAjh.cjs.map → use-dialog-filter-state-CpWblz3C.cjs.map} +1 -1
  89. package/dist/{use-dialog-filter-state-B_MqzHaT.js → use-dialog-filter-state-ZYxOp5WO.js} +2 -2
  90. package/dist/{use-dialog-filter-state-B_MqzHaT.js.map → use-dialog-filter-state-ZYxOp5WO.js.map} +1 -1
  91. package/dist/{use-record-subtitle-bfwIoUme.cjs → use-record-subtitle-B4lTR7pf.cjs} +5 -8
  92. package/dist/use-record-subtitle-B4lTR7pf.cjs.map +1 -0
  93. package/dist/{use-record-subtitle-gIaCGgbI.js → use-record-subtitle-pWMBqQx9.js} +5 -8
  94. package/dist/use-record-subtitle-pWMBqQx9.js.map +1 -0
  95. package/package.json +9 -9
  96. package/dist/bulk-summary-2HLgz7Il.cjs.map +0 -1
  97. package/dist/bulk-summary-D6A0ua21.js.map +0 -1
  98. package/dist/check-confirm-dialog-BT04Mieo.cjs.map +0 -1
  99. package/dist/filter-builder-ByGhxLf_.cjs.map +0 -1
  100. package/dist/filter-builder-z3Axzf9Y.js.map +0 -1
  101. package/dist/flow-screen-3fk6J33y.js.map +0 -1
  102. package/dist/flow-screen-6y5E_HT6.cjs.map +0 -1
  103. package/dist/lazy-relation-picker-dialog-BAKBRn3V.cjs.map +0 -1
  104. package/dist/lazy-relation-picker-dialog-DN4bvQfg.js.map +0 -1
  105. package/dist/page-flow-route-CtEfqAvU.js.map +0 -1
  106. package/dist/page-flow-route-DEjAxHe3.cjs.map +0 -1
  107. package/dist/place-node-BdxT-30h.js.map +0 -1
  108. package/dist/place-node-Bhl8B3fF.cjs.map +0 -1
  109. package/dist/related-list-timeline-DCrwN9oO.js.map +0 -1
  110. package/dist/related-list-timeline-k0DtnxTs.cjs.map +0 -1
  111. package/dist/relation-create-C43cdPQt.js.map +0 -1
  112. package/dist/relation-create-DDEYcKfw.cjs.map +0 -1
  113. package/dist/relation-many-picker-BlrGRwMV.js.map +0 -1
  114. package/dist/relation-many-picker-Br-zBHxT.cjs.map +0 -1
  115. package/dist/relation-picker-ADjxI_TI.cjs.map +0 -1
  116. package/dist/relation-picker-dialog-CyKliBkN.js.map +0 -1
  117. package/dist/relation-picker-dialog-DimVQF9Y.cjs.map +0 -1
  118. package/dist/relation-picker-x7P5HKie.js.map +0 -1
  119. package/dist/resource-page-router-BRpUnhay.js +0 -1958
  120. package/dist/resource-page-router-BRpUnhay.js.map +0 -1
  121. package/dist/resource-page-router-qEd2xb55.cjs +0 -2167
  122. package/dist/resource-page-router-qEd2xb55.cjs.map +0 -1
  123. package/dist/success-notices-Dl3M1fZP.cjs.map +0 -1
  124. package/dist/success-notices-LDEgEkc4.js.map +0 -1
  125. package/dist/use-record-subtitle-bfwIoUme.cjs.map +0 -1
  126. package/dist/use-record-subtitle-gIaCGgbI.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -1,21 +1,22 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_use_theme = require("./use-theme-DFlpXils.cjs");
3
3
  const require_toaster = require("./toaster-BbByOytP.cjs");
4
- const require_check_confirm_dialog = require("./check-confirm-dialog-BT04Mieo.cjs");
4
+ const require_check_confirm_dialog = require("./check-confirm-dialog-BMSb7wFv.cjs");
5
5
  const require_button = require("./button-BxnnE28H.cjs");
6
6
  const require_input = require("./input-BI0czGyI.cjs");
7
7
  const require_dialog = require("./dialog-vmMdfUWs.cjs");
8
- const require_relation_create = require("./relation-create-DDEYcKfw.cjs");
8
+ const require_relation_create = require("./relation-create-B8zngAcA.cjs");
9
9
  const require_skeleton = require("./skeleton-_1gP7wan.cjs");
10
- const require_place_node = require("./place-node-Bhl8B3fF.cjs");
10
+ const require_place_node = require("./place-node-C5ZmuHaN.cjs");
11
11
  const require_layout_theme_storage_key = require("./layout/theme-storage-key.cjs");
12
- const require_filter_builder = require("./filter-builder-ByGhxLf_.cjs");
13
- const require_resource_page_router = require("./resource-page-router-qEd2xb55.cjs");
12
+ const require_filter_builder = require("./filter-builder-Dt5E8PSX.cjs");
13
+ const require_record_trail_store = require("./record-trail-store-Cjo9vtod.cjs");
14
14
  const require_label = require("./label-w6JYf2cF.cjs");
15
- const require_lazy_relation_picker_dialog = require("./lazy-relation-picker-dialog-BAKBRn3V.cjs");
16
- const require_use_record_subtitle = require("./use-record-subtitle-bfwIoUme.cjs");
17
- const require_relation_picker = require("./relation-picker-ADjxI_TI.cjs");
18
- const require_use_dialog_filter_state = require("./use-dialog-filter-state-tNvqAAjh.cjs");
15
+ const require_lazy_relation_picker_dialog = require("./lazy-relation-picker-dialog-CeRzOAi0.cjs");
16
+ const require_success_notices = require("./success-notices-Cl4b6MLQ.cjs");
17
+ const require_use_record_subtitle = require("./use-record-subtitle-B4lTR7pf.cjs");
18
+ const require_relation_picker = require("./relation-picker-DmwTzgsd.cjs");
19
+ const require_use_dialog_filter_state = require("./use-dialog-filter-state-CpWblz3C.cjs");
19
20
  let _burojs_react_web = require("@burojs/react/web");
20
21
  let _burojs_core = require("@burojs/core");
21
22
  let _burojs_react = require("@burojs/react");
@@ -303,7 +304,7 @@ function DocBrowser({ className }) {
303
304
  label,
304
305
  summary: (0, _burojs_core.resolveDoc)(caps, entry.scope)?.summary,
305
306
  nested: entry.kind === "variant",
306
- group: entry.kind === "concept" ? glossaryLabel : entry.kind === "resource" ? areasLabel : void 0
307
+ group: entry.kind === "concept" ? glossaryLabel : entry.kind === "resource" || entry.kind === "base" ? areasLabel : void 0
307
308
  };
308
309
  }), [
309
310
  app,
@@ -1719,25 +1720,40 @@ function useNavIcon() {
1719
1720
  return (0, react.useCallback)((name) => resolveNavIcon(name, (key) => components[key]), [components]);
1720
1721
  }
1721
1722
  //#endregion
1723
+ //#region src/shell/use-shell-waiting.ts
1724
+ function useShellWaiting() {
1725
+ return (0, _burojs_react.usePermissionsUndecided)();
1726
+ }
1727
+ //#endregion
1722
1728
  //#region src/layout/build-nav-items.ts
1729
+ function groupNavHref(registry, group, isVisible) {
1730
+ let href;
1731
+ try {
1732
+ href = (0, _burojs_core.navHrefFor)(registry, group, { isVisible });
1733
+ } catch {
1734
+ return;
1735
+ }
1736
+ return (0, _burojs_core.matchPath)(registry, href, { isVisible }) === null ? void 0 : href;
1737
+ }
1723
1738
  function buildNavItems(args) {
1724
1739
  const { registry, caps, groupName, match, isVisible, entryFilter, icons } = args;
1725
1740
  const chain = match?.groupChain ?? [];
1726
1741
  const qualifiedMatch = match;
1727
- const activeLeaf = qualifiedMatch == null ? void 0 : qualifiedMatch.kind === "group-index" ? require_resource_page_router.canonicalNavKey({
1742
+ const activeLeaf = qualifiedMatch == null ? void 0 : qualifiedMatch.kind === "group-index" ? require_record_trail_store.canonicalNavKey({
1728
1743
  name: qualifiedMatch.target ?? qualifiedMatch.name,
1729
1744
  ref: qualifiedMatch.targetRef
1730
- }) : require_resource_page_router.canonicalNavKey(qualifiedMatch);
1745
+ }) : require_record_trail_store.canonicalNavKey(qualifiedMatch);
1731
1746
  const isEligible = (node) => isVisible(node) && (entryFilter ? entryFilter(node) : true);
1732
1747
  const out = [];
1733
1748
  for (const child of registry.groups.childrenOf(groupName)) {
1734
1749
  if (!isEligible(child)) continue;
1735
1750
  const kind = (0, _burojs_core.nodeKind)(child);
1736
- const childKey = require_resource_page_router.canonicalNavKey(child);
1737
- const href = (0, _burojs_core.navHrefFor)(registry, childKey, { isVisible: isEligible });
1751
+ const childKey = require_record_trail_store.canonicalNavKey(child);
1738
1752
  if (kind === "group") {
1753
+ const href = groupNavHref(registry, childKey, isEligible);
1754
+ if (href === void 0) continue;
1739
1755
  const label = (0, _burojs_core.resolveNavLabel)(caps, `groups.${childKey}`, (0, _burojs_core.declaredText)("chrome", child, "label"));
1740
- const active = chain.some((g) => require_resource_page_router.canonicalNavKey(g) === childKey);
1756
+ const active = chain.some((g) => require_record_trail_store.canonicalNavKey(g) === childKey);
1741
1757
  out.push({
1742
1758
  kind: "group",
1743
1759
  name: childKey,
@@ -1746,7 +1762,10 @@ function buildNavItems(args) {
1746
1762
  icon: icons?.group?.(childKey),
1747
1763
  active
1748
1764
  });
1749
- } else if (kind === "custom-page") out.push({
1765
+ continue;
1766
+ }
1767
+ const href = (0, _burojs_core.navHrefFor)(registry, childKey, { isVisible: isEligible });
1768
+ if (kind === "custom-page") out.push({
1750
1769
  kind: "custom-page",
1751
1770
  name: childKey,
1752
1771
  label: (0, _burojs_core.resolveNavLabel)(caps, `pages.${childKey}`, (0, _burojs_core.declaredText)("chrome", child, "label")),
@@ -1766,6 +1785,171 @@ function buildNavItems(args) {
1766
1785
  return out;
1767
1786
  }
1768
1787
  //#endregion
1788
+ //#region src/layout/layouts/secondary-sidebar-layout.tsx
1789
+ function Row({ it }) {
1790
+ const RouterLink = require_toaster.useLinkComponent();
1791
+ return (0, react_jsx_runtime.jsx)("li", { children: (0, react_jsx_runtime.jsxs)(RouterLink, {
1792
+ href: it.href,
1793
+ "data-testid": `nav-secondary-item:${it.name}`,
1794
+ "aria-current": it.active ? "page" : void 0,
1795
+ className: require_use_theme.cn("flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium outline-hidden ring-offset-background transition-colors", "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", it.active ? "bg-secondary text-secondary-foreground" : "text-muted-foreground hover:bg-secondary/50 hover:text-foreground"),
1796
+ children: [it.icon != null && (0, react_jsx_runtime.jsx)("span", {
1797
+ className: "inline-flex h-4 w-4 shrink-0 items-center justify-center",
1798
+ "aria-hidden": "true",
1799
+ children: it.icon
1800
+ }), (0, react_jsx_runtime.jsx)("span", {
1801
+ className: "truncate",
1802
+ title: it.label,
1803
+ children: it.label
1804
+ })]
1805
+ }) });
1806
+ }
1807
+ function SecondarySidebarLayout({ group, groupKey, items, children }) {
1808
+ const RouterLink = require_toaster.useLinkComponent();
1809
+ const caps = (0, _burojs_react.useI18nCaps)();
1810
+ const id = groupKey ?? group.name;
1811
+ const label = (0, _burojs_core.resolveNavLabel)(caps, `groups.${id}`, (0, _burojs_core.declaredText)("chrome", group, "label"));
1812
+ return (0, react_jsx_runtime.jsxs)("div", {
1813
+ className: "md:-m-6 md:flex md:min-h-[calc(100%+3rem)]",
1814
+ "data-testid": `nav-secondary:${id}`,
1815
+ children: [
1816
+ (0, react_jsx_runtime.jsx)("aside", {
1817
+ className: "hidden w-64 shrink-0 border-r bg-background text-foreground md:block",
1818
+ children: (0, react_jsx_runtime.jsxs)("div", {
1819
+ className: "space-y-4 p-4",
1820
+ children: [(0, react_jsx_runtime.jsx)("p", {
1821
+ className: "px-3 text-base font-semibold tracking-tight",
1822
+ children: label
1823
+ }), (0, react_jsx_runtime.jsx)("nav", {
1824
+ "aria-label": label,
1825
+ children: (0, react_jsx_runtime.jsx)("ul", {
1826
+ className: "space-y-0.5",
1827
+ children: items.map((it) => (0, react_jsx_runtime.jsx)(Row, { it }, it.name))
1828
+ })
1829
+ })]
1830
+ })
1831
+ }),
1832
+ (0, react_jsx_runtime.jsx)("nav", {
1833
+ "aria-label": label,
1834
+ "data-testid": `nav-secondary-select:${id}`,
1835
+ className: "-mx-1 mb-4 flex snap-x snap-proximity gap-1.5 overflow-x-auto scroll-smooth px-1 pb-1 [-ms-overflow-style:none] [mask-image:linear-gradient(to_right,transparent,black_8px,black_calc(100%-8px),transparent)] [scrollbar-width:none] md:hidden [&::-webkit-scrollbar]:hidden",
1836
+ children: items.map((it) => (0, react_jsx_runtime.jsx)(RouterLink, {
1837
+ href: it.href,
1838
+ "aria-current": it.active ? "page" : void 0,
1839
+ className: require_use_theme.cn("snap-start whitespace-nowrap rounded-full border px-3 py-1.5 text-sm outline-hidden ring-offset-background transition-colors duration-150", "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", it.active ? "border-primary/40 bg-primary/10 font-medium text-foreground" : "border-border text-muted-foreground hover:bg-accent/60 hover:text-accent-foreground"),
1840
+ children: it.label
1841
+ }, it.name))
1842
+ }),
1843
+ (0, react_jsx_runtime.jsx)("div", {
1844
+ className: "min-w-0 flex-1 md:overflow-x-hidden md:p-6",
1845
+ children
1846
+ })
1847
+ ]
1848
+ });
1849
+ }
1850
+ //#endregion
1851
+ //#region src/layout/layouts/tabs-layout.tsx
1852
+ function TabsLayout({ group, groupKey, items, children }) {
1853
+ const RouterLink = require_toaster.useLinkComponent();
1854
+ const caps = (0, _burojs_react.useI18nCaps)();
1855
+ const id = groupKey ?? group.name;
1856
+ const label = (0, _burojs_core.resolveNavLabel)(caps, `groups.${id}`, (0, _burojs_core.declaredText)("chrome", group, "label"));
1857
+ return (0, react_jsx_runtime.jsxs)("div", {
1858
+ className: "flex flex-col gap-4",
1859
+ "data-testid": `nav-tabs:${id}`,
1860
+ children: [(0, react_jsx_runtime.jsx)("nav", {
1861
+ "aria-label": label,
1862
+ className: "flex gap-1 overflow-x-auto scroll-smooth border-b border-border [-ms-overflow-style:none] [mask-image:linear-gradient(to_right,transparent,black_8px,black_calc(100%-8px),transparent)] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
1863
+ children: items.map((it) => (0, react_jsx_runtime.jsxs)(RouterLink, {
1864
+ href: it.href,
1865
+ "aria-current": it.active ? "page" : void 0,
1866
+ "data-testid": `nav-tab:${it.name}`,
1867
+ className: require_use_theme.cn("group/tab relative flex shrink-0 items-center gap-1.5 whitespace-nowrap rounded-t-sm px-3 py-2.5 text-sm outline-hidden ring-offset-background transition-colors duration-150", "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", it.active ? "font-medium text-foreground" : "text-muted-foreground hover:text-foreground"),
1868
+ children: [
1869
+ it.icon != null && (0, react_jsx_runtime.jsx)("span", {
1870
+ className: "inline-flex h-4 w-4 shrink-0 items-center justify-center",
1871
+ "aria-hidden": "true",
1872
+ children: it.icon
1873
+ }),
1874
+ it.label,
1875
+ (0, react_jsx_runtime.jsx)("span", {
1876
+ "aria-hidden": "true",
1877
+ className: require_use_theme.cn("pointer-events-none absolute inset-x-2 -bottom-px h-0.5 origin-center scale-x-0 rounded-full bg-primary opacity-0 transition-all duration-300 ease-out", it.active ? "scale-x-100 opacity-100" : "group-hover/tab:scale-x-100 group-hover/tab:opacity-30")
1878
+ })
1879
+ ]
1880
+ }, it.name))
1881
+ }), (0, react_jsx_runtime.jsx)("div", {
1882
+ className: "min-w-0",
1883
+ children
1884
+ })]
1885
+ });
1886
+ }
1887
+ //#endregion
1888
+ //#region src/layout/nav-slots.ts
1889
+ function layoutSlot(key) {
1890
+ return `layout.${key}`;
1891
+ }
1892
+ function useLayout(key) {
1893
+ return (0, _burojs_react.useComponent)(layoutSlot(key));
1894
+ }
1895
+ const BUILTIN_LAYOUTS = {
1896
+ [layoutSlot("secondary-sidebar")]: SecondarySidebarLayout,
1897
+ [layoutSlot("tabs")]: TabsLayout
1898
+ };
1899
+ function useLayoutResolver() {
1900
+ const components = (0, react.useContext)(_burojs_react.ComponentsContext);
1901
+ return (key) => components[layoutSlot(key)] ?? BUILTIN_LAYOUTS[layoutSlot(key)];
1902
+ }
1903
+ const unresolvedLayoutReported = new WeakMap();
1904
+ function useReportUnresolvedLayouts(groups, resolve) {
1905
+ const app = (0, _burojs_react.useApp)();
1906
+ (0, react.useEffect)(() => {
1907
+ if (process.env.NODE_ENV === "production") return;
1908
+ for (const group of groups) {
1909
+ const layout = group.layout;
1910
+ if (layout === "flat" || layout === "collapsible" || resolve(layout)) continue;
1911
+ const key = require_record_trail_store.canonicalNavKey(group);
1912
+ let seen = unresolvedLayoutReported.get(app);
1913
+ if (!seen) {
1914
+ seen = new Set();
1915
+ unresolvedLayoutReported.set(app, seen);
1916
+ }
1917
+ if (seen.has(key)) continue;
1918
+ seen.add(key);
1919
+ console.error(`[burojs] Nav group "${key}" declares layout "${layout}", and no renderer is registered for it. Register one as components["layout.${layout}"] on <BuroProvider>, or use a built-in layout: "secondary-sidebar", "tabs", "flat", "collapsible".`);
1920
+ }
1921
+ });
1922
+ }
1923
+ //#endregion
1924
+ //#region src/layout/use-nav-routing.ts
1925
+ function useNavVisible() {
1926
+ const ctx = (0, _burojs_react.useVisibilityCtx)();
1927
+ const allowed = usePageAllowed();
1928
+ return (0, react.useCallback)((node) => (0, _burojs_core.evaluateVisible)(node.visible, ctx) && (!(0, _burojs_core.isCustomPageDef)(node) || allowed(node)), [ctx, allowed]);
1929
+ }
1930
+ function useResourceVisible() {
1931
+ const ctx = (0, _burojs_react.useVisibilityCtx)();
1932
+ return (0, react.useCallback)((def) => (0, _burojs_core.evaluateVisible)(def.visible, ctx), [ctx]);
1933
+ }
1934
+ function usePageAllowed() {
1935
+ const permissions = (0, _burojs_react.usePermissions)();
1936
+ return (0, react.useCallback)((page) => (0, _burojs_react.pageAccessFor)(page, permissions) === "allowed", [permissions]);
1937
+ }
1938
+ function useHref(name, opts) {
1939
+ const app = (0, _burojs_react.useApp)();
1940
+ const isVisible = useNavVisible();
1941
+ return (0, _burojs_core.hrefFor)(app.registry, name, {
1942
+ ...opts,
1943
+ isVisible
1944
+ });
1945
+ }
1946
+ function useMatch() {
1947
+ const app = (0, _burojs_react.useApp)();
1948
+ const isVisible = useNavVisible();
1949
+ const path = (0, _burojs_react.useOptionalRouterAdapter)()?.pathname;
1950
+ return path === void 0 ? null : (0, _burojs_core.matchPath)(app.registry, path, { isVisible });
1951
+ }
1952
+ //#endregion
1769
1953
  //#region src/layout/use-nav-tree.ts
1770
1954
  function isActiveHref(href, currentPath) {
1771
1955
  if (!currentPath) return false;
@@ -1779,18 +1963,18 @@ function useNavTree(opts = {}) {
1779
1963
  const passesEntryFilter = (entry) => entryFilter ? entryFilter(entry) : true;
1780
1964
  const app = (0, _burojs_react.useApp)();
1781
1965
  const caps = (0, _burojs_react.useI18nCaps)();
1782
- const isResourceVisible = require_resource_page_router.useResourceVisible();
1783
- const resolveLayout = require_resource_page_router.useLayoutResolver();
1784
- const match = require_resource_page_router.useMatch();
1785
- const isVisible = require_resource_page_router.useNavVisible();
1786
- const pageAllowed = require_resource_page_router.usePageAllowed();
1966
+ const isResourceVisible = useResourceVisible();
1967
+ const resolveLayout = useLayoutResolver();
1968
+ const match = useMatch();
1969
+ const isVisible = useNavVisible();
1970
+ const pageAllowed = usePageAllowed();
1787
1971
  const isNavEligible = (node) => isVisible(node) && passesEntryFilter(node);
1788
1972
  const allResources = app.registry.list();
1789
1973
  const allCustomPages = app.registry.customPages.list();
1790
1974
  const sections = app.registry.sections.list();
1791
1975
  const groups = app.registry.groups.rootNodes().filter((n) => (0, _burojs_core.nodeKind)(n) === "group");
1792
- require_resource_page_router.useReportUnresolvedLayouts(app.registry.groups.list(), resolveLayout);
1793
- const topLevelResources = allResources.filter((r) => (0, _burojs_core.hasListPage)(r)).filter(isResourceVisible).filter(passesEntryFilter).filter((r) => !r.section && !r.group).map((r, idx) => ({
1976
+ useReportUnresolvedLayouts(app.registry.groups.list(), resolveLayout);
1977
+ const topLevelResources = allResources.filter((r) => (0, _burojs_core.hasMenuEntry)(r)).filter(isResourceVisible).filter(passesEntryFilter).filter((r) => !r.section && !r.group).map((r, idx) => ({
1794
1978
  r,
1795
1979
  idx
1796
1980
  })).sort((a, b) => {
@@ -1799,16 +1983,16 @@ function useNavTree(opts = {}) {
1799
1983
  return ao !== bo ? ao - bo : a.idx - b.idx;
1800
1984
  }).map((x) => x.r);
1801
1985
  const topLevelCustomPages = allCustomPages.filter((p) => !p.section && !p.group).filter(pageAllowed).filter(passesEntryFilter);
1802
- const resourceHref = (def) => (0, _burojs_core.hrefFor)(app.registry, require_resource_page_router.canonicalResourceKey(def));
1803
- const resourceLabel = (def) => (0, _burojs_core.resolveResourceNavLabel)(caps, require_resource_page_router.canonicalResourceKey(def), def);
1804
- const pageLabel = (page) => (0, _burojs_core.resolveNavLabel)(caps, `pages.${require_resource_page_router.canonicalNavKey(page)}`, (0, _burojs_core.declaredText)("chrome", page, "label"));
1805
- const sectionLabel = (section) => (0, _burojs_core.resolveNavLabel)(caps, `sections.${require_resource_page_router.canonicalNavKey(section)}`, (0, _burojs_core.declaredText)("chrome", section, "label"));
1806
- const groupLabel = (group) => (0, _burojs_core.resolveNavLabel)(caps, `groups.${require_resource_page_router.canonicalNavKey(group)}`, (0, _burojs_core.declaredText)("chrome", group, "label"));
1986
+ const resourceHref = (def) => (0, _burojs_core.hrefFor)(app.registry, require_record_trail_store.canonicalResourceKey(def));
1987
+ const resourceLabel = (def) => (0, _burojs_core.resolveResourceNavLabel)(caps, require_record_trail_store.canonicalResourceKey(def), def);
1988
+ const pageLabel = (page) => (0, _burojs_core.resolveNavLabel)(caps, `pages.${require_record_trail_store.canonicalNavKey(page)}`, (0, _burojs_core.declaredText)("chrome", page, "label"));
1989
+ const sectionLabel = (section) => (0, _burojs_core.resolveNavLabel)(caps, `sections.${require_record_trail_store.canonicalNavKey(section)}`, (0, _burojs_core.declaredText)("chrome", section, "label"));
1990
+ const groupLabel = (group) => (0, _burojs_core.resolveNavLabel)(caps, `groups.${require_record_trail_store.canonicalNavKey(group)}`, (0, _burojs_core.declaredText)("chrome", group, "label"));
1807
1991
  const pageEntry = (page) => {
1808
1992
  const href = page.path;
1809
1993
  return {
1810
1994
  kind: "page",
1811
- key: require_resource_page_router.canonicalNavKey(page),
1995
+ key: require_record_trail_store.canonicalNavKey(page),
1812
1996
  label: pageLabel(page),
1813
1997
  href,
1814
1998
  icon: page.icon,
@@ -1819,7 +2003,7 @@ function useNavTree(opts = {}) {
1819
2003
  const href = resourceHref(def);
1820
2004
  return {
1821
2005
  kind: "resource",
1822
- key: require_resource_page_router.canonicalResourceKey(def),
2006
+ key: require_record_trail_store.canonicalResourceKey(def),
1823
2007
  label: resourceLabel(def),
1824
2008
  href,
1825
2009
  icon: def.icon,
@@ -1836,7 +2020,7 @@ function useNavTree(opts = {}) {
1836
2020
  entryFilter
1837
2021
  }).map(itemEntry);
1838
2022
  const groupEntry = (group, label, href, active) => {
1839
- const key = require_resource_page_router.canonicalNavKey(group);
2023
+ const key = require_record_trail_store.canonicalNavKey(group);
1840
2024
  return {
1841
2025
  kind: "group",
1842
2026
  key,
@@ -1874,8 +2058,8 @@ function useNavTree(opts = {}) {
1874
2058
  entries: topEntries
1875
2059
  }];
1876
2060
  for (const section of sections) {
1877
- const sectionKey = require_resource_page_router.canonicalNavKey(section);
1878
- const entries = app.registry.sections.childrenOf(sectionKey).filter((c) => !("parent" in c) || (0, _burojs_core.hasListPage)(c)).filter((c) => (0, _burojs_core.isCustomPageDef)(c) ? pageAllowed(c) : isResourceVisible(c)).filter(passesEntryFilter).map((c) => (0, _burojs_core.isCustomPageDef)(c) ? pageEntry(c) : resourceEntry(c));
2061
+ const sectionKey = require_record_trail_store.canonicalNavKey(section);
2062
+ const entries = app.registry.sections.childrenOf(sectionKey).filter((c) => !("parent" in c) || (0, _burojs_core.hasMenuEntry)(c)).filter((c) => (0, _burojs_core.isCustomPageDef)(c) ? pageAllowed(c) : isResourceVisible(c)).filter(passesEntryFilter).map((c) => (0, _burojs_core.isCustomPageDef)(c) ? pageEntry(c) : resourceEntry(c));
1879
2063
  if (entries.length === 0) continue;
1880
2064
  const active = entries.some((e) => e.active);
1881
2065
  out.push({
@@ -1889,11 +2073,12 @@ function useNavTree(opts = {}) {
1889
2073
  });
1890
2074
  }
1891
2075
  for (const group of groups) {
1892
- const groupKey = require_resource_page_router.canonicalNavKey(group);
2076
+ const groupKey = require_record_trail_store.canonicalNavKey(group);
1893
2077
  if (!isNavEligible(group)) continue;
1894
2078
  const gLabel = groupLabel(group);
1895
2079
  if (resolveLayout(group.layout)) {
1896
- const href = (0, _burojs_core.navHrefFor)(app.registry, groupKey, { isVisible: isNavEligible });
2080
+ const href = groupNavHref(app.registry, groupKey, isNavEligible);
2081
+ if (href === void 0) continue;
1897
2082
  const entry = groupEntry(group, gLabel, href, isActiveHref(href, currentPath));
1898
2083
  out.push({
1899
2084
  key: groupKey,
@@ -1972,155 +2157,2008 @@ function CollapsibleNavSection({ name, label, icon, hasActiveChild, declaredOpen
1972
2157
  })
1973
2158
  }), (0, react_jsx_runtime.jsx)(CollapsibleContent, { children: (0, react_jsx_runtime.jsx)(SidebarMenuSub, { children }) })]
1974
2159
  })
1975
- }) }) })
2160
+ }) }) })
2161
+ });
2162
+ }
2163
+ function NavMain({ topLabel, iconForResource, iconForCustomPage, iconForSection, entryFilter }) {
2164
+ const tree = useNavTree({ entryFilter });
2165
+ const app = (0, _burojs_react.useApp)();
2166
+ const tid = (0, _burojs_react.useTestIds)();
2167
+ const t = (0, _burojs_react.useT)();
2168
+ const RouterLink = require_toaster.useLinkComponent();
2169
+ const navIcon = useNavIcon();
2170
+ const waiting = useShellWaiting();
2171
+ const intent = (0, _burojs_react.useOriginIntent)();
2172
+ const jump = (entry) => () => {
2173
+ if (entry.href !== void 0) intent(entry.href, "jump");
2174
+ };
2175
+ const ownOr = (own, name) => own !== void 0 ? own : navIcon(name);
2176
+ const groupAsSection = (key) => app.registry.sections.get(key) ?? app.registry.groups.get(key);
2177
+ const sectionIcon = (key, name) => {
2178
+ const def = iconForSection ? groupAsSection(key) : void 0;
2179
+ return ownOr(def ? iconForSection?.(def) : void 0, name);
2180
+ };
2181
+ const entryIcon = (entry) => {
2182
+ if (entry.kind === "group") return sectionIcon(entry.key, entry.icon);
2183
+ if (entry.kind === "page") {
2184
+ const page = iconForCustomPage ? app.registry.customPages.get(entry.key) : void 0;
2185
+ return ownOr(page ? iconForCustomPage?.(page) : void 0, entry.icon);
2186
+ }
2187
+ const def = iconForResource ? app.registry.get(entry.key) : void 0;
2188
+ return ownOr(def ? iconForResource?.(def) : void 0, entry.icon);
2189
+ };
2190
+ const entryTestId = (entry) => entry.kind === "page" ? tid.sidebarCustomPage(entry.key) : entry.kind === "group" ? tid.navGroup(entry.key) : tid.navMenuItem(entry.key);
2191
+ const menuItem = (entry) => {
2192
+ const icon = entryIcon(entry);
2193
+ return (0, react_jsx_runtime.jsx)(SidebarMenuItem, { children: (0, react_jsx_runtime.jsx)(SidebarMenuButton, {
2194
+ asChild: true,
2195
+ isActive: entry.active,
2196
+ tooltip: entry.label,
2197
+ children: (0, react_jsx_runtime.jsxs)(RouterLink, {
2198
+ href: entry.href ?? "",
2199
+ "aria-current": entry.active ? "page" : void 0,
2200
+ "data-testid": entryTestId(entry),
2201
+ onClick: jump(entry),
2202
+ children: [icon != null && (0, react_jsx_runtime.jsx)("span", {
2203
+ className: "inline-flex h-4 w-4 items-center justify-center",
2204
+ "aria-hidden": "true",
2205
+ children: icon
2206
+ }), (0, react_jsx_runtime.jsx)("span", { children: entry.label })]
2207
+ })
2208
+ }) }, entry.key);
2209
+ };
2210
+ const subItem = (entry) => (0, react_jsx_runtime.jsx)(SidebarMenuSubItem, { children: (0, react_jsx_runtime.jsx)(SidebarMenuSubButton, {
2211
+ asChild: true,
2212
+ isActive: entry.active,
2213
+ children: (0, react_jsx_runtime.jsx)(RouterLink, {
2214
+ href: entry.href ?? "",
2215
+ "aria-current": entry.active ? "page" : void 0,
2216
+ "data-testid": entryTestId(entry),
2217
+ onClick: jump(entry),
2218
+ children: (0, react_jsx_runtime.jsx)("span", { children: entry.label })
2219
+ })
2220
+ }) }, entry.key);
2221
+ if (waiting) return (0, react_jsx_runtime.jsx)(SidebarGroup, {
2222
+ "data-testid": "sidebar-nav-loading",
2223
+ "aria-busy": "true",
2224
+ children: (0, react_jsx_runtime.jsx)(SidebarGroupContent, { children: (0, react_jsx_runtime.jsx)(SidebarMenu, { children: [
2225
+ 0,
2226
+ 1,
2227
+ 2,
2228
+ 3
2229
+ ].map((i) => (0, react_jsx_runtime.jsx)(SidebarMenuItem, { children: (0, react_jsx_runtime.jsx)(SidebarMenuSkeleton, { showIcon: true }) }, i)) }) })
2230
+ });
2231
+ const [top, ...blocks] = tree;
2232
+ return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [top !== void 0 && top.entries.length > 0 && (0, react_jsx_runtime.jsxs)(SidebarGroup, { children: [topLabel !== null && (0, react_jsx_runtime.jsx)(SidebarGroupLabel, { children: topLabel ?? t("nav.resources") }), (0, react_jsx_runtime.jsx)(SidebarGroupContent, { children: (0, react_jsx_runtime.jsx)(SidebarMenu, { children: top.entries.map(menuItem) }) })] }), blocks.map((block) => {
2233
+ const key = block.key ?? "";
2234
+ if (block.label === null) return (0, react_jsx_runtime.jsx)(SidebarGroup, { children: (0, react_jsx_runtime.jsx)(SidebarGroupContent, { children: (0, react_jsx_runtime.jsx)(SidebarMenu, { children: block.entries.map(menuItem) }) }) }, key);
2235
+ if (block.collapsible) return (0, react_jsx_runtime.jsx)(CollapsibleNavSection, {
2236
+ name: key,
2237
+ label: block.label,
2238
+ icon: sectionIcon(key, block.icon),
2239
+ hasActiveChild: block.active,
2240
+ declaredOpen: block.defaultOpen,
2241
+ children: block.entries.map(subItem)
2242
+ }, key);
2243
+ return (0, react_jsx_runtime.jsxs)(SidebarGroup, {
2244
+ "data-testid": `sidebar-section-group:${key}`,
2245
+ children: [(0, react_jsx_runtime.jsx)(SidebarGroupLabel, {
2246
+ "data-testid": `sidebar-section:${key}`,
2247
+ children: block.label
2248
+ }), (0, react_jsx_runtime.jsx)(SidebarGroupContent, { children: (0, react_jsx_runtime.jsx)(SidebarMenu, { children: block.entries.map(menuItem) }) })]
2249
+ }, key);
2250
+ })] });
2251
+ }
2252
+ //#endregion
2253
+ //#region src/layout/app-sidebar.tsx
2254
+ function AppSidebar({ header, filters, nav, footer }) {
2255
+ const headerNode = fill(header, () => (0, react_jsx_runtime.jsx)(SidebarBrand, {}));
2256
+ const filtersNode = fill(filters, () => null);
2257
+ const navNode = fill(nav, () => (0, react_jsx_runtime.jsx)(NavMain, {}));
2258
+ const footerNode = fill(footer, () => (0, react_jsx_runtime.jsx)(UserMenu, {}));
2259
+ return (0, react_jsx_runtime.jsxs)(Sidebar, {
2260
+ collapsible: "icon",
2261
+ children: [
2262
+ (headerNode != null || filtersNode != null) && (0, react_jsx_runtime.jsxs)(SidebarHeader, {
2263
+ className: "empty:hidden",
2264
+ children: [headerNode, filtersNode]
2265
+ }),
2266
+ (0, react_jsx_runtime.jsx)(SidebarContent, { children: navNode }),
2267
+ footerNode != null && (0, react_jsx_runtime.jsx)(SidebarFooter, {
2268
+ className: "empty:hidden",
2269
+ children: footerNode
2270
+ }),
2271
+ (0, react_jsx_runtime.jsx)(SidebarRail, {})
2272
+ ]
2273
+ });
2274
+ }
2275
+ //#endregion
2276
+ //#region src/layout/nav-chrome-mounted.ts
2277
+ const NavChromeMountedContext = (0, react.createContext)(false);
2278
+ const NavChromeMountedProvider = NavChromeMountedContext.Provider;
2279
+ function useNavChromeMounted() {
2280
+ return (0, react.useContext)(NavChromeMountedContext);
2281
+ }
2282
+ //#endregion
2283
+ //#region src/layout/nav-chrome.tsx
2284
+ const DETAIL_ACTIONS = new Set([
2285
+ "show",
2286
+ "edit",
2287
+ "create"
2288
+ ]);
2289
+ function NavChrome({ children, entryFilter, icons }) {
2290
+ const app = (0, _burojs_react.useApp)();
2291
+ const caps = (0, _burojs_react.useI18nCaps)();
2292
+ const isVisible = useNavVisible();
2293
+ const match = useMatch();
2294
+ const resolveLayout = useLayoutResolver();
2295
+ useReportUnresolvedLayouts(match?.groupChain ?? [], resolveLayout);
2296
+ if (!match) return (0, react_jsx_runtime.jsx)(NavChromeMountedProvider, {
2297
+ value: true,
2298
+ children
2299
+ });
2300
+ let content = children;
2301
+ for (let i = match.groupChain.length - 1; i >= 0; i--) {
2302
+ const group = match.groupChain[i];
2303
+ if (!group) continue;
2304
+ const groupKey = require_record_trail_store.canonicalNavKey(group);
2305
+ if (group.chromeOn === "list" && match.kind === "resource" && DETAIL_ACTIONS.has(match.action)) continue;
2306
+ const Layout = resolveLayout(group.layout);
2307
+ if (!Layout) continue;
2308
+ const items = buildNavItems({
2309
+ registry: app.registry,
2310
+ caps,
2311
+ groupName: groupKey,
2312
+ match,
2313
+ isVisible,
2314
+ entryFilter,
2315
+ icons
2316
+ });
2317
+ content = (0, react_jsx_runtime.jsx)(Layout, {
2318
+ group,
2319
+ groupKey,
2320
+ items,
2321
+ children: content
2322
+ });
2323
+ }
2324
+ return (0, react_jsx_runtime.jsx)(NavChromeMountedProvider, {
2325
+ value: true,
2326
+ children: content
2327
+ });
2328
+ }
2329
+ //#endregion
2330
+ //#region src/flows/page-flow-loader.tsx
2331
+ function PageFlowRouteLoader({ match }) {
2332
+ const t = (0, _burojs_react.useOptionalT)();
2333
+ const chromeT = (0, _burojs_react.useChromeT)();
2334
+ const loaded = require_check_confirm_dialog.useLoaded(require_check_confirm_dialog.loadPageFlowRoute);
2335
+ const failed = (retry) => (0, react_jsx_runtime.jsxs)("div", {
2336
+ role: "alert",
2337
+ "data-buro-flow-load": "failed",
2338
+ className: "flex flex-col gap-3 p-6 text-sm",
2339
+ children: [(0, react_jsx_runtime.jsx)("p", { children: require_check_confirm_dialog.loadFailedText(t) }), (0, react_jsx_runtime.jsx)("div", { children: (0, react_jsx_runtime.jsx)(require_button.Button, {
2340
+ type: "button",
2341
+ onClick: retry,
2342
+ children: chromeT("actions.retry", { defaultValue: "Retry" })
2343
+ }) })]
2344
+ });
2345
+ if (loaded.error !== void 0) return failed(loaded.retry);
2346
+ if (loaded.module === void 0) return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "loading" });
2347
+ const Route = loaded.module.PageFlowRoute;
2348
+ return (0, react_jsx_runtime.jsx)(require_check_confirm_dialog.FlowBoundary, {
2349
+ fallback: (_error, reset) => failed(reset),
2350
+ children: (0, react_jsx_runtime.jsx)(Route, { match })
2351
+ });
2352
+ }
2353
+ //#endregion
2354
+ //#region src/list-kit/resource-list-page.tsx
2355
+ function ResourceListPage({ resource: resourceInput, meta, renderCell, emptyState }) {
2356
+ const resource = (0, _burojs_core.routeResourceKey)(resourceInput);
2357
+ const app = (0, _burojs_react.useRouteListImplementation)();
2358
+ const implementation = require_place_node.selectImplementation("buro:related-list", app);
2359
+ const View = implementation === void 0 ? void 0 : require_place_node.viewOf(implementation);
2360
+ const translate = (0, _burojs_react.useTranslate)();
2361
+ const route = (0, react.useMemo)(() => ({
2362
+ meta,
2363
+ renderCell,
2364
+ emptyState
2365
+ }), [
2366
+ meta,
2367
+ renderCell,
2368
+ emptyState
2369
+ ]);
2370
+ const viewProps = (0, react.useMemo)(() => ({
2371
+ props: { resource: (0, _burojs_core.normalizeEntityRef)(resource) },
2372
+ data: {},
2373
+ t: (key, options) => translate(`blocks.buro:related-list.${key}`, options)
2374
+ }), [resource, translate]);
2375
+ return (0, react_jsx_runtime.jsx)("div", {
2376
+ "data-buro-node": "place",
2377
+ "data-buro-size": "full",
2378
+ className: "min-w-0",
2379
+ children: (0, react_jsx_runtime.jsx)(require_place_node.RouteListContext.Provider, {
2380
+ value: route,
2381
+ children: (0, react_jsx_runtime.jsx)(react.Suspense, {
2382
+ fallback: null,
2383
+ children: View === void 0 ? null : (0, react_jsx_runtime.jsx)(View, { ...viewProps })
2384
+ })
2385
+ })
2386
+ });
2387
+ }
2388
+ //#endregion
2389
+ //#region src/resource/collection-create-picker.tsx
2390
+ function CollectionCreatePicker({ collection }) {
2391
+ const app = (0, _burojs_react.useApp)();
2392
+ const t = (0, _burojs_react.useOptionalT)();
2393
+ const caps = (0, _burojs_react.useI18nCaps)();
2394
+ const gate = (0, _burojs_react.useAvailabilityGate)("create");
2395
+ const Link = require_toaster.useLinkComponent();
2396
+ const key = (0, _burojs_core.routeResourceKey)(collection);
2397
+ const testid = `collection-create-picker:${key}`;
2398
+ let undecided = false;
2399
+ const members = ((0, _burojs_core.collectionFactOf)(app.registry.get(key))?.members ?? []).flatMap((entry) => {
2400
+ const def = app.registry.get(entry.ref);
2401
+ if (def === void 0 || !(0, _burojs_core.hasRecordPage)(def, "create")) return [];
2402
+ const member = (0, _burojs_core.routeResourceKey)(entry.ref);
2403
+ const state = gate(member, "create").state;
2404
+ if (state === "undecided") undecided = true;
2405
+ if (state !== "available") return [];
2406
+ return [{
2407
+ member,
2408
+ href: (0, _burojs_core.resourceCreateHref)(app.registry, def, member),
2409
+ label: (0, _burojs_core.resolveResourceLabel)(caps, member, "single", def)
2410
+ }];
2411
+ });
2412
+ return (0, react_jsx_runtime.jsxs)("div", {
2413
+ "data-testid": testid,
2414
+ className: "mx-auto flex max-w-md flex-col gap-3 px-6 py-12",
2415
+ children: [(0, react_jsx_runtime.jsx)("h2", {
2416
+ className: "text-base font-semibold tracking-tight",
2417
+ children: t("collection.createTitle", { defaultValue: "What do you want to create?" })
2418
+ }), members.length > 0 ? (0, react_jsx_runtime.jsx)("ul", {
2419
+ className: "flex flex-col gap-2",
2420
+ children: members.map((entry) => (0, react_jsx_runtime.jsx)("li", { children: (0, react_jsx_runtime.jsx)(require_button.Button, {
2421
+ asChild: true,
2422
+ variant: "outline",
2423
+ className: "w-full justify-start",
2424
+ "data-testid": `${testid}:${entry.member}`,
2425
+ children: (0, react_jsx_runtime.jsxs)(Link, {
2426
+ href: entry.href,
2427
+ children: [(0, react_jsx_runtime.jsx)(require_check_confirm_dialog.Icon, {
2428
+ name: "Plus",
2429
+ className: "mr-1 h-4 w-4"
2430
+ }), entry.label]
2431
+ })
2432
+ }) }, entry.member))
2433
+ }) : undecided ? (0, react_jsx_runtime.jsx)("div", {
2434
+ role: "status",
2435
+ "aria-busy": "true",
2436
+ className: "h-9 w-full animate-pulse rounded bg-muted/40"
2437
+ }) : (0, react_jsx_runtime.jsx)("p", {
2438
+ className: "text-sm text-muted-foreground",
2439
+ children: t("collection.createNone", { defaultValue: "There is nothing here you can create." })
2440
+ })]
2441
+ });
2442
+ }
2443
+ //#endregion
2444
+ //#region src/frames/obligations.tsx
2445
+ const SlotMountsContext = (0, react.createContext)(null);
2446
+ function useSlotOnce(slot) {
2447
+ const mounts = (0, react.useContext)(SlotMountsContext);
2448
+ const token = (0, react.useId)();
2449
+ const first = mounts === null || mounts.claim(slot, token);
2450
+ (0, react.useEffect)(() => {
2451
+ if (mounts === null) return;
2452
+ mounts.claim(slot, token);
2453
+ return () => mounts.release(slot, token);
2454
+ }, [
2455
+ mounts,
2456
+ slot,
2457
+ token
2458
+ ]);
2459
+ (0, react.useEffect)(() => {
2460
+ if (!first) mounts?.twice(slot);
2461
+ }, [
2462
+ first,
2463
+ mounts,
2464
+ slot
2465
+ ]);
2466
+ return first;
2467
+ }
2468
+ function FrameObligations({ id, mode, showActions, root, children }) {
2469
+ const told = (0, react.useRef)(new Set());
2470
+ const counts = (0, react.useRef)(new Map());
2471
+ const owners = (0, react.useRef)(new Map());
2472
+ const tell = (key, write) => {
2473
+ if (told.current.has(key) || process.env.NODE_ENV === "production") return;
2474
+ told.current.add(key);
2475
+ write();
2476
+ };
2477
+ const latestId = (0, react.useRef)(id);
2478
+ latestId.current = id;
2479
+ const slotMounts = (0, react.useMemo)(() => ({
2480
+ claim(slot, token) {
2481
+ const owner = owners.current.get(slot);
2482
+ if (owner === void 0) {
2483
+ owners.current.set(slot, token);
2484
+ return true;
2485
+ }
2486
+ return owner === token;
2487
+ },
2488
+ release(slot, token) {
2489
+ if (owners.current.get(slot) === token) owners.current.delete(slot);
2490
+ },
2491
+ twice(slot) {
2492
+ tell(`slot-twice:${slot}`, () => console.error(`[burojs] frame.slot-twice: ${latestId.current} renders slots.${slot} twice; a slot renders at most once (body twice would mount every field twice under one form).`));
2493
+ }
2494
+ }), []);
2495
+ const pieces = (0, react.useMemo)(() => ({
2496
+ stub: false,
2497
+ mount(piece) {
2498
+ counts.current.set(piece, (counts.current.get(piece) ?? 0) + 1);
2499
+ return () => counts.current.set(piece, (counts.current.get(piece) ?? 1) - 1);
2500
+ }
2501
+ }), []);
2502
+ return (0, react_jsx_runtime.jsx)(SlotMountsContext.Provider, {
2503
+ value: slotMounts,
2504
+ children: (0, react_jsx_runtime.jsxs)(_burojs_react.FrameCheckContext.Provider, {
2505
+ value: pieces,
2506
+ children: [children, (0, react_jsx_runtime.jsx)(ObligationCheck, { check: () => {
2507
+ const mounted = (piece) => (counts.current.get(piece) ?? 0) > 0;
2508
+ if (mode !== "show" && !mounted("FormActions")) tell("no-form-actions", () => console.error(`[burojs] frame.no-form-actions: ${id} renders no <FormActions/> in ${mode}; nothing can submit or cancel the form.`));
2509
+ if (mode === "show" && showActions && !mounted("RecordActions")) tell("no-actions", () => console.warn(`[burojs] screen.no-actions: ${id} renders no <RecordActions/> in show, and the resource has item actions there.`));
2510
+ if (root.current?.querySelector("h1") != null) tell("h1", () => console.error(`[burojs] ${id} renders an h1; the route draws the screen's one h1.`));
2511
+ } })]
2512
+ })
2513
+ });
2514
+ }
2515
+ function ObligationCheck({ check }) {
2516
+ (0, react.useEffect)(() => {
2517
+ check();
2518
+ });
2519
+ return null;
2520
+ }
2521
+ //#endregion
2522
+ //#region src/frames/slot-wrapper.tsx
2523
+ function DraftBanner() {
2524
+ const { resource, mode, controller } = (0, _burojs_react.useRecordFrame)();
2525
+ const t = (0, _burojs_react.useOptionalT)();
2526
+ const tid = (0, _burojs_react.useTestIds)();
2527
+ const { draft } = controller;
2528
+ if (mode === "show" || draft.pending === null) return null;
2529
+ return (0, react_jsx_runtime.jsxs)("div", {
2530
+ "data-testid": tid.formDraftBanner(resource, mode),
2531
+ role: "status",
2532
+ "aria-live": "polite",
2533
+ className: "flex flex-wrap items-center gap-2 rounded-md border border-warning/50 bg-warning/10 px-3 py-2 text-sm",
2534
+ children: [
2535
+ (0, react_jsx_runtime.jsx)("span", {
2536
+ className: "font-medium",
2537
+ children: draft.recordChanged ? t("draft.recordChanged") : t("draft.found", { params: { time: timeAgo(draft.pending.savedAt, t) } })
2538
+ }),
2539
+ draft.recordChanged ? null : (0, react_jsx_runtime.jsx)("span", {
2540
+ className: "text-muted-foreground",
2541
+ children: t("draft.restorePrompt")
2542
+ }),
2543
+ (0, react_jsx_runtime.jsxs)("div", {
2544
+ className: "ml-auto flex gap-2",
2545
+ children: [draft.recordChanged ? null : (0, react_jsx_runtime.jsx)(require_button.Button, {
2546
+ type: "button",
2547
+ size: "sm",
2548
+ variant: "outline",
2549
+ "data-testid": tid.formDraftRestore(resource, mode),
2550
+ onClick: draft.restore,
2551
+ children: t("draft.restore")
2552
+ }), (0, react_jsx_runtime.jsx)(require_button.Button, {
2553
+ type: "button",
2554
+ size: "sm",
2555
+ variant: "ghost",
2556
+ "data-testid": tid.formDraftDiscard(resource, mode),
2557
+ onClick: draft.discard,
2558
+ children: t("draft.discard")
2559
+ })]
2560
+ })
2561
+ ]
2562
+ });
2563
+ }
2564
+ function timeAgo(savedAt, t) {
2565
+ const then = new Date(savedAt).getTime();
2566
+ if (!Number.isFinite(then)) return t("draft.timeAgoRecently");
2567
+ const diff = Date.now() - then;
2568
+ if (diff < 6e4) return t("draft.timeAgoMoment");
2569
+ if (diff < 36e5) return t("draft.timeAgoMinutes", { count: Math.round(diff / 6e4) });
2570
+ if (diff < 864e5) return t("draft.timeAgoHours", { count: Math.round(diff / 36e5) });
2571
+ return t("draft.timeAgoDays", { count: Math.round(diff / 864e5) });
2572
+ }
2573
+ function frameRecordId(frame, def) {
2574
+ if (frame.recordId !== void 0) return frame.recordId;
2575
+ const id = (0, _burojs_react.recordKeyOf)(def, frame.record);
2576
+ return typeof id === "string" || typeof id === "number" ? String(id) : void 0;
2577
+ }
2578
+ function BodySlot() {
2579
+ const frame = (0, _burojs_react.useRecordFrame)();
2580
+ const { resource, mode, controller } = frame;
2581
+ const chrome = require_place_node.useFrameChrome();
2582
+ const tid = (0, _burojs_react.useTestIds)();
2583
+ const id = frameRecordId(frame, (0, _burojs_react.useApp)().registry.get(resource));
2584
+ const tree = (0, react_jsx_runtime.jsx)("div", {
2585
+ "data-buro-region": "record-body",
2586
+ "data-buro-slot": _burojs_core.FORM_SLOT,
2587
+ children: (0, react_jsx_runtime.jsx)(require_place_node.ScreenTree, {
2588
+ region: "record",
2589
+ slot: _burojs_core.FORM_SLOT,
2590
+ resource,
2591
+ mode,
2592
+ compiled: controller.screen,
2593
+ controller
2594
+ })
2595
+ });
2596
+ if (mode === "show") return tree;
2597
+ return (0, react_jsx_runtime.jsxs)("form", {
2598
+ id: chrome.formId,
2599
+ noValidate: true,
2600
+ "data-testid": tid.form(resource, mode, id),
2601
+ onSubmit: (event) => {
2602
+ event.preventDefault();
2603
+ const steps = controller.steps;
2604
+ if (steps !== null && steps.current !== void 0 && steps.current !== steps.ids[steps.ids.length - 1]) steps.next();
2605
+ else chrome.submit();
2606
+ },
2607
+ className: "flex flex-col gap-4",
2608
+ children: [(0, react_jsx_runtime.jsx)(DraftBanner, {}), tree]
2609
+ });
2610
+ }
2611
+ function DisplaySlot({ name }) {
2612
+ const { resource, mode, controller } = (0, _burojs_react.useRecordFrame)();
2613
+ return (0, react_jsx_runtime.jsx)(require_place_node.ScreenTree, {
2614
+ region: "record",
2615
+ slot: name,
2616
+ resource,
2617
+ mode,
2618
+ compiled: controller.screen,
2619
+ controller
2620
+ });
2621
+ }
2622
+ function SlotWrapper({ name }) {
2623
+ if (!useSlotOnce(name)) return null;
2624
+ return name === _burojs_core.FORM_SLOT ? (0, react_jsx_runtime.jsx)(BodySlot, {}) : (0, react_jsx_runtime.jsx)(DisplaySlot, { name });
2625
+ }
2626
+ //#endregion
2627
+ //#region src/frames/record-frame-host.tsx
2628
+ const NO_ROOT = { current: null };
2629
+ function drawnFields(roots, compiled, out) {
2630
+ for (const node of roots) {
2631
+ if (node.state === "absent") continue;
2632
+ const field = node.field ?? compiled.nodes[node.index]?.field;
2633
+ if (node.kind === "field" && field !== void 0 && node.state === "ready") out.add(field);
2634
+ drawnFields(node.children, compiled, out);
2635
+ }
2636
+ }
2637
+ function frameRecord(record, compiled, slots, idField, visible = () => true) {
2638
+ if (record === void 0 || compiled === null || slots === void 0) return void 0;
2639
+ const drawn = new Set();
2640
+ for (const roots of Object.values(slots)) drawnFields(roots, compiled, drawn);
2641
+ const declarations = new Map(compiled.fields.map((entry) => [entry.name, entry.declaration]));
2642
+ const out = {};
2643
+ if (Object.hasOwn(record, idField)) out[idField] = record[idField];
2644
+ for (const name of drawn) {
2645
+ if (!Object.hasOwn(record, name) || !visible(name)) continue;
2646
+ if ((0, _burojs_core.fieldSensitivity)(declarations.get(name)) !== void 0) continue;
2647
+ out[name] = record[name];
2648
+ }
2649
+ return Object.freeze(out);
2650
+ }
2651
+ function declaredSlots(compiled) {
2652
+ if (compiled === null) return [];
2653
+ return Object.entries(compiled.slots).filter(([, nodes]) => nodes.length > 0).map(([name]) => name);
2654
+ }
2655
+ function useEffectiveFrame(instance) {
2656
+ const { resource, mode, controller } = (0, _burojs_react.useRecordFrame)();
2657
+ const compiled = controller.screen;
2658
+ const missing = (0, react.useMemo)(() => {
2659
+ if (instance === void 0 || instance.for !== "record") return void 0;
2660
+ const own = new Set(Object.keys(instance.slots));
2661
+ return declaredSlots(compiled).find((slot) => !own.has(slot));
2662
+ }, [instance, compiled]);
2663
+ const told = (0, react.useRef)(false);
2664
+ const instanceId = instance === void 0 ? void 0 : (0, _burojs_core.formatEntityRef)(instance.ref);
2665
+ (0, react.useEffect)(() => {
2666
+ if (missing === void 0 || told.current || process.env.NODE_ENV === "production") return;
2667
+ told.current = true;
2668
+ console.error(`[burojs] <RecordScreen frame={${instanceId}}> lacks the slot ${missing} that ${resource}'s ${mode} screen fills; the screen's own frame draws it.`);
2669
+ }, [
2670
+ missing,
2671
+ instanceId,
2672
+ resource,
2673
+ mode
2674
+ ]);
2675
+ if (instance !== void 0 && instance.for === "record" && missing === void 0 && compiled !== null) return {
2676
+ ref: instance.ref,
2677
+ slotNames: Object.keys(instance.slots)
2678
+ };
2679
+ return {
2680
+ ref: compiled?.frame ?? _burojs_core.builtinFrames.record.ref,
2681
+ slotNames: compiled === null ? ["header", _burojs_core.FORM_SLOT] : Object.keys(compiled.slots)
2682
+ };
2683
+ }
2684
+ function RecordFrameView({ frame: instance }) {
2685
+ const { resource, mode, controller, record } = (0, _burojs_react.useRecordFrame)();
2686
+ const chrome = require_place_node.useFrameChrome();
2687
+ const quick = (0, _burojs_react.useQuickEntry)();
2688
+ const app = (0, _burojs_react.useApp)();
2689
+ const catalog = (0, _burojs_react.useFrameImplementations)();
2690
+ const { ref, slotNames } = useEffectiveFrame(instance);
2691
+ const id = (0, _burojs_core.formatEntityRef)(ref);
2692
+ const resolved = (0, react.useMemo)(() => require_place_node.resolveFrameView(ref, catalog, "record"), [ref, catalog]);
2693
+ const t = (0, _burojs_react.useFrameT)(id);
2694
+ const compiled = controller.screen;
2695
+ const plan = controller.plan;
2696
+ const slots = {};
2697
+ for (const name of slotNames) {
2698
+ if (name === _burojs_core.FORM_SLOT) {
2699
+ slots[name] = (0, react_jsx_runtime.jsx)(SlotWrapper, { name }, name);
2700
+ continue;
2701
+ }
2702
+ slots[name] = (plan?.slots[name] ?? []).every((node) => node.state === "absent") ? null : (0, react_jsx_runtime.jsx)(SlotWrapper, { name }, name);
2703
+ }
2704
+ slots[_burojs_core.FORM_SLOT] ??= (0, react_jsx_runtime.jsx)(SlotWrapper, { name: _burojs_core.FORM_SLOT });
2705
+ const idField = app.registry.get(resource)?.data?.idField ?? "id";
2706
+ const access = (0, _burojs_react.useFieldAccess)(resource, "record", record === void 0 ? void 0 : (0, _burojs_react.policyRecordOf)(controller, record));
2707
+ const projected = (0, react.useMemo)(() => frameRecord(record, compiled, plan?.slots, idField, (name) => access[name]?.view === "visible"), [
2708
+ record,
2709
+ compiled,
2710
+ plan,
2711
+ idField,
2712
+ access
2713
+ ]);
2714
+ const quickHost = chrome.hostTitle === true && quick !== null;
2715
+ const props = {
2716
+ slots,
2717
+ host: quickHost ? quick.host : "page",
2718
+ mode,
2719
+ screen: {
2720
+ resource,
2721
+ entry: quickHost ? "quick" : "route"
2722
+ },
2723
+ record: mode === "create" ? void 0 : projected,
2724
+ t
2725
+ };
2726
+ const policyRecord = (0, _burojs_react.policyRecordOf)(controller, record);
2727
+ const rowId = record?.[idField];
2728
+ const actionRow = (0, react.useMemo)(() => ({
2729
+ ...policyRecord ?? {},
2730
+ id: typeof rowId === "string" || typeof rowId === "number" ? String(rowId) : ""
2731
+ }), [policyRecord, rowId]);
2732
+ const showItemActions = require_place_node.useShownItemActions(resource, actionRow, "show", void 0, controller.sources);
2733
+ const showActions = mode === "show" && record !== void 0 && showItemActions.length > 0;
2734
+ const View = resolved.view;
2735
+ const builtin = require_place_node.isBuiltinRecordView(resolved);
2736
+ return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [builtin ? null : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(require_place_node.HeaderTypeNotice, { resource }), (0, react_jsx_runtime.jsx)(require_place_node.ChangeTypeButton, {})] }), (0, react_jsx_runtime.jsx)(require_place_node.TypeChromeDrawnContext.Provider, {
2737
+ value: !builtin,
2738
+ children: (0, react_jsx_runtime.jsx)(react.Suspense, {
2739
+ fallback: (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "loading" }),
2740
+ children: (0, react_jsx_runtime.jsx)(FrameObligations, {
2741
+ id,
2742
+ mode,
2743
+ showActions,
2744
+ root: chrome.root ?? NO_ROOT,
2745
+ children: (0, react_jsx_runtime.jsx)(View, { ...props })
2746
+ })
2747
+ })
2748
+ })] });
2749
+ }
2750
+ function useResourceDimensionOptions(dimension, resource, labelField) {
2751
+ const def = (0, _burojs_react.useApp)().registry.get(resource);
2752
+ const rowTitle = require_relation_create.useRowTitle(resource, labelField ?? def?.displayField);
2753
+ const rows = (0, _burojs_react.useList)(resource, {
2754
+ pagination: {
2755
+ kind: "offset",
2756
+ page: 1,
2757
+ pageSize: 100
2758
+ },
2759
+ total: false,
2760
+ scope: {
2761
+ default: "session",
2762
+ dimensions: { [dimension]: "none" }
2763
+ }
2764
+ }).data?.data;
2765
+ return (0, react.useMemo)(() => (rows ?? []).flatMap((row) => {
2766
+ const key = (0, _burojs_react.recordKeyOf)(def, row);
2767
+ return key === null || key === void 0 ? [] : [{
2768
+ value: key,
2769
+ label: rowTitle(row)
2770
+ }];
2771
+ }), [
2772
+ rows,
2773
+ def,
2774
+ rowTitle
2775
+ ]);
2776
+ }
2777
+ //#endregion
2778
+ //#region src/record/scope-mismatch-banner.tsx
2779
+ const asList = (value) => value === null ? [] : Array.isArray(value) ? value : [value];
2780
+ const isScalar = (value) => typeof value === "string" || typeof value === "number" || typeof value === "boolean";
2781
+ function ScopeMismatchBanner(props) {
2782
+ const app = (0, _burojs_react.useApp)();
2783
+ const mapping = app.registry.get(props.resource)?.data?.scope;
2784
+ if (app.scope === void 0 || mapping === void 0 || props.record === void 0) return null;
2785
+ return (0, react_jsx_runtime.jsx)(Banner, {
2786
+ ...props,
2787
+ record: props.record,
2788
+ mapping
2789
+ });
2790
+ }
2791
+ function Banner({ record, mapping, kind = "record" }) {
2792
+ const scope = (0, _burojs_react.useScope)();
2793
+ const chromeT = (0, _burojs_react.useChromeT)();
2794
+ const differences = (0, react.useMemo)(() => {
2795
+ const out = [];
2796
+ for (const [dimension, target] of Object.entries(mapping)) {
2797
+ const definition = scope.definition?.dimensions[dimension];
2798
+ if (definition === void 0 || definition.select === "none") continue;
2799
+ const selected = asList(scope.selection[dimension] ?? null);
2800
+ if (selected.length === 0) continue;
2801
+ const column = (0, _burojs_core.scopeColumnOf)(target);
2802
+ if (!Object.hasOwn(record, column)) continue;
2803
+ const held = record[column];
2804
+ if (held === null || held === void 0 || held === "") {
2805
+ if (kind === "created" || "field" in target && target.empty === "shared") continue;
2806
+ out.push({
2807
+ dimension,
2808
+ value: null,
2809
+ selected,
2810
+ select: definition.select
2811
+ });
2812
+ continue;
2813
+ }
2814
+ if (!isScalar(held)) continue;
2815
+ if (selected.some((value) => String(value) === String(held))) continue;
2816
+ out.push({
2817
+ dimension,
2818
+ value: held,
2819
+ selected,
2820
+ select: definition.select
2821
+ });
2822
+ }
2823
+ return out;
2824
+ }, [
2825
+ mapping,
2826
+ record,
2827
+ scope.definition,
2828
+ scope.selection,
2829
+ kind
2830
+ ]);
2831
+ if (differences.length === 0) return null;
2832
+ const apply = () => {
2833
+ for (const difference of differences) scope.select(difference.dimension, difference.value === null ? null : difference.select === "multiple" ? [difference.value] : difference.value);
2834
+ };
2835
+ return (0, react_jsx_runtime.jsxs)("div", {
2836
+ role: "status",
2837
+ "data-testid": "scope-mismatch:banner",
2838
+ className: "flex flex-wrap items-center justify-between gap-3 rounded-md border bg-muted/50 px-3 py-2 text-sm",
2839
+ children: [(0, react_jsx_runtime.jsxs)("div", {
2840
+ className: "space-y-1",
2841
+ children: [(0, react_jsx_runtime.jsx)("p", {
2842
+ className: "font-medium",
2843
+ children: kind === "created" ? chromeT("scope.mismatch.createdOutside", { defaultValue: "Created outside the current scope" }) : chromeT("scope.mismatch.title", { defaultValue: "This record is outside the current scope" })
2844
+ }), (0, react_jsx_runtime.jsx)("ul", {
2845
+ className: "text-muted-foreground",
2846
+ children: differences.map((difference) => (0, react_jsx_runtime.jsx)(DifferenceLine, {
2847
+ difference,
2848
+ definition: scope.definition.dimensions[difference.dimension]
2849
+ }, difference.dimension))
2850
+ })]
2851
+ }), (0, react_jsx_runtime.jsx)(require_button.Button, {
2852
+ type: "button",
2853
+ size: "sm",
2854
+ "data-testid": "scope-mismatch:switch",
2855
+ onClick: apply,
2856
+ children: chromeT("scope.mismatch.switch", { defaultValue: "Switch" })
2857
+ })]
2858
+ });
2859
+ }
2860
+ function DifferenceLine(props) {
2861
+ const source = props.definition.values;
2862
+ if (source !== void 0 && !Array.isArray(source)) {
2863
+ const { resource, label } = source;
2864
+ return (0, react_jsx_runtime.jsx)(ResourceLine, {
2865
+ ...props,
2866
+ resource,
2867
+ ...label ? { labelField: label } : {}
2868
+ });
2869
+ }
2870
+ return (0, react_jsx_runtime.jsx)(LineText, {
2871
+ difference: props.difference,
2872
+ options: source ?? []
2873
+ });
2874
+ }
2875
+ function ResourceLine({ difference, resource, labelField }) {
2876
+ const options = useResourceDimensionOptions(difference.dimension, resource, labelField);
2877
+ return (0, react_jsx_runtime.jsx)(LineText, {
2878
+ difference,
2879
+ options
2880
+ });
2881
+ }
2882
+ function LineText({ difference, options }) {
2883
+ const chromeT = (0, _burojs_react.useChromeT)();
2884
+ const labelOf = (value) => options.find((option) => String(option.value) === String(value))?.label ?? String(value);
2885
+ const field = (0, _burojs_core.humanizeKey)(difference.dimension);
2886
+ const item = difference.value === null ? chromeT("scope.mismatch.empty", { defaultValue: "not set" }) : labelOf(difference.value);
2887
+ const items = difference.selected.map(labelOf).join(", ");
2888
+ return (0, react_jsx_runtime.jsx)("li", {
2889
+ "data-testid": `scope-mismatch:line:${difference.dimension}`,
2890
+ children: chromeT("scope.mismatch.line", {
2891
+ params: {
2892
+ field,
2893
+ item,
2894
+ items
2895
+ },
2896
+ defaultValue: `${field}: ${item} (selected: ${items})`
2897
+ })
2898
+ });
2899
+ }
2900
+ //#endregion
2901
+ //#region src/record/type-offer.tsx
2902
+ function TypeOffer({ resource, offer, onChoose }) {
2903
+ const app = (0, _burojs_react.useApp)();
2904
+ const t = (0, _burojs_react.useOptionalT)();
2905
+ const tid = (0, _burojs_react.useTestIds)();
2906
+ const def = app.registry.get(resource);
2907
+ const by = def?.types?.by;
2908
+ const field = by === void 0 ? void 0 : def?.fields[by];
2909
+ const ref = def?.ref ?? {
2910
+ namespace: "default",
2911
+ id: resource
2912
+ };
2913
+ return (0, react_jsx_runtime.jsxs)("section", {
2914
+ "aria-labelledby": "type-offer-title",
2915
+ className: "flex flex-col gap-3",
2916
+ children: [(0, react_jsx_runtime.jsxs)("div", {
2917
+ className: "flex flex-col gap-1",
2918
+ children: [(0, react_jsx_runtime.jsx)("h2", {
2919
+ id: "type-offer-title",
2920
+ className: "text-base font-semibold",
2921
+ children: t("create.typeOffer.title", { defaultValue: "Choose a type" })
2922
+ }), (0, react_jsx_runtime.jsx)("p", {
2923
+ className: "text-sm text-muted-foreground",
2924
+ children: t("create.typeOffer.hint", { defaultValue: "The type decides which fields the record has." })
2925
+ })]
2926
+ }), offer.status === "pending" ? (0, react_jsx_runtime.jsxs)("div", {
2927
+ "aria-busy": "true",
2928
+ className: "flex flex-col gap-2",
2929
+ children: [(0, react_jsx_runtime.jsx)(require_skeleton.Skeleton, { className: "h-10 w-full" }), (0, react_jsx_runtime.jsx)(require_skeleton.Skeleton, { className: "h-10 w-full" })]
2930
+ }) : offer.types.length === 0 ? (0, react_jsx_runtime.jsx)("p", {
2931
+ role: "status",
2932
+ className: "text-sm text-muted-foreground",
2933
+ children: t("create.typeOffer.empty", { defaultValue: "No type can be created here." })
2934
+ }) : (0, react_jsx_runtime.jsx)("ul", {
2935
+ className: "grid grid-cols-1 gap-2 sm:grid-cols-2",
2936
+ children: offer.types.map((type) => (0, react_jsx_runtime.jsx)("li", { children: (0, react_jsx_runtime.jsx)("button", {
2937
+ type: "button",
2938
+ "data-testid": tid.typeOffer(resource, type),
2939
+ onClick: () => onChoose(type),
2940
+ className: "flex w-full items-center gap-2 rounded-md border px-3 py-2 text-left text-sm hover:bg-muted focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring",
2941
+ children: by === void 0 || field === void 0 ? type : (0, react_jsx_runtime.jsx)(require_place_node.FieldDisplay, {
2942
+ resource: ref,
2943
+ name: by,
2944
+ field,
2945
+ value: type,
2946
+ fallback: (0, react_jsx_runtime.jsx)("span", { children: type })
2947
+ })
2948
+ }) }, type))
2949
+ })]
2950
+ });
2951
+ }
2952
+ //#endregion
2953
+ //#region src/record/record-screen.tsx
2954
+ function isAbort(error) {
2955
+ if (error === null || typeof error !== "object" && typeof error !== "function") return false;
2956
+ try {
2957
+ return error.name === "AbortError";
2958
+ } catch {
2959
+ return false;
2960
+ }
2961
+ }
2962
+ const NO_ISSUES = Object.freeze([]);
2963
+ const APPLIED_UNREADABLE = Object.freeze({
2964
+ code: "applied-unreadable",
2965
+ message: Object.freeze({
2966
+ key: "errors.appliedUnreadable",
2967
+ default: "Saved. The server's answer could not be read, so the screen may not show the latest values."
2968
+ }),
2969
+ path: Object.freeze([]),
2970
+ source: "server",
2971
+ severity: "info"
2972
+ });
2973
+ function issuesOf(error) {
2974
+ if (error === null || typeof error !== "object") return void 0;
2975
+ try {
2976
+ const descriptor = Object.getOwnPropertyDescriptor(error, "issues");
2977
+ return descriptor !== void 0 && "value" in descriptor ? descriptor.value : void 0;
2978
+ } catch {
2979
+ return;
2980
+ }
2981
+ }
2982
+ const NO_EDITED = new Set();
2983
+ function sameValue(a, b) {
2984
+ if (Object.is(a, b)) return true;
2985
+ try {
2986
+ return JSON.stringify(a) === JSON.stringify(b);
2987
+ } catch {
2988
+ return false;
2989
+ }
2990
+ }
2991
+ function RecordFrameHost(props) {
2992
+ const { resource, mode } = props;
2993
+ const [failed, setFailed] = (0, react.useState)(NO_ISSUES);
2994
+ const named = (0, react.useMemo)(() => failed.length === 0 ? NO_ISSUES : (0, _burojs_core.routeServerIssues)({ issues: failed }, (segment) => segment, (field) => field !== "_form").fields, [failed]);
2995
+ const atFailure = (0, react.useRef)({});
2996
+ const [edited, setEdited] = (0, react.useState)(NO_EDITED);
2997
+ const controller = (0, _burojs_react.useFormController)({
2998
+ resource,
2999
+ mode,
3000
+ ...props.recordId === void 0 ? {} : { recordId: props.recordId },
3001
+ ...props.type === void 0 ? {} : { type: props.type },
3002
+ ...props.record === void 0 ? {} : { record: props.record },
3003
+ ...props.defaults === void 0 ? {} : { defaults: props.defaults },
3004
+ ...props.onSubmit === void 0 ? {} : { onSubmit: props.onSubmit },
3005
+ ...props.hostTitle ? { entry: "quick" } : {},
3006
+ serverIssues: named
3007
+ });
3008
+ const inputApplied = (0, react.useRef)(false);
3009
+ const { input } = props;
3010
+ const plan = controller.plan;
3011
+ (0, react.useEffect)(() => {
3012
+ if (inputApplied.current || input === void 0 || mode !== "create" || plan === null) return;
3013
+ inputApplied.current = true;
3014
+ for (const [key, value] of Object.entries(input)) if (plan.fields[key] === "active") controller.setValue(key, value);
3015
+ }, [
3016
+ input,
3017
+ mode,
3018
+ plan,
3019
+ controller
3020
+ ]);
3021
+ const tid = (0, _burojs_react.useTestIds)();
3022
+ const formId = `record-form-${(0, react.useId)()}`;
3023
+ const root = (0, react.useRef)(null);
3024
+ const [submitError, setSubmitError] = (0, react.useState)(void 0);
3025
+ const [submitApplied, setSubmitApplied] = (0, react.useState)(void 0);
3026
+ (0, react.useEffect)(() => {
3027
+ if (plan === null) return;
3028
+ const now = Object.keys(atFailure.current).filter((name) => !edited.has(name) && plan.fields[name] === "active" && !sameValue(controller.field(name).value, atFailure.current[name]));
3029
+ if (now.length > 0) setEdited((previous) => new Set([...previous, ...now]));
3030
+ }, [
3031
+ plan,
3032
+ controller,
3033
+ edited
3034
+ ]);
3035
+ const notify = require_success_notices.useNoticeSink(resource);
3036
+ const routeScreen = require_place_node.useIsRouteScreen();
3037
+ const leavesOnCreate = mode === "create" && routeScreen;
3038
+ const [created, setCreated] = (0, react.useState)(false);
3039
+ const createdRef = (0, react.useRef)(false);
3040
+ const latest = (0, react.useRef)({
3041
+ controller,
3042
+ onSuccess: props.onSuccess,
3043
+ notify,
3044
+ leavesOnCreate
3045
+ });
3046
+ latest.current = {
3047
+ controller,
3048
+ onSuccess: props.onSuccess,
3049
+ notify,
3050
+ leavesOnCreate
3051
+ };
3052
+ const mounted = (0, react.useRef)(true);
3053
+ (0, react.useEffect)(() => {
3054
+ mounted.current = true;
3055
+ return () => {
3056
+ mounted.current = false;
3057
+ };
3058
+ }, []);
3059
+ const submit = (0, react.useCallback)(async () => {
3060
+ if (createdRef.current) return;
3061
+ setSubmitError(void 0);
3062
+ setSubmitApplied(void 0);
3063
+ setFailed(NO_ISSUES);
3064
+ setEdited(NO_EDITED);
3065
+ atFailure.current = {};
3066
+ const outcome = await latest.current.controller.submit();
3067
+ if (!mounted.current) return;
3068
+ if (latest.current.leavesOnCreate && (outcome.status === "submitted" || outcome.status === "failed" && outcome.applied === "yes")) {
3069
+ createdRef.current = true;
3070
+ setCreated(true);
3071
+ }
3072
+ if (outcome.status === "submitted") {
3073
+ const notices = (0, _burojs_core.successNoticesOf)(outcome.result);
3074
+ if (notices.length > 0) latest.current.notify(notices);
3075
+ latest.current.onSuccess?.(outcome.result);
3076
+ } else if (outcome.status === "failed" && outcome.applied === "yes") {
3077
+ latest.current.notify([APPLIED_UNREADABLE]);
3078
+ latest.current.onSuccess?.(void 0);
3079
+ } else if (outcome.status === "failed" && !isAbort(outcome.error)) {
3080
+ setSubmitError(outcome.error ?? null);
3081
+ setSubmitApplied(outcome.applied);
3082
+ const issues = (0, _burojs_core.normalizeIssueInputs)(issuesOf(outcome.error)).issues;
3083
+ const next = issues.length === 0 ? NO_ISSUES : Object.freeze(issues.map(_burojs_core.issueOfInput));
3084
+ const held = {};
3085
+ const now = latest.current.controller;
3086
+ for (const issue of next) {
3087
+ const head = issue.path[0];
3088
+ if (typeof head === "string" && head !== "_form" && now.plan?.fields[head] === "active") held[head] = now.field(head).value;
3089
+ }
3090
+ atFailure.current = held;
3091
+ setFailed(next);
3092
+ }
3093
+ }, []);
3094
+ const record = controller.record;
3095
+ const recordText = props.recordId === void 0 ? void 0 : String(props.recordId);
3096
+ const frame = (0, react.useMemo)(() => ({
3097
+ resource,
3098
+ recordId: recordText,
3099
+ mode,
3100
+ record,
3101
+ controller
3102
+ }), [
3103
+ resource,
3104
+ recordText,
3105
+ mode,
3106
+ record,
3107
+ controller
3108
+ ]);
3109
+ const { chooseType } = props;
3110
+ const typedAndAccepted = mode === "create" && controller.typeOffer !== null && controller.failure === null;
3111
+ const adapter = (0, _burojs_react.useOptionalRouterAdapter)();
3112
+ const hostRouter = routeScreen ? adapter : null;
3113
+ const guardText = (0, _burojs_react.useNavigationGuardText)();
3114
+ const changeType = (0, react.useMemo)(() => typedAndAccepted ? () => {
3115
+ if (hostRouter === null && latest.current.controller.isDirty && !window.confirm(`${guardText.title}\n\n${guardText.body}`)) return;
3116
+ chooseType(void 0);
3117
+ } : void 0, [
3118
+ typedAndAccepted,
3119
+ chooseType,
3120
+ hostRouter,
3121
+ guardText.title,
3122
+ guardText.body
3123
+ ]);
3124
+ const app = (0, _burojs_react.useApp)();
3125
+ const typesDecl = app.registry.get(resource)?.types;
3126
+ const loaded = controller.record;
3127
+ const unsupportedType = (0, react.useMemo)(() => {
3128
+ if (mode === "create" || typesDecl === void 0 || loaded === void 0) return void 0;
3129
+ const value = loaded[typesDecl.by];
3130
+ const name = typeof value === "string" && value !== "" ? value : null;
3131
+ return name !== null && typesDecl.items.some((item) => item.name === name) ? void 0 : name;
3132
+ }, [
3133
+ mode,
3134
+ typesDecl,
3135
+ loaded
3136
+ ]);
3137
+ const shownFailed = (0, react.useMemo)(() => edited.size === 0 ? failed : Object.freeze(failed.filter((issue) => {
3138
+ const head = issue.path[0];
3139
+ return typeof head !== "string" || !edited.has(head);
3140
+ })), [failed, edited]);
3141
+ const chrome = (0, react.useMemo)(() => ({
3142
+ ...props.onCancel === void 0 ? {} : { onCancel: props.onCancel },
3143
+ ...props.submitLabel === void 0 ? {} : { submitLabel: props.submitLabel },
3144
+ ...props.extraActions === void 0 ? {} : { extraActions: props.extraActions },
3145
+ ...changeType === void 0 ? {} : { changeType },
3146
+ ...unsupportedType === void 0 ? {} : { unsupportedType },
3147
+ ...props.hostTitle ? { hostTitle: true } : {},
3148
+ formId,
3149
+ submitError,
3150
+ ...submitApplied === void 0 ? {} : { submitApplied },
3151
+ serverIssues: shownFailed,
3152
+ ...created ? { created: true } : {},
3153
+ submit,
3154
+ root
3155
+ }), [
3156
+ props.onCancel,
3157
+ props.submitLabel,
3158
+ props.extraActions,
3159
+ changeType,
3160
+ unsupportedType,
3161
+ props.hostTitle,
3162
+ formId,
3163
+ submitError,
3164
+ submitApplied,
3165
+ shownFailed,
3166
+ created,
3167
+ submit
3168
+ ]);
3169
+ (0, _burojs_react.usePublishDocVariant)(mode === "show" ? resource : void 0, record);
3170
+ const failure = controller.failure;
3171
+ const offering = failure?.kind === "type-required" && controller.typeOffer !== null;
3172
+ (0, react.useEffect)(() => {
3173
+ if (failure === null || offering || process.env.NODE_ENV === "production") return;
3174
+ console.error(`[burojs] <RecordScreen resource="${resource}" mode="${mode}"> cannot render its screen: ${failure.kind === "screen" ? `${failure.failure.code} at ${failure.failure.path.join(".")}: ${failure.failure.message}` : "a typed create needs an accepted type"}.`);
3175
+ }, [
3176
+ failure,
3177
+ offering,
3178
+ resource,
3179
+ mode
3180
+ ]);
3181
+ const formControl = require_place_node.useFormControlOf(controller);
3182
+ const id = frameRecordId(frame, app.registry.get(frame.resource));
3183
+ const rootId = mode === "show" ? tid.pageShow(resource, id ?? "") : mode === "edit" ? tid.pageEdit(resource, id ?? "") : tid.pageCreate(resource);
3184
+ const claimedRoute = (0, react.useContext)(_burojs_react.RouteSourceContext);
3185
+ const scopeValues = mode === "show" ? controller.record : controller.values;
3186
+ return (0, react_jsx_runtime.jsx)(_burojs_react.RecordScopeProvider, {
3187
+ resource,
3188
+ ...recordText === void 0 ? {} : { recordId: recordText },
3189
+ values: scopeValues,
3190
+ create: mode === "create",
3191
+ children: (0, react_jsx_runtime.jsx)(_burojs_react.RouteSourceContext.Provider, {
3192
+ value: null,
3193
+ children: (0, react_jsx_runtime.jsx)(_burojs_react.ActionRouteContext.Provider, {
3194
+ value: claimedRoute,
3195
+ children: (0, react_jsx_runtime.jsx)(_burojs_react.RecordFrameContext.Provider, {
3196
+ value: frame,
3197
+ children: (0, react_jsx_runtime.jsx)(require_place_node.FrameChromeContext.Provider, {
3198
+ value: chrome,
3199
+ children: (0, react_jsx_runtime.jsxs)(require_place_node.FormControlProvider, {
3200
+ value: formControl,
3201
+ children: [(0, react_jsx_runtime.jsx)(require_place_node.DeepLinkScope, {
3202
+ plan: controller.plan,
3203
+ enabled: routeScreen && mode !== "create",
3204
+ children: (0, react_jsx_runtime.jsx)("div", {
3205
+ ref: root,
3206
+ "data-testid": rootId,
3207
+ className: "flex flex-col gap-[var(--buro-section-gap)]",
3208
+ children: offering && controller.typeOffer !== null ? (0, react_jsx_runtime.jsx)(TypeOffer, {
3209
+ resource,
3210
+ offer: controller.typeOffer,
3211
+ onChoose: (type) => chooseType(type)
3212
+ }) : failure !== null ? (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "error" }), (0, react_jsx_runtime.jsx)(require_place_node.FormActions, {})] }) : mode === "edit" && unsupportedType !== void 0 ? (0, react_jsx_runtime.jsx)(require_place_node.UndeclaredTypeNotice, {
3213
+ resource,
3214
+ typeValue: unsupportedType
3215
+ }) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(ScopeMismatchBanner, {
3216
+ resource,
3217
+ record: mode === "create" ? controller.trustedSeeds : controller.record,
3218
+ kind: mode === "create" ? "created" : "record"
3219
+ }), (0, react_jsx_runtime.jsx)(RecordFrameView, { ...props.frame === void 0 ? {} : { frame: props.frame } })] })
3220
+ })
3221
+ }), controller.checkGate === null ? null : (0, react_jsx_runtime.jsx)(require_check_confirm_dialog.CheckConfirmDialog, {
3222
+ state: controller.checkGate,
3223
+ testid: `${tid.form(resource, mode, id)}:checks`
3224
+ })]
3225
+ })
3226
+ })
3227
+ })
3228
+ })
3229
+ })
3230
+ });
3231
+ }
3232
+ function RecordScreen(props) {
3233
+ const app = (0, _burojs_react.useApp)();
3234
+ const routeScreen = (0, react.useContext)(require_place_node.RouteScreenClaimContext);
3235
+ const quickScreen = (0, react.useContext)(require_place_node.QuickScreenClaimContext);
3236
+ const route = (0, react.useContext)(_burojs_react.RouteSourceContext);
3237
+ const resourceInput = props.resource;
3238
+ const resource = (0, _burojs_core.resourceKey)(resourceInput);
3239
+ const tabs = require_place_node.useTabsUrlState(props.mode, routeScreen);
3240
+ const adapter = (0, _burojs_react.useOptionalRouterAdapter)();
3241
+ const router = routeScreen ? adapter : null;
3242
+ const navigate = (0, _burojs_react.useRouteNavigate)();
3243
+ const [local, setLocal] = (0, react.useState)(props.type);
3244
+ const [typeProp, setTypeProp] = (0, react.useState)(props.type);
3245
+ if (props.type !== typeProp) {
3246
+ setTypeProp(props.type);
3247
+ setLocal(props.type);
3248
+ }
3249
+ const [chose, setChose] = (0, react.useState)(false);
3250
+ const fromUrl = router?.searchParams.get("type") ?? void 0;
3251
+ const type = props.mode !== "create" ? props.type : router === null ? local : chose ? fromUrl : props.type ?? fromUrl;
3252
+ const chooseType = (0, react.useCallback)((next) => {
3253
+ if (router === null) {
3254
+ setLocal(next);
3255
+ return;
3256
+ }
3257
+ setChose(true);
3258
+ const params = new URLSearchParams(router.searchParams);
3259
+ if (next === void 0) params.delete("type");
3260
+ else params.set("type", next);
3261
+ const query = params.toString();
3262
+ navigate(query === "" ? router.pathname : `${router.pathname}?${query}`);
3263
+ }, [router, navigate]);
3264
+ if (app.registry.get(resource) === void 0) return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "not-found" });
3265
+ const { type: _declared, ...rest } = props;
3266
+ return (0, react_jsx_runtime.jsx)(require_place_node.RouteScreenClaimContext.Provider, {
3267
+ value: false,
3268
+ children: (0, react_jsx_runtime.jsx)(require_place_node.QuickScreenClaimContext.Provider, {
3269
+ value: false,
3270
+ children: (0, react_jsx_runtime.jsx)(_burojs_react.RouteSourceContext.Provider, {
3271
+ value: routeScreen || quickScreen ? route : null,
3272
+ children: (0, react_jsx_runtime.jsx)(require_place_node.RouteScreenContext.Provider, {
3273
+ value: routeScreen,
3274
+ children: (0, react_jsx_runtime.jsx)(_burojs_react.ResourceContext.Provider, {
3275
+ value: { resource },
3276
+ children: (0, react_jsx_runtime.jsx)(_burojs_react.ScreenStateProvider, {
3277
+ open: tabs.open,
3278
+ onOpenChange: tabs.onOpenChange,
3279
+ children: (0, react_jsx_runtime.jsx)(RecordFrameHost, {
3280
+ ...rest,
3281
+ ...type === void 0 ? {} : { type },
3282
+ resource,
3283
+ chooseType,
3284
+ hostTitle: quickScreen
3285
+ }, type ?? "")
3286
+ })
3287
+ })
3288
+ })
3289
+ })
3290
+ })
3291
+ });
3292
+ }
3293
+ //#endregion
3294
+ //#region src/layout/record-targets.ts
3295
+ function isShowAvailable(registry, resource) {
3296
+ return (0, _burojs_react.recordRouteAvailable)(registry, resource, "show");
3297
+ }
3298
+ function showTarget(resource, id) {
3299
+ return {
3300
+ resource,
3301
+ action: "show",
3302
+ params: { id }
3303
+ };
3304
+ }
3305
+ function listTarget(resource) {
3306
+ return {
3307
+ resource,
3308
+ action: "list"
3309
+ };
3310
+ }
3311
+ //#endregion
3312
+ //#region src/layout/route-trail.ts
3313
+ function useTrailContext() {
3314
+ const app = (0, _burojs_react.useApp)();
3315
+ const caps = (0, _burojs_react.useI18nCaps)();
3316
+ const isVisible = useNavVisible();
3317
+ const t = (0, _burojs_react.useT)();
3318
+ return {
3319
+ registry: app.registry,
3320
+ caps,
3321
+ isVisible,
3322
+ t
3323
+ };
3324
+ }
3325
+ function groupCrumbs(ctx, chain) {
3326
+ return chain.map((group) => {
3327
+ const key = require_record_trail_store.canonicalNavKey(group);
3328
+ return {
3329
+ label: (0, _burojs_core.resolveNavLabel)(ctx.caps, `groups.${key}`, (0, _burojs_core.declaredText)("chrome", group, "label")),
3330
+ href: groupNavHref(ctx.registry, key, ctx.isVisible),
3331
+ jump: true
3332
+ };
3333
+ });
3334
+ }
3335
+ function nonEmpty(crumbs) {
3336
+ return crumbs.length > 0 ? crumbs : void 0;
3337
+ }
3338
+ function recordActionOf(match) {
3339
+ if (match === null || match.kind !== "resource") return void 0;
3340
+ switch (match.action) {
3341
+ case "show":
3342
+ case "edit":
3343
+ case "create": return match.action;
3344
+ default: return;
3345
+ }
3346
+ }
3347
+ function pathOf(href) {
3348
+ const path = href.split(/[?#]/, 1)[0] ?? "";
3349
+ return path.length > 1 && path.endsWith("/") ? path.slice(0, -1) : path;
3350
+ }
3351
+ function originTrail(ctx, origin, depth = _burojs_react.ORIGIN_DEPTH) {
3352
+ const match = (0, _burojs_core.matchPath)(ctx.registry, pathOf(origin.href), { isVisible: ctx.isVisible });
3353
+ if (match === null) return void 0;
3354
+ switch (match.kind) {
3355
+ case "resource": {
3356
+ const key = require_record_trail_store.canonicalNavKey(match);
3357
+ if (match.action === "list") return {
3358
+ leading: groupCrumbs(ctx, match.groupChain),
3359
+ resource: key,
3360
+ resourceHref: origin.href,
3361
+ segments: []
3362
+ };
3363
+ const def = ctx.registry.get(key);
3364
+ const crumb = {
3365
+ label: match.action === "create" ? ctx.t("breadcrumbs.create") : origin.title || (match.id === void 0 ? "" : `#${match.id}`),
3366
+ href: origin.href
3367
+ };
3368
+ const parent = depth > 1 && origin.origin !== void 0 ? originTrail(ctx, origin.origin, depth - 1) : void 0;
3369
+ if (parent !== void 0) return {
3370
+ ...parent,
3371
+ segments: [...parent.segments, crumb]
3372
+ };
3373
+ return {
3374
+ leading: groupCrumbs(ctx, match.groupChain),
3375
+ resource: key,
3376
+ ...def !== void 0 && (0, _burojs_core.hasListPage)(def) ? { resourceHref: (0, _burojs_core.hrefFor)(ctx.registry, key) } : {},
3377
+ segments: [crumb]
3378
+ };
3379
+ }
3380
+ case "custom-page": {
3381
+ const trail = headerTrail(ctx, match);
3382
+ if (trail === null || trail.pageLabel === void 0) return void 0;
3383
+ return {
3384
+ leading: trail.leadingSegments ?? [],
3385
+ segments: [{
3386
+ label: trail.pageLabel,
3387
+ href: origin.href
3388
+ }]
3389
+ };
3390
+ }
3391
+ case "group-index": {
3392
+ const crumbs = groupCrumbs(ctx, match.groupChain);
3393
+ const own = crumbs[crumbs.length - 1];
3394
+ if (own === void 0) return void 0;
3395
+ return {
3396
+ leading: crumbs.slice(0, -1),
3397
+ segments: [{
3398
+ label: own.label,
3399
+ href: origin.href
3400
+ }]
3401
+ };
3402
+ }
3403
+ default: return;
3404
+ }
3405
+ }
3406
+ function recordTrail(ctx, input) {
3407
+ const { resource, action, id, origin } = input;
3408
+ if (origin !== void 0 && (action === "create" || id !== "")) return originRooted(ctx, input, origin);
3409
+ const leadingSegments = nonEmpty(groupCrumbs(ctx, input.groupChain));
3410
+ if (action !== "create" && id === "") return {
3411
+ resource,
3412
+ leadingSegments
3413
+ };
3414
+ const recordLabel = input.title || id;
3415
+ const middleSegments = action === "edit" ? [isShowAvailable(ctx.registry, resource) ? {
3416
+ label: recordLabel,
3417
+ href: (0, _burojs_react.resolveRoute)(showTarget(resource, id), ctx.registry)
3418
+ } : { label: recordLabel }] : void 0;
3419
+ const pageLabel = action === "create" ? ctx.t("breadcrumbs.create") : action === "edit" ? ctx.t("breadcrumbs.edit") : recordLabel;
3420
+ return {
3421
+ resource,
3422
+ recordId: action === "create" ? void 0 : id,
3423
+ pageLabel,
3424
+ leadingSegments,
3425
+ middleSegments
3426
+ };
3427
+ }
3428
+ function originRooted(ctx, input, origin) {
3429
+ const { resource, action, id } = input;
3430
+ const recordLabel = input.title || id;
3431
+ const drawn = new Set(origin.segments.flatMap((crumb) => crumb.href === void 0 ? [] : [pathOf(crumb.href)]));
3432
+ const own = action === "edit" ? [isShowAvailable(ctx.registry, resource) ? {
3433
+ label: recordLabel,
3434
+ href: (0, _burojs_react.resolveRoute)(showTarget(resource, id), ctx.registry)
3435
+ } : { label: recordLabel }].filter((crumb) => crumb.href === void 0 || !drawn.has(pathOf(crumb.href))) : [];
3436
+ const pageLabel = action === "create" ? ctx.t("breadcrumbs.create") : action === "edit" ? ctx.t("breadcrumbs.edit") : recordLabel;
3437
+ const recordId = action === "create" ? void 0 : id;
3438
+ const middleSegments = nonEmpty([...origin.segments, ...own]);
3439
+ if (origin.resource !== void 0 && ctx.registry.get(origin.resource) === ctx.registry.get(resource)) return {
3440
+ resource,
3441
+ recordId,
3442
+ pageLabel,
3443
+ leadingSegments: nonEmpty([...origin.leading]),
3444
+ ...origin.resourceHref === void 0 ? {} : { resourceHref: origin.resourceHref },
3445
+ middleSegments
3446
+ };
3447
+ const def = origin.resource === void 0 ? void 0 : ctx.registry.get(origin.resource);
3448
+ const resourceCrumb = origin.resource === void 0 ? [] : [{
3449
+ label: (0, _burojs_core.resolveResourceLabel)(ctx.caps, origin.resource, "plural", def),
3450
+ ...origin.resourceHref === void 0 ? {} : { href: origin.resourceHref }
3451
+ }];
3452
+ return {
3453
+ resource,
3454
+ recordId,
3455
+ pageLabel,
3456
+ rootSegments: [
3457
+ ...origin.leading,
3458
+ ...resourceCrumb,
3459
+ ...origin.segments,
3460
+ ...own
3461
+ ]
3462
+ };
3463
+ }
3464
+ function recordTrailRoute(registry, match) {
3465
+ if (match === null || match.kind !== "resource") return null;
3466
+ const resource = require_record_trail_store.canonicalNavKey(match);
3467
+ const { groupChain } = match;
3468
+ if (match.action === "flow") return {
3469
+ resource,
3470
+ action: "show",
3471
+ id: match.id ?? "",
3472
+ flow: match.flow ?? "",
3473
+ groupChain
3474
+ };
3475
+ const action = recordActionOf(match);
3476
+ if (action === void 0 || !(0, _burojs_react.recordRouteAvailable)(registry, resource, action)) return null;
3477
+ return {
3478
+ resource,
3479
+ action,
3480
+ id: action === "create" ? "" : match.id ?? "",
3481
+ groupChain
3482
+ };
3483
+ }
3484
+ function headerTrail(ctx, match) {
3485
+ if (match === null) return null;
3486
+ const key = require_record_trail_store.canonicalNavKey(match);
3487
+ switch (match.kind) {
3488
+ case "resource": {
3489
+ const leadingSegments = nonEmpty(groupCrumbs(ctx, match.groupChain));
3490
+ const action = recordActionOf(match);
3491
+ if (recordTrailRoute(ctx.registry, match) !== null) return null;
3492
+ if (action === void 0) return {
3493
+ resource: key,
3494
+ leadingSegments
3495
+ };
3496
+ return {
3497
+ resource: key,
3498
+ recordId: match.id,
3499
+ pageLabel: ctx.t("router.notFoundTitle"),
3500
+ leadingSegments
3501
+ };
3502
+ }
3503
+ case "custom-page": {
3504
+ const page = ctx.registry.customPages.get(match.name);
3505
+ if (page === void 0 || !ctx.isVisible(page)) return null;
3506
+ return {
3507
+ name: key,
3508
+ pageLabel: (0, _burojs_core.resolveNavLabel)(ctx.caps, `pages.${key}`, (0, _burojs_core.declaredText)("chrome", page, "label")),
3509
+ leadingSegments: nonEmpty(groupCrumbs(ctx, match.groupChain))
3510
+ };
3511
+ }
3512
+ case "group-index": {
3513
+ const own = match.groupChain[match.groupChain.length - 1];
3514
+ if (own === void 0) return null;
3515
+ const crumbs = groupCrumbs(ctx, match.groupChain);
3516
+ const current = crumbs[crumbs.length - 1];
3517
+ return {
3518
+ name: require_record_trail_store.canonicalNavKey(own),
3519
+ pageLabel: current.label,
3520
+ leadingSegments: nonEmpty(crumbs.slice(0, -1))
3521
+ };
3522
+ }
3523
+ default: return null;
3524
+ }
3525
+ }
3526
+ function recentStorageKey(userId) {
3527
+ return `buro:recent:v2:${userId}`;
3528
+ }
3529
+ function isRecent(value) {
3530
+ if (typeof value !== "object" || value === null) return false;
3531
+ const entry = value;
3532
+ return typeof entry.canonicalRef === "string" && typeof entry.id === "string" && typeof entry.label === "string" && (entry.labelField === void 0 || typeof entry.labelField === "string") && typeof entry.at === "string";
3533
+ }
3534
+ function parse(raw) {
3535
+ if (raw === null) return [];
3536
+ try {
3537
+ const parsed = JSON.parse(raw);
3538
+ if (typeof parsed !== "object" || parsed === null) return [];
3539
+ const envelope = parsed;
3540
+ if (envelope.version !== 2 || !Array.isArray(envelope.items)) return [];
3541
+ return envelope.items.filter(isRecent);
3542
+ } catch {
3543
+ return [];
3544
+ }
3545
+ }
3546
+ function readRecentRecords(store, userId) {
3547
+ return (0, _burojs_react.maybeThen)((0, _burojs_react.settle)(() => store.get(recentStorageKey(userId)), null), parse);
3548
+ }
3549
+ function writeRecentRecord(store, userId, entry) {
3550
+ const key = recentStorageKey(userId);
3551
+ return (0, _burojs_react.maybeThen)((0, _burojs_react.settle)(() => store.get(key), null), (raw) => {
3552
+ const envelope = {
3553
+ version: 2,
3554
+ items: [entry, ...parse(raw).filter((item) => !(item.canonicalRef === entry.canonicalRef && item.id === entry.id))].slice(0, 5)
3555
+ };
3556
+ return (0, _burojs_react.settle)(() => store.set(key, JSON.stringify(envelope)), void 0);
3557
+ });
3558
+ }
3559
+ function text$1(value) {
3560
+ return typeof value === "string" && value.length > 0 ? value : void 0;
3561
+ }
3562
+ const RECENT_LABEL_KEYS = [
3563
+ "alias",
3564
+ "name",
3565
+ "title",
3566
+ "label"
3567
+ ];
3568
+ function recentLabel(record, id, isGuarded = () => false) {
3569
+ for (const key of RECENT_LABEL_KEYS) {
3570
+ if (isGuarded(key)) continue;
3571
+ const value = text$1(record[key]);
3572
+ if (value !== void 0) return {
3573
+ label: value,
3574
+ field: key
3575
+ };
3576
+ }
3577
+ return { label: id };
3578
+ }
3579
+ //#endregion
3580
+ //#region src/layout/use-record-visit.ts
3581
+ function useRecordVisit(resource, record, opts) {
3582
+ const userId = (0, _burojs_react.useCurrentUserId)();
3583
+ const store = (0, _burojs_react.usePlatformStorage)().local;
3584
+ const app = (0, _burojs_react.useApp)();
3585
+ const def = app.registry.get(resource);
3586
+ const raw = (0, _burojs_react.recordKeyOf)(def, record);
3587
+ const id = typeof raw === "string" || typeof raw === "number" ? String(raw) : void 0;
3588
+ const fields = def?.fields;
3589
+ const rules = app.ruleSource?.rules(resource) ?? [];
3590
+ const isGuarded = (field) => fields !== void 0 && Object.hasOwn(fields, field) && (0, _burojs_core.fieldSensitivity)(fields[field]) !== void 0 || (0, _burojs_core.addressesCapability)(rules, "view", {
3591
+ kind: "field",
3592
+ name: field
3593
+ });
3594
+ const picked = record != null && id !== void 0 ? recentLabel(record, id, isGuarded) : void 0;
3595
+ const label = picked?.label;
3596
+ const labelField = picked?.field;
3597
+ const canonicalRef = require_check_confirm_dialog.canonicalResourceName(resource);
3598
+ const { isCurrentData } = opts;
3599
+ (0, react.useEffect)(() => {
3600
+ if (userId === null || !isCurrentData || id === void 0 || id === "") return;
3601
+ if (label === void 0) return;
3602
+ writeRecentRecord(store, userId, {
3603
+ canonicalRef,
3604
+ id,
3605
+ label,
3606
+ ...labelField === void 0 ? {} : { labelField },
3607
+ at: new Date().toISOString()
3608
+ });
3609
+ }, [
3610
+ store,
3611
+ userId,
3612
+ isCurrentData,
3613
+ canonicalRef,
3614
+ id,
3615
+ label,
3616
+ labelField
3617
+ ]);
3618
+ }
3619
+ //#endregion
3620
+ //#region src/layout/record-page.tsx
3621
+ function useMountedRef() {
3622
+ const mounted = (0, react.useRef)(true);
3623
+ (0, react.useEffect)(() => {
3624
+ mounted.current = true;
3625
+ return () => {
3626
+ mounted.current = false;
3627
+ };
3628
+ }, []);
3629
+ return mounted;
3630
+ }
3631
+ function RecordRouteHeader({ resource, action, id, record }) {
3632
+ const recordName = (0, _burojs_react.useRecordTitle)(resource, action === "create" ? void 0 : id, record);
3633
+ require_record_trail_store.usePublishRecordTrail(action === "create" ? null : {
3634
+ key: require_record_trail_store.recordTrailKey(resource, id, action),
3635
+ title: recordName
3636
+ });
3637
+ return (0, react_jsx_runtime.jsx)(require_place_node.PageHeader, {
3638
+ resource,
3639
+ mode: action,
3640
+ ...action === "create" ? {} : { recordName }
3641
+ });
3642
+ }
3643
+ function RecordShow({ resource, id, recordId, record, shown }) {
3644
+ return (0, react_jsx_runtime.jsxs)("div", { children: [(0, react_jsx_runtime.jsx)(RecordRouteHeader, {
3645
+ resource,
3646
+ action: "show",
3647
+ id,
3648
+ record: shown
3649
+ }), (0, react_jsx_runtime.jsx)(RecordScreen, {
3650
+ resource,
3651
+ mode: "show",
3652
+ recordId,
3653
+ record
3654
+ })] });
3655
+ }
3656
+ function RecordEdit({ resource, id, recordId, record, shown }) {
3657
+ const navigate = (0, _burojs_react.useRouteNavigate)();
3658
+ const mounted = useMountedRef();
3659
+ const back = (0, _burojs_react.useReturnTarget)(resource, "edit", id);
3660
+ return (0, react_jsx_runtime.jsxs)("div", { children: [(0, react_jsx_runtime.jsx)(RecordRouteHeader, {
3661
+ resource,
3662
+ action: "edit",
3663
+ id,
3664
+ record: shown
3665
+ }), (0, react_jsx_runtime.jsx)(RecordScreen, {
3666
+ resource,
3667
+ mode: "edit",
3668
+ recordId,
3669
+ record,
3670
+ onCancel: () => navigate(back, { origin: "inherit" }),
3671
+ onSuccess: () => {
3672
+ if (mounted.current) navigate(back, { origin: "inherit" });
3673
+ }
3674
+ })] });
3675
+ }
3676
+ function createdId(result) {
3677
+ const id = result?.id;
3678
+ return typeof id === "string" || typeof id === "number" ? String(id) : void 0;
3679
+ }
3680
+ function RecordCreate({ resource, defaults }) {
3681
+ const app = (0, _burojs_react.useApp)();
3682
+ const navigate = (0, _burojs_react.useRouteNavigate)();
3683
+ const mounted = useMountedRef();
3684
+ const adapter = (0, _burojs_react.useOptionalRouterAdapter)();
3685
+ const list = listTarget(resource);
3686
+ const back = (0, _burojs_react.useReturnTarget)(resource, "create");
3687
+ const type = adapter?.searchParams.get("type") ?? void 0;
3688
+ return (0, react_jsx_runtime.jsxs)("div", { children: [(0, react_jsx_runtime.jsx)(RecordRouteHeader, {
3689
+ resource,
3690
+ action: "create",
3691
+ id: ""
3692
+ }), (0, react_jsx_runtime.jsx)(require_place_node.RouteScreenClaimContext.Provider, {
3693
+ value: true,
3694
+ children: (0, react_jsx_runtime.jsx)(RecordScreen, {
3695
+ resource,
3696
+ mode: "create",
3697
+ ...type === void 0 ? {} : { type },
3698
+ ...defaults === void 0 ? {} : { defaults },
3699
+ onCancel: () => navigate(back, { origin: "inherit" }),
3700
+ onSuccess: (result) => {
3701
+ if (!mounted.current) return;
3702
+ const id = createdId(result);
3703
+ navigate(id !== void 0 && isShowAvailable(app.registry, resource) ? showTarget(resource, id) : list, { origin: "inherit" });
3704
+ }
3705
+ })
3706
+ })] });
3707
+ }
3708
+ function RecordRead({ resource, action, id, recordId }) {
3709
+ const app = (0, _burojs_react.useApp)();
3710
+ const def = app.registry.get(resource);
3711
+ const projection = (0, react.useMemo)(() => def === void 0 ? void 0 : (0, _burojs_core.dtoFields)(def, "record"), [def]);
3712
+ const query = (0, _burojs_react.useOne)(resource, {
3713
+ id: recordId,
3714
+ retry: _burojs_react.retryRecordRead,
3715
+ ...projection === void 0 ? {} : { projection }
3716
+ });
3717
+ const result = query.data;
3718
+ const read = result?.data;
3719
+ const projected = (0, _burojs_react.useProjectedRecord)(resource, read, { placeholder: query.isPlaceholderData });
3720
+ const showAvailability = (0, _burojs_react.useAvailabilityResolver)(resource, "show");
3721
+ const permissions = (0, _burojs_react.useCtx)((c) => c.permissions);
3722
+ const showRuled = (0, _burojs_core.addressesCapability)(app.ruleSource.rules(resource), "run", {
3723
+ kind: "action",
3724
+ name: "show"
3725
+ });
3726
+ const showHidden = showRuled && read !== null && typeof read === "object" && showAvailability("show", read).state !== "available";
3727
+ const showSettled = !showRuled || !query.isPlaceholderData && !(0, _burojs_core.permissionsUndecided)(permissions) && permissions?.status !== "error";
3728
+ useRecordVisit(resource, projected.status === "ready" && showSettled && !showHidden ? projected.value : null, { isCurrentData: !query.isPlaceholderData });
3729
+ const route = (0, react.useMemo)(() => Object.freeze({ id }), [id]);
3730
+ const availability = (0, _burojs_react.useAvailabilityResolver)(resource, "edit");
3731
+ if (result !== void 0) {
3732
+ const record = result.data;
3733
+ if (record === null || typeof record !== "object") return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "not-found" });
3734
+ const loaded = record;
3735
+ if (showRuled) {
3736
+ if (query.isPlaceholderData || (0, _burojs_core.permissionsUndecided)(permissions)) return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "loading" });
3737
+ if (permissions?.status === "error") return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "not-found" });
3738
+ if (showHidden) return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "not-found" });
3739
+ }
3740
+ if (projected.status === "pending" || projected.value === null) return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "loading" });
3741
+ const shown = projected.value;
3742
+ if (action === "edit") {
3743
+ const edit = availability("edit", loaded).state;
3744
+ if (edit === "hidden" || edit === "absent") return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "not-found" });
3745
+ if (edit === "undecided") return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "loading" });
3746
+ }
3747
+ return (0, react_jsx_runtime.jsx)(_burojs_react.RouteSourceContext.Provider, {
3748
+ value: route,
3749
+ children: (0, react_jsx_runtime.jsx)(require_place_node.RouteScreenClaimContext.Provider, {
3750
+ value: true,
3751
+ children: action === "edit" ? (0, react_jsx_runtime.jsx)(RecordEdit, {
3752
+ resource,
3753
+ id,
3754
+ recordId,
3755
+ record: loaded,
3756
+ shown
3757
+ }) : (0, react_jsx_runtime.jsx)(RecordShow, {
3758
+ resource,
3759
+ id,
3760
+ recordId,
3761
+ record: loaded,
3762
+ shown
3763
+ })
3764
+ })
3765
+ });
3766
+ }
3767
+ if (query.error != null) return (0, react_jsx_runtime.jsx)(require_relation_create.LoadError, {
3768
+ surface: "record",
3769
+ resource,
3770
+ error: query.error,
3771
+ retry: () => void query.refetch()
1976
3772
  });
3773
+ return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "loading" });
1977
3774
  }
1978
- function NavMain({ topLabel, iconForResource, iconForCustomPage, iconForSection, entryFilter }) {
1979
- const tree = useNavTree({ entryFilter });
3775
+ function RecordRouteBody(props) {
3776
+ if (props.action === "create") return (0, react_jsx_runtime.jsx)(RecordCreate, { ...props });
3777
+ if (props.id === "") return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "not-found" });
3778
+ return (0, react_jsx_runtime.jsx)(RecordReadRoute, { ...props });
3779
+ }
3780
+ function RecordReadRoute(props) {
3781
+ const recordId = (0, _burojs_react.useRouteRecordId)(props.resource, props.id);
3782
+ if (recordId === void 0) return (0, react_jsx_runtime.jsx)(require_relation_create.InvalidRouteId, { resource: props.resource });
3783
+ return (0, react_jsx_runtime.jsx)(RecordRead, {
3784
+ ...props,
3785
+ recordId
3786
+ });
3787
+ }
3788
+ function RecordRoute(props) {
3789
+ const missingRuntime = (0, _burojs_react.useOptionalDataRuntime)() === null;
3790
+ (0, react.useEffect)(() => {
3791
+ if (!missingRuntime || process.env.NODE_ENV === "production") return;
3792
+ console.error(`[burojs] The '${props.resource}' record page has no data runtime to read or write with: BuroProvider.dataRuntime is not set. Pass <BuroProvider dataRuntime={…}> (createDataRuntime from @burojs/react); until then record routes render the error state.`);
3793
+ }, [missingRuntime, props.resource]);
3794
+ if (missingRuntime) return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "error" });
3795
+ return (0, react_jsx_runtime.jsx)(RecordRouteBody, { ...props }, `${props.resource}:${props.id}`);
3796
+ }
3797
+ function recordPageProblem(input) {
3798
+ const { props, resource, action } = input;
3799
+ if (resource === void 0 || action === void 0) return "[burojs] <RecordPage> needs both `resource` and `action`. Pass them; until then it renders not-found.";
3800
+ if (!input.onRecordRoute) return `[burojs] <RecordPage resource="${resource}" action="${action}"> is not on a record route (show, edit or create), so it has no record to read: render it on one, under a RouterAdapterProvider. Until then it renders not-found.`;
3801
+ if (props.defaults !== void 0 && action !== "create") return `[burojs] <RecordPage defaults> applies to create only; on this '${action}' route it is ignored.`;
3802
+ return null;
3803
+ }
3804
+ const recordPageProblemsLogged = new WeakMap();
3805
+ function RecordPage(props) {
1980
3806
  const app = (0, _burojs_react.useApp)();
1981
- const tid = (0, _burojs_react.useTestIds)();
1982
- const t = (0, _burojs_react.useT)();
1983
- const RouterLink = require_toaster.useLinkComponent();
1984
- const navIcon = useNavIcon();
1985
- const intent = (0, _burojs_react.useOriginIntent)();
1986
- const jump = (entry) => () => {
1987
- if (entry.href !== void 0) intent(entry.href, "jump");
1988
- };
1989
- const ownOr = (own, name) => own !== void 0 ? own : navIcon(name);
1990
- const groupAsSection = (key) => app.registry.sections.get(key) ?? app.registry.groups.get(key);
1991
- const sectionIcon = (key, name) => {
1992
- const def = iconForSection ? groupAsSection(key) : void 0;
1993
- return ownOr(def ? iconForSection?.(def) : void 0, name);
1994
- };
1995
- const entryIcon = (entry) => {
1996
- if (entry.kind === "group") return sectionIcon(entry.key, entry.icon);
1997
- if (entry.kind === "page") {
1998
- const page = iconForCustomPage ? app.registry.customPages.get(entry.key) : void 0;
1999
- return ownOr(page ? iconForCustomPage?.(page) : void 0, entry.icon);
3807
+ const match = useMatch();
3808
+ const id = match === null ? null : match.id ?? "";
3809
+ const { action } = props;
3810
+ const resource = props.resource === void 0 ? void 0 : (0, _burojs_core.routeResourceKey)(props.resource);
3811
+ const onRecordRoute = recordActionOf(match) !== void 0;
3812
+ const problem = recordPageProblem({
3813
+ props,
3814
+ resource,
3815
+ action,
3816
+ onRecordRoute
3817
+ });
3818
+ (0, react.useEffect)(() => {
3819
+ if (problem === null || process.env.NODE_ENV === "production") return;
3820
+ let logged = recordPageProblemsLogged.get(app);
3821
+ if (logged === void 0) {
3822
+ logged = new Set();
3823
+ recordPageProblemsLogged.set(app, logged);
2000
3824
  }
2001
- const def = iconForResource ? app.registry.get(entry.key) : void 0;
2002
- return ownOr(def ? iconForResource?.(def) : void 0, entry.icon);
2003
- };
2004
- const entryTestId = (entry) => entry.kind === "page" ? tid.sidebarCustomPage(entry.key) : entry.kind === "group" ? tid.navGroup(entry.key) : tid.navMenuItem(entry.key);
2005
- const menuItem = (entry) => {
2006
- const icon = entryIcon(entry);
2007
- return (0, react_jsx_runtime.jsx)(SidebarMenuItem, { children: (0, react_jsx_runtime.jsx)(SidebarMenuButton, {
2008
- asChild: true,
2009
- isActive: entry.active,
2010
- tooltip: entry.label,
2011
- children: (0, react_jsx_runtime.jsxs)(RouterLink, {
2012
- href: entry.href ?? "",
2013
- "aria-current": entry.active ? "page" : void 0,
2014
- "data-testid": entryTestId(entry),
2015
- onClick: jump(entry),
2016
- children: [icon != null && (0, react_jsx_runtime.jsx)("span", {
2017
- className: "inline-flex h-4 w-4 items-center justify-center",
2018
- "aria-hidden": "true",
2019
- children: icon
2020
- }), (0, react_jsx_runtime.jsx)("span", { children: entry.label })]
2021
- })
2022
- }) }, entry.key);
3825
+ if (logged.has(problem)) return;
3826
+ logged.add(problem);
3827
+ console.error(problem);
3828
+ }, [app, problem]);
3829
+ if (resource === void 0 || action === void 0 || id === null || !onRecordRoute) return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "not-found" });
3830
+ const route = action === "create" ? {
3831
+ resource,
3832
+ action,
3833
+ defaults: props.defaults
3834
+ } : {
3835
+ resource,
3836
+ action
2023
3837
  };
2024
- const subItem = (entry) => (0, react_jsx_runtime.jsx)(SidebarMenuSubItem, { children: (0, react_jsx_runtime.jsx)(SidebarMenuSubButton, {
2025
- asChild: true,
2026
- isActive: entry.active,
2027
- children: (0, react_jsx_runtime.jsx)(RouterLink, {
2028
- href: entry.href ?? "",
2029
- "aria-current": entry.active ? "page" : void 0,
2030
- "data-testid": entryTestId(entry),
2031
- onClick: jump(entry),
2032
- children: (0, react_jsx_runtime.jsx)("span", { children: entry.label })
2033
- })
2034
- }) }, entry.key);
2035
- const [top, ...blocks] = tree;
2036
- return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [top !== void 0 && top.entries.length > 0 && (0, react_jsx_runtime.jsxs)(SidebarGroup, { children: [topLabel !== null && (0, react_jsx_runtime.jsx)(SidebarGroupLabel, { children: topLabel ?? t("nav.resources") }), (0, react_jsx_runtime.jsx)(SidebarGroupContent, { children: (0, react_jsx_runtime.jsx)(SidebarMenu, { children: top.entries.map(menuItem) }) })] }), blocks.map((block) => {
2037
- const key = block.key ?? "";
2038
- if (block.label === null) return (0, react_jsx_runtime.jsx)(SidebarGroup, { children: (0, react_jsx_runtime.jsx)(SidebarGroupContent, { children: (0, react_jsx_runtime.jsx)(SidebarMenu, { children: block.entries.map(menuItem) }) }) }, key);
2039
- if (block.collapsible) return (0, react_jsx_runtime.jsx)(CollapsibleNavSection, {
2040
- name: key,
2041
- label: block.label,
2042
- icon: sectionIcon(key, block.icon),
2043
- hasActiveChild: block.active,
2044
- declaredOpen: block.defaultOpen,
2045
- children: block.entries.map(subItem)
2046
- }, key);
2047
- return (0, react_jsx_runtime.jsxs)(SidebarGroup, {
2048
- "data-testid": `sidebar-section-group:${key}`,
2049
- children: [(0, react_jsx_runtime.jsx)(SidebarGroupLabel, {
2050
- "data-testid": `sidebar-section:${key}`,
2051
- children: block.label
2052
- }), (0, react_jsx_runtime.jsx)(SidebarGroupContent, { children: (0, react_jsx_runtime.jsx)(SidebarMenu, { children: block.entries.map(menuItem) }) })]
2053
- }, key);
2054
- })] });
3838
+ return (0, react_jsx_runtime.jsx)(RecordRoute, {
3839
+ ...route,
3840
+ id
3841
+ });
2055
3842
  }
2056
3843
  //#endregion
2057
- //#region src/layout/app-sidebar.tsx
2058
- function AppSidebar({ header, filters, nav, footer }) {
2059
- const headerNode = fill(header, () => (0, react_jsx_runtime.jsx)(SidebarBrand, {}));
2060
- const filtersNode = fill(filters, () => null);
2061
- const navNode = fill(nav, () => (0, react_jsx_runtime.jsx)(NavMain, {}));
2062
- const footerNode = fill(footer, () => (0, react_jsx_runtime.jsx)(UserMenu, {}));
2063
- return (0, react_jsx_runtime.jsxs)(Sidebar, {
2064
- collapsible: "icon",
3844
+ //#region src/layout/collection-record-route.tsx
3845
+ function addressTail(searchParams, routerHash) {
3846
+ const query = searchParams?.toString() ?? "";
3847
+ const hash = routerHash ?? (typeof window === "undefined" ? "" : window.location.hash);
3848
+ return `${query === "" ? "" : `?${query}`}${hash === "#" ? "" : hash}`;
3849
+ }
3850
+ function CollectionRecordRoute(props) {
3851
+ const { collection, action, id } = props;
3852
+ const app = (0, _burojs_react.useApp)();
3853
+ const navigate = (0, _burojs_react.useRouteNavigate)();
3854
+ const adapter = (0, _burojs_react.useOptionalRouterAdapter)();
3855
+ const state = (0, _burojs_react.useCollectionMember)(collection, id);
3856
+ const flow = props.action === "flow" ? props.flow : void 0;
3857
+ const target = state.status === "member" ? (0, _burojs_core.hrefFor)(app.registry, state.member, {
3858
+ action,
3859
+ id,
3860
+ ...flow === void 0 ? {} : { flow }
3861
+ }) : void 0;
3862
+ const current = (0, react.useRef)(adapter);
3863
+ current.current = adapter;
3864
+ const sent = (0, react.useRef)(void 0);
3865
+ (0, react.useEffect)(() => {
3866
+ if (target === void 0 || sent.current === target) return;
3867
+ sent.current = target;
3868
+ navigate(`${target}${addressTail(current.current?.searchParams, current.current?.hash)}`, { replace: true });
3869
+ }, [target, navigate]);
3870
+ if (state.status === "unknown") return (0, react_jsx_runtime.jsx)(UnknownMemberCard, {
3871
+ collection,
3872
+ id,
3873
+ value: state.value
3874
+ });
3875
+ if (state.status === "not-found") return (0, react_jsx_runtime.jsx)(require_record_trail_store.NavAreaNotFound, {});
3876
+ if (state.status === "error") return (0, react_jsx_runtime.jsx)(require_relation_create.LoadError, {
3877
+ surface: "record",
3878
+ resource: (0, _burojs_core.routeResourceKey)(collection),
3879
+ error: state.error
3880
+ });
3881
+ return null;
3882
+ }
3883
+ function UnknownMemberCard({ collection, id, value }) {
3884
+ const app = (0, _burojs_react.useApp)();
3885
+ const t = (0, _burojs_react.useOptionalT)();
3886
+ const key = (0, _burojs_core.routeResourceKey)(collection);
3887
+ const fact = (0, _burojs_core.memberFactOf)(app.registry.get(key));
3888
+ const shown = value === void 0 || value === null ? "" : String(value);
3889
+ const known = (fact?.collection?.members ?? []).flatMap((member) => member.values).join(", ");
3890
+ return (0, react_jsx_runtime.jsxs)("div", {
3891
+ "data-testid": `unknown-member-card:${key}:${id}`,
3892
+ className: "flex flex-col gap-2",
2065
3893
  children: [
2066
- (headerNode != null || filtersNode != null) && (0, react_jsx_runtime.jsxs)(SidebarHeader, {
2067
- className: "empty:hidden",
2068
- children: [headerNode, filtersNode]
3894
+ process.env.NODE_ENV === "production" ? null : (0, react_jsx_runtime.jsx)("div", {
3895
+ role: "note",
3896
+ "data-testid": "unknown-member-notice",
3897
+ className: "mx-6 mt-4 rounded-md border border-dashed border-amber-500/60 bg-amber-500/10 px-3 py-2 text-sm",
3898
+ children: t("collection.unknownMemberNotice", {
3899
+ params: {
3900
+ base: fact === void 0 ? key : (0, _burojs_core.formatEntityRef)(fact.ref),
3901
+ value: shown,
3902
+ known
3903
+ },
3904
+ defaultValue: "No member of {{base}} claims the type “{{value}}”. Known types: {{known}}."
3905
+ })
2069
3906
  }),
2070
- (0, react_jsx_runtime.jsx)(SidebarContent, { children: navNode }),
2071
- footerNode != null && (0, react_jsx_runtime.jsx)(SidebarFooter, {
2072
- className: "empty:hidden",
2073
- children: footerNode
3907
+ (0, react_jsx_runtime.jsx)("p", {
3908
+ "data-testid": "unknown-member-type",
3909
+ className: "mx-6 text-sm text-muted-foreground",
3910
+ children: t("collection.unknownType", {
3911
+ params: { value: shown },
3912
+ defaultValue: "Unknown type: {{value}}"
3913
+ })
2074
3914
  }),
2075
- (0, react_jsx_runtime.jsx)(SidebarRail, {})
3915
+ (0, react_jsx_runtime.jsx)(require_place_node.ItemActionsOffContext.Provider, {
3916
+ value: true,
3917
+ children: (0, react_jsx_runtime.jsx)(RecordRoute, {
3918
+ resource: key,
3919
+ action: "show",
3920
+ id
3921
+ })
3922
+ })
2076
3923
  ]
2077
3924
  });
2078
3925
  }
2079
3926
  //#endregion
2080
- //#region src/layout/nav-chrome.tsx
2081
- const DETAIL_ACTIONS = new Set([
2082
- "show",
2083
- "edit",
2084
- "create"
2085
- ]);
2086
- function NavChrome({ children, entryFilter, icons }) {
2087
- const app = (0, _burojs_react.useApp)();
3927
+ //#region src/layout/page-host.tsx
3928
+ function PageHost({ page, match, notFound }) {
3929
+ const isVisible = useNavVisible();
3930
+ const ctx = (0, _burojs_react.useVisibilityCtx)();
3931
+ const access = (0, _burojs_react.usePageAccess)(page);
3932
+ if (!((0, _burojs_core.evaluateVisible)(page.visible, ctx) && match.groupChain.every((group) => isVisible(group)))) return notFound;
3933
+ if (access === "pending") return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "loading" });
3934
+ if (access === "denied") return notFound;
3935
+ return (0, react_jsx_runtime.jsx)(PageParams, {
3936
+ page,
3937
+ notFound
3938
+ });
3939
+ }
3940
+ const NO_SEARCH = new URLSearchParams();
3941
+ function PageParams({ page, notFound }) {
3942
+ const search = (0, _burojs_react.useOptionalRouterAdapter)()?.searchParams ?? (typeof window === "undefined" ? NO_SEARCH : new URLSearchParams(window.location.search));
3943
+ const raw = JSON.stringify((0, _burojs_core.pageParamNames)(page.params).map((name) => search.get(name)));
3944
+ const parsed = (0, react.useMemo)(() => (0, _burojs_core.parsePageParams)(page, search), [page, raw]);
3945
+ if (!parsed.ok) return notFound;
3946
+ return (0, react_jsx_runtime.jsx)(_burojs_react.RouteSourceContext.Provider, {
3947
+ value: parsed.route,
3948
+ children: (0, react_jsx_runtime.jsx)(PageBody, { page })
3949
+ });
3950
+ }
3951
+ function PageBody({ page }) {
3952
+ const snapshot = (0, _burojs_react.useApplicationSnapshot)();
3953
+ const compiled = (0, react.useMemo)(() => (0, _burojs_core.compilePageScreen)(page, {
3954
+ blocks: (0, _burojs_core.snapshotBlockLookup)(snapshot),
3955
+ frames: (0, _burojs_core.snapshotFrameLookup)(snapshot),
3956
+ appFrames: (0, _burojs_core.snapshotAppFrames)(snapshot)
3957
+ }), [page, snapshot]);
3958
+ const failure = (0, _burojs_core.isScreenFailure)(compiled) ? compiled : null;
3959
+ const screen = failure === null && !(0, _burojs_core.isScreenFailure)(compiled) ? compiled : null;
2088
3960
  const caps = (0, _burojs_react.useI18nCaps)();
2089
- const isVisible = require_resource_page_router.useNavVisible();
2090
- const match = require_resource_page_router.useMatch();
2091
- const resolveLayout = require_resource_page_router.useLayoutResolver();
2092
- require_resource_page_router.useReportUnresolvedLayouts(match?.groupChain ?? [], resolveLayout);
2093
- if (!match) return (0, react_jsx_runtime.jsx)(require_resource_page_router.NavChromeMountedProvider, {
2094
- value: true,
2095
- children
3961
+ const name = require_record_trail_store.canonicalNavKey(page);
3962
+ const label = (0, _burojs_core.resolveNavLabel)(caps, `pages.${name}`, (0, _burojs_core.declaredText)("chrome", page, "label"));
3963
+ (0, react.useEffect)(() => {
3964
+ if (failure === null || process.env.NODE_ENV === "production") return;
3965
+ console.error(`[burojs] The page "${name}" cannot render its body: ${failure.code} at ${failure.path.join(".")}: ${failure.message}.`);
3966
+ }, [failure, name]);
3967
+ return (0, react_jsx_runtime.jsxs)("div", {
3968
+ className: "flex flex-col gap-4",
3969
+ children: [(0, react_jsx_runtime.jsx)("h1", {
3970
+ className: "text-2xl font-semibold tracking-tight",
3971
+ children: label
3972
+ }), screen === null ? (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "error" }) : (0, react_jsx_runtime.jsx)(PageRouteScreen, { children: (0, react_jsx_runtime.jsx)(PlannedBody, {
3973
+ screen,
3974
+ name,
3975
+ label
3976
+ }) })]
3977
+ });
3978
+ }
3979
+ function PageRouteScreen({ children }) {
3980
+ const tabs = require_place_node.useTabsUrlState("show", true);
3981
+ return (0, react_jsx_runtime.jsx)(require_place_node.RouteScreenClaimContext.Provider, {
3982
+ value: false,
3983
+ children: (0, react_jsx_runtime.jsx)(require_place_node.RouteScreenContext.Provider, {
3984
+ value: true,
3985
+ children: (0, react_jsx_runtime.jsx)(_burojs_react.ScreenStateProvider, {
3986
+ open: tabs.open,
3987
+ onOpenChange: tabs.onOpenChange,
3988
+ children
3989
+ })
3990
+ })
2096
3991
  });
2097
- let content = children;
2098
- for (let i = match.groupChain.length - 1; i >= 0; i--) {
2099
- const group = match.groupChain[i];
2100
- if (!group) continue;
2101
- const groupKey = require_resource_page_router.canonicalNavKey(group);
2102
- if (group.chromeOn === "list" && match.kind === "resource" && DETAIL_ACTIONS.has(match.action)) continue;
2103
- const Layout = resolveLayout(group.layout);
2104
- if (!Layout) continue;
2105
- const items = buildNavItems({
2106
- registry: app.registry,
2107
- caps,
2108
- groupName: groupKey,
2109
- match,
2110
- isVisible,
2111
- entryFilter,
2112
- icons
2113
- });
2114
- content = (0, react_jsx_runtime.jsx)(Layout, {
2115
- group,
2116
- groupKey,
2117
- items,
2118
- children: content
2119
- });
3992
+ }
3993
+ function PlannedBody({ screen, name, label, record }) {
3994
+ const pageOptions = (0, react.useMemo)(() => record === void 0 ? {} : { record }, [record]);
3995
+ const page = (0, _burojs_react.usePageScreen)(screen, pageOptions);
3996
+ const { PlacementScope } = page;
3997
+ const route = (0, react.useContext)(_burojs_react.RouteSourceContext);
3998
+ const catalog = (0, _burojs_react.useFrameImplementations)();
3999
+ const id = (0, _burojs_core.formatEntityRef)(screen.frame);
4000
+ const resolved = (0, react.useMemo)(() => require_place_node.resolveFrameView(screen.frame, catalog, "page"), [screen.frame, catalog]);
4001
+ const t = (0, _burojs_react.useFrameT)(id);
4002
+ const slots = {};
4003
+ for (const slot of Object.keys(screen.slots)) slots[slot] = (page.plan.slots[slot] ?? []).every((node) => node.state === "absent") ? null : (0, react_jsx_runtime.jsx)(require_place_node.ScreenTree, {
4004
+ region: slot === "body" ? "page-body" : "record",
4005
+ slot,
4006
+ resource: name,
4007
+ mode: "show",
4008
+ compiled: screen,
4009
+ page
4010
+ }, slot);
4011
+ const View = resolved.view;
4012
+ const viewProps = {
4013
+ slots,
4014
+ label,
4015
+ params: route ?? {},
4016
+ t
4017
+ };
4018
+ return (0, react_jsx_runtime.jsx)(_burojs_react.RouteSourceContext.Provider, {
4019
+ value: null,
4020
+ children: (0, react_jsx_runtime.jsx)(_burojs_react.ActionRouteContext.Provider, {
4021
+ value: route,
4022
+ children: (0, react_jsx_runtime.jsx)(PlacementScope, { children: (0, react_jsx_runtime.jsx)(require_place_node.DeepLinkScope, {
4023
+ plan: page.plan,
4024
+ enabled: true,
4025
+ children: (0, react_jsx_runtime.jsx)("div", {
4026
+ "data-buro-region": "page-body",
4027
+ children: (0, react_jsx_runtime.jsx)(react.Suspense, {
4028
+ fallback: null,
4029
+ children: (0, react_jsx_runtime.jsx)(View, { ...viewProps })
4030
+ })
4031
+ })
4032
+ }) })
4033
+ })
4034
+ });
4035
+ }
4036
+ //#endregion
4037
+ //#region src/layout/resource-page-router.tsx
4038
+ function ResourcePageRouterEmpty() {
4039
+ const t = (0, _burojs_react.useT)();
4040
+ return (0, react_jsx_runtime.jsxs)("div", {
4041
+ "data-testid": "resource-page-router-empty",
4042
+ className: "flex flex-col items-center justify-center gap-1 px-6 py-24 text-center",
4043
+ children: [(0, react_jsx_runtime.jsx)("h2", {
4044
+ className: "text-base font-semibold tracking-tight",
4045
+ children: t("router.emptyTitle")
4046
+ }), (0, react_jsx_runtime.jsx)("p", {
4047
+ className: "max-w-sm text-sm text-muted-foreground",
4048
+ children: t("router.emptyBody")
4049
+ })]
4050
+ });
4051
+ }
4052
+ function ResourcePageRouter({ match }) {
4053
+ const app = (0, _burojs_react.useApp)();
4054
+ const qualifiedMatch = match;
4055
+ const resource = require_record_trail_store.canonicalNavKey(qualifiedMatch);
4056
+ const target = require_record_trail_store.canonicalNavKey({
4057
+ name: match.target ?? match.name,
4058
+ ref: qualifiedMatch.targetRef
4059
+ });
4060
+ const recordAction = recordActionOf(match);
4061
+ switch (match.kind) {
4062
+ case "resource": {
4063
+ if (match.action === "list") {
4064
+ const def = app.registry.get(resource);
4065
+ return def !== void 0 && !(0, _burojs_core.hasListPage)(def) ? (0, react_jsx_runtime.jsx)(require_record_trail_store.NavAreaNotFound, {}) : (0, react_jsx_runtime.jsx)(ResourceListPage, { resource });
4066
+ }
4067
+ const collection = (0, _burojs_core.collectionFactOf)(app.registry.get(resource)) !== void 0;
4068
+ if (collection && match.id !== void 0 && (match.action === "show" || match.action === "edit" || match.action === "flow")) {
4069
+ if (!(0, _burojs_react.recordRouteAvailable)(app.registry, resource, "show")) return (0, react_jsx_runtime.jsx)(require_record_trail_store.NavAreaNotFound, {});
4070
+ return match.action === "flow" ? (0, react_jsx_runtime.jsx)(CollectionRecordRoute, {
4071
+ collection: resource,
4072
+ action: "flow",
4073
+ id: match.id,
4074
+ flow: match.flow ?? ""
4075
+ }) : (0, react_jsx_runtime.jsx)(CollectionRecordRoute, {
4076
+ collection: resource,
4077
+ action: match.action,
4078
+ id: match.id
4079
+ });
4080
+ }
4081
+ if (match.action === "flow") return (0, react_jsx_runtime.jsx)(PageFlowRouteLoader, { match });
4082
+ if (recordAction === void 0) return (0, react_jsx_runtime.jsx)(ResourcePageRouterEmpty, {});
4083
+ if (!(0, _burojs_react.recordRouteAvailable)(app.registry, resource, recordAction)) return (0, react_jsx_runtime.jsx)(require_record_trail_store.NavAreaNotFound, {});
4084
+ if (collection && recordAction === "create") return (0, react_jsx_runtime.jsx)(CollectionCreatePicker, { collection: resource });
4085
+ return (0, react_jsx_runtime.jsx)(RecordRoute, {
4086
+ resource,
4087
+ action: recordAction,
4088
+ id: match.id ?? ""
4089
+ });
4090
+ }
4091
+ case "custom-page": {
4092
+ const page = app.registry.customPages.get(resource);
4093
+ if (page === void 0) return (0, react_jsx_runtime.jsx)(ResourcePageRouterEmpty, {});
4094
+ if (!page.body?.length) return (0, react_jsx_runtime.jsx)(require_record_trail_store.NavAreaNotFound, {});
4095
+ return (0, react_jsx_runtime.jsx)(PageHost, {
4096
+ page,
4097
+ match,
4098
+ notFound: (0, react_jsx_runtime.jsx)(require_record_trail_store.NavAreaNotFound, {})
4099
+ }, resource);
4100
+ }
4101
+ case "group-index": {
4102
+ const indexPage = app.registry.customPages.get(target);
4103
+ if (indexPage?.body?.length) return (0, react_jsx_runtime.jsx)(PageHost, {
4104
+ page: indexPage,
4105
+ match,
4106
+ notFound: (0, react_jsx_runtime.jsx)(require_record_trail_store.NavAreaNotFound, {})
4107
+ }, target);
4108
+ const targetDef = app.registry.get(target);
4109
+ if (targetDef !== void 0) return (0, _burojs_core.hasListPage)(targetDef) ? (0, react_jsx_runtime.jsx)(ResourceListPage, { resource: target }) : (0, react_jsx_runtime.jsx)(require_record_trail_store.NavAreaNotFound, {});
4110
+ return (0, react_jsx_runtime.jsx)(ResourcePageRouterEmpty, {});
4111
+ }
4112
+ default: return (0, react_jsx_runtime.jsx)(ResourcePageRouterEmpty, {});
2120
4113
  }
2121
- return (0, react_jsx_runtime.jsx)(require_resource_page_router.NavChromeMountedProvider, {
2122
- value: true,
2123
- children: content
4114
+ }
4115
+ function NavAreaPageSkeleton() {
4116
+ return (0, react_jsx_runtime.jsxs)("div", {
4117
+ className: "space-y-3 p-6",
4118
+ role: "status",
4119
+ "aria-busy": "true",
4120
+ "aria-live": "polite",
4121
+ "data-testid": "nav-area-skeleton",
4122
+ children: [
4123
+ (0, react_jsx_runtime.jsx)("span", {
4124
+ className: "sr-only",
4125
+ children: "Loading…"
4126
+ }),
4127
+ (0, react_jsx_runtime.jsx)("div", { className: "h-6 w-48 animate-pulse rounded bg-muted/60" }),
4128
+ (0, react_jsx_runtime.jsx)("div", { className: "h-4 w-full animate-pulse rounded bg-muted/40" }),
4129
+ (0, react_jsx_runtime.jsx)("div", { className: "h-4 w-5/6 animate-pulse rounded bg-muted/40" }),
4130
+ (0, react_jsx_runtime.jsx)("div", { className: "h-4 w-2/3 animate-pulse rounded bg-muted/40" })
4131
+ ]
4132
+ });
4133
+ }
4134
+ const adapterNoticeGiven = new WeakSet();
4135
+ const chromeNoticeGiven = new WeakSet();
4136
+ function NavAreaPage() {
4137
+ const match = useMatch();
4138
+ const app = (0, _burojs_react.useApp)();
4139
+ const noAdapter = (0, _burojs_react.useOptionalRouterAdapter)() === null;
4140
+ const chromeMounted = useNavChromeMounted();
4141
+ const resolveLayout = useLayoutResolver();
4142
+ const chromeGroup = match?.groupChain.find((g) => resolveLayout(g.layout)) ?? null;
4143
+ (0, react.useEffect)(() => {
4144
+ if (process.env.NODE_ENV === "production") return;
4145
+ if (chromeMounted || !chromeGroup || chromeNoticeGiven.has(app)) return;
4146
+ chromeNoticeGiven.add(app);
4147
+ console.error(`[burojs] <NavAreaPage> is inside the nav group "${require_record_trail_store.canonicalNavKey(chromeGroup)}" whose layout "${chromeGroup.layout}" draws area chrome, and no <NavChrome> is mounted above it. <AppShell> mounts one by default; with your own frame, wrap your routes in <NavChrome>.`);
4148
+ }, [
4149
+ app,
4150
+ chromeMounted,
4151
+ chromeGroup
4152
+ ]);
4153
+ (0, react.useEffect)(() => {
4154
+ if (!noAdapter || process.env.NODE_ENV === "production") return;
4155
+ if (adapterNoticeGiven.has(app)) return;
4156
+ adapterNoticeGiven.add(app);
4157
+ console.error("[burojs] <NavAreaPage> has no location to match: no RouterAdapterProvider is mounted. Mount your router’s adapter (RouterAdapterProvider from @burojs/react) above <BuroProvider>; until then every route renders not-found.");
4158
+ }, [app, noAdapter]);
4159
+ return (0, react_jsx_runtime.jsx)(react.Suspense, {
4160
+ fallback: (0, react_jsx_runtime.jsx)(NavAreaPageSkeleton, {}),
4161
+ children: match ? (0, react_jsx_runtime.jsx)(ResourcePageRouter, { match }) : (0, react_jsx_runtime.jsx)(require_record_trail_store.NavAreaNotFound, {})
2124
4162
  });
2125
4163
  }
2126
4164
  //#endregion
@@ -2188,7 +4226,7 @@ function Breadcrumbs(input) {
2188
4226
  });
2189
4227
  if (!def) return null;
2190
4228
  const { recordId, pageLabel, middleSegments, rootSegments } = props;
2191
- const resourceKey = require_resource_page_router.canonicalResourceKey(def);
4229
+ const resourceKey = require_record_trail_store.canonicalResourceKey(def);
2192
4230
  if (rootSegments !== void 0 && rootSegments.length > 0) return (0, react_jsx_runtime.jsxs)("nav", {
2193
4231
  className: navClass,
2194
4232
  "aria-label": ariaLabel,
@@ -2259,20 +4297,23 @@ function Breadcrumbs(input) {
2259
4297
  //#region src/layout/record-breadcrumbs.tsx
2260
4298
  function viewOrigin(ctx, trail, resource) {
2261
4299
  if (trail === void 0 || trail.resource === void 0 || trail.segments.length > 0) return void 0;
2262
- const target = ctx.registry.get(trail.resource)?.routesTo?.show;
2263
- if (target === void 0 || ctx.registry.get(target) !== ctx.registry.get(resource)) return void 0;
2264
- return trail.resource;
4300
+ const def = ctx.registry.get(trail.resource);
4301
+ const target = def?.routesTo?.show;
4302
+ if (target !== void 0 && ctx.registry.get(target) === ctx.registry.get(resource)) return trail.resource;
4303
+ const collected = (0, _burojs_core.collectionFactOf)(def) === void 0 ? void 0 : (0, _burojs_core.memberFactOf)(def)?.ref;
4304
+ const memberBase = (0, _burojs_core.memberFactOf)(ctx.registry.get(resource))?.ref;
4305
+ if (collected !== void 0 && memberBase !== void 0 && (0, _burojs_core.sameEntityRef)(collected, memberBase)) return trail.resource;
2265
4306
  }
2266
4307
  function RecordBreadcrumbs() {
2267
- const ctx = require_resource_page_router.useTrailContext();
2268
- const match = require_resource_page_router.useMatch();
4308
+ const ctx = useTrailContext();
4309
+ const match = useMatch();
2269
4310
  const snapshot = (0, _burojs_react.useApplicationSnapshot)();
2270
- const route = require_resource_page_router.recordTrailRoute(ctx.registry, match);
2271
- const published = require_resource_page_router.usePublishedRecordTrail(route === null ? "" : require_resource_page_router.recordTrailKey(route.resource, route.id, route.flow === void 0 ? route.action : `flow:${route.flow}`));
4311
+ const route = recordTrailRoute(ctx.registry, match);
4312
+ const published = require_record_trail_store.usePublishedRecordTrail(route === null ? "" : require_record_trail_store.recordTrailKey(route.resource, route.id, route.flow === void 0 ? route.action : `flow:${route.flow}`));
2272
4313
  const idTitle = (0, _burojs_react.useRecordTitle)(route?.resource, route?.id);
2273
4314
  (0, _burojs_react.usePublishOriginTitle)(published?.title || void 0);
2274
4315
  const origin = (0, _burojs_react.useNavigationOrigin)();
2275
- const rooted = origin === null ? void 0 : require_resource_page_router.originTrail(ctx, origin);
4316
+ const rooted = origin === null ? void 0 : originTrail(ctx, origin);
2276
4317
  const view = route === null ? void 0 : viewOrigin(ctx, rooted, route.resource);
2277
4318
  const viewScopes = (0, _burojs_react.useDocTrailScopes)(view);
2278
4319
  const ownScopes = (0, _burojs_react.useDocTrailScopes)(view === void 0 ? void 0 : route?.resource);
@@ -2285,7 +4326,7 @@ function RecordBreadcrumbs() {
2285
4326
  if ((0, _burojs_core.effectiveFlow)(snapshot, match.ref, route.flow) === void 0) return null;
2286
4327
  const flowLabel = published?.flowLabel;
2287
4328
  if (flowLabel === void 0) return (0, react_jsx_runtime.jsx)(Breadcrumbs, {
2288
- ...require_resource_page_router.recordTrail(ctx, {
4329
+ ...recordTrail(ctx, {
2289
4330
  resource,
2290
4331
  action: "show",
2291
4332
  id,
@@ -2297,7 +4338,7 @@ function RecordBreadcrumbs() {
2297
4338
  "data-testid": "record-breadcrumbs"
2298
4339
  });
2299
4340
  return (0, react_jsx_runtime.jsx)(Breadcrumbs, {
2300
- ...require_resource_page_router.recordTrail(ctx, {
4341
+ ...recordTrail(ctx, {
2301
4342
  resource,
2302
4343
  action: "edit",
2303
4344
  id,
@@ -2311,7 +4352,7 @@ function RecordBreadcrumbs() {
2311
4352
  });
2312
4353
  }
2313
4354
  return (0, react_jsx_runtime.jsx)(Breadcrumbs, {
2314
- ...require_resource_page_router.recordTrail(ctx, {
4355
+ ...recordTrail(ctx, {
2315
4356
  resource,
2316
4357
  action: route.action,
2317
4358
  id,
@@ -2325,7 +4366,7 @@ function RecordBreadcrumbs() {
2325
4366
  }
2326
4367
  //#endregion
2327
4368
  //#region src/layout/default-nav-layouts.ts
2328
- const defaultNavLayouts = { ...require_resource_page_router.BUILTIN_LAYOUTS };
4369
+ const defaultNavLayouts = { ...BUILTIN_LAYOUTS };
2329
4370
  //#endregion
2330
4371
  //#region src/layout/context-picker.tsx
2331
4372
  const ALL = "\0all";
@@ -2398,7 +4439,7 @@ function ScopeDimensionPicker(props) {
2398
4439
  });
2399
4440
  }
2400
4441
  function ResourceDimension({ resource, labelField, ...rest }) {
2401
- const options = require_resource_page_router.useResourceDimensionOptions(rest.dimension, resource, labelField);
4442
+ const options = useResourceDimensionOptions(rest.dimension, resource, labelField);
2402
4443
  return (0, react_jsx_runtime.jsx)(DimensionControl, {
2403
4444
  ...rest,
2404
4445
  options
@@ -2485,10 +4526,10 @@ function LanguageSwitch({ onChange, className }) {
2485
4526
  //#endregion
2486
4527
  //#region src/layout/header-breadcrumbs.tsx
2487
4528
  function HeaderBreadcrumbs() {
2488
- const ctx = require_resource_page_router.useTrailContext();
2489
- const match = require_resource_page_router.useMatch();
2490
- if (require_resource_page_router.recordTrailRoute(ctx.registry, match) !== null) return (0, react_jsx_runtime.jsx)(RecordBreadcrumbs, {});
2491
- const trail = require_resource_page_router.headerTrail(ctx, match);
4529
+ const ctx = useTrailContext();
4530
+ const match = useMatch();
4531
+ if (recordTrailRoute(ctx.registry, match) !== null) return (0, react_jsx_runtime.jsx)(RecordBreadcrumbs, {});
4532
+ const trail = headerTrail(ctx, match);
2492
4533
  if (trail === null) return null;
2493
4534
  return (0, react_jsx_runtime.jsx)(Breadcrumbs, {
2494
4535
  ...trail,
@@ -2636,20 +4677,20 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
2636
4677
  const visibilityCtx = (0, _burojs_react.useVisibilityCtx)();
2637
4678
  const t = (0, _burojs_react.useOptionalT)();
2638
4679
  const navigate = (0, _burojs_react.useRouteNavigate)();
2639
- const isVisible = require_resource_page_router.useNavVisible();
2640
- const resolveLayout = require_resource_page_router.useLayoutResolver();
2641
- const isResourceVisible = require_resource_page_router.useResourceVisible();
2642
- const pageAllowed = require_resource_page_router.usePageAllowed();
4680
+ const isVisible = useNavVisible();
4681
+ const resolveLayout = useLayoutResolver();
4682
+ const isResourceVisible = useResourceVisible();
4683
+ const pageAllowed = usePageAllowed();
2643
4684
  const isPageVisible = (p) => (0, _burojs_core.evaluateVisible)(p.visible, visibilityCtx) && pageAllowed(p);
2644
4685
  const { topLevelResources, topLevelPages, sectionGroups } = (0, react.useMemo)(() => {
2645
4686
  const allResources = app.registry.list();
2646
4687
  const allPages = app.registry.customPages.list();
2647
4688
  const allSections = app.registry.sections.list();
2648
- const tlResources = allResources.filter((r) => (0, _burojs_core.hasListPage)(r)).filter(isResourceVisible).filter((r) => !r.section && !r.group);
4689
+ const tlResources = allResources.filter((r) => (0, _burojs_core.hasMenuEntry)(r)).filter(isResourceVisible).filter((r) => !r.section && !r.group);
2649
4690
  const tlPages = allPages.filter((p) => !p.section && !p.group).filter(isPageVisible);
2650
4691
  const groups = [];
2651
4692
  for (const section of allSections) {
2652
- const children = app.registry.sections.childrenOf(require_resource_page_router.canonicalNavKey(section)).filter((c) => !c.group).filter((c) => !("parent" in c) || (0, _burojs_core.hasListPage)(c)).filter((c) => (0, _burojs_core.isCustomPageDef)(c) ? isPageVisible(c) : isResourceVisible(c));
4693
+ const children = app.registry.sections.childrenOf(require_record_trail_store.canonicalNavKey(section)).filter((c) => !c.group).filter((c) => !("parent" in c) || (0, _burojs_core.hasMenuEntry)(c)).filter((c) => (0, _burojs_core.isCustomPageDef)(c) ? isPageVisible(c) : isResourceVisible(c));
2653
4694
  if (children.length === 0) continue;
2654
4695
  groups.push({
2655
4696
  section,
@@ -2666,13 +4707,13 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
2666
4707
  onSelect?.();
2667
4708
  navigate(href, { origin: "jump" });
2668
4709
  };
2669
- const resourceLabel = (def) => (0, _burojs_core.resolveResourceLabel)(caps, require_resource_page_router.canonicalResourceKey(def), "plural", def);
2670
- const pageLabel = (def) => (0, _burojs_core.resolveNavLabel)(caps, `pages.${require_resource_page_router.canonicalNavKey(def)}`, (0, _burojs_core.declaredText)("chrome", def, "label"));
4710
+ const resourceLabel = (def) => (0, _burojs_core.resolveResourceLabel)(caps, require_record_trail_store.canonicalResourceKey(def), "plural", def);
4711
+ const pageLabel = (def) => (0, _burojs_core.resolveNavLabel)(caps, `pages.${require_record_trail_store.canonicalNavKey(def)}`, (0, _burojs_core.declaredText)("chrome", def, "label"));
2671
4712
  const groups = [];
2672
4713
  if (topLevelResources.length > 0) groups.push((0, react_jsx_runtime.jsx)(require_relation_create.CommandGroup, {
2673
4714
  heading: t("commandPalette.resources", { defaultValue: "Resources" }),
2674
4715
  children: topLevelResources.map((def) => {
2675
- const resource = require_resource_page_router.canonicalResourceKey(def);
4716
+ const resource = require_record_trail_store.canonicalResourceKey(def);
2676
4717
  const label = resourceLabel(def);
2677
4718
  const href = (0, _burojs_core.hrefFor)(app.registry, resource, { isVisible });
2678
4719
  return (0, react_jsx_runtime.jsx)(require_relation_create.CommandItem, {
@@ -2686,7 +4727,7 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
2686
4727
  if (topLevelPages.length > 0) groups.push((0, react_jsx_runtime.jsx)(require_relation_create.CommandGroup, {
2687
4728
  heading: t("commandPalette.pages", { defaultValue: "Pages" }),
2688
4729
  children: topLevelPages.map((page) => {
2689
- const pageKey = require_resource_page_router.canonicalNavKey(page);
4730
+ const pageKey = require_record_trail_store.canonicalNavKey(page);
2690
4731
  const label = pageLabel(page);
2691
4732
  const href = page.path;
2692
4733
  return (0, react_jsx_runtime.jsx)(require_relation_create.CommandItem, {
@@ -2698,7 +4739,7 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
2698
4739
  })
2699
4740
  }, "pages"));
2700
4741
  for (const { section, children } of sectionGroups) {
2701
- const sectionKey = require_resource_page_router.canonicalNavKey(section);
4742
+ const sectionKey = require_record_trail_store.canonicalNavKey(section);
2702
4743
  const sectionLabel = (0, _burojs_core.resolveNavLabel)(caps, `sections.${sectionKey}`, (0, _burojs_core.declaredText)("chrome", section, "label"));
2703
4744
  groups.push((0, react_jsx_runtime.jsxs)(require_relation_create.CommandGroup, {
2704
4745
  heading: sectionLabel,
@@ -2710,7 +4751,7 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
2710
4751
  children: sectionLabel
2711
4752
  }, `__section_header_${sectionKey}`), children.map((child) => {
2712
4753
  if ((0, _burojs_core.isCustomPageDef)(child)) {
2713
- const pageKey = require_resource_page_router.canonicalNavKey(child);
4754
+ const pageKey = require_record_trail_store.canonicalNavKey(child);
2714
4755
  const href = child.path;
2715
4756
  const label = pageLabel(child);
2716
4757
  return (0, react_jsx_runtime.jsx)(require_relation_create.CommandItem, {
@@ -2721,7 +4762,7 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
2721
4762
  children: label
2722
4763
  }, `section:${sectionKey}:page:${pageKey}`);
2723
4764
  }
2724
- const resource = require_resource_page_router.canonicalResourceKey(child);
4765
+ const resource = require_record_trail_store.canonicalResourceKey(child);
2725
4766
  const label = resourceLabel(child);
2726
4767
  const href = (0, _burojs_core.hrefFor)(app.registry, resource, { isVisible });
2727
4768
  return (0, react_jsx_runtime.jsx)(require_relation_create.CommandItem, {
@@ -2736,10 +4777,10 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
2736
4777
  }
2737
4778
  const collectGroupItems = (group, idPath, depth) => {
2738
4779
  const items = [];
2739
- if (!!resolveLayout(group.layout)) {
2740
- const groupKey = require_resource_page_router.canonicalNavKey(group);
4780
+ const href = !!resolveLayout(group.layout) ? groupNavHref(app.registry, require_record_trail_store.canonicalNavKey(group), isVisible) : void 0;
4781
+ if (href !== void 0) {
4782
+ const groupKey = require_record_trail_store.canonicalNavKey(group);
2741
4783
  const label = (0, _burojs_core.resolveNavLabel)(caps, `groups.${groupKey}`, (0, _burojs_core.declaredText)("chrome", group, "label"));
2742
- const href = (0, _burojs_core.navHrefFor)(app.registry, groupKey, { isVisible });
2743
4784
  items.push((0, react_jsx_runtime.jsx)(require_relation_create.CommandItem, {
2744
4785
  value: `group:${idPath}:${label}`,
2745
4786
  onSelect: () => goTo(href),
@@ -2748,17 +4789,18 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
2748
4789
  children: label
2749
4790
  }, `group:${idPath}`));
2750
4791
  }
2751
- for (const child of app.registry.groups.childrenOf(require_resource_page_router.canonicalNavKey(group))) {
4792
+ for (const child of app.registry.groups.childrenOf(require_record_trail_store.canonicalNavKey(group))) {
2752
4793
  const kind = (0, _burojs_core.nodeKind)(child);
2753
4794
  if (kind === "group") {
2754
4795
  const sub = child;
2755
4796
  if (!isVisible(sub)) continue;
2756
- items.push(...collectGroupItems(sub, `${idPath}:${require_resource_page_router.canonicalNavKey(sub)}`, depth + 1));
4797
+ items.push(...collectGroupItems(sub, `${idPath}:${require_record_trail_store.canonicalNavKey(sub)}`, depth + 1));
2757
4798
  continue;
2758
4799
  }
2759
4800
  if (kind === "custom-page") {
2760
4801
  const page = child;
2761
- const pageKey = require_resource_page_router.canonicalNavKey(page);
4802
+ if (!isPageVisible(page)) continue;
4803
+ const pageKey = require_record_trail_store.canonicalNavKey(page);
2762
4804
  const label = pageLabel(page);
2763
4805
  const href = page.path;
2764
4806
  items.push((0, react_jsx_runtime.jsx)(require_relation_create.CommandItem, {
@@ -2773,7 +4815,7 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
2773
4815
  const resource = child;
2774
4816
  if (!(0, _burojs_core.hasListPage)(resource)) continue;
2775
4817
  if (!isResourceVisible(resource)) continue;
2776
- const resourceId = require_resource_page_router.canonicalResourceKey(resource);
4818
+ const resourceId = require_record_trail_store.canonicalResourceKey(resource);
2777
4819
  const label = resourceLabel(resource);
2778
4820
  const href = (0, _burojs_core.hrefFor)(app.registry, resourceId, { isVisible });
2779
4821
  items.push((0, react_jsx_runtime.jsx)(require_relation_create.CommandItem, {
@@ -2789,7 +4831,7 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
2789
4831
  const rootGroups = app.registry.groups.rootNodes().filter((n) => (0, _burojs_core.nodeKind)(n) === "group");
2790
4832
  for (const group of rootGroups) {
2791
4833
  if (!isVisible(group)) continue;
2792
- const groupKey = require_resource_page_router.canonicalNavKey(group);
4834
+ const groupKey = require_record_trail_store.canonicalNavKey(group);
2793
4835
  const items = collectGroupItems(group, groupKey, 0);
2794
4836
  if (items.length === 0) continue;
2795
4837
  const heading = (0, _burojs_core.resolveNavLabel)(caps, `groups.${groupKey}`, (0, _burojs_core.declaredText)("chrome", group, "label"));
@@ -2829,7 +4871,7 @@ function CommandPaletteRecentGroup({ onSelect, getTestId, heading, refreshKey, w
2829
4871
  const navigate = (0, _burojs_react.useRouteNavigate)();
2830
4872
  const quick = (0, _burojs_react.useQuick)();
2831
4873
  const userId = (0, _burojs_react.useCurrentUserId)();
2832
- const isResourceVisible = require_resource_page_router.useResourceVisible();
4874
+ const isResourceVisible = useResourceVisible();
2833
4875
  const resolvedHeading = heading ?? t("commandPalette.recent", { defaultValue: "Recent" });
2834
4876
  const store = (0, _burojs_react.usePlatformStorage)().local;
2835
4877
  const [stored, setStored] = (0, react.useState)([]);
@@ -2839,7 +4881,7 @@ function CommandPaletteRecentGroup({ onSelect, getTestId, heading, refreshKey, w
2839
4881
  return;
2840
4882
  }
2841
4883
  let current = true;
2842
- const read = require_resource_page_router.readRecentRecords(store, userId);
4884
+ const read = readRecentRecords(store, userId);
2843
4885
  if (Array.isArray(read)) setStored(read);
2844
4886
  else read.then((entries) => {
2845
4887
  if (current) setStored(entries);
@@ -2888,7 +4930,7 @@ function RecentItem({ entry, href, onGo, getTestId }) {
2888
4930
  const resourceLabel = (0, _burojs_core.resolveResourceLabel)(caps, entry.canonicalRef, "single", def);
2889
4931
  const key = `${entry.canonicalRef}:${entry.id}`;
2890
4932
  const declared = Object.keys(def?.fields ?? {});
2891
- const candidates = def?.recordTitle === void 0 ? [...declared.filter((name) => require_resource_page_router.RECENT_LABEL_KEYS.includes(name)), ...def?.displayField === void 0 ? [] : [def.displayField]] : declared;
4933
+ const candidates = def?.recordTitle === void 0 ? [...declared.filter((name) => RECENT_LABEL_KEYS.includes(name)), ...def?.displayField === void 0 ? [] : [def.displayField]] : declared;
2892
4934
  const legacyTrusted = entry.label === entry.id || access.status === "ready" && candidates.every((name) => access.fieldVisible(name));
2893
4935
  const shown = entry.labelField === void 0 ? legacyTrusted ? entry.label : entry.id : access.status === "ready" && access.fieldVisible(entry.labelField) ? entry.label : entry.id;
2894
4936
  return (0, react_jsx_runtime.jsxs)(require_relation_create.CommandItem, {
@@ -2926,12 +4968,12 @@ function CommandPaletteRecordsGroup({ enabled = true, pageSize = 5, minQueryLeng
2926
4968
  const t = (0, _burojs_react.useOptionalT)();
2927
4969
  const navigate = (0, _burojs_react.useRouteNavigate)();
2928
4970
  const quick = (0, _burojs_react.useQuick)();
2929
- const isResourceVisible = require_resource_page_router.useResourceVisible();
4971
+ const isResourceVisible = useResourceVisible();
2930
4972
  const resolvedHeading = heading ?? t("commandPalette.records", { defaultValue: "Records" });
2931
4973
  const liveQuery = (0, cmdk.useCommandState)((state) => state.search) ?? "";
2932
4974
  const debouncedQuery = (0, _burojs_react.useDebouncedValue)(liveQuery, debounceMs);
2933
4975
  const searchableResources = (0, react.useMemo)(() => {
2934
- return app.registry.list().filter((r) => require_resource_page_router.isShowAvailable(app.registry, require_resource_page_router.canonicalResourceKey(r)) || opensInQuick(app.registry, require_resource_page_router.canonicalResourceKey(r), "show")).filter(isResourceVisible).map((def) => {
4976
+ return app.registry.list().filter((r) => isShowAvailable(app.registry, require_record_trail_store.canonicalResourceKey(r)) || opensInQuick(app.registry, require_record_trail_store.canonicalResourceKey(r), "show")).filter(isResourceVisible).map((def) => {
2935
4977
  const displayField = resolveDisplayField(def);
2936
4978
  return displayField ? {
2937
4979
  def,
@@ -2957,12 +4999,12 @@ function CommandPaletteRecordsGroup({ enabled = true, pageSize = 5, minQueryLeng
2957
4999
  recordHref,
2958
5000
  registry: app.registry,
2959
5001
  getTestId
2960
- }, require_resource_page_router.canonicalResourceKey(def)))
5002
+ }, require_record_trail_store.canonicalResourceKey(def)))
2961
5003
  }, "records");
2962
5004
  }
2963
5005
  function PerResourceSearchHits({ def, displayField, query, pageSize, goTo, recordHref, registry, getTestId }) {
2964
5006
  const caps = (0, _burojs_react.useI18nCaps)();
2965
- const resource = require_resource_page_router.canonicalResourceKey(def);
5007
+ const resource = require_record_trail_store.canonicalResourceKey(def);
2966
5008
  const access = (0, _burojs_react.useListAccess)(resource);
2967
5009
  const titleVisible = access.status === "ready" && access.fieldVisible(displayField);
2968
5010
  const shouldFetch = query.length > 0 && titleVisible;
@@ -2987,7 +5029,7 @@ function PerResourceSearchHits({ def, displayField, query, pageSize, goTo, recor
2987
5029
  report(rows.length);
2988
5030
  }, [report, rows.length]);
2989
5031
  if (rows.length === 0) return null;
2990
- const resourceLabel = (0, _burojs_core.resolveResourceLabel)(caps, require_resource_page_router.canonicalResourceKey(def), "single", def);
5032
+ const resourceLabel = (0, _burojs_core.resolveResourceLabel)(caps, require_record_trail_store.canonicalResourceKey(def), "single", def);
2991
5033
  const declaredIdField = def.data?.idField;
2992
5034
  const idField = typeof declaredIdField === "string" && declaredIdField.length > 0 ? declaredIdField : "id";
2993
5035
  return (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: rows.map((row) => {
@@ -2997,7 +5039,7 @@ function PerResourceSearchHits({ def, displayField, query, pageSize, goTo, recor
2997
5039
  const display = titleVisible ? row[displayField] : void 0;
2998
5040
  const labelText = typeof display === "string" && display.length > 0 ? display : id;
2999
5041
  const subtitle = rowSubtitle(row) ?? null;
3000
- const href = recordHref ? recordHref(resource, id) : require_resource_page_router.isShowAvailable(registry, resource) ? (0, _burojs_core.resourceShowHref)(registry, def, resource, id) : null;
5042
+ const href = recordHref ? recordHref(resource, id) : isShowAvailable(registry, resource) ? (0, _burojs_core.resourceShowHref)(registry, def, resource, id, row) : null;
3001
5043
  return (0, react_jsx_runtime.jsxs)(require_relation_create.CommandItem, {
3002
5044
  value: `record:${resource}:${id}:${labelText}`,
3003
5045
  forceMount: true,
@@ -3076,7 +5118,7 @@ function CommandPaletteActionsGroup({ actions, onSelect, getTestId, heading }) {
3076
5118
  const propActions = actions ?? EMPTY_ACTIONS;
3077
5119
  const resolvedHeading = heading ?? t("commandPalette.actions", { defaultValue: "Actions" });
3078
5120
  const { items, collidingIds } = (0, react.useMemo)(() => {
3079
- return mergeActions(registryEntries.map((entry) => appActionToItem(entry, present, caps)), propActions);
5121
+ return mergeActions(registryEntries.filter((entry) => entry.undecided !== true).map((entry) => appActionToItem(entry, present, caps)), propActions);
3080
5122
  }, [
3081
5123
  registryEntries,
3082
5124
  propActions,
@@ -3145,7 +5187,7 @@ function CommandPaletteActionsGroup({ actions, onSelect, getTestId, heading }) {
3145
5187
  function CommandPaletteCreateGroup({ resourceFilter, onSelect, getTestId, heading, createHref, prefix }) {
3146
5188
  const caps = (0, _burojs_react.useI18nCaps)();
3147
5189
  const app = (0, _burojs_react.useApp)();
3148
- const isResourceVisible = require_resource_page_router.useResourceVisible();
5190
+ const isResourceVisible = useResourceVisible();
3149
5191
  const gate = (0, _burojs_react.useAvailabilityGate)();
3150
5192
  const t = (0, _burojs_react.useOptionalT)();
3151
5193
  const navigate = (0, _burojs_react.useRouteNavigate)();
@@ -3153,7 +5195,7 @@ function CommandPaletteCreateGroup({ resourceFilter, onSelect, getTestId, headin
3153
5195
  const resolvedHeading = heading ?? t("commandPalette.create", { defaultValue: "Create" });
3154
5196
  const resolvedPrefix = prefix ?? t("commandPalette.createNew", { defaultValue: "Create new" });
3155
5197
  const visibleResources = (0, react.useMemo)(() => {
3156
- return app.registry.list().filter((r) => (0, _burojs_core.hasListPage)(r)).filter((r) => gate(require_resource_page_router.canonicalResourceKey(r), "create").state === "available").filter((r) => (0, _burojs_core.hasRecordPage)(r, "create") || opensInQuick(app.registry, require_resource_page_router.canonicalResourceKey(r), "create")).filter(isResourceVisible).filter((r) => resourceFilter ? resourceFilter(r) : true);
5198
+ return app.registry.list().filter((r) => (0, _burojs_core.hasListPage)(r)).filter((r) => (0, _burojs_core.collectionFactOf)(r) === void 0).filter((r) => gate(require_record_trail_store.canonicalResourceKey(r), "create").state === "available").filter((r) => (0, _burojs_core.hasRecordPage)(r, "create") || opensInQuick(app.registry, require_record_trail_store.canonicalResourceKey(r), "create")).filter(isResourceVisible).filter((r) => resourceFilter ? resourceFilter(r) : true);
3157
5199
  }, [
3158
5200
  app,
3159
5201
  gate,
@@ -3171,13 +5213,13 @@ function CommandPaletteCreateGroup({ resourceFilter, onSelect, getTestId, headin
3171
5213
  return;
3172
5214
  }
3173
5215
  onSelect?.();
3174
- quick.create(require_resource_page_router.canonicalResourceKey(def));
5216
+ quick.create(require_record_trail_store.canonicalResourceKey(def));
3175
5217
  };
3176
- const resourceLabel = (def) => (0, _burojs_core.resolveResourceLabel)(caps, require_resource_page_router.canonicalResourceKey(def), "single", def);
5218
+ const resourceLabel = (def) => (0, _burojs_core.resolveResourceLabel)(caps, require_record_trail_store.canonicalResourceKey(def), "single", def);
3177
5219
  return (0, react_jsx_runtime.jsx)(require_relation_create.CommandGroup, {
3178
5220
  heading: resolvedHeading,
3179
5221
  children: visibleResources.map((def) => {
3180
- const resource = require_resource_page_router.canonicalResourceKey(def);
5222
+ const resource = require_record_trail_store.canonicalResourceKey(def);
3181
5223
  const label = resourceLabel(def);
3182
5224
  const href = createHref?.(def) ?? (0, _burojs_core.resourceCreateHref)(app.registry, def, resource);
3183
5225
  const value = `create:${resource}:${resolvedPrefix}:${label}`;
@@ -3229,19 +5271,21 @@ function AppActions() {
3229
5271
  className: "flex items-center gap-1",
3230
5272
  "data-testid": "app-actions",
3231
5273
  children: links.map(({ action, href }) => {
5274
+ const inert = action.disabledReason !== void 0 || action.undecided === true;
3232
5275
  const label = (0, _burojs_core.resolveNavLabel)(caps, `appActions.${action.name}`, action.label);
3233
5276
  const content = action.icon === void 0 ? label : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(require_check_confirm_dialog.Icon, { name: action.icon }), (0, react_jsx_runtime.jsx)("span", {
3234
5277
  className: "max-md:sr-only",
3235
5278
  children: label
3236
5279
  })] });
3237
5280
  return (0, react_jsx_runtime.jsx)(require_button.Button, {
3238
- asChild: action.disabledReason === void 0,
5281
+ asChild: !inert,
3239
5282
  variant: "outline",
3240
5283
  size: "sm",
3241
- disabled: action.disabledReason !== void 0,
5284
+ disabled: inert,
5285
+ "aria-busy": action.undecided === true ? "true" : void 0,
3242
5286
  title: action.disabledReason === void 0 ? void 0 : require_check_confirm_dialog.reasonText(caps, action.disabledReason),
3243
5287
  "data-testid": `app-action:${action.name}`,
3244
- children: action.disabledReason === void 0 ? (0, react_jsx_runtime.jsx)(RouterLink, {
5288
+ children: !inert ? (0, react_jsx_runtime.jsx)(RouterLink, {
3245
5289
  href,
3246
5290
  children: content
3247
5291
  }) : (0, react_jsx_runtime.jsx)("span", { children: content })
@@ -3622,6 +5666,7 @@ function EnumChoiceGroup({ control, options, current, settling, value, onChange,
3622
5666
  //#endregion
3623
5667
  //#region src/enum/enum-picker.tsx
3624
5668
  const ENUM_PICKER_CLEAR_SENTINEL = "__buro_clear__";
5669
+ const NO_VALUES = Object.freeze([]);
3625
5670
  function withSummary(summary) {
3626
5671
  return summary === void 0 ? {} : { summary };
3627
5672
  }
@@ -3632,7 +5677,10 @@ function EnumPicker({ enumName: enumInput, value, onChange, control = "select",
3632
5677
  const def = app.registry.enums.get(enumName);
3633
5678
  const caps = (0, _burojs_react.useI18nCaps)();
3634
5679
  const ns = def?.i18nNamespace ?? enumName;
3635
- const { values, isLoading, error } = (0, _burojs_react.useEnumValues)(enumName);
5680
+ const loaderParams = def !== void 0 && def.values === void 0 && use !== void 0 ? (0, _burojs_core_internal.resolveEnumParams)(def.params, use.params, use.sources) : void 0;
5681
+ const unsettledParams = loaderParams !== void 0 && loaderParams.status !== "ready";
5682
+ const { values: loadedValues, isLoading, error } = (0, _burojs_react.useEnumValues)(enumName, loaderParams?.status === "ready" ? loaderParams.params : void 0, { enabled: !unsettledParams });
5683
+ const values = unsettledParams ? NO_VALUES : loadedValues;
3636
5684
  const available = (0, _burojs_react.useAvailableEnumValues)({
3637
5685
  values: isLoading || values === void 0 ? "pending" : values,
3638
5686
  ...def === void 0 ? {} : { enum: def },
@@ -4480,7 +6528,7 @@ function JsonInput({ name, id, value, onChange, testid, disabled, required, aria
4480
6528
  }
4481
6529
  //#endregion
4482
6530
  //#region src/fields/lazy-relation-many.tsx
4483
- const RelationManyPickerInput = (0, react.lazy)(() => Promise.resolve().then(() => require("./relation-many-picker-Br-zBHxT.cjs")).then((module) => ({ default: module.RelationManyPickerInput })));
6531
+ const RelationManyPickerInput = (0, react.lazy)(() => Promise.resolve().then(() => require("./relation-many-picker-Cq0EHY5I.cjs")).then((module) => ({ default: module.RelationManyPickerInput })));
4484
6532
  function LazyRelationManyInput(props) {
4485
6533
  return (0, react_jsx_runtime.jsx)(react.Suspense, {
4486
6534
  fallback: (0, react_jsx_runtime.jsx)(require_skeleton.Skeleton, {
@@ -5801,7 +7849,7 @@ function BlockScreen({ block, props, resource, record, label }) {
5801
7849
  children: (0, react_jsx_runtime.jsx)("div", {
5802
7850
  "data-testid": "modal-block",
5803
7851
  className: "min-w-0",
5804
- children: (0, react_jsx_runtime.jsx)(require_resource_page_router.PlannedBody, {
7852
+ children: (0, react_jsx_runtime.jsx)(PlannedBody, {
5805
7853
  screen: compiled,
5806
7854
  name: "modal",
5807
7855
  label: label ?? "",
@@ -6327,7 +8375,7 @@ function QuickLoaded({ entry, recordId, typedId, row, isCurrentData }) {
6327
8375
  const answer = gate(entry.resource, entry.mode === "edit" ? "edit" : "show", row);
6328
8376
  const open = answer.state === "open";
6329
8377
  const title = (0, _burojs_react.useProjectedTitle)(entry.resource, recordId, row, { placeholder: !isCurrentData });
6330
- require_resource_page_router.useRecordVisit(entry.resource, open && entry.mode === "show" ? row : null, { isCurrentData });
8378
+ useRecordVisit(entry.resource, open && entry.mode === "show" ? row : null, { isCurrentData });
6331
8379
  const stack = quick?.stack;
6332
8380
  (0, react.useEffect)(() => {
6333
8381
  if (open && stack !== void 0) stack.nameTop(title);
@@ -6413,7 +8461,7 @@ function QuickScreenOf({ entry, route, recordId }) {
6413
8461
  value: route,
6414
8462
  children: (0, react_jsx_runtime.jsx)(require_place_node.QuickScreenClaimContext.Provider, {
6415
8463
  value: true,
6416
- children: (0, react_jsx_runtime.jsx)(require_resource_page_router.RecordScreen, {
8464
+ children: (0, react_jsx_runtime.jsx)(RecordScreen, {
6417
8465
  resource: entry.resource,
6418
8466
  mode: entry.mode,
6419
8467
  ...recordId === void 0 ? {} : { recordId },
@@ -6922,6 +8970,7 @@ const spacing = {
6922
8970
  const groupTestId = (role, id) => `command-palette:${role}:${id}`;
6923
8971
  function DefaultCommandPalette({ open, onOpenChange, actions, children }) {
6924
8972
  const t = (0, _burojs_react.useOptionalT)();
8973
+ const waiting = useShellWaiting();
6925
8974
  const locale = (0, _burojs_react.useLocale)();
6926
8975
  const canSearchRecords = (0, _burojs_react.useOptionalDataRuntime)() !== null;
6927
8976
  const close = () => onOpenChange(false);
@@ -6960,21 +9009,21 @@ function DefaultCommandPalette({ open, onOpenChange, actions, children }) {
6960
9009
  locale,
6961
9010
  onSelect: close
6962
9011
  }),
6963
- (0, react_jsx_runtime.jsx)(CommandPaletteRecentGroup, {
9012
+ waiting ? null : (0, react_jsx_runtime.jsx)(CommandPaletteRecentGroup, {
6964
9013
  onSelect: close,
6965
9014
  refreshKey: open,
6966
9015
  getTestId: groupTestId
6967
9016
  }),
6968
- canSearchRecords ? (0, react_jsx_runtime.jsx)(CommandPaletteRecordsGroup, {
9017
+ canSearchRecords && !waiting ? (0, react_jsx_runtime.jsx)(CommandPaletteRecordsGroup, {
6969
9018
  enabled: open,
6970
9019
  onSelect: close,
6971
9020
  getTestId: groupTestId
6972
9021
  }) : null,
6973
- (0, react_jsx_runtime.jsx)(CommandPaletteNavigationGroups, {
9022
+ waiting ? null : (0, react_jsx_runtime.jsx)(CommandPaletteNavigationGroups, {
6974
9023
  onSelect: close,
6975
9024
  getTestId: (role, id) => `command-palette:nav:${role}:${id}`
6976
9025
  }),
6977
- (0, react_jsx_runtime.jsx)(CommandPaletteCreateGroup, {
9026
+ waiting ? null : (0, react_jsx_runtime.jsx)(CommandPaletteCreateGroup, {
6978
9027
  onSelect: close,
6979
9028
  getTestId: groupTestId
6980
9029
  }),
@@ -6990,6 +9039,10 @@ function DefaultCommandPalette({ open, onOpenChange, actions, children }) {
6990
9039
  //#region src/shell/app-shell.tsx
6991
9040
  function AppShell({ brand, user, loginPath, sidebar, header, palette, docPanel, navChrome, children }) {
6992
9041
  const enabled = palette !== false;
9042
+ const waiting = useShellWaiting();
9043
+ const decidedOnce = (0, react.useRef)(false);
9044
+ if (!waiting) decidedOnce.current = true;
9045
+ const holding = waiting && !decidedOnce.current;
6993
9046
  const { open, setOpen, toggle } = (0, _burojs_react.useCommandPalette)();
6994
9047
  (0, _burojs_react_web.useGlobalShortcut)({
6995
9048
  key: "k",
@@ -7012,7 +9065,7 @@ function AppShell({ brand, user, loginPath, sidebar, header, palette, docPanel,
7012
9065
  sidebar: fill(sidebar, () => (0, react_jsx_runtime.jsx)(AppSidebar, {})),
7013
9066
  header: fill(header, () => (0, react_jsx_runtime.jsx)(AppHeader, {})),
7014
9067
  ...docPanel !== void 0 ? { docPanel } : {},
7015
- children: navChrome === false ? children : (0, react_jsx_runtime.jsx)(NavChrome, { children })
9068
+ children: holding ? (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "loading" }) : navChrome === false ? children : (0, react_jsx_runtime.jsx)(NavChrome, { children })
7016
9069
  }), paletteNode]
7017
9070
  });
7018
9071
  }
@@ -7161,6 +9214,8 @@ exports.Checkbox = require_place_node.Checkbox;
7161
9214
  exports.Collapsible = Collapsible;
7162
9215
  exports.CollapsibleContent = CollapsibleContent;
7163
9216
  exports.CollapsibleTrigger = CollapsibleTrigger;
9217
+ exports.CollectionCreatePicker = CollectionCreatePicker;
9218
+ exports.CollectionRecordRoute = CollectionRecordRoute;
7164
9219
  exports.ColumnsToggle = require_place_node.ColumnsToggle;
7165
9220
  exports.Command = require_relation_create.Command;
7166
9221
  exports.CommandDialog = require_relation_create.CommandDialog;
@@ -7281,7 +9336,8 @@ exports.ListLive = require_place_node.ListLive;
7281
9336
  exports.ListSavedViews = require_place_node.ListSavedViews;
7282
9337
  exports.ListSearchInput = require_place_node.ListSearchInput;
7283
9338
  exports.LoginForm = LoginForm;
7284
- exports.NavAreaPage = require_resource_page_router.NavAreaPage;
9339
+ exports.NavAreaNotFound = require_record_trail_store.NavAreaNotFound;
9340
+ exports.NavAreaPage = NavAreaPage;
7285
9341
  exports.NavChrome = NavChrome;
7286
9342
  exports.NavMain = NavMain;
7287
9343
  exports.NavigationGuardDialog = NavigationGuardDialog;
@@ -7301,8 +9357,8 @@ exports.PresetFilterControls = require_filter_builder.PresetFilterControls;
7301
9357
  exports.Progress = Progress;
7302
9358
  exports.RecordActions = require_place_node.RecordActions;
7303
9359
  exports.RecordBreadcrumbs = RecordBreadcrumbs;
7304
- exports.RecordPage = require_resource_page_router.RecordPage;
7305
- exports.RecordScreen = require_resource_page_router.RecordScreen;
9360
+ exports.RecordPage = RecordPage;
9361
+ exports.RecordScreen = RecordScreen;
7306
9362
  exports.RecordTitle = require_place_node.RecordTitle;
7307
9363
  exports.RefreshButton = RefreshButton;
7308
9364
  exports.RelationDisplay = require_relation_create.RelationDisplay;
@@ -7312,12 +9368,12 @@ exports.RelationPicker = require_relation_picker.RelationPicker;
7312
9368
  exports.RelationPickerDialog = require_lazy_relation_picker_dialog.LazyRelationPickerDialog;
7313
9369
  exports.RelationPickerInput = require_relation_picker.RelationPickerInput;
7314
9370
  exports.ResourceList = require_place_node.ResourceList;
7315
- exports.ResourceListPage = require_resource_page_router.ResourceListPage;
7316
- exports.ResourcePageRouter = require_resource_page_router.ResourcePageRouter;
9371
+ exports.ResourceListPage = ResourceListPage;
9372
+ exports.ResourcePageRouter = ResourcePageRouter;
7317
9373
  exports.SavedViewsDropdown = require_place_node.SavedViewsDropdown;
7318
9374
  exports.ScopeDimensionPicker = ScopeDimensionPicker;
7319
9375
  exports.ScopeSwitcher = ScopeSwitcher;
7320
- exports.SecondarySidebarLayout = require_resource_page_router.SecondarySidebarLayout;
9376
+ exports.SecondarySidebarLayout = SecondarySidebarLayout;
7321
9377
  exports.Select = require_filter_builder.Select;
7322
9378
  exports.SelectContent = require_filter_builder.SelectContent;
7323
9379
  exports.SelectGroup = require_filter_builder.SelectGroup;
@@ -7377,7 +9433,7 @@ exports.TableHeader = require_filter_builder.TableHeader;
7377
9433
  exports.TableRow = require_filter_builder.TableRow;
7378
9434
  exports.Tabs = require_place_node.Tabs;
7379
9435
  exports.TabsContent = require_place_node.TabsContent;
7380
- exports.TabsLayout = require_resource_page_router.TabsLayout;
9436
+ exports.TabsLayout = TabsLayout;
7381
9437
  exports.TabsList = require_place_node.TabsList;
7382
9438
  exports.TabsTrigger = require_place_node.TabsTrigger;
7383
9439
  exports.TaskRunPanel = TaskRunPanel;
@@ -7393,6 +9449,7 @@ exports.Tooltip = require_check_confirm_dialog.Tooltip;
7393
9449
  exports.TooltipContent = require_check_confirm_dialog.TooltipContent;
7394
9450
  exports.TooltipProvider = require_check_confirm_dialog.TooltipProvider;
7395
9451
  exports.TooltipTrigger = require_check_confirm_dialog.TooltipTrigger;
9452
+ exports.UnknownMemberCard = UnknownMemberCard;
7396
9453
  exports.UserMenu = UserMenu;
7397
9454
  exports.badgeVariants = require_filter_builder.badgeVariants;
7398
9455
  exports.buildNavItems = buildNavItems;
@@ -7406,7 +9463,7 @@ exports.formatOperatorLabel = formatOperatorLabel;
7406
9463
  exports.hasIcon = require_check_confirm_dialog.hasIcon;
7407
9464
  exports.i18nPrefixToRef = _burojs_core.i18nPrefixToRef;
7408
9465
  exports.isImage = _burojs_file_storage.isImage;
7409
- exports.layoutSlot = require_resource_page_router.layoutSlot;
9466
+ exports.layoutSlot = layoutSlot;
7410
9467
  exports.listSlot = require_check_confirm_dialog.listSlot;
7411
9468
  exports.loadLocale = require_filter_builder.loadLocale;
7412
9469
  exports.localeLabel = localeLabel;
@@ -7436,18 +9493,18 @@ exports.useDocumentTitle = require_place_node.useDocumentTitle;
7436
9493
  exports.useExportRunWatcher = require_place_node.useExportRunWatcher;
7437
9494
  exports.useFormControl = require_place_node.useFormControl;
7438
9495
  exports.useFormField = useFormField;
7439
- exports.useHref = require_resource_page_router.useHref;
9496
+ exports.useHref = useHref;
7440
9497
  exports.useIsMobile = useIsMobile;
7441
9498
  exports.useLanguagePaletteActions = useLanguagePaletteActions;
7442
9499
  exports.useLanguageSwitch = useLanguageSwitch;
7443
- exports.useLayout = require_resource_page_router.useLayout;
7444
- exports.useLayoutResolver = require_resource_page_router.useLayoutResolver;
9500
+ exports.useLayout = useLayout;
9501
+ exports.useLayoutResolver = useLayoutResolver;
7445
9502
  exports.useLinkComponent = require_toaster.useLinkComponent;
7446
9503
  exports.useListSlot = require_check_confirm_dialog.useListSlot;
7447
- exports.useMatch = require_resource_page_router.useMatch;
9504
+ exports.useMatch = useMatch;
7448
9505
  exports.useNavIcon = useNavIcon;
7449
9506
  exports.useNavTree = useNavTree;
7450
- exports.useNavVisible = require_resource_page_router.useNavVisible;
9507
+ exports.useNavVisible = useNavVisible;
7451
9508
  exports.useOptionalSidebar = useOptionalSidebar;
7452
9509
  exports.usePaletteState = require_place_node.usePaletteState;
7453
9510
  exports.usePresentationCopy = usePresentationCopy;