@burojs/ui-shadcn 0.9.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 (108) 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-QvoY2bOQ.js → candidates-relation-picker-DRsHKe6N.js} +3 -3
  6. package/dist/{candidates-relation-picker-QvoY2bOQ.js.map → candidates-relation-picker-DRsHKe6N.js.map} +1 -1
  7. package/dist/{candidates-relation-picker-pEAWKQEY.cjs → candidates-relation-picker-GIxsp7D_.cjs} +3 -3
  8. package/dist/{candidates-relation-picker-pEAWKQEY.cjs.map → candidates-relation-picker-GIxsp7D_.cjs.map} +1 -1
  9. package/dist/{check-confirm-dialog-W-8WOmGh.cjs → check-confirm-dialog-BMSb7wFv.cjs} +17 -9
  10. package/dist/check-confirm-dialog-BMSb7wFv.cjs.map +1 -0
  11. package/dist/{check-confirm-dialog-B-CbJTln.js → check-confirm-dialog-B_u3YVHS.js} +18 -10
  12. package/dist/{check-confirm-dialog-B-CbJTln.js.map → check-confirm-dialog-B_u3YVHS.js.map} +1 -1
  13. package/dist/{filter-builder-04nas3eq.js → filter-builder-DX-xC3Yd.js} +2 -2
  14. package/dist/{filter-builder-04nas3eq.js.map → filter-builder-DX-xC3Yd.js.map} +1 -1
  15. package/dist/{filter-builder-DQX-TMFh.cjs → filter-builder-Dt5E8PSX.cjs} +2 -2
  16. package/dist/{filter-builder-DQX-TMFh.cjs.map → filter-builder-Dt5E8PSX.cjs.map} +1 -1
  17. package/dist/{flow-runtime-DyNIYfUP.cjs → flow-runtime-CQ4wf8co.cjs} +2 -2
  18. package/dist/{flow-runtime-DyNIYfUP.cjs.map → flow-runtime-CQ4wf8co.cjs.map} +1 -1
  19. package/dist/{flow-runtime-BEIyym7d.js → flow-runtime-Q2vD7R3c.js} +2 -2
  20. package/dist/{flow-runtime-BEIyym7d.js.map → flow-runtime-Q2vD7R3c.js.map} +1 -1
  21. package/dist/{flow-screen-DY1Z9PbG.js → flow-screen-B1y2yizP.js} +18 -18
  22. package/dist/flow-screen-B1y2yizP.js.map +1 -0
  23. package/dist/{flow-screen-FE5Xhb3t.cjs → flow-screen-sw2cP70t.cjs} +18 -18
  24. package/dist/flow-screen-sw2cP70t.cjs.map +1 -0
  25. package/dist/index.cjs +2183 -109
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.cts +76 -8
  28. package/dist/index.d.ts +76 -8
  29. package/dist/index.js +2095 -24
  30. package/dist/index.js.map +1 -1
  31. package/dist/{inline-flow-host-yVLo6-sM.cjs → inline-flow-host-CkhoA69R.cjs} +3 -3
  32. package/dist/{inline-flow-host-yVLo6-sM.cjs.map → inline-flow-host-CkhoA69R.cjs.map} +1 -1
  33. package/dist/{inline-flow-host-D6u-RlsV.js → inline-flow-host-DqbXqcPS.js} +3 -3
  34. package/dist/{inline-flow-host-D6u-RlsV.js.map → inline-flow-host-DqbXqcPS.js.map} +1 -1
  35. package/dist/{lazy-relation-picker-dialog-BaORufxQ.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-C_VlGlDz.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-CyMzUidK.js → page-flow-route-CP7cS7FY.js} +5 -5
  40. package/dist/page-flow-route-CP7cS7FY.js.map +1 -0
  41. package/dist/{page-flow-route-OFx7h7Ja.cjs → page-flow-route-UDx8qvdM.cjs} +9 -9
  42. package/dist/page-flow-route-UDx8qvdM.cjs.map +1 -0
  43. package/dist/{place-node-BZF5Af6x.cjs → place-node-C5ZmuHaN.cjs} +149 -40
  44. package/dist/place-node-C5ZmuHaN.cjs.map +1 -0
  45. package/dist/{place-node-DRjmJGQ_.js → place-node-DwWAigv0.js} +146 -43
  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-xVvgSlu-.cjs → related-list-cards-BypKfm9t.cjs} +3 -3
  52. package/dist/{related-list-cards-xVvgSlu-.cjs.map → related-list-cards-BypKfm9t.cjs.map} +1 -1
  53. package/dist/{related-list-cards-2hLitVkg.js → related-list-cards-Dcmruy09.js} +3 -3
  54. package/dist/{related-list-cards-2hLitVkg.js.map → related-list-cards-Dcmruy09.js.map} +1 -1
  55. package/dist/{related-list-timeline-Dsf5WewG.cjs → related-list-timeline-D-KClgKb.cjs} +4 -4
  56. package/dist/{related-list-timeline-Dsf5WewG.cjs.map → related-list-timeline-D-KClgKb.cjs.map} +1 -1
  57. package/dist/{related-list-timeline-CxJqe6eK.js → related-list-timeline-DZON_qSc.js} +4 -4
  58. package/dist/{related-list-timeline-CxJqe6eK.js.map → related-list-timeline-DZON_qSc.js.map} +1 -1
  59. package/dist/{related-rows-DDhp9axl.cjs → related-rows-DgF05ssi.cjs} +4 -4
  60. package/dist/{related-rows-DDhp9axl.cjs.map → related-rows-DgF05ssi.cjs.map} +1 -1
  61. package/dist/{related-rows-DL6CWsrj.js → related-rows-ETZl5CB9.js} +4 -4
  62. package/dist/{related-rows-DL6CWsrj.js.map → related-rows-ETZl5CB9.js.map} +1 -1
  63. package/dist/{relation-create-_SFuPQGM.cjs → relation-create-B8zngAcA.cjs} +46 -11
  64. package/dist/relation-create-B8zngAcA.cjs.map +1 -0
  65. package/dist/{relation-create-6WicROWA.js → relation-create-CeCWyxIb.js} +47 -12
  66. package/dist/relation-create-CeCWyxIb.js.map +1 -0
  67. package/dist/{relation-many-picker-mGEQDWo2.js → relation-many-picker-CT7nKfE2.js} +4 -4
  68. package/dist/{relation-many-picker-mGEQDWo2.js.map → relation-many-picker-CT7nKfE2.js.map} +1 -1
  69. package/dist/{relation-many-picker-BBNsmkaX.cjs → relation-many-picker-Cq0EHY5I.cjs} +4 -4
  70. package/dist/{relation-many-picker-BBNsmkaX.cjs.map → relation-many-picker-Cq0EHY5I.cjs.map} +1 -1
  71. package/dist/{relation-picker-BbO41cFV.js → relation-picker-CCyuMeGq.js} +6 -6
  72. package/dist/{relation-picker-BbO41cFV.js.map → relation-picker-CCyuMeGq.js.map} +1 -1
  73. package/dist/{relation-picker-jk9D_uwn.cjs → relation-picker-DmwTzgsd.cjs} +6 -6
  74. package/dist/{relation-picker-jk9D_uwn.cjs.map → relation-picker-DmwTzgsd.cjs.map} +1 -1
  75. package/dist/{relation-picker-dialog-BgSG_8bU.js → relation-picker-dialog-CoWKjNv8.js} +4 -4
  76. package/dist/{relation-picker-dialog-BgSG_8bU.js.map → relation-picker-dialog-CoWKjNv8.js.map} +1 -1
  77. package/dist/{relation-picker-dialog-Duqy2r0n.cjs → relation-picker-dialog-mbwyNK43.cjs} +4 -4
  78. package/dist/{relation-picker-dialog-Duqy2r0n.cjs.map → relation-picker-dialog-mbwyNK43.cjs.map} +1 -1
  79. package/dist/{relation-select-C3aV18kT.cjs → relation-select-CguIo2M5.cjs} +2 -2
  80. package/dist/{relation-select-C3aV18kT.cjs.map → relation-select-CguIo2M5.cjs.map} +1 -1
  81. package/dist/{relation-select-CjQT9LpS.js → relation-select-nAYxhopN.js} +2 -2
  82. package/dist/{relation-select-CjQT9LpS.js.map → relation-select-nAYxhopN.js.map} +1 -1
  83. package/dist/{use-dialog-filter-state-lsTJxrB4.cjs → use-dialog-filter-state-CpWblz3C.cjs} +2 -2
  84. package/dist/{use-dialog-filter-state-lsTJxrB4.cjs.map → use-dialog-filter-state-CpWblz3C.cjs.map} +1 -1
  85. package/dist/{use-dialog-filter-state-CJoeY-1j.js → use-dialog-filter-state-ZYxOp5WO.js} +2 -2
  86. package/dist/{use-dialog-filter-state-CJoeY-1j.js.map → use-dialog-filter-state-ZYxOp5WO.js.map} +1 -1
  87. package/dist/{use-record-subtitle-BJ9rnj6F.cjs → use-record-subtitle-B4lTR7pf.cjs} +2 -2
  88. package/dist/{use-record-subtitle-BJ9rnj6F.cjs.map → use-record-subtitle-B4lTR7pf.cjs.map} +1 -1
  89. package/dist/{use-record-subtitle-w3ZhXNlf.js → use-record-subtitle-pWMBqQx9.js} +2 -2
  90. package/dist/{use-record-subtitle-w3ZhXNlf.js.map → use-record-subtitle-pWMBqQx9.js.map} +1 -1
  91. package/package.json +9 -9
  92. package/dist/bulk-summary-2HLgz7Il.cjs.map +0 -1
  93. package/dist/bulk-summary-D6A0ua21.js.map +0 -1
  94. package/dist/check-confirm-dialog-W-8WOmGh.cjs.map +0 -1
  95. package/dist/flow-screen-DY1Z9PbG.js.map +0 -1
  96. package/dist/flow-screen-FE5Xhb3t.cjs.map +0 -1
  97. package/dist/lazy-relation-picker-dialog-BaORufxQ.js.map +0 -1
  98. package/dist/lazy-relation-picker-dialog-C_VlGlDz.cjs.map +0 -1
  99. package/dist/page-flow-route-CyMzUidK.js.map +0 -1
  100. package/dist/page-flow-route-OFx7h7Ja.cjs.map +0 -1
  101. package/dist/place-node-BZF5Af6x.cjs.map +0 -1
  102. package/dist/place-node-DRjmJGQ_.js.map +0 -1
  103. package/dist/relation-create-6WicROWA.js.map +0 -1
  104. package/dist/relation-create-_SFuPQGM.cjs.map +0 -1
  105. package/dist/resource-page-router-CzaNATSp.js +0 -2010
  106. package/dist/resource-page-router-CzaNATSp.js.map +0 -1
  107. package/dist/resource-page-router-dmVIeu5s.cjs +0 -2231
  108. package/dist/resource-page-router-dmVIeu5s.cjs.map +0 -1
package/dist/index.js CHANGED
@@ -1,26 +1,27 @@
1
1
  import { c as scrollToDocAnchor, l as cn, n as useTheme, s as readDocHash, t as THEME_CHOICES } from "./use-theme-dnE3Od3I.js";
2
2
  import { a as technicalText, c as LinkComponentProvider, d as PopoverAnchor, f as PopoverClose, l as useLinkComponent, m as PopoverTrigger, n as toast, p as PopoverContent, r as friendlyStringsFrom, s as toFriendlyError, t as Toaster, u as Popover } from "./toaster-Ct_YHGs6.js";
3
- import { $ as DropdownMenuTrigger, A as useLoaded, B as DropdownMenuCheckboxItem, E as loadFlowScreen, F as SheetPresentationShell, G as DropdownMenuPortal, H as DropdownMenuGroup, I as Icon, J as DropdownMenuSeparator, K as DropdownMenuRadioGroup, L as hasIcon, N as DialogPresentationShell, P as OwnTitleContext, Q as DropdownMenuSubTrigger, R as registerIcons, U as DropdownMenuItem, V as DropdownMenuContent, W as DropdownMenuLabel, X as DropdownMenuSub, Y as DropdownMenuShortcut, Z as DropdownMenuSubContent, at as SheetClose, b as FlowLoadFailed, c as listSlot, ct as SheetFooter, d as openExternal, dt as SheetTrigger, et as Tooltip, ft as DocInfo, it as Sheet, j as OwnTitleHeading, l as useListSlot, lt as SheetHeader, n as ActionButton, nt as TooltipProvider, o as modeForSurface, ot as SheetContent, p as FlowActionButton, q as DropdownMenuRadioItem, r as DisabledAction, rt as TooltipTrigger, s as canonicalResourceName, st as SheetDescription, t as CheckConfirmDialog, tt as TooltipContent, u as isExternalHref, ut as SheetTitle, v as reasonText, y as FlowBoundary, z as DropdownMenu } from "./check-confirm-dialog-B-CbJTln.js";
3
+ import { $ as DropdownMenuTrigger, A as useLoaded, B as DropdownMenuCheckboxItem, E as loadFlowScreen, F as SheetPresentationShell, G as DropdownMenuPortal, H as DropdownMenuGroup, I as Icon, J as DropdownMenuSeparator, K as DropdownMenuRadioGroup, L as hasIcon, N as DialogPresentationShell, O as loadPageFlowRoute, P as OwnTitleContext, Q as DropdownMenuSubTrigger, R as registerIcons, T as loadFailedText, U as DropdownMenuItem, V as DropdownMenuContent, W as DropdownMenuLabel, X as DropdownMenuSub, Y as DropdownMenuShortcut, Z as DropdownMenuSubContent, at as SheetClose, b as FlowLoadFailed, c as listSlot, ct as SheetFooter, d as openExternal, dt as SheetTrigger, et as Tooltip, ft as DocInfo, it as Sheet, j as OwnTitleHeading, l as useListSlot, lt as SheetHeader, n as ActionButton, nt as TooltipProvider, o as modeForSurface, ot as SheetContent, p as FlowActionButton, q as DropdownMenuRadioItem, r as DisabledAction, rt as TooltipTrigger, s as canonicalResourceName, st as SheetDescription, t as CheckConfirmDialog, tt as TooltipContent, u as isExternalHref, ut as SheetTitle, v as reasonText, y as FlowBoundary, z as DropdownMenu } from "./check-confirm-dialog-B_u3YVHS.js";
4
4
  import { n as buttonVariants, t as Button } from "./button-MWVeZaqj.js";
5
5
  import { t as Input } from "./input-CUPStzZO.js";
6
6
  import { a as DialogFooter, c as DialogTrigger, i as DialogDescription, n as DialogClose, o as DialogHeader, r as DialogContent, s as DialogTitle, t as Dialog } from "./dialog-C123sVQ8.js";
7
- import { A as CommandSeparator, C as CommandDialog, D as CommandItem, E as CommandInput, O as CommandList, S as Command, T as CommandGroup, b as LoadError, c as RelationField, d as peekAnchorOpener, f as PeekContext, g as recordDisplayName, k as CommandLoading, l as relationLinkClassName, p as PeekHostContext, s as RelationDisplay, u as focusWithoutPeek, w as CommandEmpty, x as RecordState, y as InvalidRouteId } from "./relation-create-6WicROWA.js";
7
+ import { A as CommandSeparator, C as CommandDialog, D as CommandItem, E as CommandInput, O as CommandList, S as Command, T as CommandGroup, b as LoadError, c as RelationField, d as peekAnchorOpener, f as PeekContext, g as recordDisplayName, k as CommandLoading, l as relationLinkClassName, m as useRowTitle, p as PeekHostContext, s as RelationDisplay, u as focusWithoutPeek, w as CommandEmpty, x as RecordState, y as InvalidRouteId } from "./relation-create-CeCWyxIb.js";
8
8
  import { t as Skeleton } from "./skeleton-U2noefj5.js";
9
- import { $ as CursorLoadMore, A as ListSearchInput, At as AppFlowButton, B as ExportDialog, C as ListControls, D as ListFlows, Dt as EnumSettlingRow, E as ListLive, Et as EnumBadge, F as ListColumns, Ft as toDisplayText, H as ScreenTree, I as ColumnsToggle, It as ShellProvider, L as DataTableViewOptions, Lt as defaultUserMapper, M as ExportButton, Mt as FieldDisplay, N as ListCreate, Nt as i18nPrefixToRef, O as ListFilters, Ot as unknownEnumValueLabel, P as CreateButton, Pt as FieldValueFrame, Q as ResourceList, R as ListBulkBar, Rt as usePaletteState, St as ActionOverflow, T as SavedViewsDropdown, Tt as downloadArtifact, V as DeclarativeForm, W as QuickScreenClaimContext, Y as useFormControl, Z as ListBody, _ as CopyId, _t as ShowPageHeader, a as peekFieldDefinition, at as DataTable, b as RecordTitle, bt as useDocumentTitle, c as peekRow, ct as TabsContent, d as resolveFrameView, et as ListErrorState, f as shadcnFrameViews, gt as PageHeader, ht as EditPageHeader, it as useBuroDataTable, j as ListExport, jt as Field, k as FilterRegion, l as useRelationPicker, lt as TabsList, nt as resolveUpdater, o as peekLeafAllowed, ot as Checkbox, r as shadcnBlockImplementations, rt as tanStackSortingToBuro, s as peekRecord, st as Tabs, tt as buroSortingToTanStack, ut as TabsTrigger, v as FormActions, vt as resolveResourceTitle, w as ListSavedViews, wt as useExportRunWatcher, xt as typography, y as RecordActions, yt as DocumentTitleProvider, z as BulkActionToolbar, zt as useShell } from "./place-node-DRjmJGQ_.js";
9
+ import { $ as ResourceList, A as FilterRegion, At as DeepLinkScope, B as BulkActionToolbar, Bt as useShell, C as useFrameChrome, Ct as ActionOverflow, D as ListLive, Dt as EnumBadge, E as SavedViewsDropdown, Et as downloadArtifact, F as CreateButton, Ft as FieldValueFrame, G as QuickScreenClaimContext, H as DeclarativeForm, I as ListColumns, It as toDisplayText, J as useIsRouteScreen, K as RouteScreenClaimContext, L as ColumnsToggle, Lt as ShellProvider, M as ListExport, Mt as Field, N as ExportButton, Nt as FieldDisplay, O as ListFlows, Ot as EnumSettlingRow, P as ListCreate, Pt as i18nPrefixToRef, Q as ListBody, R as DataTableViewOptions, Rt as defaultUserMapper, S as ItemActionsOffContext, St as typography, T as ListSavedViews, Tt as useExportRunWatcher, U as ScreenTree, V as ExportDialog, W as useTabsUrlState, X as useFormControl, Y as FormControlProvider, Z as useFormControlOf, _ as CopyId, _t as PageHeader, a as peekFieldDefinition, at as useBuroDataTable, b as RecordTitle, bt as DocumentTitleProvider, c as peekRow, ct as Tabs, d as resolveFrameView, dt as TabsTrigger, et as CursorLoadMore, f as shadcnFrameViews, g as UndeclaredTypeNotice, gt as EditPageHeader, h as TypeChromeDrawnContext, i as RouteListContext, it as tanStackSortingToBuro, j as ListSearchInput, jt as AppFlowButton, k as ListFilters, kt as unknownEnumValueLabel, l as useRelationPicker, lt as TabsContent, m as HeaderTypeNotice, n as viewOf, nt as buroSortingToTanStack, o as peekLeafAllowed, ot as DataTable, p as ChangeTypeButton, q as RouteScreenContext, r as shadcnBlockImplementations, rt as resolveUpdater, s as peekRecord, st as Checkbox, t as selectImplementation, tt as ListErrorState, u as isBuiltinRecordView, ut as TabsList, v as FormActions, vt as ShowPageHeader, w as ListControls, wt as useShownItemActions, x as FrameChromeContext, xt as useDocumentTitle, y as RecordActions, yt as resolveResourceTitle, z as ListBulkBar, zt as usePaletteState } from "./place-node-DwWAigv0.js";
10
10
  import { THEME_STORAGE_KEY } from "./layout/theme-storage-key.js";
11
- import { A as TableHeader, B as DEFAULT_LANGUAGE_STORAGE_KEY, C as SelectTrigger, D as TableCaption, E as TableBody, F as ResolvedFieldDisplay, H as saveLocale, M as Badge, N as badgeVariants, O as TableCell, S as SelectSeparator, T as Table, V as loadLocale, _ as SelectGroup, a as PinnedFilterControls, b as SelectScrollDownButton, c as fromLocalDateTimeText, d as useFieldTimeZone, f as FilterBadges, g as SelectContent, h as Select, i as FacetedFilterPicker, j as TableRow, k as TableHead, l as toLocalDateTimeText, m as localeTag, n as PresetFilterControls, o as FilterPanel, p as formatNumber, r as DataTableFacetedFilter, s as FilterValueControl, t as FilterBuilder, u as dateDisplayParams, v as SelectItem, w as SelectValue, x as SelectScrollUpButton, y as SelectLabel, z as lowerLegacyField } from "./filter-builder-04nas3eq.js";
12
- import { A as useLayoutResolver, C as useMatch, D as BUILTIN_LAYOUTS, E as useResourceVisible, F as groupNavHref, I as canonicalNavKey, L as canonicalResourceKey$1, M as TabsLayout, N as SecondarySidebarLayout, O as layoutSlot, P as buildNavItems, S as useHref, T as usePageAllowed, _ as RecordScreen, a as useRecordVisit, b as ResourceListPage, c as headerTrail, d as recordTrailRoute, f as useTrailContext, g as usePublishedRecordTrail, i as RecordPage, j as useReportUnresolvedLayouts, k as useLayout, l as originTrail, m as recordTrailKey, n as NavAreaPage, o as RECENT_LABEL_KEYS, p as isShowAvailable, r as ResourcePageRouter, s as readRecentRecords, t as NavAreaNotFound, u as recordTrail, v as useResourceDimensionOptions, w as useNavVisible, x as NavChromeMountedProvider, y as PlannedBody } from "./resource-page-router-CzaNATSp.js";
11
+ import { A as TableHeader, B as DEFAULT_LANGUAGE_STORAGE_KEY, C as SelectTrigger, D as TableCaption, E as TableBody, F as ResolvedFieldDisplay, H as saveLocale, M as Badge, N as badgeVariants, O as TableCell, S as SelectSeparator, T as Table, V as loadLocale, _ as SelectGroup, a as PinnedFilterControls, b as SelectScrollDownButton, c as fromLocalDateTimeText, d as useFieldTimeZone, f as FilterBadges, g as SelectContent, h as Select, i as FacetedFilterPicker, j as TableRow, k as TableHead, l as toLocalDateTimeText, m as localeTag, n as PresetFilterControls, o as FilterPanel, p as formatNumber, r as DataTableFacetedFilter, s as FilterValueControl, t as FilterBuilder, u as dateDisplayParams, v as SelectItem, w as SelectValue, x as SelectScrollUpButton, y as SelectLabel, z as lowerLegacyField } from "./filter-builder-DX-xC3Yd.js";
12
+ import { a as canonicalNavKey, i as NavAreaNotFound, n as usePublishRecordTrail, o as canonicalResourceKey$1, r as usePublishedRecordTrail, t as recordTrailKey } from "./record-trail-store-Dn6bVry4.js";
13
13
  import { t as Label } from "./label-66W1qbke.js";
14
- import { t as LazyRelationPickerDialog } from "./lazy-relation-picker-dialog-BaORufxQ.js";
15
- import { n as useRecordSubtitle, r as useRowSubtitle } from "./use-record-subtitle-w3ZhXNlf.js";
16
- import { n as RelationPicker, r as RelationPickerInput } from "./relation-picker-BbO41cFV.js";
17
- import { t as useDialogFilterState } from "./use-dialog-filter-state-CJoeY-1j.js";
14
+ import { t as LazyRelationPickerDialog } from "./lazy-relation-picker-dialog-BaIEWLbF.js";
15
+ import { t as useNoticeSink } from "./success-notices-CrcWOGSo.js";
16
+ import { n as useRecordSubtitle, r as useRowSubtitle } from "./use-record-subtitle-pWMBqQx9.js";
17
+ import { n as RelationPicker, r as RelationPickerInput } from "./relation-picker-CCyuMeGq.js";
18
+ import { t as useDialogFilterState } from "./use-dialog-filter-state-ZYxOp5WO.js";
18
19
  import { useGlobalShortcut, webPlatform } from "@burojs/react/web";
19
- import { ENUM_CONTROLS, builtinFrames, canonicalInstant, columnName, compilePageScreen, compiledScreenFor, declaredField, declaredText, dtoFields, effectiveFlow, enumFallbackKey, enumFallbackText, enumNamespaceOf, enumValueText, epochMsToInstant, evaluateVisible, fieldOptionText, formatEntityRef, formatTimeValue, hasListPage, hasRecordPage, hrefFor, humanizeKey, isCalendarDate, isCustomPageDef, isEnumControl, isRelationField, isScreenFailure, linkOf, nodeKind, normalizeDataError, normalizeEntityRef, projectDto, recordEntries, relationAmbiguousError, resolveConceptLabel, resolveContentSlot, resolveDoc, resolveEnumLabel, resolveFieldLabel, resolveNavLabel, resolveResourceLabel, resolveResourceNavLabel, resolveStaticAvailability, resourceCreateHref, resourceKey, resourceShowHref, routeResourceKey, snapshotAppFrames, snapshotBlockLookup, snapshotFrameLookup, taskRunFraction, taskRunOutcome, zoneShortName } from "@burojs/core";
20
- import { ComponentsContext, DispatcherProvider, I18nContext, NO_RECORD_SCOPE_FRAMES, QUICK_ANCHOR_ATTRIBUTE, QuickEntryContext, RecordScopeChain, RouteSourceContext, ScreenStateProvider, formatBytes, optionFieldName, recordRouteAvailable, resolveErrorText, resolveOptionLabel, retryRecordRead, useApp, useAppActions, useApplicationSnapshot, useAvailabilityGate, useAvailableEnumValues, useBoundEnum, useCapabilityResolver, useChangeLocale, useChromeT, useCommandPalette, useCurrentUserId, useDebouncedValue, useDispatcherEffects, useDocPanel, useDocScopes, useDocTopics, useDocTrailScopes, useDocsConfig, useDocumentedScopes, useEntryGate, useEnumValues, useFieldAccess, useFieldMetaSources, useFileField, useFileUrls, useFormController, useFrameImplementations, useFrameT, useI18nCaps, useIdentity, useLanguageStorageKey, useLinkKeys, useList, useListAccess, useLocale, useLogout, useNavigationGuardText, useNavigationOrigin, useOne, useOptionCaps, useOptionalApp, useOptionalAuthController, useOptionalDataRuntime, useOptionalFileStorage, useOptionalLocale, useOptionalRouterAdapter, useOptionalT, useOriginIntent, usePermissionsUndecided, usePlatformStorage, usePresentBlock, useProjectedRecord, useProjectedTitle, usePublishOriginTitle, useQuick, useQuickEntry, useQuickEntryValue, useQuickOpener, useRecordTitle, useRefresh, useRegisterNavigationGuardDialog, useRelatedRecord, useRouteNavigate, useRouteRecordId, useRouterAdapter, useScope, useT, useTestIds, useTimeZone, useUIInstance, useUIPresentationRuntime, useVisibilityCtx } from "@burojs/react";
20
+ import { ENUM_CONTROLS, FORM_SLOT, addressesCapability, builtinFrames, canonicalInstant, collectionFactOf, columnName, compilePageScreen, compiledScreenFor, declaredField, declaredText, dtoFields, effectiveFlow, enumFallbackKey, enumFallbackText, enumNamespaceOf, enumValueText, epochMsToInstant, evaluateVisible, fieldOptionText, fieldSensitivity, formatEntityRef, formatTimeValue, hasListPage, hasMenuEntry, hasRecordPage, hrefFor, humanizeKey, isCalendarDate, isCustomPageDef, isEnumControl, isRelationField, isScreenFailure, issueOfInput, linkOf, matchPath, memberFactOf, navHrefFor, nodeKind, normalizeDataError, normalizeEntityRef, normalizeIssueInputs, pageParamNames, parsePageParams, permissionsUndecided, projectDto, recordEntries, relationAmbiguousError, resolveConceptLabel, resolveContentSlot, resolveDoc, resolveEnumLabel, resolveFieldLabel, resolveNavLabel, resolveResourceLabel, resolveResourceNavLabel, resolveStaticAvailability, resourceCreateHref, resourceKey, resourceShowHref, routeResourceKey, routeServerIssues, sameEntityRef, scopeColumnOf, snapshotAppFrames, snapshotBlockLookup, snapshotFrameLookup, successNoticesOf, taskRunFraction, taskRunOutcome, zoneShortName } from "@burojs/core";
21
+ import { ActionRouteContext, ComponentsContext, DispatcherProvider, FrameCheckContext, I18nContext, NO_RECORD_SCOPE_FRAMES, ORIGIN_DEPTH, QUICK_ANCHOR_ATTRIBUTE, QuickEntryContext, RecordFrameContext, RecordScopeChain, RecordScopeProvider, ResourceContext, RouteSourceContext, ScreenStateProvider, formatBytes, maybeThen, optionFieldName, pageAccessFor, policyRecordOf, recordKeyOf, recordRouteAvailable, resolveErrorText, resolveOptionLabel, resolveRoute, retryRecordRead, settle, useApp, useAppActions, useApplicationSnapshot, useAvailabilityGate, useAvailabilityResolver, useAvailableEnumValues, useBoundEnum, useCapabilityResolver, useChangeLocale, useChromeT, useCollectionMember, useCommandPalette, useComponent, useCtx, useCurrentUserId, useDebouncedValue, useDispatcherEffects, useDocPanel, useDocScopes, useDocTopics, useDocTrailScopes, useDocsConfig, useDocumentedScopes, useEntryGate, useEnumValues, useFieldAccess, useFieldMetaSources, useFileField, useFileUrls, useFormController, useFrameImplementations, useFrameT, useI18nCaps, useIdentity, useLanguageStorageKey, useLinkKeys, useList, useListAccess, useLocale, useLogout, useNavigationGuardText, useNavigationOrigin, useOne, useOptionCaps, useOptionalApp, useOptionalAuthController, useOptionalDataRuntime, useOptionalFileStorage, useOptionalLocale, useOptionalRouterAdapter, useOptionalT, useOriginIntent, usePageAccess, usePageScreen, usePermissions, usePermissionsUndecided, usePlatformStorage, usePresentBlock, useProjectedRecord, useProjectedTitle, usePublishDocVariant, usePublishOriginTitle, useQuick, useQuickEntry, useQuickEntryValue, useQuickOpener, useRecordFrame, useRecordTitle, useRefresh, useRegisterNavigationGuardDialog, useRelatedRecord, useReturnTarget, useRouteListImplementation, useRouteNavigate, useRouteRecordId, useRouterAdapter, useScope, useT, useTestIds, useTimeZone, useTranslate, useUIInstance, useUIPresentationRuntime, useVisibilityCtx } from "@burojs/react";
21
22
  import { IconAlertCircle, IconArrowDown, IconArrowLeft, IconArrowUp, IconArrowUpRight, IconBook2, IconCheck, IconChevronDown, IconChevronRight, IconDeviceDesktop, IconDots, IconExternalLink, IconHelp, IconHelpHexagon, IconLayoutSidebar, IconLoader2, IconLogin, IconLogout, IconMaximize, IconMinimize, IconMoon, IconPlus, IconRefresh, IconRotate, IconSearch, IconSelector, IconSun, IconTrash, IconUpload, IconUser, IconX } from "@tabler/icons-react";
22
23
  import * as React from "react";
23
- import { Children, Fragment, Suspense, cloneElement, createContext, createElement, isValidElement, lazy, useCallback, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
24
+ import { Children, Fragment, Suspense, cloneElement, createContext, createElement, isValidElement, lazy, useCallback, useContext, useEffect, useId, useMemo, useRef, useState, useSyncExternalStore } from "react";
24
25
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
25
26
  import { Slot } from "@radix-ui/react-slot";
26
27
  import { cva } from "class-variance-authority";
@@ -296,7 +297,7 @@ function DocBrowser({ className }) {
296
297
  label,
297
298
  summary: resolveDoc(caps, entry.scope)?.summary,
298
299
  nested: entry.kind === "variant",
299
- group: entry.kind === "concept" ? glossaryLabel : entry.kind === "resource" ? areasLabel : void 0
300
+ group: entry.kind === "concept" ? glossaryLabel : entry.kind === "resource" || entry.kind === "base" ? areasLabel : void 0
300
301
  };
301
302
  }), [
302
303
  app,
@@ -1717,6 +1718,231 @@ function useShellWaiting() {
1717
1718
  return usePermissionsUndecided();
1718
1719
  }
1719
1720
  //#endregion
1721
+ //#region src/layout/build-nav-items.ts
1722
+ function groupNavHref(registry, group, isVisible) {
1723
+ let href;
1724
+ try {
1725
+ href = navHrefFor(registry, group, { isVisible });
1726
+ } catch {
1727
+ return;
1728
+ }
1729
+ return matchPath(registry, href, { isVisible }) === null ? void 0 : href;
1730
+ }
1731
+ function buildNavItems(args) {
1732
+ const { registry, caps, groupName, match, isVisible, entryFilter, icons } = args;
1733
+ const chain = match?.groupChain ?? [];
1734
+ const qualifiedMatch = match;
1735
+ const activeLeaf = qualifiedMatch == null ? void 0 : qualifiedMatch.kind === "group-index" ? canonicalNavKey({
1736
+ name: qualifiedMatch.target ?? qualifiedMatch.name,
1737
+ ref: qualifiedMatch.targetRef
1738
+ }) : canonicalNavKey(qualifiedMatch);
1739
+ const isEligible = (node) => isVisible(node) && (entryFilter ? entryFilter(node) : true);
1740
+ const out = [];
1741
+ for (const child of registry.groups.childrenOf(groupName)) {
1742
+ if (!isEligible(child)) continue;
1743
+ const kind = nodeKind(child);
1744
+ const childKey = canonicalNavKey(child);
1745
+ if (kind === "group") {
1746
+ const href = groupNavHref(registry, childKey, isEligible);
1747
+ if (href === void 0) continue;
1748
+ const label = resolveNavLabel(caps, `groups.${childKey}`, declaredText("chrome", child, "label"));
1749
+ const active = chain.some((g) => canonicalNavKey(g) === childKey);
1750
+ out.push({
1751
+ kind: "group",
1752
+ name: childKey,
1753
+ label,
1754
+ href,
1755
+ icon: icons?.group?.(childKey),
1756
+ active
1757
+ });
1758
+ continue;
1759
+ }
1760
+ const href = navHrefFor(registry, childKey, { isVisible: isEligible });
1761
+ if (kind === "custom-page") out.push({
1762
+ kind: "custom-page",
1763
+ name: childKey,
1764
+ label: resolveNavLabel(caps, `pages.${childKey}`, declaredText("chrome", child, "label")),
1765
+ href,
1766
+ icon: icons?.page?.(childKey),
1767
+ active: activeLeaf === childKey
1768
+ });
1769
+ else out.push({
1770
+ kind: "resource",
1771
+ name: childKey,
1772
+ label: resolveResourceNavLabel(caps, childKey, child),
1773
+ href,
1774
+ icon: icons?.resource?.(childKey),
1775
+ active: activeLeaf === childKey
1776
+ });
1777
+ }
1778
+ return out;
1779
+ }
1780
+ //#endregion
1781
+ //#region src/layout/layouts/secondary-sidebar-layout.tsx
1782
+ function Row({ it }) {
1783
+ const RouterLink = useLinkComponent();
1784
+ return jsx("li", { children: jsxs(RouterLink, {
1785
+ href: it.href,
1786
+ "data-testid": `nav-secondary-item:${it.name}`,
1787
+ "aria-current": it.active ? "page" : void 0,
1788
+ className: 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"),
1789
+ children: [it.icon != null && jsx("span", {
1790
+ className: "inline-flex h-4 w-4 shrink-0 items-center justify-center",
1791
+ "aria-hidden": "true",
1792
+ children: it.icon
1793
+ }), jsx("span", {
1794
+ className: "truncate",
1795
+ title: it.label,
1796
+ children: it.label
1797
+ })]
1798
+ }) });
1799
+ }
1800
+ function SecondarySidebarLayout({ group, groupKey, items, children }) {
1801
+ const RouterLink = useLinkComponent();
1802
+ const caps = useI18nCaps();
1803
+ const id = groupKey ?? group.name;
1804
+ const label = resolveNavLabel(caps, `groups.${id}`, declaredText("chrome", group, "label"));
1805
+ return jsxs("div", {
1806
+ className: "md:-m-6 md:flex md:min-h-[calc(100%+3rem)]",
1807
+ "data-testid": `nav-secondary:${id}`,
1808
+ children: [
1809
+ jsx("aside", {
1810
+ className: "hidden w-64 shrink-0 border-r bg-background text-foreground md:block",
1811
+ children: jsxs("div", {
1812
+ className: "space-y-4 p-4",
1813
+ children: [jsx("p", {
1814
+ className: "px-3 text-base font-semibold tracking-tight",
1815
+ children: label
1816
+ }), jsx("nav", {
1817
+ "aria-label": label,
1818
+ children: jsx("ul", {
1819
+ className: "space-y-0.5",
1820
+ children: items.map((it) => jsx(Row, { it }, it.name))
1821
+ })
1822
+ })]
1823
+ })
1824
+ }),
1825
+ jsx("nav", {
1826
+ "aria-label": label,
1827
+ "data-testid": `nav-secondary-select:${id}`,
1828
+ 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",
1829
+ children: items.map((it) => jsx(RouterLink, {
1830
+ href: it.href,
1831
+ "aria-current": it.active ? "page" : void 0,
1832
+ className: 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"),
1833
+ children: it.label
1834
+ }, it.name))
1835
+ }),
1836
+ jsx("div", {
1837
+ className: "min-w-0 flex-1 md:overflow-x-hidden md:p-6",
1838
+ children
1839
+ })
1840
+ ]
1841
+ });
1842
+ }
1843
+ //#endregion
1844
+ //#region src/layout/layouts/tabs-layout.tsx
1845
+ function TabsLayout({ group, groupKey, items, children }) {
1846
+ const RouterLink = useLinkComponent();
1847
+ const caps = useI18nCaps();
1848
+ const id = groupKey ?? group.name;
1849
+ const label = resolveNavLabel(caps, `groups.${id}`, declaredText("chrome", group, "label"));
1850
+ return jsxs("div", {
1851
+ className: "flex flex-col gap-4",
1852
+ "data-testid": `nav-tabs:${id}`,
1853
+ children: [jsx("nav", {
1854
+ "aria-label": label,
1855
+ 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",
1856
+ children: items.map((it) => jsxs(RouterLink, {
1857
+ href: it.href,
1858
+ "aria-current": it.active ? "page" : void 0,
1859
+ "data-testid": `nav-tab:${it.name}`,
1860
+ className: 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"),
1861
+ children: [
1862
+ it.icon != null && jsx("span", {
1863
+ className: "inline-flex h-4 w-4 shrink-0 items-center justify-center",
1864
+ "aria-hidden": "true",
1865
+ children: it.icon
1866
+ }),
1867
+ it.label,
1868
+ jsx("span", {
1869
+ "aria-hidden": "true",
1870
+ className: 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")
1871
+ })
1872
+ ]
1873
+ }, it.name))
1874
+ }), jsx("div", {
1875
+ className: "min-w-0",
1876
+ children
1877
+ })]
1878
+ });
1879
+ }
1880
+ //#endregion
1881
+ //#region src/layout/nav-slots.ts
1882
+ function layoutSlot(key) {
1883
+ return `layout.${key}`;
1884
+ }
1885
+ function useLayout(key) {
1886
+ return useComponent(layoutSlot(key));
1887
+ }
1888
+ const BUILTIN_LAYOUTS = {
1889
+ [layoutSlot("secondary-sidebar")]: SecondarySidebarLayout,
1890
+ [layoutSlot("tabs")]: TabsLayout
1891
+ };
1892
+ function useLayoutResolver() {
1893
+ const components = useContext(ComponentsContext);
1894
+ return (key) => components[layoutSlot(key)] ?? BUILTIN_LAYOUTS[layoutSlot(key)];
1895
+ }
1896
+ const unresolvedLayoutReported = new WeakMap();
1897
+ function useReportUnresolvedLayouts(groups, resolve) {
1898
+ const app = useApp();
1899
+ useEffect(() => {
1900
+ if (process.env.NODE_ENV === "production") return;
1901
+ for (const group of groups) {
1902
+ const layout = group.layout;
1903
+ if (layout === "flat" || layout === "collapsible" || resolve(layout)) continue;
1904
+ const key = canonicalNavKey(group);
1905
+ let seen = unresolvedLayoutReported.get(app);
1906
+ if (!seen) {
1907
+ seen = new Set();
1908
+ unresolvedLayoutReported.set(app, seen);
1909
+ }
1910
+ if (seen.has(key)) continue;
1911
+ seen.add(key);
1912
+ 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".`);
1913
+ }
1914
+ });
1915
+ }
1916
+ //#endregion
1917
+ //#region src/layout/use-nav-routing.ts
1918
+ function useNavVisible() {
1919
+ const ctx = useVisibilityCtx();
1920
+ const allowed = usePageAllowed();
1921
+ return useCallback((node) => evaluateVisible(node.visible, ctx) && (!isCustomPageDef(node) || allowed(node)), [ctx, allowed]);
1922
+ }
1923
+ function useResourceVisible() {
1924
+ const ctx = useVisibilityCtx();
1925
+ return useCallback((def) => evaluateVisible(def.visible, ctx), [ctx]);
1926
+ }
1927
+ function usePageAllowed() {
1928
+ const permissions = usePermissions();
1929
+ return useCallback((page) => pageAccessFor(page, permissions) === "allowed", [permissions]);
1930
+ }
1931
+ function useHref(name, opts) {
1932
+ const app = useApp();
1933
+ const isVisible = useNavVisible();
1934
+ return hrefFor(app.registry, name, {
1935
+ ...opts,
1936
+ isVisible
1937
+ });
1938
+ }
1939
+ function useMatch() {
1940
+ const app = useApp();
1941
+ const isVisible = useNavVisible();
1942
+ const path = useOptionalRouterAdapter()?.pathname;
1943
+ return path === void 0 ? null : matchPath(app.registry, path, { isVisible });
1944
+ }
1945
+ //#endregion
1720
1946
  //#region src/layout/use-nav-tree.ts
1721
1947
  function isActiveHref(href, currentPath) {
1722
1948
  if (!currentPath) return false;
@@ -1741,7 +1967,7 @@ function useNavTree(opts = {}) {
1741
1967
  const sections = app.registry.sections.list();
1742
1968
  const groups = app.registry.groups.rootNodes().filter((n) => nodeKind(n) === "group");
1743
1969
  useReportUnresolvedLayouts(app.registry.groups.list(), resolveLayout);
1744
- const topLevelResources = allResources.filter((r) => hasListPage(r)).filter(isResourceVisible).filter(passesEntryFilter).filter((r) => !r.section && !r.group).map((r, idx) => ({
1970
+ const topLevelResources = allResources.filter((r) => hasMenuEntry(r)).filter(isResourceVisible).filter(passesEntryFilter).filter((r) => !r.section && !r.group).map((r, idx) => ({
1745
1971
  r,
1746
1972
  idx
1747
1973
  })).sort((a, b) => {
@@ -1826,7 +2052,7 @@ function useNavTree(opts = {}) {
1826
2052
  }];
1827
2053
  for (const section of sections) {
1828
2054
  const sectionKey = canonicalNavKey(section);
1829
- const entries = app.registry.sections.childrenOf(sectionKey).filter((c) => !("parent" in c) || hasListPage(c)).filter((c) => isCustomPageDef(c) ? pageAllowed(c) : isResourceVisible(c)).filter(passesEntryFilter).map((c) => isCustomPageDef(c) ? pageEntry(c) : resourceEntry(c));
2055
+ const entries = app.registry.sections.childrenOf(sectionKey).filter((c) => !("parent" in c) || hasMenuEntry(c)).filter((c) => isCustomPageDef(c) ? pageAllowed(c) : isResourceVisible(c)).filter(passesEntryFilter).map((c) => isCustomPageDef(c) ? pageEntry(c) : resourceEntry(c));
1830
2056
  if (entries.length === 0) continue;
1831
2057
  const active = entries.some((e) => e.active);
1832
2058
  out.push({
@@ -2040,6 +2266,13 @@ function AppSidebar({ header, filters, nav, footer }) {
2040
2266
  });
2041
2267
  }
2042
2268
  //#endregion
2269
+ //#region src/layout/nav-chrome-mounted.ts
2270
+ const NavChromeMountedContext = createContext(false);
2271
+ const NavChromeMountedProvider = NavChromeMountedContext.Provider;
2272
+ function useNavChromeMounted() {
2273
+ return useContext(NavChromeMountedContext);
2274
+ }
2275
+ //#endregion
2043
2276
  //#region src/layout/nav-chrome.tsx
2044
2277
  const DETAIL_ACTIONS = new Set([
2045
2278
  "show",
@@ -2087,6 +2320,1841 @@ function NavChrome({ children, entryFilter, icons }) {
2087
2320
  });
2088
2321
  }
2089
2322
  //#endregion
2323
+ //#region src/flows/page-flow-loader.tsx
2324
+ function PageFlowRouteLoader({ match }) {
2325
+ const t = useOptionalT();
2326
+ const chromeT = useChromeT();
2327
+ const loaded = useLoaded(loadPageFlowRoute);
2328
+ const failed = (retry) => jsxs("div", {
2329
+ role: "alert",
2330
+ "data-buro-flow-load": "failed",
2331
+ className: "flex flex-col gap-3 p-6 text-sm",
2332
+ children: [jsx("p", { children: loadFailedText(t) }), jsx("div", { children: jsx(Button, {
2333
+ type: "button",
2334
+ onClick: retry,
2335
+ children: chromeT("actions.retry", { defaultValue: "Retry" })
2336
+ }) })]
2337
+ });
2338
+ if (loaded.error !== void 0) return failed(loaded.retry);
2339
+ if (loaded.module === void 0) return jsx(RecordState, { state: "loading" });
2340
+ const Route = loaded.module.PageFlowRoute;
2341
+ return jsx(FlowBoundary, {
2342
+ fallback: (_error, reset) => failed(reset),
2343
+ children: jsx(Route, { match })
2344
+ });
2345
+ }
2346
+ //#endregion
2347
+ //#region src/list-kit/resource-list-page.tsx
2348
+ function ResourceListPage({ resource: resourceInput, meta, renderCell, emptyState }) {
2349
+ const resource = routeResourceKey(resourceInput);
2350
+ const app = useRouteListImplementation();
2351
+ const implementation = selectImplementation("buro:related-list", app);
2352
+ const View = implementation === void 0 ? void 0 : viewOf(implementation);
2353
+ const translate = useTranslate();
2354
+ const route = useMemo(() => ({
2355
+ meta,
2356
+ renderCell,
2357
+ emptyState
2358
+ }), [
2359
+ meta,
2360
+ renderCell,
2361
+ emptyState
2362
+ ]);
2363
+ const viewProps = useMemo(() => ({
2364
+ props: { resource: normalizeEntityRef(resource) },
2365
+ data: {},
2366
+ t: (key, options) => translate(`blocks.buro:related-list.${key}`, options)
2367
+ }), [resource, translate]);
2368
+ return jsx("div", {
2369
+ "data-buro-node": "place",
2370
+ "data-buro-size": "full",
2371
+ className: "min-w-0",
2372
+ children: jsx(RouteListContext.Provider, {
2373
+ value: route,
2374
+ children: jsx(Suspense, {
2375
+ fallback: null,
2376
+ children: View === void 0 ? null : jsx(View, { ...viewProps })
2377
+ })
2378
+ })
2379
+ });
2380
+ }
2381
+ //#endregion
2382
+ //#region src/resource/collection-create-picker.tsx
2383
+ function CollectionCreatePicker({ collection }) {
2384
+ const app = useApp();
2385
+ const t = useOptionalT();
2386
+ const caps = useI18nCaps();
2387
+ const gate = useAvailabilityGate("create");
2388
+ const Link = useLinkComponent();
2389
+ const key = routeResourceKey(collection);
2390
+ const testid = `collection-create-picker:${key}`;
2391
+ let undecided = false;
2392
+ const members = (collectionFactOf(app.registry.get(key))?.members ?? []).flatMap((entry) => {
2393
+ const def = app.registry.get(entry.ref);
2394
+ if (def === void 0 || !hasRecordPage(def, "create")) return [];
2395
+ const member = routeResourceKey(entry.ref);
2396
+ const state = gate(member, "create").state;
2397
+ if (state === "undecided") undecided = true;
2398
+ if (state !== "available") return [];
2399
+ return [{
2400
+ member,
2401
+ href: resourceCreateHref(app.registry, def, member),
2402
+ label: resolveResourceLabel(caps, member, "single", def)
2403
+ }];
2404
+ });
2405
+ return jsxs("div", {
2406
+ "data-testid": testid,
2407
+ className: "mx-auto flex max-w-md flex-col gap-3 px-6 py-12",
2408
+ children: [jsx("h2", {
2409
+ className: "text-base font-semibold tracking-tight",
2410
+ children: t("collection.createTitle", { defaultValue: "What do you want to create?" })
2411
+ }), members.length > 0 ? jsx("ul", {
2412
+ className: "flex flex-col gap-2",
2413
+ children: members.map((entry) => jsx("li", { children: jsx(Button, {
2414
+ asChild: true,
2415
+ variant: "outline",
2416
+ className: "w-full justify-start",
2417
+ "data-testid": `${testid}:${entry.member}`,
2418
+ children: jsxs(Link, {
2419
+ href: entry.href,
2420
+ children: [jsx(Icon, {
2421
+ name: "Plus",
2422
+ className: "mr-1 h-4 w-4"
2423
+ }), entry.label]
2424
+ })
2425
+ }) }, entry.member))
2426
+ }) : undecided ? jsx("div", {
2427
+ role: "status",
2428
+ "aria-busy": "true",
2429
+ className: "h-9 w-full animate-pulse rounded bg-muted/40"
2430
+ }) : jsx("p", {
2431
+ className: "text-sm text-muted-foreground",
2432
+ children: t("collection.createNone", { defaultValue: "There is nothing here you can create." })
2433
+ })]
2434
+ });
2435
+ }
2436
+ //#endregion
2437
+ //#region src/frames/obligations.tsx
2438
+ const SlotMountsContext = createContext(null);
2439
+ function useSlotOnce(slot) {
2440
+ const mounts = useContext(SlotMountsContext);
2441
+ const token = useId();
2442
+ const first = mounts === null || mounts.claim(slot, token);
2443
+ useEffect(() => {
2444
+ if (mounts === null) return;
2445
+ mounts.claim(slot, token);
2446
+ return () => mounts.release(slot, token);
2447
+ }, [
2448
+ mounts,
2449
+ slot,
2450
+ token
2451
+ ]);
2452
+ useEffect(() => {
2453
+ if (!first) mounts?.twice(slot);
2454
+ }, [
2455
+ first,
2456
+ mounts,
2457
+ slot
2458
+ ]);
2459
+ return first;
2460
+ }
2461
+ function FrameObligations({ id, mode, showActions, root, children }) {
2462
+ const told = useRef(new Set());
2463
+ const counts = useRef(new Map());
2464
+ const owners = useRef(new Map());
2465
+ const tell = (key, write) => {
2466
+ if (told.current.has(key) || process.env.NODE_ENV === "production") return;
2467
+ told.current.add(key);
2468
+ write();
2469
+ };
2470
+ const latestId = useRef(id);
2471
+ latestId.current = id;
2472
+ const slotMounts = useMemo(() => ({
2473
+ claim(slot, token) {
2474
+ const owner = owners.current.get(slot);
2475
+ if (owner === void 0) {
2476
+ owners.current.set(slot, token);
2477
+ return true;
2478
+ }
2479
+ return owner === token;
2480
+ },
2481
+ release(slot, token) {
2482
+ if (owners.current.get(slot) === token) owners.current.delete(slot);
2483
+ },
2484
+ twice(slot) {
2485
+ 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).`));
2486
+ }
2487
+ }), []);
2488
+ const pieces = useMemo(() => ({
2489
+ stub: false,
2490
+ mount(piece) {
2491
+ counts.current.set(piece, (counts.current.get(piece) ?? 0) + 1);
2492
+ return () => counts.current.set(piece, (counts.current.get(piece) ?? 1) - 1);
2493
+ }
2494
+ }), []);
2495
+ return jsx(SlotMountsContext.Provider, {
2496
+ value: slotMounts,
2497
+ children: jsxs(FrameCheckContext.Provider, {
2498
+ value: pieces,
2499
+ children: [children, jsx(ObligationCheck, { check: () => {
2500
+ const mounted = (piece) => (counts.current.get(piece) ?? 0) > 0;
2501
+ 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.`));
2502
+ 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.`));
2503
+ if (root.current?.querySelector("h1") != null) tell("h1", () => console.error(`[burojs] ${id} renders an h1; the route draws the screen's one h1.`));
2504
+ } })]
2505
+ })
2506
+ });
2507
+ }
2508
+ function ObligationCheck({ check }) {
2509
+ useEffect(() => {
2510
+ check();
2511
+ });
2512
+ return null;
2513
+ }
2514
+ //#endregion
2515
+ //#region src/frames/slot-wrapper.tsx
2516
+ function DraftBanner() {
2517
+ const { resource, mode, controller } = useRecordFrame();
2518
+ const t = useOptionalT();
2519
+ const tid = useTestIds();
2520
+ const { draft } = controller;
2521
+ if (mode === "show" || draft.pending === null) return null;
2522
+ return jsxs("div", {
2523
+ "data-testid": tid.formDraftBanner(resource, mode),
2524
+ role: "status",
2525
+ "aria-live": "polite",
2526
+ className: "flex flex-wrap items-center gap-2 rounded-md border border-warning/50 bg-warning/10 px-3 py-2 text-sm",
2527
+ children: [
2528
+ jsx("span", {
2529
+ className: "font-medium",
2530
+ children: draft.recordChanged ? t("draft.recordChanged") : t("draft.found", { params: { time: timeAgo(draft.pending.savedAt, t) } })
2531
+ }),
2532
+ draft.recordChanged ? null : jsx("span", {
2533
+ className: "text-muted-foreground",
2534
+ children: t("draft.restorePrompt")
2535
+ }),
2536
+ jsxs("div", {
2537
+ className: "ml-auto flex gap-2",
2538
+ children: [draft.recordChanged ? null : jsx(Button, {
2539
+ type: "button",
2540
+ size: "sm",
2541
+ variant: "outline",
2542
+ "data-testid": tid.formDraftRestore(resource, mode),
2543
+ onClick: draft.restore,
2544
+ children: t("draft.restore")
2545
+ }), jsx(Button, {
2546
+ type: "button",
2547
+ size: "sm",
2548
+ variant: "ghost",
2549
+ "data-testid": tid.formDraftDiscard(resource, mode),
2550
+ onClick: draft.discard,
2551
+ children: t("draft.discard")
2552
+ })]
2553
+ })
2554
+ ]
2555
+ });
2556
+ }
2557
+ function timeAgo(savedAt, t) {
2558
+ const then = new Date(savedAt).getTime();
2559
+ if (!Number.isFinite(then)) return t("draft.timeAgoRecently");
2560
+ const diff = Date.now() - then;
2561
+ if (diff < 6e4) return t("draft.timeAgoMoment");
2562
+ if (diff < 36e5) return t("draft.timeAgoMinutes", { count: Math.round(diff / 6e4) });
2563
+ if (diff < 864e5) return t("draft.timeAgoHours", { count: Math.round(diff / 36e5) });
2564
+ return t("draft.timeAgoDays", { count: Math.round(diff / 864e5) });
2565
+ }
2566
+ function frameRecordId(frame, def) {
2567
+ if (frame.recordId !== void 0) return frame.recordId;
2568
+ const id = recordKeyOf(def, frame.record);
2569
+ return typeof id === "string" || typeof id === "number" ? String(id) : void 0;
2570
+ }
2571
+ function BodySlot() {
2572
+ const frame = useRecordFrame();
2573
+ const { resource, mode, controller } = frame;
2574
+ const chrome = useFrameChrome();
2575
+ const tid = useTestIds();
2576
+ const id = frameRecordId(frame, useApp().registry.get(resource));
2577
+ const tree = jsx("div", {
2578
+ "data-buro-region": "record-body",
2579
+ "data-buro-slot": FORM_SLOT,
2580
+ children: jsx(ScreenTree, {
2581
+ region: "record",
2582
+ slot: FORM_SLOT,
2583
+ resource,
2584
+ mode,
2585
+ compiled: controller.screen,
2586
+ controller
2587
+ })
2588
+ });
2589
+ if (mode === "show") return tree;
2590
+ return jsxs("form", {
2591
+ id: chrome.formId,
2592
+ noValidate: true,
2593
+ "data-testid": tid.form(resource, mode, id),
2594
+ onSubmit: (event) => {
2595
+ event.preventDefault();
2596
+ const steps = controller.steps;
2597
+ if (steps !== null && steps.current !== void 0 && steps.current !== steps.ids[steps.ids.length - 1]) steps.next();
2598
+ else chrome.submit();
2599
+ },
2600
+ className: "flex flex-col gap-4",
2601
+ children: [jsx(DraftBanner, {}), tree]
2602
+ });
2603
+ }
2604
+ function DisplaySlot({ name }) {
2605
+ const { resource, mode, controller } = useRecordFrame();
2606
+ return jsx(ScreenTree, {
2607
+ region: "record",
2608
+ slot: name,
2609
+ resource,
2610
+ mode,
2611
+ compiled: controller.screen,
2612
+ controller
2613
+ });
2614
+ }
2615
+ function SlotWrapper({ name }) {
2616
+ if (!useSlotOnce(name)) return null;
2617
+ return name === FORM_SLOT ? jsx(BodySlot, {}) : jsx(DisplaySlot, { name });
2618
+ }
2619
+ //#endregion
2620
+ //#region src/frames/record-frame-host.tsx
2621
+ const NO_ROOT = { current: null };
2622
+ function drawnFields(roots, compiled, out) {
2623
+ for (const node of roots) {
2624
+ if (node.state === "absent") continue;
2625
+ const field = node.field ?? compiled.nodes[node.index]?.field;
2626
+ if (node.kind === "field" && field !== void 0 && node.state === "ready") out.add(field);
2627
+ drawnFields(node.children, compiled, out);
2628
+ }
2629
+ }
2630
+ function frameRecord(record, compiled, slots, idField, visible = () => true) {
2631
+ if (record === void 0 || compiled === null || slots === void 0) return void 0;
2632
+ const drawn = new Set();
2633
+ for (const roots of Object.values(slots)) drawnFields(roots, compiled, drawn);
2634
+ const declarations = new Map(compiled.fields.map((entry) => [entry.name, entry.declaration]));
2635
+ const out = {};
2636
+ if (Object.hasOwn(record, idField)) out[idField] = record[idField];
2637
+ for (const name of drawn) {
2638
+ if (!Object.hasOwn(record, name) || !visible(name)) continue;
2639
+ if (fieldSensitivity(declarations.get(name)) !== void 0) continue;
2640
+ out[name] = record[name];
2641
+ }
2642
+ return Object.freeze(out);
2643
+ }
2644
+ function declaredSlots(compiled) {
2645
+ if (compiled === null) return [];
2646
+ return Object.entries(compiled.slots).filter(([, nodes]) => nodes.length > 0).map(([name]) => name);
2647
+ }
2648
+ function useEffectiveFrame(instance) {
2649
+ const { resource, mode, controller } = useRecordFrame();
2650
+ const compiled = controller.screen;
2651
+ const missing = useMemo(() => {
2652
+ if (instance === void 0 || instance.for !== "record") return void 0;
2653
+ const own = new Set(Object.keys(instance.slots));
2654
+ return declaredSlots(compiled).find((slot) => !own.has(slot));
2655
+ }, [instance, compiled]);
2656
+ const told = useRef(false);
2657
+ const instanceId = instance === void 0 ? void 0 : formatEntityRef(instance.ref);
2658
+ useEffect(() => {
2659
+ if (missing === void 0 || told.current || process.env.NODE_ENV === "production") return;
2660
+ told.current = true;
2661
+ console.error(`[burojs] <RecordScreen frame={${instanceId}}> lacks the slot ${missing} that ${resource}'s ${mode} screen fills; the screen's own frame draws it.`);
2662
+ }, [
2663
+ missing,
2664
+ instanceId,
2665
+ resource,
2666
+ mode
2667
+ ]);
2668
+ if (instance !== void 0 && instance.for === "record" && missing === void 0 && compiled !== null) return {
2669
+ ref: instance.ref,
2670
+ slotNames: Object.keys(instance.slots)
2671
+ };
2672
+ return {
2673
+ ref: compiled?.frame ?? builtinFrames.record.ref,
2674
+ slotNames: compiled === null ? ["header", FORM_SLOT] : Object.keys(compiled.slots)
2675
+ };
2676
+ }
2677
+ function RecordFrameView({ frame: instance }) {
2678
+ const { resource, mode, controller, record } = useRecordFrame();
2679
+ const chrome = useFrameChrome();
2680
+ const quick = useQuickEntry();
2681
+ const app = useApp();
2682
+ const catalog = useFrameImplementations();
2683
+ const { ref, slotNames } = useEffectiveFrame(instance);
2684
+ const id = formatEntityRef(ref);
2685
+ const resolved = useMemo(() => resolveFrameView(ref, catalog, "record"), [ref, catalog]);
2686
+ const t = useFrameT(id);
2687
+ const compiled = controller.screen;
2688
+ const plan = controller.plan;
2689
+ const slots = {};
2690
+ for (const name of slotNames) {
2691
+ if (name === FORM_SLOT) {
2692
+ slots[name] = jsx(SlotWrapper, { name }, name);
2693
+ continue;
2694
+ }
2695
+ slots[name] = (plan?.slots[name] ?? []).every((node) => node.state === "absent") ? null : jsx(SlotWrapper, { name }, name);
2696
+ }
2697
+ slots[FORM_SLOT] ??= jsx(SlotWrapper, { name: FORM_SLOT });
2698
+ const idField = app.registry.get(resource)?.data?.idField ?? "id";
2699
+ const access = useFieldAccess(resource, "record", record === void 0 ? void 0 : policyRecordOf(controller, record));
2700
+ const projected = useMemo(() => frameRecord(record, compiled, plan?.slots, idField, (name) => access[name]?.view === "visible"), [
2701
+ record,
2702
+ compiled,
2703
+ plan,
2704
+ idField,
2705
+ access
2706
+ ]);
2707
+ const quickHost = chrome.hostTitle === true && quick !== null;
2708
+ const props = {
2709
+ slots,
2710
+ host: quickHost ? quick.host : "page",
2711
+ mode,
2712
+ screen: {
2713
+ resource,
2714
+ entry: quickHost ? "quick" : "route"
2715
+ },
2716
+ record: mode === "create" ? void 0 : projected,
2717
+ t
2718
+ };
2719
+ const policyRecord = policyRecordOf(controller, record);
2720
+ const rowId = record?.[idField];
2721
+ const actionRow = useMemo(() => ({
2722
+ ...policyRecord ?? {},
2723
+ id: typeof rowId === "string" || typeof rowId === "number" ? String(rowId) : ""
2724
+ }), [policyRecord, rowId]);
2725
+ const showItemActions = useShownItemActions(resource, actionRow, "show", void 0, controller.sources);
2726
+ const showActions = mode === "show" && record !== void 0 && showItemActions.length > 0;
2727
+ const View = resolved.view;
2728
+ const builtin = isBuiltinRecordView(resolved);
2729
+ return jsxs(Fragment$1, { children: [builtin ? null : jsxs(Fragment$1, { children: [jsx(HeaderTypeNotice, { resource }), jsx(ChangeTypeButton, {})] }), jsx(TypeChromeDrawnContext.Provider, {
2730
+ value: !builtin,
2731
+ children: jsx(Suspense, {
2732
+ fallback: jsx(RecordState, { state: "loading" }),
2733
+ children: jsx(FrameObligations, {
2734
+ id,
2735
+ mode,
2736
+ showActions,
2737
+ root: chrome.root ?? NO_ROOT,
2738
+ children: jsx(View, { ...props })
2739
+ })
2740
+ })
2741
+ })] });
2742
+ }
2743
+ function useResourceDimensionOptions(dimension, resource, labelField) {
2744
+ const def = useApp().registry.get(resource);
2745
+ const rowTitle = useRowTitle(resource, labelField ?? def?.displayField);
2746
+ const rows = useList(resource, {
2747
+ pagination: {
2748
+ kind: "offset",
2749
+ page: 1,
2750
+ pageSize: 100
2751
+ },
2752
+ total: false,
2753
+ scope: {
2754
+ default: "session",
2755
+ dimensions: { [dimension]: "none" }
2756
+ }
2757
+ }).data?.data;
2758
+ return useMemo(() => (rows ?? []).flatMap((row) => {
2759
+ const key = recordKeyOf(def, row);
2760
+ return key === null || key === void 0 ? [] : [{
2761
+ value: key,
2762
+ label: rowTitle(row)
2763
+ }];
2764
+ }), [
2765
+ rows,
2766
+ def,
2767
+ rowTitle
2768
+ ]);
2769
+ }
2770
+ //#endregion
2771
+ //#region src/record/scope-mismatch-banner.tsx
2772
+ const asList = (value) => value === null ? [] : Array.isArray(value) ? value : [value];
2773
+ const isScalar = (value) => typeof value === "string" || typeof value === "number" || typeof value === "boolean";
2774
+ function ScopeMismatchBanner(props) {
2775
+ const app = useApp();
2776
+ const mapping = app.registry.get(props.resource)?.data?.scope;
2777
+ if (app.scope === void 0 || mapping === void 0 || props.record === void 0) return null;
2778
+ return jsx(Banner, {
2779
+ ...props,
2780
+ record: props.record,
2781
+ mapping
2782
+ });
2783
+ }
2784
+ function Banner({ record, mapping, kind = "record" }) {
2785
+ const scope = useScope();
2786
+ const chromeT = useChromeT();
2787
+ const differences = useMemo(() => {
2788
+ const out = [];
2789
+ for (const [dimension, target] of Object.entries(mapping)) {
2790
+ const definition = scope.definition?.dimensions[dimension];
2791
+ if (definition === void 0 || definition.select === "none") continue;
2792
+ const selected = asList(scope.selection[dimension] ?? null);
2793
+ if (selected.length === 0) continue;
2794
+ const column = scopeColumnOf(target);
2795
+ if (!Object.hasOwn(record, column)) continue;
2796
+ const held = record[column];
2797
+ if (held === null || held === void 0 || held === "") {
2798
+ if (kind === "created" || "field" in target && target.empty === "shared") continue;
2799
+ out.push({
2800
+ dimension,
2801
+ value: null,
2802
+ selected,
2803
+ select: definition.select
2804
+ });
2805
+ continue;
2806
+ }
2807
+ if (!isScalar(held)) continue;
2808
+ if (selected.some((value) => String(value) === String(held))) continue;
2809
+ out.push({
2810
+ dimension,
2811
+ value: held,
2812
+ selected,
2813
+ select: definition.select
2814
+ });
2815
+ }
2816
+ return out;
2817
+ }, [
2818
+ mapping,
2819
+ record,
2820
+ scope.definition,
2821
+ scope.selection,
2822
+ kind
2823
+ ]);
2824
+ if (differences.length === 0) return null;
2825
+ const apply = () => {
2826
+ for (const difference of differences) scope.select(difference.dimension, difference.value === null ? null : difference.select === "multiple" ? [difference.value] : difference.value);
2827
+ };
2828
+ return jsxs("div", {
2829
+ role: "status",
2830
+ "data-testid": "scope-mismatch:banner",
2831
+ className: "flex flex-wrap items-center justify-between gap-3 rounded-md border bg-muted/50 px-3 py-2 text-sm",
2832
+ children: [jsxs("div", {
2833
+ className: "space-y-1",
2834
+ children: [jsx("p", {
2835
+ className: "font-medium",
2836
+ 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" })
2837
+ }), jsx("ul", {
2838
+ className: "text-muted-foreground",
2839
+ children: differences.map((difference) => jsx(DifferenceLine, {
2840
+ difference,
2841
+ definition: scope.definition.dimensions[difference.dimension]
2842
+ }, difference.dimension))
2843
+ })]
2844
+ }), jsx(Button, {
2845
+ type: "button",
2846
+ size: "sm",
2847
+ "data-testid": "scope-mismatch:switch",
2848
+ onClick: apply,
2849
+ children: chromeT("scope.mismatch.switch", { defaultValue: "Switch" })
2850
+ })]
2851
+ });
2852
+ }
2853
+ function DifferenceLine(props) {
2854
+ const source = props.definition.values;
2855
+ if (source !== void 0 && !Array.isArray(source)) {
2856
+ const { resource, label } = source;
2857
+ return jsx(ResourceLine, {
2858
+ ...props,
2859
+ resource,
2860
+ ...label ? { labelField: label } : {}
2861
+ });
2862
+ }
2863
+ return jsx(LineText, {
2864
+ difference: props.difference,
2865
+ options: source ?? []
2866
+ });
2867
+ }
2868
+ function ResourceLine({ difference, resource, labelField }) {
2869
+ const options = useResourceDimensionOptions(difference.dimension, resource, labelField);
2870
+ return jsx(LineText, {
2871
+ difference,
2872
+ options
2873
+ });
2874
+ }
2875
+ function LineText({ difference, options }) {
2876
+ const chromeT = useChromeT();
2877
+ const labelOf = (value) => options.find((option) => String(option.value) === String(value))?.label ?? String(value);
2878
+ const field = humanizeKey(difference.dimension);
2879
+ const item = difference.value === null ? chromeT("scope.mismatch.empty", { defaultValue: "not set" }) : labelOf(difference.value);
2880
+ const items = difference.selected.map(labelOf).join(", ");
2881
+ return jsx("li", {
2882
+ "data-testid": `scope-mismatch:line:${difference.dimension}`,
2883
+ children: chromeT("scope.mismatch.line", {
2884
+ params: {
2885
+ field,
2886
+ item,
2887
+ items
2888
+ },
2889
+ defaultValue: `${field}: ${item} (selected: ${items})`
2890
+ })
2891
+ });
2892
+ }
2893
+ //#endregion
2894
+ //#region src/record/type-offer.tsx
2895
+ function TypeOffer({ resource, offer, onChoose }) {
2896
+ const app = useApp();
2897
+ const t = useOptionalT();
2898
+ const tid = useTestIds();
2899
+ const def = app.registry.get(resource);
2900
+ const by = def?.types?.by;
2901
+ const field = by === void 0 ? void 0 : def?.fields[by];
2902
+ const ref = def?.ref ?? {
2903
+ namespace: "default",
2904
+ id: resource
2905
+ };
2906
+ return jsxs("section", {
2907
+ "aria-labelledby": "type-offer-title",
2908
+ className: "flex flex-col gap-3",
2909
+ children: [jsxs("div", {
2910
+ className: "flex flex-col gap-1",
2911
+ children: [jsx("h2", {
2912
+ id: "type-offer-title",
2913
+ className: "text-base font-semibold",
2914
+ children: t("create.typeOffer.title", { defaultValue: "Choose a type" })
2915
+ }), jsx("p", {
2916
+ className: "text-sm text-muted-foreground",
2917
+ children: t("create.typeOffer.hint", { defaultValue: "The type decides which fields the record has." })
2918
+ })]
2919
+ }), offer.status === "pending" ? jsxs("div", {
2920
+ "aria-busy": "true",
2921
+ className: "flex flex-col gap-2",
2922
+ children: [jsx(Skeleton, { className: "h-10 w-full" }), jsx(Skeleton, { className: "h-10 w-full" })]
2923
+ }) : offer.types.length === 0 ? jsx("p", {
2924
+ role: "status",
2925
+ className: "text-sm text-muted-foreground",
2926
+ children: t("create.typeOffer.empty", { defaultValue: "No type can be created here." })
2927
+ }) : jsx("ul", {
2928
+ className: "grid grid-cols-1 gap-2 sm:grid-cols-2",
2929
+ children: offer.types.map((type) => jsx("li", { children: jsx("button", {
2930
+ type: "button",
2931
+ "data-testid": tid.typeOffer(resource, type),
2932
+ onClick: () => onChoose(type),
2933
+ 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",
2934
+ children: by === void 0 || field === void 0 ? type : jsx(FieldDisplay, {
2935
+ resource: ref,
2936
+ name: by,
2937
+ field,
2938
+ value: type,
2939
+ fallback: jsx("span", { children: type })
2940
+ })
2941
+ }) }, type))
2942
+ })]
2943
+ });
2944
+ }
2945
+ //#endregion
2946
+ //#region src/record/record-screen.tsx
2947
+ function isAbort(error) {
2948
+ if (error === null || typeof error !== "object" && typeof error !== "function") return false;
2949
+ try {
2950
+ return error.name === "AbortError";
2951
+ } catch {
2952
+ return false;
2953
+ }
2954
+ }
2955
+ const NO_ISSUES = Object.freeze([]);
2956
+ const APPLIED_UNREADABLE = Object.freeze({
2957
+ code: "applied-unreadable",
2958
+ message: Object.freeze({
2959
+ key: "errors.appliedUnreadable",
2960
+ default: "Saved. The server's answer could not be read, so the screen may not show the latest values."
2961
+ }),
2962
+ path: Object.freeze([]),
2963
+ source: "server",
2964
+ severity: "info"
2965
+ });
2966
+ function issuesOf(error) {
2967
+ if (error === null || typeof error !== "object") return void 0;
2968
+ try {
2969
+ const descriptor = Object.getOwnPropertyDescriptor(error, "issues");
2970
+ return descriptor !== void 0 && "value" in descriptor ? descriptor.value : void 0;
2971
+ } catch {
2972
+ return;
2973
+ }
2974
+ }
2975
+ const NO_EDITED = new Set();
2976
+ function sameValue(a, b) {
2977
+ if (Object.is(a, b)) return true;
2978
+ try {
2979
+ return JSON.stringify(a) === JSON.stringify(b);
2980
+ } catch {
2981
+ return false;
2982
+ }
2983
+ }
2984
+ function RecordFrameHost(props) {
2985
+ const { resource, mode } = props;
2986
+ const [failed, setFailed] = useState(NO_ISSUES);
2987
+ const named = useMemo(() => failed.length === 0 ? NO_ISSUES : routeServerIssues({ issues: failed }, (segment) => segment, (field) => field !== "_form").fields, [failed]);
2988
+ const atFailure = useRef({});
2989
+ const [edited, setEdited] = useState(NO_EDITED);
2990
+ const controller = useFormController({
2991
+ resource,
2992
+ mode,
2993
+ ...props.recordId === void 0 ? {} : { recordId: props.recordId },
2994
+ ...props.type === void 0 ? {} : { type: props.type },
2995
+ ...props.record === void 0 ? {} : { record: props.record },
2996
+ ...props.defaults === void 0 ? {} : { defaults: props.defaults },
2997
+ ...props.onSubmit === void 0 ? {} : { onSubmit: props.onSubmit },
2998
+ ...props.hostTitle ? { entry: "quick" } : {},
2999
+ serverIssues: named
3000
+ });
3001
+ const inputApplied = useRef(false);
3002
+ const { input } = props;
3003
+ const plan = controller.plan;
3004
+ useEffect(() => {
3005
+ if (inputApplied.current || input === void 0 || mode !== "create" || plan === null) return;
3006
+ inputApplied.current = true;
3007
+ for (const [key, value] of Object.entries(input)) if (plan.fields[key] === "active") controller.setValue(key, value);
3008
+ }, [
3009
+ input,
3010
+ mode,
3011
+ plan,
3012
+ controller
3013
+ ]);
3014
+ const tid = useTestIds();
3015
+ const formId = `record-form-${useId()}`;
3016
+ const root = useRef(null);
3017
+ const [submitError, setSubmitError] = useState(void 0);
3018
+ const [submitApplied, setSubmitApplied] = useState(void 0);
3019
+ useEffect(() => {
3020
+ if (plan === null) return;
3021
+ const now = Object.keys(atFailure.current).filter((name) => !edited.has(name) && plan.fields[name] === "active" && !sameValue(controller.field(name).value, atFailure.current[name]));
3022
+ if (now.length > 0) setEdited((previous) => new Set([...previous, ...now]));
3023
+ }, [
3024
+ plan,
3025
+ controller,
3026
+ edited
3027
+ ]);
3028
+ const notify = useNoticeSink(resource);
3029
+ const routeScreen = useIsRouteScreen();
3030
+ const leavesOnCreate = mode === "create" && routeScreen;
3031
+ const [created, setCreated] = useState(false);
3032
+ const createdRef = useRef(false);
3033
+ const latest = useRef({
3034
+ controller,
3035
+ onSuccess: props.onSuccess,
3036
+ notify,
3037
+ leavesOnCreate
3038
+ });
3039
+ latest.current = {
3040
+ controller,
3041
+ onSuccess: props.onSuccess,
3042
+ notify,
3043
+ leavesOnCreate
3044
+ };
3045
+ const mounted = useRef(true);
3046
+ useEffect(() => {
3047
+ mounted.current = true;
3048
+ return () => {
3049
+ mounted.current = false;
3050
+ };
3051
+ }, []);
3052
+ const submit = useCallback(async () => {
3053
+ if (createdRef.current) return;
3054
+ setSubmitError(void 0);
3055
+ setSubmitApplied(void 0);
3056
+ setFailed(NO_ISSUES);
3057
+ setEdited(NO_EDITED);
3058
+ atFailure.current = {};
3059
+ const outcome = await latest.current.controller.submit();
3060
+ if (!mounted.current) return;
3061
+ if (latest.current.leavesOnCreate && (outcome.status === "submitted" || outcome.status === "failed" && outcome.applied === "yes")) {
3062
+ createdRef.current = true;
3063
+ setCreated(true);
3064
+ }
3065
+ if (outcome.status === "submitted") {
3066
+ const notices = successNoticesOf(outcome.result);
3067
+ if (notices.length > 0) latest.current.notify(notices);
3068
+ latest.current.onSuccess?.(outcome.result);
3069
+ } else if (outcome.status === "failed" && outcome.applied === "yes") {
3070
+ latest.current.notify([APPLIED_UNREADABLE]);
3071
+ latest.current.onSuccess?.(void 0);
3072
+ } else if (outcome.status === "failed" && !isAbort(outcome.error)) {
3073
+ setSubmitError(outcome.error ?? null);
3074
+ setSubmitApplied(outcome.applied);
3075
+ const issues = normalizeIssueInputs(issuesOf(outcome.error)).issues;
3076
+ const next = issues.length === 0 ? NO_ISSUES : Object.freeze(issues.map(issueOfInput));
3077
+ const held = {};
3078
+ const now = latest.current.controller;
3079
+ for (const issue of next) {
3080
+ const head = issue.path[0];
3081
+ if (typeof head === "string" && head !== "_form" && now.plan?.fields[head] === "active") held[head] = now.field(head).value;
3082
+ }
3083
+ atFailure.current = held;
3084
+ setFailed(next);
3085
+ }
3086
+ }, []);
3087
+ const record = controller.record;
3088
+ const recordText = props.recordId === void 0 ? void 0 : String(props.recordId);
3089
+ const frame = useMemo(() => ({
3090
+ resource,
3091
+ recordId: recordText,
3092
+ mode,
3093
+ record,
3094
+ controller
3095
+ }), [
3096
+ resource,
3097
+ recordText,
3098
+ mode,
3099
+ record,
3100
+ controller
3101
+ ]);
3102
+ const { chooseType } = props;
3103
+ const typedAndAccepted = mode === "create" && controller.typeOffer !== null && controller.failure === null;
3104
+ const adapter = useOptionalRouterAdapter();
3105
+ const hostRouter = routeScreen ? adapter : null;
3106
+ const guardText = useNavigationGuardText();
3107
+ const changeType = useMemo(() => typedAndAccepted ? () => {
3108
+ if (hostRouter === null && latest.current.controller.isDirty && !window.confirm(`${guardText.title}\n\n${guardText.body}`)) return;
3109
+ chooseType(void 0);
3110
+ } : void 0, [
3111
+ typedAndAccepted,
3112
+ chooseType,
3113
+ hostRouter,
3114
+ guardText.title,
3115
+ guardText.body
3116
+ ]);
3117
+ const app = useApp();
3118
+ const typesDecl = app.registry.get(resource)?.types;
3119
+ const loaded = controller.record;
3120
+ const unsupportedType = useMemo(() => {
3121
+ if (mode === "create" || typesDecl === void 0 || loaded === void 0) return void 0;
3122
+ const value = loaded[typesDecl.by];
3123
+ const name = typeof value === "string" && value !== "" ? value : null;
3124
+ return name !== null && typesDecl.items.some((item) => item.name === name) ? void 0 : name;
3125
+ }, [
3126
+ mode,
3127
+ typesDecl,
3128
+ loaded
3129
+ ]);
3130
+ const shownFailed = useMemo(() => edited.size === 0 ? failed : Object.freeze(failed.filter((issue) => {
3131
+ const head = issue.path[0];
3132
+ return typeof head !== "string" || !edited.has(head);
3133
+ })), [failed, edited]);
3134
+ const chrome = useMemo(() => ({
3135
+ ...props.onCancel === void 0 ? {} : { onCancel: props.onCancel },
3136
+ ...props.submitLabel === void 0 ? {} : { submitLabel: props.submitLabel },
3137
+ ...props.extraActions === void 0 ? {} : { extraActions: props.extraActions },
3138
+ ...changeType === void 0 ? {} : { changeType },
3139
+ ...unsupportedType === void 0 ? {} : { unsupportedType },
3140
+ ...props.hostTitle ? { hostTitle: true } : {},
3141
+ formId,
3142
+ submitError,
3143
+ ...submitApplied === void 0 ? {} : { submitApplied },
3144
+ serverIssues: shownFailed,
3145
+ ...created ? { created: true } : {},
3146
+ submit,
3147
+ root
3148
+ }), [
3149
+ props.onCancel,
3150
+ props.submitLabel,
3151
+ props.extraActions,
3152
+ changeType,
3153
+ unsupportedType,
3154
+ props.hostTitle,
3155
+ formId,
3156
+ submitError,
3157
+ submitApplied,
3158
+ shownFailed,
3159
+ created,
3160
+ submit
3161
+ ]);
3162
+ usePublishDocVariant(mode === "show" ? resource : void 0, record);
3163
+ const failure = controller.failure;
3164
+ const offering = failure?.kind === "type-required" && controller.typeOffer !== null;
3165
+ useEffect(() => {
3166
+ if (failure === null || offering || process.env.NODE_ENV === "production") return;
3167
+ 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"}.`);
3168
+ }, [
3169
+ failure,
3170
+ offering,
3171
+ resource,
3172
+ mode
3173
+ ]);
3174
+ const formControl = useFormControlOf(controller);
3175
+ const id = frameRecordId(frame, app.registry.get(frame.resource));
3176
+ const rootId = mode === "show" ? tid.pageShow(resource, id ?? "") : mode === "edit" ? tid.pageEdit(resource, id ?? "") : tid.pageCreate(resource);
3177
+ const claimedRoute = useContext(RouteSourceContext);
3178
+ const scopeValues = mode === "show" ? controller.record : controller.values;
3179
+ return jsx(RecordScopeProvider, {
3180
+ resource,
3181
+ ...recordText === void 0 ? {} : { recordId: recordText },
3182
+ values: scopeValues,
3183
+ create: mode === "create",
3184
+ children: jsx(RouteSourceContext.Provider, {
3185
+ value: null,
3186
+ children: jsx(ActionRouteContext.Provider, {
3187
+ value: claimedRoute,
3188
+ children: jsx(RecordFrameContext.Provider, {
3189
+ value: frame,
3190
+ children: jsx(FrameChromeContext.Provider, {
3191
+ value: chrome,
3192
+ children: jsxs(FormControlProvider, {
3193
+ value: formControl,
3194
+ children: [jsx(DeepLinkScope, {
3195
+ plan: controller.plan,
3196
+ enabled: routeScreen && mode !== "create",
3197
+ children: jsx("div", {
3198
+ ref: root,
3199
+ "data-testid": rootId,
3200
+ className: "flex flex-col gap-[var(--buro-section-gap)]",
3201
+ children: offering && controller.typeOffer !== null ? jsx(TypeOffer, {
3202
+ resource,
3203
+ offer: controller.typeOffer,
3204
+ onChoose: (type) => chooseType(type)
3205
+ }) : failure !== null ? jsxs(Fragment$1, { children: [jsx(RecordState, { state: "error" }), jsx(FormActions, {})] }) : mode === "edit" && unsupportedType !== void 0 ? jsx(UndeclaredTypeNotice, {
3206
+ resource,
3207
+ typeValue: unsupportedType
3208
+ }) : jsxs(Fragment$1, { children: [jsx(ScopeMismatchBanner, {
3209
+ resource,
3210
+ record: mode === "create" ? controller.trustedSeeds : controller.record,
3211
+ kind: mode === "create" ? "created" : "record"
3212
+ }), jsx(RecordFrameView, { ...props.frame === void 0 ? {} : { frame: props.frame } })] })
3213
+ })
3214
+ }), controller.checkGate === null ? null : jsx(CheckConfirmDialog, {
3215
+ state: controller.checkGate,
3216
+ testid: `${tid.form(resource, mode, id)}:checks`
3217
+ })]
3218
+ })
3219
+ })
3220
+ })
3221
+ })
3222
+ })
3223
+ });
3224
+ }
3225
+ function RecordScreen(props) {
3226
+ const app = useApp();
3227
+ const routeScreen = useContext(RouteScreenClaimContext);
3228
+ const quickScreen = useContext(QuickScreenClaimContext);
3229
+ const route = useContext(RouteSourceContext);
3230
+ const resourceInput = props.resource;
3231
+ const resource = resourceKey(resourceInput);
3232
+ const tabs = useTabsUrlState(props.mode, routeScreen);
3233
+ const adapter = useOptionalRouterAdapter();
3234
+ const router = routeScreen ? adapter : null;
3235
+ const navigate = useRouteNavigate();
3236
+ const [local, setLocal] = useState(props.type);
3237
+ const [typeProp, setTypeProp] = useState(props.type);
3238
+ if (props.type !== typeProp) {
3239
+ setTypeProp(props.type);
3240
+ setLocal(props.type);
3241
+ }
3242
+ const [chose, setChose] = useState(false);
3243
+ const fromUrl = router?.searchParams.get("type") ?? void 0;
3244
+ const type = props.mode !== "create" ? props.type : router === null ? local : chose ? fromUrl : props.type ?? fromUrl;
3245
+ const chooseType = useCallback((next) => {
3246
+ if (router === null) {
3247
+ setLocal(next);
3248
+ return;
3249
+ }
3250
+ setChose(true);
3251
+ const params = new URLSearchParams(router.searchParams);
3252
+ if (next === void 0) params.delete("type");
3253
+ else params.set("type", next);
3254
+ const query = params.toString();
3255
+ navigate(query === "" ? router.pathname : `${router.pathname}?${query}`);
3256
+ }, [router, navigate]);
3257
+ if (app.registry.get(resource) === void 0) return jsx(RecordState, { state: "not-found" });
3258
+ const { type: _declared, ...rest } = props;
3259
+ return jsx(RouteScreenClaimContext.Provider, {
3260
+ value: false,
3261
+ children: jsx(QuickScreenClaimContext.Provider, {
3262
+ value: false,
3263
+ children: jsx(RouteSourceContext.Provider, {
3264
+ value: routeScreen || quickScreen ? route : null,
3265
+ children: jsx(RouteScreenContext.Provider, {
3266
+ value: routeScreen,
3267
+ children: jsx(ResourceContext.Provider, {
3268
+ value: { resource },
3269
+ children: jsx(ScreenStateProvider, {
3270
+ open: tabs.open,
3271
+ onOpenChange: tabs.onOpenChange,
3272
+ children: jsx(RecordFrameHost, {
3273
+ ...rest,
3274
+ ...type === void 0 ? {} : { type },
3275
+ resource,
3276
+ chooseType,
3277
+ hostTitle: quickScreen
3278
+ }, type ?? "")
3279
+ })
3280
+ })
3281
+ })
3282
+ })
3283
+ })
3284
+ });
3285
+ }
3286
+ //#endregion
3287
+ //#region src/layout/record-targets.ts
3288
+ function isShowAvailable(registry, resource) {
3289
+ return recordRouteAvailable(registry, resource, "show");
3290
+ }
3291
+ function showTarget(resource, id) {
3292
+ return {
3293
+ resource,
3294
+ action: "show",
3295
+ params: { id }
3296
+ };
3297
+ }
3298
+ function listTarget(resource) {
3299
+ return {
3300
+ resource,
3301
+ action: "list"
3302
+ };
3303
+ }
3304
+ //#endregion
3305
+ //#region src/layout/route-trail.ts
3306
+ function useTrailContext() {
3307
+ const app = useApp();
3308
+ const caps = useI18nCaps();
3309
+ const isVisible = useNavVisible();
3310
+ const t = useT();
3311
+ return {
3312
+ registry: app.registry,
3313
+ caps,
3314
+ isVisible,
3315
+ t
3316
+ };
3317
+ }
3318
+ function groupCrumbs(ctx, chain) {
3319
+ return chain.map((group) => {
3320
+ const key = canonicalNavKey(group);
3321
+ return {
3322
+ label: resolveNavLabel(ctx.caps, `groups.${key}`, declaredText("chrome", group, "label")),
3323
+ href: groupNavHref(ctx.registry, key, ctx.isVisible),
3324
+ jump: true
3325
+ };
3326
+ });
3327
+ }
3328
+ function nonEmpty(crumbs) {
3329
+ return crumbs.length > 0 ? crumbs : void 0;
3330
+ }
3331
+ function recordActionOf(match) {
3332
+ if (match === null || match.kind !== "resource") return void 0;
3333
+ switch (match.action) {
3334
+ case "show":
3335
+ case "edit":
3336
+ case "create": return match.action;
3337
+ default: return;
3338
+ }
3339
+ }
3340
+ function pathOf(href) {
3341
+ const path = href.split(/[?#]/, 1)[0] ?? "";
3342
+ return path.length > 1 && path.endsWith("/") ? path.slice(0, -1) : path;
3343
+ }
3344
+ function originTrail(ctx, origin, depth = ORIGIN_DEPTH) {
3345
+ const match = matchPath(ctx.registry, pathOf(origin.href), { isVisible: ctx.isVisible });
3346
+ if (match === null) return void 0;
3347
+ switch (match.kind) {
3348
+ case "resource": {
3349
+ const key = canonicalNavKey(match);
3350
+ if (match.action === "list") return {
3351
+ leading: groupCrumbs(ctx, match.groupChain),
3352
+ resource: key,
3353
+ resourceHref: origin.href,
3354
+ segments: []
3355
+ };
3356
+ const def = ctx.registry.get(key);
3357
+ const crumb = {
3358
+ label: match.action === "create" ? ctx.t("breadcrumbs.create") : origin.title || (match.id === void 0 ? "" : `#${match.id}`),
3359
+ href: origin.href
3360
+ };
3361
+ const parent = depth > 1 && origin.origin !== void 0 ? originTrail(ctx, origin.origin, depth - 1) : void 0;
3362
+ if (parent !== void 0) return {
3363
+ ...parent,
3364
+ segments: [...parent.segments, crumb]
3365
+ };
3366
+ return {
3367
+ leading: groupCrumbs(ctx, match.groupChain),
3368
+ resource: key,
3369
+ ...def !== void 0 && hasListPage(def) ? { resourceHref: hrefFor(ctx.registry, key) } : {},
3370
+ segments: [crumb]
3371
+ };
3372
+ }
3373
+ case "custom-page": {
3374
+ const trail = headerTrail(ctx, match);
3375
+ if (trail === null || trail.pageLabel === void 0) return void 0;
3376
+ return {
3377
+ leading: trail.leadingSegments ?? [],
3378
+ segments: [{
3379
+ label: trail.pageLabel,
3380
+ href: origin.href
3381
+ }]
3382
+ };
3383
+ }
3384
+ case "group-index": {
3385
+ const crumbs = groupCrumbs(ctx, match.groupChain);
3386
+ const own = crumbs[crumbs.length - 1];
3387
+ if (own === void 0) return void 0;
3388
+ return {
3389
+ leading: crumbs.slice(0, -1),
3390
+ segments: [{
3391
+ label: own.label,
3392
+ href: origin.href
3393
+ }]
3394
+ };
3395
+ }
3396
+ default: return;
3397
+ }
3398
+ }
3399
+ function recordTrail(ctx, input) {
3400
+ const { resource, action, id, origin } = input;
3401
+ if (origin !== void 0 && (action === "create" || id !== "")) return originRooted(ctx, input, origin);
3402
+ const leadingSegments = nonEmpty(groupCrumbs(ctx, input.groupChain));
3403
+ if (action !== "create" && id === "") return {
3404
+ resource,
3405
+ leadingSegments
3406
+ };
3407
+ const recordLabel = input.title || id;
3408
+ const middleSegments = action === "edit" ? [isShowAvailable(ctx.registry, resource) ? {
3409
+ label: recordLabel,
3410
+ href: resolveRoute(showTarget(resource, id), ctx.registry)
3411
+ } : { label: recordLabel }] : void 0;
3412
+ const pageLabel = action === "create" ? ctx.t("breadcrumbs.create") : action === "edit" ? ctx.t("breadcrumbs.edit") : recordLabel;
3413
+ return {
3414
+ resource,
3415
+ recordId: action === "create" ? void 0 : id,
3416
+ pageLabel,
3417
+ leadingSegments,
3418
+ middleSegments
3419
+ };
3420
+ }
3421
+ function originRooted(ctx, input, origin) {
3422
+ const { resource, action, id } = input;
3423
+ const recordLabel = input.title || id;
3424
+ const drawn = new Set(origin.segments.flatMap((crumb) => crumb.href === void 0 ? [] : [pathOf(crumb.href)]));
3425
+ const own = action === "edit" ? [isShowAvailable(ctx.registry, resource) ? {
3426
+ label: recordLabel,
3427
+ href: resolveRoute(showTarget(resource, id), ctx.registry)
3428
+ } : { label: recordLabel }].filter((crumb) => crumb.href === void 0 || !drawn.has(pathOf(crumb.href))) : [];
3429
+ const pageLabel = action === "create" ? ctx.t("breadcrumbs.create") : action === "edit" ? ctx.t("breadcrumbs.edit") : recordLabel;
3430
+ const recordId = action === "create" ? void 0 : id;
3431
+ const middleSegments = nonEmpty([...origin.segments, ...own]);
3432
+ if (origin.resource !== void 0 && ctx.registry.get(origin.resource) === ctx.registry.get(resource)) return {
3433
+ resource,
3434
+ recordId,
3435
+ pageLabel,
3436
+ leadingSegments: nonEmpty([...origin.leading]),
3437
+ ...origin.resourceHref === void 0 ? {} : { resourceHref: origin.resourceHref },
3438
+ middleSegments
3439
+ };
3440
+ const def = origin.resource === void 0 ? void 0 : ctx.registry.get(origin.resource);
3441
+ const resourceCrumb = origin.resource === void 0 ? [] : [{
3442
+ label: resolveResourceLabel(ctx.caps, origin.resource, "plural", def),
3443
+ ...origin.resourceHref === void 0 ? {} : { href: origin.resourceHref }
3444
+ }];
3445
+ return {
3446
+ resource,
3447
+ recordId,
3448
+ pageLabel,
3449
+ rootSegments: [
3450
+ ...origin.leading,
3451
+ ...resourceCrumb,
3452
+ ...origin.segments,
3453
+ ...own
3454
+ ]
3455
+ };
3456
+ }
3457
+ function recordTrailRoute(registry, match) {
3458
+ if (match === null || match.kind !== "resource") return null;
3459
+ const resource = canonicalNavKey(match);
3460
+ const { groupChain } = match;
3461
+ if (match.action === "flow") return {
3462
+ resource,
3463
+ action: "show",
3464
+ id: match.id ?? "",
3465
+ flow: match.flow ?? "",
3466
+ groupChain
3467
+ };
3468
+ const action = recordActionOf(match);
3469
+ if (action === void 0 || !recordRouteAvailable(registry, resource, action)) return null;
3470
+ return {
3471
+ resource,
3472
+ action,
3473
+ id: action === "create" ? "" : match.id ?? "",
3474
+ groupChain
3475
+ };
3476
+ }
3477
+ function headerTrail(ctx, match) {
3478
+ if (match === null) return null;
3479
+ const key = canonicalNavKey(match);
3480
+ switch (match.kind) {
3481
+ case "resource": {
3482
+ const leadingSegments = nonEmpty(groupCrumbs(ctx, match.groupChain));
3483
+ const action = recordActionOf(match);
3484
+ if (recordTrailRoute(ctx.registry, match) !== null) return null;
3485
+ if (action === void 0) return {
3486
+ resource: key,
3487
+ leadingSegments
3488
+ };
3489
+ return {
3490
+ resource: key,
3491
+ recordId: match.id,
3492
+ pageLabel: ctx.t("router.notFoundTitle"),
3493
+ leadingSegments
3494
+ };
3495
+ }
3496
+ case "custom-page": {
3497
+ const page = ctx.registry.customPages.get(match.name);
3498
+ if (page === void 0 || !ctx.isVisible(page)) return null;
3499
+ return {
3500
+ name: key,
3501
+ pageLabel: resolveNavLabel(ctx.caps, `pages.${key}`, declaredText("chrome", page, "label")),
3502
+ leadingSegments: nonEmpty(groupCrumbs(ctx, match.groupChain))
3503
+ };
3504
+ }
3505
+ case "group-index": {
3506
+ const own = match.groupChain[match.groupChain.length - 1];
3507
+ if (own === void 0) return null;
3508
+ const crumbs = groupCrumbs(ctx, match.groupChain);
3509
+ const current = crumbs[crumbs.length - 1];
3510
+ return {
3511
+ name: canonicalNavKey(own),
3512
+ pageLabel: current.label,
3513
+ leadingSegments: nonEmpty(crumbs.slice(0, -1))
3514
+ };
3515
+ }
3516
+ default: return null;
3517
+ }
3518
+ }
3519
+ function recentStorageKey(userId) {
3520
+ return `buro:recent:v2:${userId}`;
3521
+ }
3522
+ function isRecent(value) {
3523
+ if (typeof value !== "object" || value === null) return false;
3524
+ const entry = value;
3525
+ 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";
3526
+ }
3527
+ function parse(raw) {
3528
+ if (raw === null) return [];
3529
+ try {
3530
+ const parsed = JSON.parse(raw);
3531
+ if (typeof parsed !== "object" || parsed === null) return [];
3532
+ const envelope = parsed;
3533
+ if (envelope.version !== 2 || !Array.isArray(envelope.items)) return [];
3534
+ return envelope.items.filter(isRecent);
3535
+ } catch {
3536
+ return [];
3537
+ }
3538
+ }
3539
+ function readRecentRecords(store, userId) {
3540
+ return maybeThen(settle(() => store.get(recentStorageKey(userId)), null), parse);
3541
+ }
3542
+ function writeRecentRecord(store, userId, entry) {
3543
+ const key = recentStorageKey(userId);
3544
+ return maybeThen(settle(() => store.get(key), null), (raw) => {
3545
+ const envelope = {
3546
+ version: 2,
3547
+ items: [entry, ...parse(raw).filter((item) => !(item.canonicalRef === entry.canonicalRef && item.id === entry.id))].slice(0, 5)
3548
+ };
3549
+ return settle(() => store.set(key, JSON.stringify(envelope)), void 0);
3550
+ });
3551
+ }
3552
+ function text$1(value) {
3553
+ return typeof value === "string" && value.length > 0 ? value : void 0;
3554
+ }
3555
+ const RECENT_LABEL_KEYS = [
3556
+ "alias",
3557
+ "name",
3558
+ "title",
3559
+ "label"
3560
+ ];
3561
+ function recentLabel(record, id, isGuarded = () => false) {
3562
+ for (const key of RECENT_LABEL_KEYS) {
3563
+ if (isGuarded(key)) continue;
3564
+ const value = text$1(record[key]);
3565
+ if (value !== void 0) return {
3566
+ label: value,
3567
+ field: key
3568
+ };
3569
+ }
3570
+ return { label: id };
3571
+ }
3572
+ //#endregion
3573
+ //#region src/layout/use-record-visit.ts
3574
+ function useRecordVisit(resource, record, opts) {
3575
+ const userId = useCurrentUserId();
3576
+ const store = usePlatformStorage().local;
3577
+ const app = useApp();
3578
+ const def = app.registry.get(resource);
3579
+ const raw = recordKeyOf(def, record);
3580
+ const id = typeof raw === "string" || typeof raw === "number" ? String(raw) : void 0;
3581
+ const fields = def?.fields;
3582
+ const rules = app.ruleSource?.rules(resource) ?? [];
3583
+ const isGuarded = (field) => fields !== void 0 && Object.hasOwn(fields, field) && fieldSensitivity(fields[field]) !== void 0 || addressesCapability(rules, "view", {
3584
+ kind: "field",
3585
+ name: field
3586
+ });
3587
+ const picked = record != null && id !== void 0 ? recentLabel(record, id, isGuarded) : void 0;
3588
+ const label = picked?.label;
3589
+ const labelField = picked?.field;
3590
+ const canonicalRef = canonicalResourceName(resource);
3591
+ const { isCurrentData } = opts;
3592
+ useEffect(() => {
3593
+ if (userId === null || !isCurrentData || id === void 0 || id === "") return;
3594
+ if (label === void 0) return;
3595
+ writeRecentRecord(store, userId, {
3596
+ canonicalRef,
3597
+ id,
3598
+ label,
3599
+ ...labelField === void 0 ? {} : { labelField },
3600
+ at: new Date().toISOString()
3601
+ });
3602
+ }, [
3603
+ store,
3604
+ userId,
3605
+ isCurrentData,
3606
+ canonicalRef,
3607
+ id,
3608
+ label,
3609
+ labelField
3610
+ ]);
3611
+ }
3612
+ //#endregion
3613
+ //#region src/layout/record-page.tsx
3614
+ function useMountedRef() {
3615
+ const mounted = useRef(true);
3616
+ useEffect(() => {
3617
+ mounted.current = true;
3618
+ return () => {
3619
+ mounted.current = false;
3620
+ };
3621
+ }, []);
3622
+ return mounted;
3623
+ }
3624
+ function RecordRouteHeader({ resource, action, id, record }) {
3625
+ const recordName = useRecordTitle(resource, action === "create" ? void 0 : id, record);
3626
+ usePublishRecordTrail(action === "create" ? null : {
3627
+ key: recordTrailKey(resource, id, action),
3628
+ title: recordName
3629
+ });
3630
+ return jsx(PageHeader, {
3631
+ resource,
3632
+ mode: action,
3633
+ ...action === "create" ? {} : { recordName }
3634
+ });
3635
+ }
3636
+ function RecordShow({ resource, id, recordId, record, shown }) {
3637
+ return jsxs("div", { children: [jsx(RecordRouteHeader, {
3638
+ resource,
3639
+ action: "show",
3640
+ id,
3641
+ record: shown
3642
+ }), jsx(RecordScreen, {
3643
+ resource,
3644
+ mode: "show",
3645
+ recordId,
3646
+ record
3647
+ })] });
3648
+ }
3649
+ function RecordEdit({ resource, id, recordId, record, shown }) {
3650
+ const navigate = useRouteNavigate();
3651
+ const mounted = useMountedRef();
3652
+ const back = useReturnTarget(resource, "edit", id);
3653
+ return jsxs("div", { children: [jsx(RecordRouteHeader, {
3654
+ resource,
3655
+ action: "edit",
3656
+ id,
3657
+ record: shown
3658
+ }), jsx(RecordScreen, {
3659
+ resource,
3660
+ mode: "edit",
3661
+ recordId,
3662
+ record,
3663
+ onCancel: () => navigate(back, { origin: "inherit" }),
3664
+ onSuccess: () => {
3665
+ if (mounted.current) navigate(back, { origin: "inherit" });
3666
+ }
3667
+ })] });
3668
+ }
3669
+ function createdId(result) {
3670
+ const id = result?.id;
3671
+ return typeof id === "string" || typeof id === "number" ? String(id) : void 0;
3672
+ }
3673
+ function RecordCreate({ resource, defaults }) {
3674
+ const app = useApp();
3675
+ const navigate = useRouteNavigate();
3676
+ const mounted = useMountedRef();
3677
+ const adapter = useOptionalRouterAdapter();
3678
+ const list = listTarget(resource);
3679
+ const back = useReturnTarget(resource, "create");
3680
+ const type = adapter?.searchParams.get("type") ?? void 0;
3681
+ return jsxs("div", { children: [jsx(RecordRouteHeader, {
3682
+ resource,
3683
+ action: "create",
3684
+ id: ""
3685
+ }), jsx(RouteScreenClaimContext.Provider, {
3686
+ value: true,
3687
+ children: jsx(RecordScreen, {
3688
+ resource,
3689
+ mode: "create",
3690
+ ...type === void 0 ? {} : { type },
3691
+ ...defaults === void 0 ? {} : { defaults },
3692
+ onCancel: () => navigate(back, { origin: "inherit" }),
3693
+ onSuccess: (result) => {
3694
+ if (!mounted.current) return;
3695
+ const id = createdId(result);
3696
+ navigate(id !== void 0 && isShowAvailable(app.registry, resource) ? showTarget(resource, id) : list, { origin: "inherit" });
3697
+ }
3698
+ })
3699
+ })] });
3700
+ }
3701
+ function RecordRead({ resource, action, id, recordId }) {
3702
+ const app = useApp();
3703
+ const def = app.registry.get(resource);
3704
+ const projection = useMemo(() => def === void 0 ? void 0 : dtoFields(def, "record"), [def]);
3705
+ const query = useOne(resource, {
3706
+ id: recordId,
3707
+ retry: retryRecordRead,
3708
+ ...projection === void 0 ? {} : { projection }
3709
+ });
3710
+ const result = query.data;
3711
+ const read = result?.data;
3712
+ const projected = useProjectedRecord(resource, read, { placeholder: query.isPlaceholderData });
3713
+ const showAvailability = useAvailabilityResolver(resource, "show");
3714
+ const permissions = useCtx((c) => c.permissions);
3715
+ const showRuled = addressesCapability(app.ruleSource.rules(resource), "run", {
3716
+ kind: "action",
3717
+ name: "show"
3718
+ });
3719
+ const showHidden = showRuled && read !== null && typeof read === "object" && showAvailability("show", read).state !== "available";
3720
+ const showSettled = !showRuled || !query.isPlaceholderData && !permissionsUndecided(permissions) && permissions?.status !== "error";
3721
+ useRecordVisit(resource, projected.status === "ready" && showSettled && !showHidden ? projected.value : null, { isCurrentData: !query.isPlaceholderData });
3722
+ const route = useMemo(() => Object.freeze({ id }), [id]);
3723
+ const availability = useAvailabilityResolver(resource, "edit");
3724
+ if (result !== void 0) {
3725
+ const record = result.data;
3726
+ if (record === null || typeof record !== "object") return jsx(RecordState, { state: "not-found" });
3727
+ const loaded = record;
3728
+ if (showRuled) {
3729
+ if (query.isPlaceholderData || permissionsUndecided(permissions)) return jsx(RecordState, { state: "loading" });
3730
+ if (permissions?.status === "error") return jsx(RecordState, { state: "not-found" });
3731
+ if (showHidden) return jsx(RecordState, { state: "not-found" });
3732
+ }
3733
+ if (projected.status === "pending" || projected.value === null) return jsx(RecordState, { state: "loading" });
3734
+ const shown = projected.value;
3735
+ if (action === "edit") {
3736
+ const edit = availability("edit", loaded).state;
3737
+ if (edit === "hidden" || edit === "absent") return jsx(RecordState, { state: "not-found" });
3738
+ if (edit === "undecided") return jsx(RecordState, { state: "loading" });
3739
+ }
3740
+ return jsx(RouteSourceContext.Provider, {
3741
+ value: route,
3742
+ children: jsx(RouteScreenClaimContext.Provider, {
3743
+ value: true,
3744
+ children: action === "edit" ? jsx(RecordEdit, {
3745
+ resource,
3746
+ id,
3747
+ recordId,
3748
+ record: loaded,
3749
+ shown
3750
+ }) : jsx(RecordShow, {
3751
+ resource,
3752
+ id,
3753
+ recordId,
3754
+ record: loaded,
3755
+ shown
3756
+ })
3757
+ })
3758
+ });
3759
+ }
3760
+ if (query.error != null) return jsx(LoadError, {
3761
+ surface: "record",
3762
+ resource,
3763
+ error: query.error,
3764
+ retry: () => void query.refetch()
3765
+ });
3766
+ return jsx(RecordState, { state: "loading" });
3767
+ }
3768
+ function RecordRouteBody(props) {
3769
+ if (props.action === "create") return jsx(RecordCreate, { ...props });
3770
+ if (props.id === "") return jsx(RecordState, { state: "not-found" });
3771
+ return jsx(RecordReadRoute, { ...props });
3772
+ }
3773
+ function RecordReadRoute(props) {
3774
+ const recordId = useRouteRecordId(props.resource, props.id);
3775
+ if (recordId === void 0) return jsx(InvalidRouteId, { resource: props.resource });
3776
+ return jsx(RecordRead, {
3777
+ ...props,
3778
+ recordId
3779
+ });
3780
+ }
3781
+ function RecordRoute(props) {
3782
+ const missingRuntime = useOptionalDataRuntime() === null;
3783
+ useEffect(() => {
3784
+ if (!missingRuntime || process.env.NODE_ENV === "production") return;
3785
+ 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.`);
3786
+ }, [missingRuntime, props.resource]);
3787
+ if (missingRuntime) return jsx(RecordState, { state: "error" });
3788
+ return jsx(RecordRouteBody, { ...props }, `${props.resource}:${props.id}`);
3789
+ }
3790
+ function recordPageProblem(input) {
3791
+ const { props, resource, action } = input;
3792
+ if (resource === void 0 || action === void 0) return "[burojs] <RecordPage> needs both `resource` and `action`. Pass them; until then it renders not-found.";
3793
+ 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.`;
3794
+ if (props.defaults !== void 0 && action !== "create") return `[burojs] <RecordPage defaults> applies to create only; on this '${action}' route it is ignored.`;
3795
+ return null;
3796
+ }
3797
+ const recordPageProblemsLogged = new WeakMap();
3798
+ function RecordPage(props) {
3799
+ const app = useApp();
3800
+ const match = useMatch();
3801
+ const id = match === null ? null : match.id ?? "";
3802
+ const { action } = props;
3803
+ const resource = props.resource === void 0 ? void 0 : routeResourceKey(props.resource);
3804
+ const onRecordRoute = recordActionOf(match) !== void 0;
3805
+ const problem = recordPageProblem({
3806
+ props,
3807
+ resource,
3808
+ action,
3809
+ onRecordRoute
3810
+ });
3811
+ useEffect(() => {
3812
+ if (problem === null || process.env.NODE_ENV === "production") return;
3813
+ let logged = recordPageProblemsLogged.get(app);
3814
+ if (logged === void 0) {
3815
+ logged = new Set();
3816
+ recordPageProblemsLogged.set(app, logged);
3817
+ }
3818
+ if (logged.has(problem)) return;
3819
+ logged.add(problem);
3820
+ console.error(problem);
3821
+ }, [app, problem]);
3822
+ if (resource === void 0 || action === void 0 || id === null || !onRecordRoute) return jsx(RecordState, { state: "not-found" });
3823
+ const route = action === "create" ? {
3824
+ resource,
3825
+ action,
3826
+ defaults: props.defaults
3827
+ } : {
3828
+ resource,
3829
+ action
3830
+ };
3831
+ return jsx(RecordRoute, {
3832
+ ...route,
3833
+ id
3834
+ });
3835
+ }
3836
+ //#endregion
3837
+ //#region src/layout/collection-record-route.tsx
3838
+ function addressTail(searchParams, routerHash) {
3839
+ const query = searchParams?.toString() ?? "";
3840
+ const hash = routerHash ?? (typeof window === "undefined" ? "" : window.location.hash);
3841
+ return `${query === "" ? "" : `?${query}`}${hash === "#" ? "" : hash}`;
3842
+ }
3843
+ function CollectionRecordRoute(props) {
3844
+ const { collection, action, id } = props;
3845
+ const app = useApp();
3846
+ const navigate = useRouteNavigate();
3847
+ const adapter = useOptionalRouterAdapter();
3848
+ const state = useCollectionMember(collection, id);
3849
+ const flow = props.action === "flow" ? props.flow : void 0;
3850
+ const target = state.status === "member" ? hrefFor(app.registry, state.member, {
3851
+ action,
3852
+ id,
3853
+ ...flow === void 0 ? {} : { flow }
3854
+ }) : void 0;
3855
+ const current = useRef(adapter);
3856
+ current.current = adapter;
3857
+ const sent = useRef(void 0);
3858
+ useEffect(() => {
3859
+ if (target === void 0 || sent.current === target) return;
3860
+ sent.current = target;
3861
+ navigate(`${target}${addressTail(current.current?.searchParams, current.current?.hash)}`, { replace: true });
3862
+ }, [target, navigate]);
3863
+ if (state.status === "unknown") return jsx(UnknownMemberCard, {
3864
+ collection,
3865
+ id,
3866
+ value: state.value
3867
+ });
3868
+ if (state.status === "not-found") return jsx(NavAreaNotFound, {});
3869
+ if (state.status === "error") return jsx(LoadError, {
3870
+ surface: "record",
3871
+ resource: routeResourceKey(collection),
3872
+ error: state.error
3873
+ });
3874
+ return null;
3875
+ }
3876
+ function UnknownMemberCard({ collection, id, value }) {
3877
+ const app = useApp();
3878
+ const t = useOptionalT();
3879
+ const key = routeResourceKey(collection);
3880
+ const fact = memberFactOf(app.registry.get(key));
3881
+ const shown = value === void 0 || value === null ? "" : String(value);
3882
+ const known = (fact?.collection?.members ?? []).flatMap((member) => member.values).join(", ");
3883
+ return jsxs("div", {
3884
+ "data-testid": `unknown-member-card:${key}:${id}`,
3885
+ className: "flex flex-col gap-2",
3886
+ children: [
3887
+ process.env.NODE_ENV === "production" ? null : jsx("div", {
3888
+ role: "note",
3889
+ "data-testid": "unknown-member-notice",
3890
+ className: "mx-6 mt-4 rounded-md border border-dashed border-amber-500/60 bg-amber-500/10 px-3 py-2 text-sm",
3891
+ children: t("collection.unknownMemberNotice", {
3892
+ params: {
3893
+ base: fact === void 0 ? key : formatEntityRef(fact.ref),
3894
+ value: shown,
3895
+ known
3896
+ },
3897
+ defaultValue: "No member of {{base}} claims the type “{{value}}”. Known types: {{known}}."
3898
+ })
3899
+ }),
3900
+ jsx("p", {
3901
+ "data-testid": "unknown-member-type",
3902
+ className: "mx-6 text-sm text-muted-foreground",
3903
+ children: t("collection.unknownType", {
3904
+ params: { value: shown },
3905
+ defaultValue: "Unknown type: {{value}}"
3906
+ })
3907
+ }),
3908
+ jsx(ItemActionsOffContext.Provider, {
3909
+ value: true,
3910
+ children: jsx(RecordRoute, {
3911
+ resource: key,
3912
+ action: "show",
3913
+ id
3914
+ })
3915
+ })
3916
+ ]
3917
+ });
3918
+ }
3919
+ //#endregion
3920
+ //#region src/layout/page-host.tsx
3921
+ function PageHost({ page, match, notFound }) {
3922
+ const isVisible = useNavVisible();
3923
+ const ctx = useVisibilityCtx();
3924
+ const access = usePageAccess(page);
3925
+ if (!(evaluateVisible(page.visible, ctx) && match.groupChain.every((group) => isVisible(group)))) return notFound;
3926
+ if (access === "pending") return jsx(RecordState, { state: "loading" });
3927
+ if (access === "denied") return notFound;
3928
+ return jsx(PageParams, {
3929
+ page,
3930
+ notFound
3931
+ });
3932
+ }
3933
+ const NO_SEARCH = new URLSearchParams();
3934
+ function PageParams({ page, notFound }) {
3935
+ const search = useOptionalRouterAdapter()?.searchParams ?? (typeof window === "undefined" ? NO_SEARCH : new URLSearchParams(window.location.search));
3936
+ const raw = JSON.stringify(pageParamNames(page.params).map((name) => search.get(name)));
3937
+ const parsed = useMemo(() => parsePageParams(page, search), [page, raw]);
3938
+ if (!parsed.ok) return notFound;
3939
+ return jsx(RouteSourceContext.Provider, {
3940
+ value: parsed.route,
3941
+ children: jsx(PageBody, { page })
3942
+ });
3943
+ }
3944
+ function PageBody({ page }) {
3945
+ const snapshot = useApplicationSnapshot();
3946
+ const compiled = useMemo(() => compilePageScreen(page, {
3947
+ blocks: snapshotBlockLookup(snapshot),
3948
+ frames: snapshotFrameLookup(snapshot),
3949
+ appFrames: snapshotAppFrames(snapshot)
3950
+ }), [page, snapshot]);
3951
+ const failure = isScreenFailure(compiled) ? compiled : null;
3952
+ const screen = failure === null && !isScreenFailure(compiled) ? compiled : null;
3953
+ const caps = useI18nCaps();
3954
+ const name = canonicalNavKey(page);
3955
+ const label = resolveNavLabel(caps, `pages.${name}`, declaredText("chrome", page, "label"));
3956
+ useEffect(() => {
3957
+ if (failure === null || process.env.NODE_ENV === "production") return;
3958
+ console.error(`[burojs] The page "${name}" cannot render its body: ${failure.code} at ${failure.path.join(".")}: ${failure.message}.`);
3959
+ }, [failure, name]);
3960
+ return jsxs("div", {
3961
+ className: "flex flex-col gap-4",
3962
+ children: [jsx("h1", {
3963
+ className: "text-2xl font-semibold tracking-tight",
3964
+ children: label
3965
+ }), screen === null ? jsx(RecordState, { state: "error" }) : jsx(PageRouteScreen, { children: jsx(PlannedBody, {
3966
+ screen,
3967
+ name,
3968
+ label
3969
+ }) })]
3970
+ });
3971
+ }
3972
+ function PageRouteScreen({ children }) {
3973
+ const tabs = useTabsUrlState("show", true);
3974
+ return jsx(RouteScreenClaimContext.Provider, {
3975
+ value: false,
3976
+ children: jsx(RouteScreenContext.Provider, {
3977
+ value: true,
3978
+ children: jsx(ScreenStateProvider, {
3979
+ open: tabs.open,
3980
+ onOpenChange: tabs.onOpenChange,
3981
+ children
3982
+ })
3983
+ })
3984
+ });
3985
+ }
3986
+ function PlannedBody({ screen, name, label, record }) {
3987
+ const pageOptions = useMemo(() => record === void 0 ? {} : { record }, [record]);
3988
+ const page = usePageScreen(screen, pageOptions);
3989
+ const { PlacementScope } = page;
3990
+ const route = useContext(RouteSourceContext);
3991
+ const catalog = useFrameImplementations();
3992
+ const id = formatEntityRef(screen.frame);
3993
+ const resolved = useMemo(() => resolveFrameView(screen.frame, catalog, "page"), [screen.frame, catalog]);
3994
+ const t = useFrameT(id);
3995
+ const slots = {};
3996
+ for (const slot of Object.keys(screen.slots)) slots[slot] = (page.plan.slots[slot] ?? []).every((node) => node.state === "absent") ? null : jsx(ScreenTree, {
3997
+ region: slot === "body" ? "page-body" : "record",
3998
+ slot,
3999
+ resource: name,
4000
+ mode: "show",
4001
+ compiled: screen,
4002
+ page
4003
+ }, slot);
4004
+ const View = resolved.view;
4005
+ const viewProps = {
4006
+ slots,
4007
+ label,
4008
+ params: route ?? {},
4009
+ t
4010
+ };
4011
+ return jsx(RouteSourceContext.Provider, {
4012
+ value: null,
4013
+ children: jsx(ActionRouteContext.Provider, {
4014
+ value: route,
4015
+ children: jsx(PlacementScope, { children: jsx(DeepLinkScope, {
4016
+ plan: page.plan,
4017
+ enabled: true,
4018
+ children: jsx("div", {
4019
+ "data-buro-region": "page-body",
4020
+ children: jsx(Suspense, {
4021
+ fallback: null,
4022
+ children: jsx(View, { ...viewProps })
4023
+ })
4024
+ })
4025
+ }) })
4026
+ })
4027
+ });
4028
+ }
4029
+ //#endregion
4030
+ //#region src/layout/resource-page-router.tsx
4031
+ function ResourcePageRouterEmpty() {
4032
+ const t = useT();
4033
+ return jsxs("div", {
4034
+ "data-testid": "resource-page-router-empty",
4035
+ className: "flex flex-col items-center justify-center gap-1 px-6 py-24 text-center",
4036
+ children: [jsx("h2", {
4037
+ className: "text-base font-semibold tracking-tight",
4038
+ children: t("router.emptyTitle")
4039
+ }), jsx("p", {
4040
+ className: "max-w-sm text-sm text-muted-foreground",
4041
+ children: t("router.emptyBody")
4042
+ })]
4043
+ });
4044
+ }
4045
+ function ResourcePageRouter({ match }) {
4046
+ const app = useApp();
4047
+ const qualifiedMatch = match;
4048
+ const resource = canonicalNavKey(qualifiedMatch);
4049
+ const target = canonicalNavKey({
4050
+ name: match.target ?? match.name,
4051
+ ref: qualifiedMatch.targetRef
4052
+ });
4053
+ const recordAction = recordActionOf(match);
4054
+ switch (match.kind) {
4055
+ case "resource": {
4056
+ if (match.action === "list") {
4057
+ const def = app.registry.get(resource);
4058
+ return def !== void 0 && !hasListPage(def) ? jsx(NavAreaNotFound, {}) : jsx(ResourceListPage, { resource });
4059
+ }
4060
+ const collection = collectionFactOf(app.registry.get(resource)) !== void 0;
4061
+ if (collection && match.id !== void 0 && (match.action === "show" || match.action === "edit" || match.action === "flow")) {
4062
+ if (!recordRouteAvailable(app.registry, resource, "show")) return jsx(NavAreaNotFound, {});
4063
+ return match.action === "flow" ? jsx(CollectionRecordRoute, {
4064
+ collection: resource,
4065
+ action: "flow",
4066
+ id: match.id,
4067
+ flow: match.flow ?? ""
4068
+ }) : jsx(CollectionRecordRoute, {
4069
+ collection: resource,
4070
+ action: match.action,
4071
+ id: match.id
4072
+ });
4073
+ }
4074
+ if (match.action === "flow") return jsx(PageFlowRouteLoader, { match });
4075
+ if (recordAction === void 0) return jsx(ResourcePageRouterEmpty, {});
4076
+ if (!recordRouteAvailable(app.registry, resource, recordAction)) return jsx(NavAreaNotFound, {});
4077
+ if (collection && recordAction === "create") return jsx(CollectionCreatePicker, { collection: resource });
4078
+ return jsx(RecordRoute, {
4079
+ resource,
4080
+ action: recordAction,
4081
+ id: match.id ?? ""
4082
+ });
4083
+ }
4084
+ case "custom-page": {
4085
+ const page = app.registry.customPages.get(resource);
4086
+ if (page === void 0) return jsx(ResourcePageRouterEmpty, {});
4087
+ if (!page.body?.length) return jsx(NavAreaNotFound, {});
4088
+ return jsx(PageHost, {
4089
+ page,
4090
+ match,
4091
+ notFound: jsx(NavAreaNotFound, {})
4092
+ }, resource);
4093
+ }
4094
+ case "group-index": {
4095
+ const indexPage = app.registry.customPages.get(target);
4096
+ if (indexPage?.body?.length) return jsx(PageHost, {
4097
+ page: indexPage,
4098
+ match,
4099
+ notFound: jsx(NavAreaNotFound, {})
4100
+ }, target);
4101
+ const targetDef = app.registry.get(target);
4102
+ if (targetDef !== void 0) return hasListPage(targetDef) ? jsx(ResourceListPage, { resource: target }) : jsx(NavAreaNotFound, {});
4103
+ return jsx(ResourcePageRouterEmpty, {});
4104
+ }
4105
+ default: return jsx(ResourcePageRouterEmpty, {});
4106
+ }
4107
+ }
4108
+ function NavAreaPageSkeleton() {
4109
+ return jsxs("div", {
4110
+ className: "space-y-3 p-6",
4111
+ role: "status",
4112
+ "aria-busy": "true",
4113
+ "aria-live": "polite",
4114
+ "data-testid": "nav-area-skeleton",
4115
+ children: [
4116
+ jsx("span", {
4117
+ className: "sr-only",
4118
+ children: "Loading…"
4119
+ }),
4120
+ jsx("div", { className: "h-6 w-48 animate-pulse rounded bg-muted/60" }),
4121
+ jsx("div", { className: "h-4 w-full animate-pulse rounded bg-muted/40" }),
4122
+ jsx("div", { className: "h-4 w-5/6 animate-pulse rounded bg-muted/40" }),
4123
+ jsx("div", { className: "h-4 w-2/3 animate-pulse rounded bg-muted/40" })
4124
+ ]
4125
+ });
4126
+ }
4127
+ const adapterNoticeGiven = new WeakSet();
4128
+ const chromeNoticeGiven = new WeakSet();
4129
+ function NavAreaPage() {
4130
+ const match = useMatch();
4131
+ const app = useApp();
4132
+ const noAdapter = useOptionalRouterAdapter() === null;
4133
+ const chromeMounted = useNavChromeMounted();
4134
+ const resolveLayout = useLayoutResolver();
4135
+ const chromeGroup = match?.groupChain.find((g) => resolveLayout(g.layout)) ?? null;
4136
+ useEffect(() => {
4137
+ if (process.env.NODE_ENV === "production") return;
4138
+ if (chromeMounted || !chromeGroup || chromeNoticeGiven.has(app)) return;
4139
+ chromeNoticeGiven.add(app);
4140
+ console.error(`[burojs] <NavAreaPage> is inside the nav group "${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>.`);
4141
+ }, [
4142
+ app,
4143
+ chromeMounted,
4144
+ chromeGroup
4145
+ ]);
4146
+ useEffect(() => {
4147
+ if (!noAdapter || process.env.NODE_ENV === "production") return;
4148
+ if (adapterNoticeGiven.has(app)) return;
4149
+ adapterNoticeGiven.add(app);
4150
+ 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.");
4151
+ }, [app, noAdapter]);
4152
+ return jsx(Suspense, {
4153
+ fallback: jsx(NavAreaPageSkeleton, {}),
4154
+ children: match ? jsx(ResourcePageRouter, { match }) : jsx(NavAreaNotFound, {})
4155
+ });
4156
+ }
4157
+ //#endregion
2090
4158
  //#region src/layout/breadcrumbs.tsx
2091
4159
  const LINK_CLASS = "rounded hover:text-foreground transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2";
2092
4160
  function Chevron() {
@@ -2222,9 +4290,12 @@ function Breadcrumbs(input) {
2222
4290
  //#region src/layout/record-breadcrumbs.tsx
2223
4291
  function viewOrigin(ctx, trail, resource) {
2224
4292
  if (trail === void 0 || trail.resource === void 0 || trail.segments.length > 0) return void 0;
2225
- const target = ctx.registry.get(trail.resource)?.routesTo?.show;
2226
- if (target === void 0 || ctx.registry.get(target) !== ctx.registry.get(resource)) return void 0;
2227
- return trail.resource;
4293
+ const def = ctx.registry.get(trail.resource);
4294
+ const target = def?.routesTo?.show;
4295
+ if (target !== void 0 && ctx.registry.get(target) === ctx.registry.get(resource)) return trail.resource;
4296
+ const collected = collectionFactOf(def) === void 0 ? void 0 : memberFactOf(def)?.ref;
4297
+ const memberBase = memberFactOf(ctx.registry.get(resource))?.ref;
4298
+ if (collected !== void 0 && memberBase !== void 0 && sameEntityRef(collected, memberBase)) return trail.resource;
2228
4299
  }
2229
4300
  function RecordBreadcrumbs() {
2230
4301
  const ctx = useTrailContext();
@@ -2608,11 +4679,11 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
2608
4679
  const allResources = app.registry.list();
2609
4680
  const allPages = app.registry.customPages.list();
2610
4681
  const allSections = app.registry.sections.list();
2611
- const tlResources = allResources.filter((r) => hasListPage(r)).filter(isResourceVisible).filter((r) => !r.section && !r.group);
4682
+ const tlResources = allResources.filter((r) => hasMenuEntry(r)).filter(isResourceVisible).filter((r) => !r.section && !r.group);
2612
4683
  const tlPages = allPages.filter((p) => !p.section && !p.group).filter(isPageVisible);
2613
4684
  const groups = [];
2614
4685
  for (const section of allSections) {
2615
- const children = app.registry.sections.childrenOf(canonicalNavKey(section)).filter((c) => !c.group).filter((c) => !("parent" in c) || hasListPage(c)).filter((c) => isCustomPageDef(c) ? isPageVisible(c) : isResourceVisible(c));
4686
+ const children = app.registry.sections.childrenOf(canonicalNavKey(section)).filter((c) => !c.group).filter((c) => !("parent" in c) || hasMenuEntry(c)).filter((c) => isCustomPageDef(c) ? isPageVisible(c) : isResourceVisible(c));
2616
4687
  if (children.length === 0) continue;
2617
4688
  groups.push({
2618
4689
  section,
@@ -2961,7 +5032,7 @@ function PerResourceSearchHits({ def, displayField, query, pageSize, goTo, recor
2961
5032
  const display = titleVisible ? row[displayField] : void 0;
2962
5033
  const labelText = typeof display === "string" && display.length > 0 ? display : id;
2963
5034
  const subtitle = rowSubtitle(row) ?? null;
2964
- const href = recordHref ? recordHref(resource, id) : isShowAvailable(registry, resource) ? resourceShowHref(registry, def, resource, id) : null;
5035
+ const href = recordHref ? recordHref(resource, id) : isShowAvailable(registry, resource) ? resourceShowHref(registry, def, resource, id, row) : null;
2965
5036
  return jsxs(CommandItem, {
2966
5037
  value: `record:${resource}:${id}:${labelText}`,
2967
5038
  forceMount: true,
@@ -3117,7 +5188,7 @@ function CommandPaletteCreateGroup({ resourceFilter, onSelect, getTestId, headin
3117
5188
  const resolvedHeading = heading ?? t("commandPalette.create", { defaultValue: "Create" });
3118
5189
  const resolvedPrefix = prefix ?? t("commandPalette.createNew", { defaultValue: "Create new" });
3119
5190
  const visibleResources = useMemo(() => {
3120
- return app.registry.list().filter((r) => hasListPage(r)).filter((r) => gate(canonicalResourceKey$1(r), "create").state === "available").filter((r) => hasRecordPage(r, "create") || opensInQuick(app.registry, canonicalResourceKey$1(r), "create")).filter(isResourceVisible).filter((r) => resourceFilter ? resourceFilter(r) : true);
5191
+ return app.registry.list().filter((r) => hasListPage(r)).filter((r) => collectionFactOf(r) === void 0).filter((r) => gate(canonicalResourceKey$1(r), "create").state === "available").filter((r) => hasRecordPage(r, "create") || opensInQuick(app.registry, canonicalResourceKey$1(r), "create")).filter(isResourceVisible).filter((r) => resourceFilter ? resourceFilter(r) : true);
3121
5192
  }, [
3122
5193
  app,
3123
5194
  gate,
@@ -4450,7 +6521,7 @@ function JsonInput({ name, id, value, onChange, testid, disabled, required, aria
4450
6521
  }
4451
6522
  //#endregion
4452
6523
  //#region src/fields/lazy-relation-many.tsx
4453
- const RelationManyPickerInput = lazy(() => import("./relation-many-picker-mGEQDWo2.js").then((module) => ({ default: module.RelationManyPickerInput })));
6524
+ const RelationManyPickerInput = lazy(() => import("./relation-many-picker-CT7nKfE2.js").then((module) => ({ default: module.RelationManyPickerInput })));
4454
6525
  function LazyRelationManyInput(props) {
4455
6526
  return jsx(Suspense, {
4456
6527
  fallback: jsx(Skeleton, {
@@ -7095,6 +9166,6 @@ function ScopeSwitcher({ options, value, onChange, label, extra, placeholder })
7095
9166
  const PACKAGE_NAME = "@burojs/ui-shadcn";
7096
9167
  const PACKAGE_VERSION = "0.0.0";
7097
9168
  //#endregion
7098
- export { ActionButton, ActionOverflow, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AppActions, AppFlowButton, AppHeader, AppLayout, AppShell, AppSidebar, AuthPage, Avatar, AvatarFallback, AvatarImage, Badge, BooleanDisplay, BooleanInput, BrandMark, Breadcrumbs, BulkActionToolbar, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CheckConfirmDialog, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, ColumnsToggle, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandLoading, CommandPalette, CommandPaletteActionsGroup, CommandPaletteCreateGroup, CommandPaletteDocsGroup, CommandPaletteNavigationGroups, CommandPaletteRecentGroup, CommandPaletteRecordsGroup, CommandPaletteTrigger, CommandSeparator, ContextPicker, CopyId, CreateButton, CursorLoadMore, DEFAULT_LANGUAGE_STORAGE_KEY, DataTable, DataTableDateRangeFilter, DataTableEnumFilter, DataTableFacetedFilter, DataTableNumRangeFilter, DataTableOperatorFilter, DataTableRowActions, DataTableTextFilter, DataTableToolbar, DataTableViewOptions, DateDisplay, DateInput, DeclarativeDisplay, DeclarativeForm, DefaultCommandPalette, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogPresentationHost, DialogPresentationShell, DialogTitle, DialogTrigger, DisabledAction, DocBrowser, DocInfo, DocPanel, DocTrailHelp, DocumentTitleProvider, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, ENUM_PICKER_CLEAR_SENTINEL, EditPageHeader, EnumBadge, EnumDisplay, EnumInput, EnumPicker, EnumDisplay$1 as EnumValueDisplay, ExportButton, ExportDialog, FacetedFilterPicker, Field, FieldDisplay, FileDisplay, FileField, FileInput, FilterBadges, FilterBuilder, FilterPanel, FilterRegion, FilterValueControl, FlowActionButton, Form, FormActions, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, HeaderBreadcrumbs, HelpButton, Icon, Input, Label, LanguageSubmenu, LanguageSwitch, LinkComponentProvider, LinkKeysDisplay, ListBody, ListBulkBar, ListColumns, ListControls, ListCreate, ListErrorState, ListExport, ListFilters, ListFlows, ListLive, ListSavedViews, ListSearchInput, LoginForm, NavAreaNotFound, NavAreaPage, NavChrome, NavMain, NavigationGuardDialog, NumberDisplay, NumberInput, PACKAGE_NAME, PACKAGE_VERSION, PageHeader, PinnedFilterControls, Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverPresentationHost, PopoverTrigger, PresetFilterControls, Progress, RecordActions, RecordBreadcrumbs, RecordPage, RecordScreen, RecordTitle, RefreshButton, RelationDisplay, RelationField, RelationManyDisplay, RelationPicker, LazyRelationPickerDialog as RelationPickerDialog, RelationPickerInput, ResourceList, ResourceListPage, ResourcePageRouter, SavedViewsDropdown, ScopeDimensionPicker, ScopeSwitcher, SecondarySidebarLayout, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetPresentationHost, SheetPresentationShell, SheetTitle, SheetTrigger, ShellProvider, ShowPageHeader, Sidebar, SidebarBrand, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, THEME_CHOICES, THEME_STORAGE_KEY, Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsLayout, TabsList, TabsTrigger, TaskRunPanel, TextDisplay, TextInput, Textarea, TextareaDisplay, TextareaInput, ThemeSubmenu, ThemeToggle, Toaster, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UserMenu, badgeVariants, buildNavItems, buroSortingToTanStack, buttonVariants, cn, defaultNavLayouts, defaultUserMapper, downloadArtifact, formatOperatorLabel, hasIcon, i18nPrefixToRef, isImage, layoutSlot, listSlot, loadLocale, localeLabel, modeForSurface, recordDisplayName, registerIcons, relationLinkClassName, resolveNavIcon, resolveUpdater, saveLocale, shadcnBlockImplementations, shadcnFieldImplementations, shadcnPresentationHosts, spacing, tanStackSortingToBuro, toast, typography, useBuroDataTable, useCurrentUser, useDialogFilterState, useDocumentTitle, useExportRunWatcher, useFormControl, useFormField, useHref, useIsMobile, useLanguagePaletteActions, useLanguageSwitch, useLayout, useLayoutResolver, useLinkComponent, useListSlot, useMatch, useNavIcon, useNavTree, useNavVisible, useOptionalSidebar, usePaletteState, usePresentationCopy, useRelationPicker, useShell, useSidebar, useTheme, useThemePaletteActions, webPlatform, wrapperEnabled };
9169
+ export { ActionButton, ActionOverflow, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AppActions, AppFlowButton, AppHeader, AppLayout, AppShell, AppSidebar, AuthPage, Avatar, AvatarFallback, AvatarImage, Badge, BooleanDisplay, BooleanInput, BrandMark, Breadcrumbs, BulkActionToolbar, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CheckConfirmDialog, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, CollectionCreatePicker, CollectionRecordRoute, ColumnsToggle, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandLoading, CommandPalette, CommandPaletteActionsGroup, CommandPaletteCreateGroup, CommandPaletteDocsGroup, CommandPaletteNavigationGroups, CommandPaletteRecentGroup, CommandPaletteRecordsGroup, CommandPaletteTrigger, CommandSeparator, ContextPicker, CopyId, CreateButton, CursorLoadMore, DEFAULT_LANGUAGE_STORAGE_KEY, DataTable, DataTableDateRangeFilter, DataTableEnumFilter, DataTableFacetedFilter, DataTableNumRangeFilter, DataTableOperatorFilter, DataTableRowActions, DataTableTextFilter, DataTableToolbar, DataTableViewOptions, DateDisplay, DateInput, DeclarativeDisplay, DeclarativeForm, DefaultCommandPalette, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogPresentationHost, DialogPresentationShell, DialogTitle, DialogTrigger, DisabledAction, DocBrowser, DocInfo, DocPanel, DocTrailHelp, DocumentTitleProvider, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, ENUM_PICKER_CLEAR_SENTINEL, EditPageHeader, EnumBadge, EnumDisplay, EnumInput, EnumPicker, EnumDisplay$1 as EnumValueDisplay, ExportButton, ExportDialog, FacetedFilterPicker, Field, FieldDisplay, FileDisplay, FileField, FileInput, FilterBadges, FilterBuilder, FilterPanel, FilterRegion, FilterValueControl, FlowActionButton, Form, FormActions, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, HeaderBreadcrumbs, HelpButton, Icon, Input, Label, LanguageSubmenu, LanguageSwitch, LinkComponentProvider, LinkKeysDisplay, ListBody, ListBulkBar, ListColumns, ListControls, ListCreate, ListErrorState, ListExport, ListFilters, ListFlows, ListLive, ListSavedViews, ListSearchInput, LoginForm, NavAreaNotFound, NavAreaPage, NavChrome, NavMain, NavigationGuardDialog, NumberDisplay, NumberInput, PACKAGE_NAME, PACKAGE_VERSION, PageHeader, PinnedFilterControls, Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverPresentationHost, PopoverTrigger, PresetFilterControls, Progress, RecordActions, RecordBreadcrumbs, RecordPage, RecordScreen, RecordTitle, RefreshButton, RelationDisplay, RelationField, RelationManyDisplay, RelationPicker, LazyRelationPickerDialog as RelationPickerDialog, RelationPickerInput, ResourceList, ResourceListPage, ResourcePageRouter, SavedViewsDropdown, ScopeDimensionPicker, ScopeSwitcher, SecondarySidebarLayout, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetPresentationHost, SheetPresentationShell, SheetTitle, SheetTrigger, ShellProvider, ShowPageHeader, Sidebar, SidebarBrand, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, THEME_CHOICES, THEME_STORAGE_KEY, Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsLayout, TabsList, TabsTrigger, TaskRunPanel, TextDisplay, TextInput, Textarea, TextareaDisplay, TextareaInput, ThemeSubmenu, ThemeToggle, Toaster, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UnknownMemberCard, UserMenu, badgeVariants, buildNavItems, buroSortingToTanStack, buttonVariants, cn, defaultNavLayouts, defaultUserMapper, downloadArtifact, formatOperatorLabel, hasIcon, i18nPrefixToRef, isImage, layoutSlot, listSlot, loadLocale, localeLabel, modeForSurface, recordDisplayName, registerIcons, relationLinkClassName, resolveNavIcon, resolveUpdater, saveLocale, shadcnBlockImplementations, shadcnFieldImplementations, shadcnPresentationHosts, spacing, tanStackSortingToBuro, toast, typography, useBuroDataTable, useCurrentUser, useDialogFilterState, useDocumentTitle, useExportRunWatcher, useFormControl, useFormField, useHref, useIsMobile, useLanguagePaletteActions, useLanguageSwitch, useLayout, useLayoutResolver, useLinkComponent, useListSlot, useMatch, useNavIcon, useNavTree, useNavVisible, useOptionalSidebar, usePaletteState, usePresentationCopy, useRelationPicker, useShell, useSidebar, useTheme, useThemePaletteActions, webPlatform, wrapperEnabled };
7099
9170
 
7100
9171
  //# sourceMappingURL=index.js.map