@burojs/ui-shadcn 0.6.0 → 0.7.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 (152) hide show
  1. package/README.md +9 -0
  2. package/dist/bulk-summary-BWSAS7k2.js +143 -0
  3. package/dist/bulk-summary-BWSAS7k2.js.map +1 -0
  4. package/dist/bulk-summary-CrEij5vq.cjs +143 -0
  5. package/dist/bulk-summary-CrEij5vq.cjs.map +1 -0
  6. package/dist/{candidates-relation-picker-B116Bmqi.js → candidates-relation-picker-CS_JZ4Fd.js} +3 -3
  7. package/dist/{candidates-relation-picker-B116Bmqi.js.map → candidates-relation-picker-CS_JZ4Fd.js.map} +1 -1
  8. package/dist/{candidates-relation-picker-Cy0rTxvI.cjs → candidates-relation-picker-y5M6_oe4.cjs} +4 -4
  9. package/dist/{candidates-relation-picker-Cy0rTxvI.cjs.map → candidates-relation-picker-y5M6_oe4.cjs.map} +1 -1
  10. package/dist/{check-confirm-dialog-bRT8lt0d.js → check-confirm-dialog-2j0gOd7x.js} +384 -108
  11. package/dist/check-confirm-dialog-2j0gOd7x.js.map +1 -0
  12. package/dist/{check-confirm-dialog--gPFnEeg.cjs → check-confirm-dialog-C-NHgMST.cjs} +468 -107
  13. package/dist/check-confirm-dialog-C-NHgMST.cjs.map +1 -0
  14. package/dist/{dialog-B_rt9S1c.js → dialog-C123sVQ8.js} +4 -4
  15. package/dist/dialog-C123sVQ8.js.map +1 -0
  16. package/dist/{dialog-DRNUq9EA.cjs → dialog-vmMdfUWs.cjs} +3 -3
  17. package/dist/dialog-vmMdfUWs.cjs.map +1 -0
  18. package/dist/{filter-builder-nXqtM_h4.cjs → filter-builder-DFu0JP-1.cjs} +923 -120
  19. package/dist/filter-builder-DFu0JP-1.cjs.map +1 -0
  20. package/dist/{filter-builder-Bhn-dhZV.js → filter-builder-DaWHUZuV.js} +839 -108
  21. package/dist/filter-builder-DaWHUZuV.js.map +1 -0
  22. package/dist/{flow-runtime-D3avVH0I.cjs → flow-runtime-BpmrIUb6.cjs} +61 -29
  23. package/dist/flow-runtime-BpmrIUb6.cjs.map +1 -0
  24. package/dist/{flow-runtime-s6lkRPKF.js → flow-runtime-DyqTmK3H.js} +62 -30
  25. package/dist/flow-runtime-DyqTmK3H.js.map +1 -0
  26. package/dist/{flow-screen-Ci_Sik4Y.cjs → flow-screen-Bcz9NF2V.cjs} +128 -87
  27. package/dist/flow-screen-Bcz9NF2V.cjs.map +1 -0
  28. package/dist/{flow-screen-CCvgDI9G.js → flow-screen-DCdli6Ha.js} +128 -87
  29. package/dist/flow-screen-DCdli6Ha.js.map +1 -0
  30. package/dist/index.cjs +731 -906
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.d.cts +455 -247
  33. package/dist/index.d.ts +455 -247
  34. package/dist/index.js +647 -828
  35. package/dist/index.js.map +1 -1
  36. package/dist/{inline-flow-host-DV1et3c6.cjs → inline-flow-host-3vw7LzzD.cjs} +5 -5
  37. package/dist/inline-flow-host-3vw7LzzD.cjs.map +1 -0
  38. package/dist/{inline-flow-host-B6FI0ctQ.js → inline-flow-host-C0rI9B7f.js} +5 -5
  39. package/dist/inline-flow-host-C0rI9B7f.js.map +1 -0
  40. package/dist/{candidates-gate-D33jXLHO.cjs → lazy-relation-picker-dialog-Bt8lrEIu.cjs} +10 -10
  41. package/dist/lazy-relation-picker-dialog-Bt8lrEIu.cjs.map +1 -0
  42. package/dist/{candidates-gate-Bb70LPAy.js → lazy-relation-picker-dialog-CAScLPb2.js} +11 -11
  43. package/dist/lazy-relation-picker-dialog-CAScLPb2.js.map +1 -0
  44. package/dist/{page-flow-route-i3ZfJ1sd.js → page-flow-route-BHUEpn0I.js} +36 -23
  45. package/dist/page-flow-route-BHUEpn0I.js.map +1 -0
  46. package/dist/{page-flow-route-hdnULWqd.cjs → page-flow-route-DS8IVTVH.cjs} +41 -28
  47. package/dist/page-flow-route-DS8IVTVH.cjs.map +1 -0
  48. package/dist/{place-node-C5SmIAYU.cjs → place-node-CNb3w-c7.cjs} +1869 -947
  49. package/dist/place-node-CNb3w-c7.cjs.map +1 -0
  50. package/dist/{place-node-NraNYKPx.js → place-node-CfzQvh4Y.js} +1824 -926
  51. package/dist/place-node-CfzQvh4Y.js.map +1 -0
  52. package/dist/{related-list-cards-BWZ9GfOG.js → related-list-cards-BIqqY69Y.js} +9 -4
  53. package/dist/{related-list-cards-BWZ9GfOG.js.map → related-list-cards-BIqqY69Y.js.map} +1 -1
  54. package/dist/{related-list-cards-CFq3meUn.cjs → related-list-cards-CelMxl4q.cjs} +9 -4
  55. package/dist/{related-list-cards-CFq3meUn.cjs.map → related-list-cards-CelMxl4q.cjs.map} +1 -1
  56. package/dist/{related-list-timeline-yrPsjA3F.js → related-list-timeline-CRh7xwLD.js} +6 -7
  57. package/dist/related-list-timeline-CRh7xwLD.js.map +1 -0
  58. package/dist/{related-list-timeline-CCzl71aA.cjs → related-list-timeline-DsLdi8sv.cjs} +5 -6
  59. package/dist/related-list-timeline-DsLdi8sv.cjs.map +1 -0
  60. package/dist/{related-rows-o0_t-Yce.js → related-rows--uP2iKQC.js} +25 -14
  61. package/dist/related-rows--uP2iKQC.js.map +1 -0
  62. package/dist/{related-rows-ea43qhhy.cjs → related-rows-MPnLCmPF.cjs} +27 -16
  63. package/dist/related-rows-MPnLCmPF.cjs.map +1 -0
  64. package/dist/{search-access-CPPmfuvy.js → relation-create-C43cdPQt.js} +595 -13
  65. package/dist/relation-create-C43cdPQt.js.map +1 -0
  66. package/dist/{search-access-Dugvttlg.cjs → relation-create-DDEYcKfw.cjs} +633 -14
  67. package/dist/relation-create-DDEYcKfw.cjs.map +1 -0
  68. package/dist/{relation-many-picker-bvkjkv-k.js → relation-many-picker-BJhaEqxz.js} +203 -102
  69. package/dist/relation-many-picker-BJhaEqxz.js.map +1 -0
  70. package/dist/{relation-many-picker-C8zFEjwd.cjs → relation-many-picker-DzuGJpEl.cjs} +211 -110
  71. package/dist/relation-many-picker-DzuGJpEl.cjs.map +1 -0
  72. package/dist/{relation-picker-Z0ZJJ5uS.js → relation-picker-D-tBBZW_.js} +23 -59
  73. package/dist/relation-picker-D-tBBZW_.js.map +1 -0
  74. package/dist/{relation-picker-gag0qSR5.cjs → relation-picker-DaIMzf2H.cjs} +29 -71
  75. package/dist/relation-picker-DaIMzf2H.cjs.map +1 -0
  76. package/dist/{relation-picker-dialog-0IzkjmiA.cjs → relation-picker-dialog-9Vg5vvR1.cjs} +133 -35
  77. package/dist/relation-picker-dialog-9Vg5vvR1.cjs.map +1 -0
  78. package/dist/{relation-picker-dialog-B6nIiJBf.js → relation-picker-dialog-DoEY8EkH.js} +134 -36
  79. package/dist/relation-picker-dialog-DoEY8EkH.js.map +1 -0
  80. package/dist/relation-select-B8Fq4o-t.js +48 -0
  81. package/dist/relation-select-B8Fq4o-t.js.map +1 -0
  82. package/dist/relation-select-Cr3CfNLy.cjs +55 -0
  83. package/dist/relation-select-Cr3CfNLy.cjs.map +1 -0
  84. package/dist/{resource-page-router-PXfMW9nh.cjs → resource-page-router-C_kGW2o_.cjs} +543 -300
  85. package/dist/resource-page-router-C_kGW2o_.cjs.map +1 -0
  86. package/dist/{resource-page-router-3RUf9d1j.js → resource-page-router-Diw6S6TK.js} +498 -255
  87. package/dist/resource-page-router-Diw6S6TK.js.map +1 -0
  88. package/dist/{rich-text-vTyVjDoa.cjs → rich-text-C_7JCvRo.cjs} +2 -2
  89. package/dist/{rich-text-vTyVjDoa.cjs.map → rich-text-C_7JCvRo.cjs.map} +1 -1
  90. package/dist/{rich-text-DFerywgz.js → rich-text-RcPBf6hr.js} +2 -2
  91. package/dist/{rich-text-DFerywgz.js.map → rich-text-RcPBf6hr.js.map} +1 -1
  92. package/dist/success-notices-Dl3M1fZP.cjs +46 -0
  93. package/dist/success-notices-Dl3M1fZP.cjs.map +1 -0
  94. package/dist/success-notices-LDEgEkc4.js +41 -0
  95. package/dist/success-notices-LDEgEkc4.js.map +1 -0
  96. package/dist/{toaster-Cr51X7bz.cjs → toaster-BbByOytP.cjs} +60 -15
  97. package/dist/toaster-BbByOytP.cjs.map +1 -0
  98. package/dist/{toaster-C02XbB9r.js → toaster-Ct_YHGs6.js} +43 -16
  99. package/dist/toaster-Ct_YHGs6.js.map +1 -0
  100. package/dist/{use-dialog-filter-state-C--oMAZG.js → use-dialog-filter-state-B_MqzHaT.js} +5 -4
  101. package/dist/use-dialog-filter-state-B_MqzHaT.js.map +1 -0
  102. package/dist/{use-dialog-filter-state-Dhe8PcB5.cjs → use-dialog-filter-state-tNvqAAjh.cjs} +6 -5
  103. package/dist/use-dialog-filter-state-tNvqAAjh.cjs.map +1 -0
  104. package/package.json +11 -11
  105. package/dist/bulk-summary-CwSd6Yjb.cjs +0 -108
  106. package/dist/bulk-summary-CwSd6Yjb.cjs.map +0 -1
  107. package/dist/bulk-summary-GxMDP4bw.js +0 -108
  108. package/dist/bulk-summary-GxMDP4bw.js.map +0 -1
  109. package/dist/candidates-gate-Bb70LPAy.js.map +0 -1
  110. package/dist/candidates-gate-D33jXLHO.cjs.map +0 -1
  111. package/dist/check-confirm-dialog--gPFnEeg.cjs.map +0 -1
  112. package/dist/check-confirm-dialog-bRT8lt0d.js.map +0 -1
  113. package/dist/dialog-B_rt9S1c.js.map +0 -1
  114. package/dist/dialog-DRNUq9EA.cjs.map +0 -1
  115. package/dist/filter-builder-Bhn-dhZV.js.map +0 -1
  116. package/dist/filter-builder-nXqtM_h4.cjs.map +0 -1
  117. package/dist/flow-runtime-D3avVH0I.cjs.map +0 -1
  118. package/dist/flow-runtime-s6lkRPKF.js.map +0 -1
  119. package/dist/flow-screen-CCvgDI9G.js.map +0 -1
  120. package/dist/flow-screen-Ci_Sik4Y.cjs.map +0 -1
  121. package/dist/inline-flow-host-B6FI0ctQ.js.map +0 -1
  122. package/dist/inline-flow-host-DV1et3c6.cjs.map +0 -1
  123. package/dist/page-flow-route-hdnULWqd.cjs.map +0 -1
  124. package/dist/page-flow-route-i3ZfJ1sd.js.map +0 -1
  125. package/dist/place-node-C5SmIAYU.cjs.map +0 -1
  126. package/dist/place-node-NraNYKPx.js.map +0 -1
  127. package/dist/related-list-timeline-CCzl71aA.cjs.map +0 -1
  128. package/dist/related-list-timeline-yrPsjA3F.js.map +0 -1
  129. package/dist/related-rows-ea43qhhy.cjs.map +0 -1
  130. package/dist/related-rows-o0_t-Yce.js.map +0 -1
  131. package/dist/relation-create-IA40t1hi.cjs +0 -364
  132. package/dist/relation-create-IA40t1hi.cjs.map +0 -1
  133. package/dist/relation-create-h6F9B4C4.js +0 -339
  134. package/dist/relation-create-h6F9B4C4.js.map +0 -1
  135. package/dist/relation-many-picker-C8zFEjwd.cjs.map +0 -1
  136. package/dist/relation-many-picker-bvkjkv-k.js.map +0 -1
  137. package/dist/relation-picker-Z0ZJJ5uS.js.map +0 -1
  138. package/dist/relation-picker-dialog-0IzkjmiA.cjs.map +0 -1
  139. package/dist/relation-picker-dialog-B6nIiJBf.js.map +0 -1
  140. package/dist/relation-picker-gag0qSR5.cjs.map +0 -1
  141. package/dist/resource-page-router-3RUf9d1j.js.map +0 -1
  142. package/dist/resource-page-router-PXfMW9nh.cjs.map +0 -1
  143. package/dist/search-access-CPPmfuvy.js.map +0 -1
  144. package/dist/search-access-Dugvttlg.cjs.map +0 -1
  145. package/dist/shell-BPlk8hEa.js +0 -205
  146. package/dist/shell-BPlk8hEa.js.map +0 -1
  147. package/dist/shell-DxhlsPwm.cjs +0 -271
  148. package/dist/shell-DxhlsPwm.cjs.map +0 -1
  149. package/dist/toaster-C02XbB9r.js.map +0 -1
  150. package/dist/toaster-Cr51X7bz.cjs.map +0 -1
  151. package/dist/use-dialog-filter-state-C--oMAZG.js.map +0 -1
  152. package/dist/use-dialog-filter-state-Dhe8PcB5.cjs.map +0 -1
package/dist/index.js CHANGED
@@ -1,23 +1,23 @@
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
- import { a as LinkComponentProvider, c as PopoverAnchor, d as PopoverTrigger, i as toFriendlyError, l as PopoverClose, n as toast, o as useLinkComponent, r as friendlyStringsFrom, s as Popover, t as Toaster, u as PopoverContent } from "./toaster-C02XbB9r.js";
3
- import { A as hasIcon, B as DropdownMenuRadioItem, F as DropdownMenuGroup, G as DropdownMenuSubTrigger, H as DropdownMenuShortcut, I as DropdownMenuItem, J as TooltipContent, K as DropdownMenuTrigger, L as DropdownMenuLabel, M as DropdownMenu, N as DropdownMenuCheckboxItem, O as useLoaded, P as DropdownMenuContent, R as DropdownMenuPortal, U as DropdownMenuSub, V as DropdownMenuSeparator, W as DropdownMenuSubContent, X as TooltipTrigger, Y as TooltipProvider, Z as DocInfo, _ as FlowBoundary, a as modeForSurface, c as useListSlot, f as FlowActionButton, j as registerIcons, k as Icon, l as isExternalHref, n as ActionButton, o as canonicalResourceName, q as Tooltip, r as DisabledAction, s as listSlot, t as CheckConfirmDialog, u as openExternal, v as FlowLoadFailed, w as loadFlowScreen, z as DropdownMenuRadioGroup } from "./check-confirm-dialog-bRT8lt0d.js";
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 Tooltip, A as OwnTitleHeading, B as DropdownMenuContent, F as Icon, G as DropdownMenuRadioGroup, H as DropdownMenuItem, I as hasIcon, J as DropdownMenuShortcut, K as DropdownMenuRadioItem, L as registerIcons, M as DialogPresentationShell, N as OwnTitleContext, P as SheetPresentationShell, Q as DropdownMenuTrigger, R as DropdownMenu, T as loadFlowScreen, U as DropdownMenuLabel, V as DropdownMenuGroup, W as DropdownMenuPortal, X as DropdownMenuSubContent, Y as DropdownMenuSub, Z as DropdownMenuSubTrigger, _ as reasonText, a as modeForSurface, at as SheetContent, c as useListSlot, ct as SheetHeader, dt as DocInfo, et as TooltipContent, f as FlowActionButton, it as SheetClose, k as useLoaded, l as isExternalHref, lt as SheetTitle, n as ActionButton, nt as TooltipTrigger, o as canonicalResourceName, ot as SheetDescription, q as DropdownMenuSeparator, r as DisabledAction, rt as Sheet, s as listSlot, st as SheetFooter, t as CheckConfirmDialog, tt as TooltipProvider, u as openExternal, ut as SheetTrigger, v as FlowBoundary, y as FlowLoadFailed, z as DropdownMenuCheckboxItem } from "./check-confirm-dialog-2j0gOd7x.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
- 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-B_rt9S1c.js";
7
- import { C as CommandSeparator, S as CommandLoading, _ as CommandEmpty, b as CommandItem, c as peekAnchorOpener, f as recordDisplayName, g as CommandDialog, h as Command, i as RelationField, l as PeekContext, o as relationLinkClassName, r as RelationDisplay, s as focusWithoutPeek, u as PeekHostContext, v as CommandGroup, x as CommandList, y as CommandInput } from "./search-access-CPPmfuvy.js";
8
- import { a as SheetClose, c as SheetFooter, d as SheetTrigger, i as Sheet, l as SheetHeader, n as OwnTitleContext, o as SheetContent, r as SheetPresentationShell, s as SheetDescription, t as DialogPresentationShell, u as SheetTitle } from "./shell-BPlk8hEa.js";
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 { C as CommandEmpty, D as CommandList, E as CommandItem, O as CommandLoading, S as CommandDialog, T as CommandInput, b as RecordState, c as RelationField, d as peekAnchorOpener, f as PeekContext, h as recordDisplayName, k as CommandSeparator, l as relationLinkClassName, p as PeekHostContext, s as RelationDisplay, u as focusWithoutPeek, v as InvalidRouteId, w as CommandGroup, x as Command, y as LoadError } from "./relation-create-C43cdPQt.js";
9
8
  import { t as Skeleton } from "./skeleton-U2noefj5.js";
10
- import { $ as tanStackSortingToBuro, A as ListExport, At as i18nPrefixToRef, B as DeclarativeForm, C as ListSavedViews, Ct as useExportRunWatcher, D as ListFilters, Dt as AppFlowButton, E as ListFlows, F as ColumnsToggle, Ft as defaultUserMapper, I as DataTableViewOptions, It as usePaletteState, J as ResourceList, L as ListBulkBar, Lt as useShell, M as ListCreate, Mt as lowerLegacyField, N as CreateButton, Nt as toDisplayText, O as FilterRegion, Ot as Field, P as ListColumns, Pt as ShellProvider, Q as resolveUpdater, R as BulkActionToolbar, S as ListControls, T as ListLive, Tt as EnumBadge, U as QuickScreenClaimContext, V as ScreenTree, X as ListErrorState, Y as CursorLoadMore, Z as buroSortingToTanStack, _ as FormActions, a as peekFieldDefinition, at as TabsList, c as peekRow, d as shadcnFrameViews, dt as PageHeader, et as useBuroDataTable, ft as ShowPageHeader, g as CopyId, gt as isShowAvailable, ht as typography, it as TabsContent, j as ExportButton, jt as ResolvedFieldDisplay, k as ListSearchInput, kt as FieldDisplay, mt as useDocumentTitle, nt as Checkbox, o as peekLeafAllowed, ot as TabsTrigger, pt as DocumentTitleProvider, q as ListBody, r as shadcnBlockImplementations, rt as Tabs, s as peekRecord, tt as DataTable, u as resolveFrameView, ut as EditPageHeader, v as RecordActions, w as SavedViewsDropdown, wt as downloadArtifact, xt as ActionOverflow, y as RecordTitle, yt as recordRouteAvailable, z as ExportDialog } from "./place-node-NraNYKPx.js";
9
+ import { $ as CursorLoadMore, A as ListSearchInput, At as EnumBadge, B as ExportDialog, Bt as usePaletteState, C as ListControls, D as ListFlows, E as ListLive, Et as ActionOverflow, F as ListColumns, Ft as i18nPrefixToRef, H as ScreenTree, I as ColumnsToggle, It as FieldValueFrame, L as DataTableViewOptions, Lt as toDisplayText, M as ExportButton, Mt as AppFlowButton, N as ListCreate, Nt as Field, O as ListFilters, Ot as useExportRunWatcher, P as CreateButton, Pt as FieldDisplay, Q as ResourceList, R as ListBulkBar, Rt as ShellProvider, T as SavedViewsDropdown, V as DeclarativeForm, Vt as useShell, W as QuickScreenClaimContext, Y as useFormControl, Z as ListBody, _ as CopyId, _t as resolveResourceTitle, a as peekFieldDefinition, at as DataTable, b as RecordTitle, bt as typography, c as peekRow, ct as TabsContent, d as resolveFrameView, et as ListErrorState, f as shadcnFrameViews, gt as ShowPageHeader, ht as PageHeader, it as useBuroDataTable, j as ListExport, k as FilterRegion, kt as downloadArtifact, l as useRelationPicker, lt as TabsList, mt as EditPageHeader, 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 DocumentTitleProvider, w as ListSavedViews, wt as recordRouteAvailable, xt as isShowAvailable, y as RecordActions, yt as useDocumentTitle, z as BulkActionToolbar, zt as defaultUserMapper } from "./place-node-CfzQvh4Y.js";
11
10
  import { THEME_STORAGE_KEY } from "./layout/theme-storage-key.js";
12
- import { C as TableHeader, D as DEFAULT_LANGUAGE_STORAGE_KEY, E as badgeVariants, O as loadLocale, S as TableHead, T as Badge, _ as SelectValue, a as FilterBadges, b as TableCaption, c as Select, d as SelectItem, f as SelectLabel, g as SelectTrigger, h as SelectSeparator, i as FilterValueControl, k as saveLocale, l as SelectContent, m as SelectScrollUpButton, n as PinnedFilterControls, o as formatDate, p as SelectScrollDownButton, r as FilterPanel, s as formatNumber, t as FilterBuilder, u as SelectGroup, v as Table, w as TableRow, x as TableCell, y as TableBody } from "./filter-builder-Bhn-dhZV.js";
13
- import { A as useLayoutResolver, C as useNavChromeBoundary, D as usePageAllowed, E as useNavVisible, M as canonicalNavKey, N as canonicalResourceKey, O as layoutSlot, S as NavChromeBoundaryProvider, T as useMatch, _ as useFormControl, a as recordErrorState, b as RecordState, c as readRecentRecords, d as recordTrailRoute, f as useTrailContext, g as RecordScreen, h as usePublishedRecordTrail, i as RecordPage, j as buildNavItems, k as useLayout, l as headerTrail, n as NavAreaPage, o as useRecordVisit, p as recordTrailKey, r as ResourcePageRouter, s as RECENT_LABEL_KEYS, u as recordTrail, v as PlannedBody, w as useHref, x as NavChrome, y as ResourceListPage } from "./resource-page-router-3RUf9d1j.js";
11
+ import { A as TableRow, B as loadLocale, C as SelectValue, D as TableCell, E as TableCaption, M as badgeVariants, O as TableHead, P as ResolvedFieldDisplay, R as lowerLegacyField, S as SelectTrigger, T as TableBody, V as saveLocale, _ as SelectItem, a as PinnedFilterControls, b as SelectScrollUpButton, c as fromLocalDateTimeText, d as formatDate, f as formatDateTime, g as SelectGroup, h as SelectContent, i as FacetedFilterPicker, j as Badge, k as TableHeader, l as toLocalDateTimeText, m as Select, n as PresetFilterControls, o as FilterPanel, p as formatNumber, r as DataTableFacetedFilter, s as FilterValueControl, t as FilterBuilder, u as FilterBadges, v as SelectLabel, w as Table, x as SelectSeparator, y as SelectScrollDownButton, z as DEFAULT_LANGUAGE_STORAGE_KEY } from "./filter-builder-DaWHUZuV.js";
12
+ import { A as TabsLayout, C as usePageAllowed, D as useLayout, E as layoutSlot, M as canonicalNavKey, N as canonicalResourceKey$1, O as useLayoutResolver, S as useNavVisible, T as BUILTIN_LAYOUTS, _ as PlannedBody, a as useRecordVisit, b as useHref, c as headerTrail, d as useTrailContext, f as recordTrailKey, g as useResourceDimensionOptions, h as RecordScreen, i as RecordPage, j as SecondarySidebarLayout, k as useReportUnresolvedLayouts, l as recordTrail, m as usePublishedRecordTrail, n as NavAreaPage, o as RECENT_LABEL_KEYS, r as ResourcePageRouter, s as readRecentRecords, u as recordTrailRoute, v as ResourceListPage, w as useResourceVisible, x as useMatch, y as NavChromeMountedProvider } from "./resource-page-router-Diw6S6TK.js";
14
13
  import { t as Label } from "./label-66W1qbke.js";
15
- import { i as useRelationSelect, n as RelationPicker, r as RelationPickerInput } from "./relation-picker-Z0ZJJ5uS.js";
16
- import { r as LazyRelationPickerDialog, t as useCandidateSelection } from "./candidates-gate-Bb70LPAy.js";
17
- import { t as useDialogFilterState } from "./use-dialog-filter-state-C--oMAZG.js";
18
- import { builtinFrames, compilePageScreen, compiledScreenFor, declaredField, declaredText, dtoFields, effectiveFlow, enumFallbackKey, enumFallbackText, enumNamespaceOf, enumValueText, evaluateVisible, fieldOptionText, formatEntityRef, groupChain, hasListPage, hasRecordPage, hrefFor, humanizeKey, isCustomPageDef, isRelationField, isScreenFailure, linkOf, navHrefFor, nodeKind, normalizeDataError, normalizeEntityRef, projectDto, recordEntries, relationAmbiguousError, resolveConceptLabel, resolveContentSlot, resolveDoc, resolveEnumLabel, resolveFieldLabel, resolveFieldOptionLabel, resolveNavLabel, resolveResourceLabel, resolveResourceNavLabel, resolveStaticAvailability, resourceCreateHref, resourceKey, resourceShowHref, snapshotAppFrames, snapshotBlockLookup, snapshotFrameLookup, taskRunFraction, taskRunOutcome } from "@burojs/core";
19
- import { ComponentsContext, DispatcherProvider, I18nContext, NO_RECORD_SCOPE_FRAMES, QUICK_ANCHOR_ATTRIBUTE, QuickEntryContext, RecordScopeChain, ResourceContext, RouteSourceContext, ScreenStateProvider, formatBytes, retryRecordRead, useApp, useAppActions, useApplicationSnapshot, useAvailabilityGate, useCapabilityResolver, useChangeLocale, useCommandPalette, useCurrentUserId, useDataRuntime, useDebouncedValue, useDispatcherEffects, useDocPanel, useDocScopes, useDocTopics, useDocTrailScopes, useDocsConfig, useDocumentedScopes, useEntryGate, useEnumValues, useFieldAccess, useFileField, useFileUrls, useFormController, useFrameImplementations, useFrameT, useI18nCaps, useIdentity, useLanguageStorageKey, useLinkKeys, useList, useListAccess, useLocale, useLogout, useNavigationGuardText, useOne, useOptionalApp, useOptionalAuthController, useOptionalDataRuntime, useOptionalFileStorage, useOptionalLocale, useOptionalRecordFrame, useOptionalRouterAdapter, useOptionalT, usePresentBlock, useProjectedRecord, useProjectedTitle, useQuick, useQuickEntry, useQuickEntryValue, useQuickOpener, useRecordScopeFrames, useRecordTitle, useRefresh, useRegisterNavigationGuardDialog, useRelatedRecord, useRouteNavigate, useRouterAdapter, useT, useTestIds, useUIInstance, useUIPresentationRuntime, useVisibilityCtx } from "@burojs/react";
20
- import { IconAlertCircle, IconArrowLeft, IconArrowUpRight, IconBook2, IconCheck, IconChevronDown, IconChevronRight, IconCirclePlus, IconDeviceDesktop, IconDots, IconExternalLink, IconHelp, IconHelpHexagon, IconLayoutSidebar, IconLoader2, IconLogin, IconLogout, IconMaximize, IconMinimize, IconMoon, IconRefresh, IconRotate, IconSearch, IconSelector, IconSun, IconUpload, IconUser, IconX } from "@tabler/icons-react";
14
+ import { t as LazyRelationPickerDialog } from "./lazy-relation-picker-dialog-CAScLPb2.js";
15
+ import { n as RelationPicker, r as RelationPickerInput } from "./relation-picker-D-tBBZW_.js";
16
+ import { t as useDialogFilterState } from "./use-dialog-filter-state-B_MqzHaT.js";
17
+ import { useGlobalShortcut, webPlatform } from "@burojs/react/web";
18
+ import { ENUM_CONTROLS, builtinFrames, columnName, compilePageScreen, compiledScreenFor, declaredField, declaredText, dtoFields, effectiveFlow, enumFallbackKey, enumFallbackText, enumNamespaceOf, enumValueText, evaluateVisible, fieldOptionText, formatEntityRef, hasListPage, hasRecordPage, hrefFor, humanizeKey, isCustomPageDef, isEnumControl, isRelationField, isScreenFailure, linkOf, navHrefFor, nodeKind, normalizeDataError, normalizeEntityRef, projectDto, recordEntries, relationAmbiguousError, resolveConceptLabel, resolveContentSlot, resolveDoc, resolveEnumLabel, resolveFieldLabel, resolveNavLabel, resolveResourceLabel, resolveResourceNavLabel, resolveStaticAvailability, resourceCreateHref, resourceKey, resourceShowHref, routeResourceKey, snapshotAppFrames, snapshotBlockLookup, snapshotFrameLookup, taskRunFraction, taskRunOutcome } from "@burojs/core";
19
+ import { ComponentsContext, DispatcherProvider, I18nContext, NO_RECORD_SCOPE_FRAMES, QUICK_ANCHOR_ATTRIBUTE, QuickEntryContext, RecordScopeChain, RouteSourceContext, ScreenStateProvider, formatBytes, optionFieldName, resolveErrorText, resolveOptionLabel, retryRecordRead, useApp, useAppActions, useApplicationSnapshot, useAvailabilityGate, useBoundEnum, useCapabilityResolver, useChangeLocale, useChromeT, useCommandPalette, useCurrentUserId, useDebouncedValue, useDispatcherEffects, useDocPanel, useDocScopes, useDocTopics, useDocTrailScopes, useDocsConfig, useDocumentedScopes, useEntryGate, useEnumValues, useFieldAccess, useFileField, useFileUrls, useFormController, useFrameImplementations, useFrameT, useI18nCaps, useIdentity, useLanguageStorageKey, useLinkKeys, useList, useListAccess, useLocale, useLogout, useNavigationGuardText, useOne, useOptionCaps, useOptionalApp, useOptionalAuthController, useOptionalDataRuntime, useOptionalFileStorage, useOptionalLocale, useOptionalRouterAdapter, useOptionalT, usePlatformStorage, usePresentBlock, useProjectedRecord, useProjectedTitle, useQuick, useQuickEntry, useQuickEntryValue, useQuickOpener, useRecordTitle, useRefresh, useRegisterNavigationGuardDialog, useRelatedRecord, useRouteNavigate, useRouteRecordId, useRouterAdapter, useScope, useT, useTestIds, useUIInstance, useUIPresentationRuntime, useVisibilityCtx } from "@burojs/react";
20
+ import { IconAlertCircle, IconArrowLeft, IconArrowUpRight, IconBook2, IconCheck, IconChevronDown, IconChevronRight, IconDeviceDesktop, IconDots, IconExternalLink, IconHelp, IconHelpHexagon, IconLayoutSidebar, IconLoader2, IconLogin, IconLogout, IconMaximize, IconMinimize, IconMoon, IconRefresh, IconRotate, IconSearch, IconSelector, IconSun, IconUpload, IconUser, IconX } from "@tabler/icons-react";
21
21
  import * as React from "react";
22
22
  import { Children, Fragment, Suspense, cloneElement, createContext, createElement, isValidElement, lazy, useCallback, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
23
23
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
@@ -29,6 +29,7 @@ import * as SeparatorPrimitive from "@radix-ui/react-separator";
29
29
  import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
30
30
  import * as AvatarPrimitive from "@radix-ui/react-avatar";
31
31
  import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
32
+ import { enumBindingKey } from "@burojs/core/internal";
32
33
  import { Controller, FormProvider, useForm, useFormContext } from "react-hook-form";
33
34
  import { zodResolver } from "@hookform/resolvers/zod";
34
35
  import { z } from "zod";
@@ -489,7 +490,7 @@ function ScopeSummary({ scope, summary }) {
489
490
  const caps = useI18nCaps();
490
491
  const t = useOptionalT();
491
492
  const links = (scope !== void 0 ? resolveDoc(caps, scope) : void 0)?.links ?? [];
492
- const newTabNote = t("docPanel.newTab", { defaultValue: "opens in a new tab" });
493
+ const newTabNote = t("docPanel.opensInNewTab", { defaultValue: "(opens in a new tab)" });
493
494
  if (summary === void 0 && links.length === 0) return null;
494
495
  return jsxs("div", {
495
496
  className: "mt-2 flex flex-col items-start gap-3",
@@ -1111,7 +1112,7 @@ AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
1111
1112
  function NavigationGuardDialog() {
1112
1113
  const prompt = useRegisterNavigationGuardDialog();
1113
1114
  const text = useNavigationGuardText();
1114
- const unsavedAction = useOptionalT()("navigation.unsavedAction");
1115
+ const unsavedAction = useOptionalT()("navigation.unsavedAction", { defaultValue: "An action on this screen has unsaved input" });
1115
1116
  const returnFocus = useRef(null);
1116
1117
  const wasOpen = useRef(false);
1117
1118
  const open = prompt !== null;
@@ -1134,7 +1135,7 @@ function NavigationGuardDialog() {
1134
1135
  event.preventDefault();
1135
1136
  element.focus();
1136
1137
  },
1137
- children: [jsxs(AlertDialogHeader, { children: [jsx(AlertDialogTitle, { children: text.title }), jsxs(AlertDialogDescription, { children: [text.body, prompt !== null && prompt.labels.length > 0 ? ` ${unsavedAction === "navigation.unsavedAction" ? "An action on this screen has unsaved input" : unsavedAction}: ${prompt.labels.join(", ")}.` : null] })] }), jsxs(AlertDialogFooter, { children: [jsx(AlertDialogCancel, {
1138
+ children: [jsxs(AlertDialogHeader, { children: [jsx(AlertDialogTitle, { children: text.title }), jsxs(AlertDialogDescription, { children: [text.body, prompt !== null && prompt.labels.length > 0 ? ` ${unsavedAction}: ${prompt.labels.join(", ")}.` : null] })] }), jsxs(AlertDialogFooter, { children: [jsx(AlertDialogCancel, {
1138
1139
  "data-testid": "nav-guard-stay",
1139
1140
  children: text.stay
1140
1141
  }), jsx(AlertDialogAction, {
@@ -1694,14 +1695,14 @@ const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger;
1694
1695
  const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent;
1695
1696
  //#endregion
1696
1697
  //#region src/shell/use-nav-icon.tsx
1697
- const warned = new Set();
1698
+ const warned$1 = new Set();
1698
1699
  function resolveNavIcon(name, components) {
1699
1700
  if (name === void 0 || name === "") return void 0;
1700
1701
  const slot = components(name);
1701
1702
  if (typeof slot === "function" || typeof slot === "object" && slot !== null) return jsx(slot, { className: "h-4 w-4" });
1702
1703
  if (hasIcon(name)) return jsx(Icon, { name });
1703
- if (process.env.NODE_ENV !== "production" && !warned.has(name)) {
1704
- warned.add(name);
1704
+ if (process.env.NODE_ENV !== "production" && !warned$1.has(name)) {
1705
+ warned$1.add(name);
1705
1706
  console.warn(`[buro] unknown nav icon "${name}"`);
1706
1707
  }
1707
1708
  }
@@ -1710,6 +1711,53 @@ function useNavIcon() {
1710
1711
  return useCallback((name) => resolveNavIcon(name, (key) => components[key]), [components]);
1711
1712
  }
1712
1713
  //#endregion
1714
+ //#region src/layout/build-nav-items.ts
1715
+ function buildNavItems(args) {
1716
+ const { registry, caps, groupName, match, isVisible, entryFilter, icons } = args;
1717
+ const chain = match?.groupChain ?? [];
1718
+ const qualifiedMatch = match;
1719
+ const activeLeaf = qualifiedMatch == null ? void 0 : qualifiedMatch.kind === "group-index" ? canonicalNavKey({
1720
+ name: qualifiedMatch.target ?? qualifiedMatch.name,
1721
+ ref: qualifiedMatch.targetRef
1722
+ }) : canonicalNavKey(qualifiedMatch);
1723
+ const isEligible = (node) => isVisible(node) && (entryFilter ? entryFilter(node) : true);
1724
+ const out = [];
1725
+ for (const child of registry.groups.childrenOf(groupName)) {
1726
+ if (!isEligible(child)) continue;
1727
+ const kind = nodeKind(child);
1728
+ const childKey = canonicalNavKey(child);
1729
+ const href = navHrefFor(registry, childKey, { isVisible: isEligible });
1730
+ if (kind === "group") {
1731
+ const label = resolveNavLabel(caps, `groups.${childKey}`, declaredText("chrome", child, "label"));
1732
+ const active = chain.some((g) => canonicalNavKey(g) === childKey);
1733
+ out.push({
1734
+ kind: "group",
1735
+ name: childKey,
1736
+ label,
1737
+ href,
1738
+ icon: icons?.group?.(childKey),
1739
+ active
1740
+ });
1741
+ } else if (kind === "custom-page") out.push({
1742
+ kind: "custom-page",
1743
+ name: childKey,
1744
+ label: resolveNavLabel(caps, `pages.${childKey}`, declaredText("chrome", child, "label")),
1745
+ href,
1746
+ icon: icons?.page?.(childKey),
1747
+ active: activeLeaf === childKey
1748
+ });
1749
+ else out.push({
1750
+ kind: "resource",
1751
+ name: childKey,
1752
+ label: resolveResourceNavLabel(caps, childKey, child),
1753
+ href,
1754
+ icon: icons?.resource?.(childKey),
1755
+ active: activeLeaf === childKey
1756
+ });
1757
+ }
1758
+ return out;
1759
+ }
1760
+ //#endregion
1713
1761
  //#region src/layout/use-nav-tree.ts
1714
1762
  function isActiveHref(href, currentPath) {
1715
1763
  if (!currentPath) return false;
@@ -1723,8 +1771,7 @@ function useNavTree(opts = {}) {
1723
1771
  const passesEntryFilter = (entry) => entryFilter ? entryFilter(entry) : true;
1724
1772
  const app = useApp();
1725
1773
  const caps = useI18nCaps();
1726
- const visibilityCtx = useVisibilityCtx();
1727
- const isResourceVisible = (r) => evaluateVisible(r.visible, visibilityCtx);
1774
+ const isResourceVisible = useResourceVisible();
1728
1775
  const resolveLayout = useLayoutResolver();
1729
1776
  const match = useMatch();
1730
1777
  const isVisible = useNavVisible();
@@ -1734,6 +1781,7 @@ function useNavTree(opts = {}) {
1734
1781
  const allCustomPages = app.registry.customPages.list();
1735
1782
  const sections = app.registry.sections.list();
1736
1783
  const groups = app.registry.groups.rootNodes().filter((n) => nodeKind(n) === "group");
1784
+ useReportUnresolvedLayouts(app.registry.groups.list(), resolveLayout);
1737
1785
  const topLevelResources = allResources.filter((r) => hasListPage(r)).filter(isResourceVisible).filter(passesEntryFilter).filter((r) => !r.section && !r.group).map((r, idx) => ({
1738
1786
  r,
1739
1787
  idx
@@ -1743,8 +1791,8 @@ function useNavTree(opts = {}) {
1743
1791
  return ao !== bo ? ao - bo : a.idx - b.idx;
1744
1792
  }).map((x) => x.r);
1745
1793
  const topLevelCustomPages = allCustomPages.filter((p) => !p.section && !p.group).filter(pageAllowed).filter(passesEntryFilter);
1746
- const resourceHref = (def) => hrefFor(app.registry, canonicalResourceKey(def));
1747
- const resourceLabel = (def) => resolveResourceNavLabel(caps, canonicalResourceKey(def), def);
1794
+ const resourceHref = (def) => hrefFor(app.registry, canonicalResourceKey$1(def));
1795
+ const resourceLabel = (def) => resolveResourceNavLabel(caps, canonicalResourceKey$1(def), def);
1748
1796
  const pageLabel = (page) => resolveNavLabel(caps, `pages.${canonicalNavKey(page)}`, declaredText("chrome", page, "label"));
1749
1797
  const sectionLabel = (section) => resolveNavLabel(caps, `sections.${canonicalNavKey(section)}`, declaredText("chrome", section, "label"));
1750
1798
  const groupLabel = (group) => resolveNavLabel(caps, `groups.${canonicalNavKey(group)}`, declaredText("chrome", group, "label"));
@@ -1763,7 +1811,7 @@ function useNavTree(opts = {}) {
1763
1811
  const href = resourceHref(def);
1764
1812
  return {
1765
1813
  kind: "resource",
1766
- key: canonicalResourceKey(def),
1814
+ key: canonicalResourceKey$1(def),
1767
1815
  label: resourceLabel(def),
1768
1816
  href,
1769
1817
  icon: def.icon,
@@ -1971,7 +2019,7 @@ function NavMain({ topLabel, iconForResource, iconForCustomPage, iconForSection,
1971
2019
  })
1972
2020
  }) }, entry.key);
1973
2021
  const [top, ...blocks] = tree;
1974
- return jsxs(Fragment$1, { children: [jsxs(SidebarGroup, { children: [topLabel !== null && jsx(SidebarGroupLabel, { children: topLabel ?? t("nav.resources") }), jsx(SidebarGroupContent, { children: jsx(SidebarMenu, { children: top?.entries.map(menuItem) }) })] }), blocks.map((block) => {
2022
+ return jsxs(Fragment$1, { children: [top !== void 0 && top.entries.length > 0 && jsxs(SidebarGroup, { children: [topLabel !== null && jsx(SidebarGroupLabel, { children: topLabel ?? t("nav.resources") }), jsx(SidebarGroupContent, { children: jsx(SidebarMenu, { children: top.entries.map(menuItem) }) })] }), blocks.map((block) => {
1975
2023
  const key = block.key ?? "";
1976
2024
  if (block.label === null) return jsx(SidebarGroup, { children: jsx(SidebarGroupContent, { children: jsx(SidebarMenu, { children: block.entries.map(menuItem) }) }) }, key);
1977
2025
  if (block.collapsible) return jsx(CollapsibleNavSection, {
@@ -2015,126 +2063,31 @@ function AppSidebar({ header, filters, nav, footer }) {
2015
2063
  });
2016
2064
  }
2017
2065
  //#endregion
2018
- //#region src/layout/layouts/secondary-sidebar-layout.tsx
2019
- function Row({ it }) {
2020
- const RouterLink = useLinkComponent();
2021
- return jsx("li", { children: jsxs(RouterLink, {
2022
- href: it.href,
2023
- "data-testid": `nav-secondary-item:${it.name}`,
2024
- "aria-current": it.active ? "page" : void 0,
2025
- 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"),
2026
- children: [it.icon != null && jsx("span", {
2027
- className: "inline-flex h-4 w-4 shrink-0 items-center justify-center",
2028
- "aria-hidden": "true",
2029
- children: it.icon
2030
- }), jsx("span", {
2031
- className: "truncate",
2032
- title: it.label,
2033
- children: it.label
2034
- })]
2035
- }) });
2036
- }
2037
- function SecondarySidebarLayout({ group, groupKey, items, children }) {
2038
- const RouterLink = useLinkComponent();
2039
- const caps = useI18nCaps();
2040
- const id = groupKey ?? group.name;
2041
- const label = resolveNavLabel(caps, `groups.${id}`, declaredText("chrome", group, "label"));
2042
- return jsxs("div", {
2043
- className: "md:-m-6 md:flex md:min-h-[calc(100%+3rem)]",
2044
- "data-testid": `nav-secondary:${id}`,
2045
- children: [
2046
- jsx("aside", {
2047
- className: "hidden w-64 shrink-0 border-r bg-background text-foreground md:block",
2048
- children: jsxs("div", {
2049
- className: "space-y-4 p-4",
2050
- children: [jsx("p", {
2051
- className: "px-3 text-base font-semibold tracking-tight",
2052
- children: label
2053
- }), jsx("nav", {
2054
- "aria-label": label,
2055
- children: jsx("ul", {
2056
- className: "space-y-0.5",
2057
- children: items.map((it) => jsx(Row, { it }, it.name))
2058
- })
2059
- })]
2060
- })
2061
- }),
2062
- jsx("nav", {
2063
- "aria-label": label,
2064
- "data-testid": `nav-secondary-select:${id}`,
2065
- 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",
2066
- children: items.map((it) => jsx(RouterLink, {
2067
- href: it.href,
2068
- "aria-current": it.active ? "page" : void 0,
2069
- 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"),
2070
- children: it.label
2071
- }, it.name))
2072
- }),
2073
- jsx("div", {
2074
- className: "min-w-0 flex-1 md:overflow-x-hidden md:p-6",
2075
- children
2076
- })
2077
- ]
2078
- });
2079
- }
2080
- //#endregion
2081
- //#region src/layout/layouts/tabs-layout.tsx
2082
- function TabsLayout({ group, groupKey, items, children }) {
2083
- const RouterLink = useLinkComponent();
2084
- const caps = useI18nCaps();
2085
- const id = groupKey ?? group.name;
2086
- const label = resolveNavLabel(caps, `groups.${id}`, declaredText("chrome", group, "label"));
2087
- return jsxs("div", {
2088
- className: "flex flex-col gap-4",
2089
- "data-testid": `nav-tabs:${id}`,
2090
- children: [jsx("nav", {
2091
- "aria-label": label,
2092
- 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",
2093
- children: items.map((it) => jsxs(RouterLink, {
2094
- href: it.href,
2095
- "aria-current": it.active ? "page" : void 0,
2096
- "data-testid": `nav-tab:${it.name}`,
2097
- 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"),
2098
- children: [
2099
- it.icon != null && jsx("span", {
2100
- className: "inline-flex h-4 w-4 shrink-0 items-center justify-center",
2101
- "aria-hidden": "true",
2102
- children: it.icon
2103
- }),
2104
- it.label,
2105
- jsx("span", {
2106
- "aria-hidden": "true",
2107
- 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")
2108
- })
2109
- ]
2110
- }, it.name))
2111
- }), jsx("div", {
2112
- className: "min-w-0",
2113
- children
2114
- })]
2115
- });
2116
- }
2117
- //#endregion
2118
- //#region src/layout/nav-area-layout.tsx
2066
+ //#region src/layout/nav-chrome.tsx
2119
2067
  const DETAIL_ACTIONS = new Set([
2120
2068
  "show",
2121
2069
  "edit",
2122
2070
  "create"
2123
2071
  ]);
2124
- function NavAreaLayout({ groupName, children, entryFilter, icons }) {
2072
+ function NavChrome({ children, entryFilter, icons }) {
2125
2073
  const app = useApp();
2126
2074
  const caps = useI18nCaps();
2127
2075
  const isVisible = useNavVisible();
2128
2076
  const match = useMatch();
2129
2077
  const resolveLayout = useLayoutResolver();
2130
- const group = app.registry.groups.get(groupName);
2131
- if (!group) return jsx(Fragment$1, { children });
2132
- const groupKey = canonicalNavKey(group);
2133
- const claimed = [groupKey, ...groupChain(app.registry, group).map(canonicalNavKey)];
2134
- const collapse = group.chromeOn === "list" && match?.kind === "resource" && DETAIL_ACTIONS.has(match.action);
2135
- const Layout = resolveLayout(group.layout);
2078
+ useReportUnresolvedLayouts(match?.groupChain ?? [], resolveLayout);
2079
+ if (!match) return jsx(NavChromeMountedProvider, {
2080
+ value: true,
2081
+ children
2082
+ });
2136
2083
  let content = children;
2137
- if (Layout && !collapse) {
2084
+ for (let i = match.groupChain.length - 1; i >= 0; i--) {
2085
+ const group = match.groupChain[i];
2086
+ if (!group) continue;
2087
+ const groupKey = canonicalNavKey(group);
2088
+ if (group.chromeOn === "list" && match.kind === "resource" && DETAIL_ACTIONS.has(match.action)) continue;
2089
+ const Layout = resolveLayout(group.layout);
2090
+ if (!Layout) continue;
2138
2091
  const items = buildNavItems({
2139
2092
  registry: app.registry,
2140
2093
  caps,
@@ -2148,11 +2101,11 @@ function NavAreaLayout({ groupName, children, entryFilter, icons }) {
2148
2101
  group,
2149
2102
  groupKey,
2150
2103
  items,
2151
- children
2104
+ children: content
2152
2105
  });
2153
2106
  }
2154
- return jsx(NavChromeBoundaryProvider, {
2155
- claim: claimed,
2107
+ return jsx(NavChromeMountedProvider, {
2108
+ value: true,
2156
2109
  children: content
2157
2110
  });
2158
2111
  }
@@ -2165,10 +2118,12 @@ function Chevron() {
2165
2118
  "aria-hidden": "true"
2166
2119
  });
2167
2120
  }
2168
- function Breadcrumbs(props) {
2121
+ function Breadcrumbs(input) {
2122
+ const props = input;
2169
2123
  const { leadingSegments, className, docScopes, "data-testid": testId } = props;
2170
2124
  const app = useApp();
2171
- const def = props.resource === void 0 ? void 0 : app.registry.get(props.resource);
2125
+ const resource = props.resource === void 0 ? void 0 : routeResourceKey(props.resource);
2126
+ const def = resource === void 0 ? void 0 : app.registry.get(resource);
2172
2127
  const tid = useTestIds();
2173
2128
  const t = useOptionalT();
2174
2129
  const RouterLink = useLinkComponent();
@@ -2213,7 +2168,7 @@ function Breadcrumbs(props) {
2213
2168
  });
2214
2169
  if (!def) return null;
2215
2170
  const { recordId, pageLabel, middleSegments } = props;
2216
- const resourceKey = canonicalResourceKey(def);
2171
+ const resourceKey = canonicalResourceKey$1(def);
2217
2172
  const listHref = hrefFor(app.registry, resourceKey);
2218
2173
  const resourceLabel = resolveResourceLabel(caps, resourceKey, "plural", def);
2219
2174
  const resourceIsCurrent = !pageLabel && !(middleSegments && middleSegments.length > 0);
@@ -2223,7 +2178,12 @@ function Breadcrumbs(props) {
2223
2178
  "data-testid": testId,
2224
2179
  children: [
2225
2180
  leading(resourceKey),
2226
- resourceIsCurrent ? current(tid.navBreadcrumb(resourceKey), resourceLabel) : jsx(RouterLink, {
2181
+ resourceIsCurrent ? current(tid.navBreadcrumb(resourceKey), resourceLabel) : !hasListPage(def) ? jsx("span", {
2182
+ "data-testid": tid.navBreadcrumb(resourceKey),
2183
+ className: "truncate",
2184
+ title: resourceLabel,
2185
+ children: resourceLabel
2186
+ }) : jsx(RouterLink, {
2227
2187
  href: listHref,
2228
2188
  "data-testid": tid.navBreadcrumb(resourceKey),
2229
2189
  className: cn(LINK_CLASS, "truncate"),
@@ -2299,15 +2259,15 @@ function RecordBreadcrumbs() {
2299
2259
  }
2300
2260
  //#endregion
2301
2261
  //#region src/layout/default-nav-layouts.ts
2302
- const defaultNavLayouts = {
2303
- [layoutSlot("secondary-sidebar")]: SecondarySidebarLayout,
2304
- [layoutSlot("tabs")]: TabsLayout
2305
- };
2262
+ const defaultNavLayouts = { ...BUILTIN_LAYOUTS };
2306
2263
  //#endregion
2307
2264
  //#region src/layout/context-picker.tsx
2308
- function ContextPicker({ sliceName, label, options, value, onChange, placeholder, disabled, className, hideLabel }) {
2265
+ const ALL = "\0all";
2266
+ function ContextPicker({ sliceName, label, options, value, onChange, placeholder, disabled, className, hideLabel, allOption }) {
2309
2267
  const tid = useTestIds();
2310
2268
  const t = useOptionalT();
2269
+ const chromeT = useChromeT();
2270
+ const allLabel = typeof allOption === "string" ? allOption : chromeT("scope.all", { defaultValue: "All" });
2311
2271
  const displayLabel = label ?? humanizeKey(sliceName);
2312
2272
  return jsxs("div", {
2313
2273
  className: cn("space-y-1", className),
@@ -2316,21 +2276,112 @@ function ContextPicker({ sliceName, label, options, value, onChange, placeholder
2316
2276
  className: hideLabel ? "sr-only" : "text-xs font-medium text-muted-foreground uppercase tracking-wide",
2317
2277
  children: displayLabel
2318
2278
  }), jsxs(Select, {
2319
- value: value ?? "",
2320
- onValueChange: onChange,
2279
+ value: value ?? (allOption === void 0 ? "" : ALL),
2280
+ onValueChange: (next) => {
2281
+ if (allOption === void 0) onChange(next);
2282
+ else onChange(next === ALL ? null : next);
2283
+ },
2321
2284
  disabled,
2322
2285
  children: [jsx(SelectTrigger, {
2323
2286
  id: `context-picker:${sliceName}`,
2324
2287
  "data-testid": tid.contextPicker(sliceName),
2325
2288
  className: cn("w-full", hideLabel ? "h-8 text-xs" : void 0),
2326
2289
  children: jsx(SelectValue, { placeholder: placeholder ?? t("field.select", { defaultValue: "Select…" }) })
2327
- }), jsx(SelectContent, { children: options.map((o) => jsx(SelectItem, {
2290
+ }), jsxs(SelectContent, { children: [allOption === void 0 ? null : jsx(SelectItem, {
2291
+ value: ALL,
2292
+ "data-testid": tid.contextPickerOption(sliceName, "all"),
2293
+ children: allLabel
2294
+ }), options.map((o) => jsx(SelectItem, {
2328
2295
  value: o.value,
2329
2296
  "data-testid": tid.contextPickerOption(sliceName, o.value),
2330
2297
  children: o.label
2331
- }, o.value)) })]
2298
+ }, o.value))] })]
2299
+ })]
2300
+ });
2301
+ }
2302
+ //#endregion
2303
+ //#region src/layout/scope-dimension-picker.tsx
2304
+ function ScopeDimensionPicker(props) {
2305
+ const scope = useScope();
2306
+ const definition = scope.definition?.dimensions[props.dimension];
2307
+ if (definition === void 0) throw new Error(`ScopeDimensionPicker: '${props.dimension}' is not a dimension of the app's defineScope(...)`);
2308
+ if (definition.select === "none") return null;
2309
+ const source = definition.values;
2310
+ if (source === void 0) throw new Error(`ScopeDimensionPicker: dimension '${props.dimension}' declares no values; add values: { resource } or a { value, label } list`);
2311
+ const allowed = scope.access[props.dimension]?.allowed;
2312
+ const permitted = Array.isArray(allowed) ? allowed : void 0;
2313
+ const common = {
2314
+ ...props,
2315
+ multiple: definition.select === "multiple",
2316
+ all: definition.all,
2317
+ selected: scope.selection[props.dimension] ?? null,
2318
+ select: (value) => scope.select(props.dimension, value)
2319
+ };
2320
+ if (Array.isArray(source)) {
2321
+ const options = source.filter((option) => permitted === void 0 || permitted.includes(option.value));
2322
+ return jsx(DimensionControl, {
2323
+ ...common,
2324
+ options
2325
+ });
2326
+ }
2327
+ const { resource, label } = source;
2328
+ return jsx(ResourceDimension, {
2329
+ ...common,
2330
+ resource,
2331
+ ...label ? { labelField: label } : {}
2332
+ });
2333
+ }
2334
+ function ResourceDimension({ resource, labelField, ...rest }) {
2335
+ const options = useResourceDimensionOptions(rest.dimension, resource, labelField);
2336
+ return jsx(DimensionControl, {
2337
+ ...rest,
2338
+ options
2339
+ });
2340
+ }
2341
+ function DimensionControl({ dimension, label, hideLabel, className, multiple, all, selected, select, options }) {
2342
+ const tid = useTestIds();
2343
+ const chromeT = useChromeT();
2344
+ const byText = useMemo(() => new Map(options.map((option) => [String(option.value), option.value])), [options]);
2345
+ const textOptions = useMemo(() => options.map((option) => ({
2346
+ value: String(option.value),
2347
+ label: option.label
2348
+ })), [options]);
2349
+ const picked = (Array.isArray(selected) ? selected : selected === null ? [] : [selected]).map(String);
2350
+ const text = label ?? humanizeKey(dimension);
2351
+ if (multiple) return jsxs("div", {
2352
+ className: cn("space-y-1", className),
2353
+ children: [jsx("span", {
2354
+ className: hideLabel ? "sr-only" : "text-xs font-medium text-muted-foreground uppercase tracking-wide",
2355
+ children: text
2356
+ }), jsx(FacetedFilterPicker, {
2357
+ title: text,
2358
+ options: textOptions,
2359
+ selected: picked,
2360
+ ...all ? { emptyLabel: chromeT("scope.all", { defaultValue: "All" }) } : { clearable: false },
2361
+ onChange: (next) => {
2362
+ if (next.length === 0 && !all) return;
2363
+ select(next.length === 0 ? null : next.map((value) => byText.get(value) ?? value));
2364
+ },
2365
+ getTestId: (role, value) => role === "trigger" ? tid.contextPicker(dimension) : role === "option" ? tid.contextPickerOption(dimension, value ?? "") : role === "clear" ? tid.contextPickerOption(dimension, "all") : void 0
2332
2366
  })]
2333
2367
  });
2368
+ const common = {
2369
+ sliceName: dimension,
2370
+ ...label === void 0 ? {} : { label },
2371
+ options: textOptions,
2372
+ value: picked[0] ?? null,
2373
+ ...hideLabel === void 0 ? {} : { hideLabel },
2374
+ ...className === void 0 ? {} : { className }
2375
+ };
2376
+ const choose = (value) => select(value === null ? null : byText.get(value) ?? value);
2377
+ return all ? jsx(ContextPicker, {
2378
+ ...common,
2379
+ allOption: true,
2380
+ onChange: choose
2381
+ }) : jsx(ContextPicker, {
2382
+ ...common,
2383
+ onChange: choose
2384
+ });
2334
2385
  }
2335
2386
  //#endregion
2336
2387
  //#region src/layout/language-switch.tsx
@@ -2521,7 +2572,7 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
2521
2572
  const navigate = useRouteNavigate();
2522
2573
  const isVisible = useNavVisible();
2523
2574
  const resolveLayout = useLayoutResolver();
2524
- const isResourceVisible = (r) => evaluateVisible(r.visible, visibilityCtx);
2575
+ const isResourceVisible = useResourceVisible();
2525
2576
  const pageAllowed = usePageAllowed();
2526
2577
  const isPageVisible = (p) => evaluateVisible(p.visible, visibilityCtx) && pageAllowed(p);
2527
2578
  const { topLevelResources, topLevelPages, sectionGroups } = useMemo(() => {
@@ -2549,13 +2600,13 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
2549
2600
  onSelect?.();
2550
2601
  navigate(href);
2551
2602
  };
2552
- const resourceLabel = (def) => resolveResourceLabel(caps, canonicalResourceKey(def), "plural", def);
2603
+ const resourceLabel = (def) => resolveResourceLabel(caps, canonicalResourceKey$1(def), "plural", def);
2553
2604
  const pageLabel = (def) => resolveNavLabel(caps, `pages.${canonicalNavKey(def)}`, declaredText("chrome", def, "label"));
2554
2605
  const groups = [];
2555
2606
  if (topLevelResources.length > 0) groups.push(jsx(CommandGroup, {
2556
2607
  heading: t("commandPalette.resources", { defaultValue: "Resources" }),
2557
2608
  children: topLevelResources.map((def) => {
2558
- const resource = canonicalResourceKey(def);
2609
+ const resource = canonicalResourceKey$1(def);
2559
2610
  const label = resourceLabel(def);
2560
2611
  const href = hrefFor(app.registry, resource, { isVisible });
2561
2612
  return jsx(CommandItem, {
@@ -2604,7 +2655,7 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
2604
2655
  children: label
2605
2656
  }, `section:${sectionKey}:page:${pageKey}`);
2606
2657
  }
2607
- const resource = canonicalResourceKey(child);
2658
+ const resource = canonicalResourceKey$1(child);
2608
2659
  const label = resourceLabel(child);
2609
2660
  const href = hrefFor(app.registry, resource, { isVisible });
2610
2661
  return jsx(CommandItem, {
@@ -2656,7 +2707,7 @@ function CommandPaletteNavigationGroups({ onSelect, getTestId }) {
2656
2707
  const resource = child;
2657
2708
  if (!hasListPage(resource)) continue;
2658
2709
  if (!isResourceVisible(resource)) continue;
2659
- const resourceId = canonicalResourceKey(resource);
2710
+ const resourceId = canonicalResourceKey$1(resource);
2660
2711
  const label = resourceLabel(resource);
2661
2712
  const href = hrefFor(app.registry, resourceId, { isVisible });
2662
2713
  items.push(jsx(CommandItem, {
@@ -2695,10 +2746,10 @@ function opensInQuick(registry, resource, mode) {
2695
2746
  }
2696
2747
  //#endregion
2697
2748
  //#region src/layout/command-palette-recent-group.tsx
2698
- function entryHref(registry, entry, visibilityCtx) {
2749
+ function entryHref(registry, entry, isResourceVisible) {
2699
2750
  const def = registry.get(entry.canonicalRef);
2700
2751
  if (def === void 0) return void 0;
2701
- if (!evaluateVisible(def.visible, visibilityCtx)) return void 0;
2752
+ if (!isResourceVisible(def)) return void 0;
2702
2753
  for (const action of ["show", "edit"]) if (recordRouteAvailable(registry, entry.canonicalRef, action)) return hrefFor(registry, entry.canonicalRef, {
2703
2754
  action,
2704
2755
  id: entry.id
@@ -2712,27 +2763,39 @@ function CommandPaletteRecentGroup({ onSelect, getTestId, heading, refreshKey, w
2712
2763
  const navigate = useRouteNavigate();
2713
2764
  const quick = useQuick();
2714
2765
  const userId = useCurrentUserId();
2715
- const visibilityCtx = useVisibilityCtx();
2766
+ const isResourceVisible = useResourceVisible();
2716
2767
  const resolvedHeading = heading ?? t("commandPalette.recent", { defaultValue: "Recent" });
2717
- const [hydrated, setHydrated] = useState(false);
2768
+ const store = usePlatformStorage().local;
2769
+ const [stored, setStored] = useState([]);
2718
2770
  useEffect(() => {
2719
- setHydrated(true);
2720
- }, []);
2721
- const recents = useMemo(() => {
2722
- if (!hydrated || userId === null) return [];
2723
- return readRecentRecords(userId).flatMap((entry) => {
2724
- const href = entryHref(app.registry, entry, visibilityCtx);
2725
- return href === void 0 ? [] : [{
2726
- entry,
2727
- href
2728
- }];
2729
- });
2771
+ if (userId === null) {
2772
+ setStored([]);
2773
+ return;
2774
+ }
2775
+ let current = true;
2776
+ const read = readRecentRecords(store, userId);
2777
+ if (Array.isArray(read)) setStored(read);
2778
+ else read.then((entries) => {
2779
+ if (current) setStored(entries);
2780
+ }, () => void 0);
2781
+ return () => {
2782
+ current = false;
2783
+ };
2730
2784
  }, [
2731
- hydrated,
2785
+ store,
2732
2786
  userId,
2733
- refreshKey,
2787
+ refreshKey
2788
+ ]);
2789
+ const recents = useMemo(() => stored.flatMap((entry) => {
2790
+ const href = entryHref(app.registry, entry, isResourceVisible);
2791
+ return href === void 0 ? [] : [{
2792
+ entry,
2793
+ href
2794
+ }];
2795
+ }), [
2796
+ stored,
2734
2797
  app.registry,
2735
- visibilityCtx
2798
+ isResourceVisible
2736
2799
  ]);
2737
2800
  if ((useCommandState((state) => state.search) ?? "").length > 0) return null;
2738
2801
  if (recents.length === 0) return null;
@@ -2797,18 +2860,19 @@ function CommandPaletteRecordsGroup({ enabled = true, pageSize = 5, minQueryLeng
2797
2860
  const t = useOptionalT();
2798
2861
  const navigate = useRouteNavigate();
2799
2862
  const quick = useQuick();
2863
+ const isResourceVisible = useResourceVisible();
2800
2864
  const resolvedHeading = heading ?? t("commandPalette.records", { defaultValue: "Records" });
2801
2865
  const liveQuery = useCommandState((state) => state.search) ?? "";
2802
2866
  const debouncedQuery = useDebouncedValue(liveQuery, debounceMs);
2803
2867
  const searchableResources = useMemo(() => {
2804
- return app.registry.list().filter((r) => isShowAvailable(app.registry, canonicalResourceKey(r)) || opensInQuick(app.registry, canonicalResourceKey(r), "show")).map((def) => {
2868
+ return app.registry.list().filter((r) => isShowAvailable(app.registry, canonicalResourceKey$1(r)) || opensInQuick(app.registry, canonicalResourceKey$1(r), "show")).filter(isResourceVisible).map((def) => {
2805
2869
  const displayField = resolveDisplayField(def);
2806
2870
  return displayField ? {
2807
2871
  def,
2808
2872
  displayField
2809
2873
  } : null;
2810
2874
  }).filter((entry) => entry !== null);
2811
- }, [app.registry]);
2875
+ }, [app.registry, isResourceVisible]);
2812
2876
  if (!(enabled && debouncedQuery.length >= minQueryLength && searchableResources.length > 0)) return null;
2813
2877
  const goTo = (href, resource, id) => {
2814
2878
  onSelect?.();
@@ -2827,12 +2891,12 @@ function CommandPaletteRecordsGroup({ enabled = true, pageSize = 5, minQueryLeng
2827
2891
  recordHref,
2828
2892
  registry: app.registry,
2829
2893
  getTestId
2830
- }, canonicalResourceKey(def)))
2894
+ }, canonicalResourceKey$1(def)))
2831
2895
  }, "records");
2832
2896
  }
2833
2897
  function PerResourceSearchHits({ def, displayField, query, pageSize, goTo, recordHref, registry, getTestId }) {
2834
2898
  const caps = useI18nCaps();
2835
- const resource = canonicalResourceKey(def);
2899
+ const resource = canonicalResourceKey$1(def);
2836
2900
  const access = useListAccess(resource);
2837
2901
  const titleVisible = access.status === "ready" && access.fieldVisible(displayField);
2838
2902
  const shouldFetch = query.length > 0 && titleVisible;
@@ -2856,9 +2920,11 @@ function PerResourceSearchHits({ def, displayField, query, pageSize, goTo, recor
2856
2920
  report(rows.length);
2857
2921
  }, [report, rows.length]);
2858
2922
  if (rows.length === 0) return null;
2859
- const resourceLabel = resolveResourceLabel(caps, canonicalResourceKey(def), "single", def);
2923
+ const resourceLabel = resolveResourceLabel(caps, canonicalResourceKey$1(def), "single", def);
2924
+ const declaredIdField = def.data?.idField;
2925
+ const idField = typeof declaredIdField === "string" && declaredIdField.length > 0 ? declaredIdField : "id";
2860
2926
  return jsx(Fragment$1, { children: rows.map((row) => {
2861
- const idVal = row.id ?? row.event_id ?? row.job_id;
2927
+ const idVal = row[idField] ?? row.id ?? row.event_id ?? row.job_id;
2862
2928
  const id = idVal == null ? "" : String(idVal);
2863
2929
  if (!id) return null;
2864
2930
  const display = titleVisible ? row[displayField] : void 0;
@@ -3003,7 +3069,7 @@ function CommandPaletteActionsGroup({ actions, onSelect, getTestId, heading }) {
3003
3069
  function CommandPaletteCreateGroup({ resourceFilter, onSelect, getTestId, heading, createHref, prefix }) {
3004
3070
  const caps = useI18nCaps();
3005
3071
  const app = useApp();
3006
- const visibilityCtx = useVisibilityCtx();
3072
+ const isResourceVisible = useResourceVisible();
3007
3073
  const gate = useAvailabilityGate();
3008
3074
  const t = useOptionalT();
3009
3075
  const navigate = useRouteNavigate();
@@ -3011,11 +3077,11 @@ function CommandPaletteCreateGroup({ resourceFilter, onSelect, getTestId, headin
3011
3077
  const resolvedHeading = heading ?? t("commandPalette.create", { defaultValue: "Create" });
3012
3078
  const resolvedPrefix = prefix ?? t("commandPalette.createNew", { defaultValue: "Create new" });
3013
3079
  const visibleResources = useMemo(() => {
3014
- return app.registry.list().filter((r) => hasListPage(r)).filter((r) => gate(canonicalResourceKey(r), "create").state === "available").filter((r) => hasRecordPage(r, "create") || opensInQuick(app.registry, canonicalResourceKey(r), "create")).filter((r) => evaluateVisible(r.visible, visibilityCtx)).filter((r) => resourceFilter ? resourceFilter(r) : true);
3080
+ 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);
3015
3081
  }, [
3016
3082
  app,
3017
3083
  gate,
3018
- visibilityCtx,
3084
+ isResourceVisible,
3019
3085
  resourceFilter
3020
3086
  ]);
3021
3087
  if (visibleResources.length === 0) return null;
@@ -3029,13 +3095,13 @@ function CommandPaletteCreateGroup({ resourceFilter, onSelect, getTestId, headin
3029
3095
  return;
3030
3096
  }
3031
3097
  onSelect?.();
3032
- quick.create(canonicalResourceKey(def));
3098
+ quick.create(canonicalResourceKey$1(def));
3033
3099
  };
3034
- const resourceLabel = (def) => resolveResourceLabel(caps, canonicalResourceKey(def), "single", def);
3100
+ const resourceLabel = (def) => resolveResourceLabel(caps, canonicalResourceKey$1(def), "single", def);
3035
3101
  return jsx(CommandGroup, {
3036
3102
  heading: resolvedHeading,
3037
3103
  children: visibleResources.map((def) => {
3038
- const resource = canonicalResourceKey(def);
3104
+ const resource = canonicalResourceKey$1(def);
3039
3105
  const label = resourceLabel(def);
3040
3106
  const href = createHref?.(def) ?? resourceCreateHref(app.registry, def, resource);
3041
3107
  const value = `create:${resource}:${resolvedPrefix}:${label}`;
@@ -3097,7 +3163,7 @@ function AppActions() {
3097
3163
  variant: "outline",
3098
3164
  size: "sm",
3099
3165
  disabled: action.disabledReason !== void 0,
3100
- title: action.disabledReason,
3166
+ title: action.disabledReason === void 0 ? void 0 : reasonText(caps, action.disabledReason),
3101
3167
  "data-testid": `app-action:${action.name}`,
3102
3168
  children: action.disabledReason === void 0 ? jsx(RouterLink, {
3103
3169
  href,
@@ -3219,6 +3285,7 @@ function localizedSchema(t) {
3219
3285
  function LoginForm({ onSubmit, title, description, className }) {
3220
3286
  const tid = useTestIds();
3221
3287
  const t = useOptionalT();
3288
+ const caps = useI18nCaps();
3222
3289
  const resolvedTitle = title ?? t("auth.signIn", { defaultValue: "Sign in" });
3223
3290
  const { register, handleSubmit, formState: { errors, isSubmitting } } = useForm({
3224
3291
  resolver: zodResolver(localizedSchema(t)),
@@ -3233,9 +3300,11 @@ function LoginForm({ onSubmit, title, description, className }) {
3233
3300
  try {
3234
3301
  await onSubmit(values);
3235
3302
  } catch (e) {
3236
- const raw = e instanceof Error ? e.message : String(e);
3303
+ const dataCode = e !== null && typeof e === "object" && !(e instanceof Error) ? e.code : void 0;
3304
+ const raw = e instanceof Error ? e.message : technicalText(e) ?? (dataCode === void 0 ? String(e) : "");
3237
3305
  const friendly = toFriendlyError(raw, "", friendlyStringsFrom(t));
3238
- setSubmitError(friendly.replaced ? `${friendly.title}. ${friendly.detail}` : credentialsMessage(raw, t));
3306
+ const credentials = credentialsMessage(raw, t);
3307
+ setSubmitError(friendly.replaced ? `${friendly.title}. ${friendly.detail}` : typeof dataCode === "string" && credentials === raw ? resolveErrorText(e, caps) : credentials);
3239
3308
  }
3240
3309
  });
3241
3310
  return jsxs(Card, {
@@ -3360,9 +3429,108 @@ function AuthPage({ children, brand, footer, className }) {
3360
3429
  });
3361
3430
  }
3362
3431
  //#endregion
3432
+ //#region src/enum/enum-choice-group.tsx
3433
+ const NONE = "__none__";
3434
+ function isEmpty$1(value) {
3435
+ return value === null || value === void 0 || value === "";
3436
+ }
3437
+ function EnumChoiceGroup({ control, options, value, onChange, testid, name, id, required, disabled, ariaInvalid, ariaDescribedBy, ariaErrorMessage, ariaLabelledBy, className }) {
3438
+ const t = useOptionalT();
3439
+ const generatedName = React.useId();
3440
+ const groupName = name ?? generatedName;
3441
+ const empty = isEmpty$1(value);
3442
+ const noneLabel = t("field.none", { defaultValue: "None" });
3443
+ const pick = (next) => {
3444
+ if (!disabled) onChange(next);
3445
+ };
3446
+ const ariaProps = {
3447
+ "aria-invalid": ariaInvalid || void 0,
3448
+ "aria-describedby": ariaDescribedBy,
3449
+ ...ariaErrorMessage ? { "aria-errormessage": ariaErrorMessage } : {}
3450
+ };
3451
+ if (control === "segmented") {
3452
+ const segment = (key, label, active, select) => jsx("button", {
3453
+ type: "button",
3454
+ "aria-pressed": active,
3455
+ "data-state": active ? "active" : "inactive",
3456
+ "data-testid": `${testid}:option:${key}`,
3457
+ disabled,
3458
+ onClick: select,
3459
+ className: cn("inline-flex items-center justify-center gap-1.5 whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium transition-all", "data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-xs", "disabled:pointer-events-none disabled:opacity-50", "focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"),
3460
+ children: label
3461
+ }, key);
3462
+ return jsxs("div", {
3463
+ role: "group",
3464
+ id,
3465
+ "aria-labelledby": ariaLabelledBy,
3466
+ "data-testid": testid,
3467
+ className: cn("inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground", className),
3468
+ ...ariaProps,
3469
+ children: [required ? null : segment(NONE, noneLabel, empty, () => pick(void 0)), options.map((option) => segment(option.value, jsxs(Fragment$1, { children: [option.icon ? jsx("span", {
3470
+ "data-testid": `${testid}:option:${option.value}:icon`,
3471
+ className: "contents",
3472
+ children: jsx(Icon, {
3473
+ name: option.icon,
3474
+ className: "size-3.5 shrink-0"
3475
+ })
3476
+ }) : null, option.label] }), value === option.value, () => pick(option.value)))]
3477
+ });
3478
+ }
3479
+ const cards = control === "cards";
3480
+ const choice = (key, option, label, checked, select) => {
3481
+ const inputId = `${id ?? groupName}:${key}`;
3482
+ return jsxs("label", {
3483
+ htmlFor: inputId,
3484
+ className: cn("flex items-start gap-2.5", cards && "cursor-pointer rounded-lg border px-3 py-2.5 transition-colors hover:bg-accent/50 has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-ring", cards && (checked ? "border-primary" : "border-input"), disabled && "cursor-not-allowed opacity-60"),
3485
+ children: [jsx("input", {
3486
+ type: "radio",
3487
+ id: inputId,
3488
+ name: groupName,
3489
+ value: key,
3490
+ checked,
3491
+ onChange: select,
3492
+ disabled,
3493
+ ...ariaProps,
3494
+ "data-testid": `${testid}:option:${key}`,
3495
+ className: cn("h-4 w-4 shrink-0 accent-primary", cards ? "mt-0.5" : "mt-1")
3496
+ }), jsxs("span", {
3497
+ className: "flex min-w-0 flex-col gap-0.5",
3498
+ children: [jsxs("span", {
3499
+ className: cn("flex items-center gap-1.5", cards && "font-medium"),
3500
+ children: [option?.icon ? jsx("span", {
3501
+ "data-testid": `${testid}:option:${key}:icon`,
3502
+ className: "contents",
3503
+ children: jsx(Icon, {
3504
+ name: option.icon,
3505
+ className: "size-4 shrink-0"
3506
+ })
3507
+ }) : null, jsx("span", { children: label })]
3508
+ }), option?.summary === void 0 || option.summary === "" ? null : jsx("span", {
3509
+ "data-testid": `${testid}:option:${key}:doc`,
3510
+ className: "text-sm text-muted-foreground",
3511
+ children: option.summary
3512
+ })]
3513
+ })]
3514
+ }, key);
3515
+ };
3516
+ return jsxs("div", {
3517
+ role: "radiogroup",
3518
+ id,
3519
+ "aria-labelledby": ariaLabelledBy,
3520
+ "data-testid": testid,
3521
+ "aria-required": required,
3522
+ className: cn("flex flex-col", cards ? "gap-2" : "gap-1.5", className),
3523
+ children: [required ? null : choice(NONE, void 0, noneLabel, empty, () => pick(void 0)), options.map((option) => choice(option.value, option, option.label, value === option.value, () => pick(option.value)))]
3524
+ });
3525
+ }
3526
+ //#endregion
3363
3527
  //#region src/enum/enum-picker.tsx
3364
3528
  const ENUM_PICKER_CLEAR_SENTINEL = "__buro_clear__";
3365
- function EnumPicker({ enumName, value, onChange, renderAs = "select", name, id, testid, placeholder, disabled, required, ariaInvalid, ariaDescribedBy, ariaErrorMessage, className, clearable = false, clearLabel = "All" }) {
3529
+ function withSummary(summary) {
3530
+ return summary === void 0 ? {} : { summary };
3531
+ }
3532
+ function EnumPicker({ enumName: enumInput, value, onChange, control = "select", name, id, testid, placeholder, disabled, required, ariaInvalid, ariaDescribedBy, ariaErrorMessage, ariaLabelledBy, className, clearable = false, clearLabel = "All" }) {
3533
+ const enumName = enumBindingKey(enumInput) ?? "";
3366
3534
  const app = useApp();
3367
3535
  const t = useOptionalT();
3368
3536
  const def = app.registry.enums.get(enumName);
@@ -3393,63 +3561,43 @@ function EnumPicker({ enumName, value, onChange, renderAs = "select", name, id,
3393
3561
  children: jsx(SelectValue, { placeholder: t("field.loading", { defaultValue: "Loading…" }) })
3394
3562
  }), jsx(SelectContent, {})]
3395
3563
  });
3396
- if (error || !values) return jsxs("span", {
3397
- "data-testid": `${tid}:error`,
3564
+ if (error || !values) return jsxs(LoadError, {
3565
+ surface: "picker",
3566
+ error,
3567
+ testId: `${tid}:error`,
3398
3568
  className: "text-muted-foreground",
3399
- title: error?.message,
3569
+ fallback: {
3570
+ key: "relation.failed",
3571
+ default: "Failed to load options."
3572
+ },
3400
3573
  children: [
3401
3574
  "(failed to load enum ‘",
3402
3575
  enumName,
3403
3576
  "’)"
3404
3577
  ]
3405
3578
  });
3406
- if (renderAs === "radio") return jsx("div", {
3407
- role: "radiogroup",
3408
- "data-testid": tid,
3409
- className: cn("flex flex-col gap-2", className),
3410
- "aria-required": required,
3411
- children: values.map((entry) => {
3412
- const inputId = `${id ?? tid}:${entry.value}`;
3413
- return jsxs("label", {
3414
- htmlFor: inputId,
3415
- className: "flex items-center gap-2",
3416
- children: [jsx("input", {
3417
- type: "radio",
3418
- id: inputId,
3419
- name: name ?? tid,
3420
- value: entry.value,
3421
- checked: value === entry.value,
3422
- onChange: (e) => onChange(e.target.value),
3423
- disabled,
3424
- "aria-invalid": ariaInvalid || void 0,
3425
- "aria-describedby": ariaDescribedBy,
3426
- ...ariaErrorMessage ? { "aria-errormessage": ariaErrorMessage } : {},
3427
- "data-testid": `${tid}:option:${entry.value}`,
3428
- className: "h-4 w-4"
3429
- }), jsx("span", { children: resolveEnumLabel(caps, ns, entry.value, enumValueText(def, entry.value) ?? entry.label) })]
3430
- }, entry.value);
3431
- })
3432
- });
3433
- if (renderAs === "segmented") return jsx("div", {
3434
- role: "group",
3435
- "data-testid": tid,
3436
- className: cn("inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground", className),
3437
- "aria-invalid": ariaInvalid || void 0,
3438
- "aria-describedby": ariaDescribedBy,
3439
- ...ariaErrorMessage ? { "aria-errormessage": ariaErrorMessage } : {},
3440
- children: values.map((entry) => {
3441
- const isActive = value === entry.value;
3442
- return jsx("button", {
3443
- type: "button",
3444
- "aria-pressed": isActive,
3445
- "data-state": isActive ? "active" : "inactive",
3446
- "data-testid": `${tid}:option:${entry.value}`,
3447
- disabled,
3448
- onClick: () => onChange(entry.value),
3449
- className: cn("inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium transition-all", "data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-xs", "disabled:pointer-events-none disabled:opacity-50", "focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"),
3450
- children: resolveEnumLabel(caps, ns, entry.value, enumValueText(def, entry.value) ?? entry.label)
3451
- }, entry.value);
3452
- })
3579
+ const labelOf = (entry) => resolveEnumLabel(caps, ns, entry.value, enumValueText(def, entry.value) ?? entry.label);
3580
+ const summaryOf = (entry) => resolveDoc(caps, `enum/${ns}/${entry.value}`)?.summary || void 0;
3581
+ if (control !== "select") return jsx(EnumChoiceGroup, {
3582
+ control,
3583
+ options: values.map((entry) => ({
3584
+ value: entry.value,
3585
+ label: labelOf(entry),
3586
+ ...entry.icon === void 0 ? {} : { icon: entry.icon },
3587
+ ...withSummary(summaryOf(entry))
3588
+ })),
3589
+ value,
3590
+ onChange,
3591
+ testid: tid,
3592
+ name,
3593
+ id,
3594
+ required,
3595
+ disabled,
3596
+ ariaInvalid,
3597
+ ariaDescribedBy,
3598
+ ariaErrorMessage,
3599
+ ariaLabelledBy,
3600
+ className
3453
3601
  });
3454
3602
  const selectValue = value == null ? clearable ? ENUM_PICKER_CLEAR_SENTINEL : "" : value;
3455
3603
  const handleValueChange = (next) => {
@@ -3479,36 +3627,49 @@ function EnumPicker({ enumName, value, onChange, renderAs = "select", name, id,
3479
3627
  "data-testid": `${tid}:option:__clear__`,
3480
3628
  children: clearLabel
3481
3629
  }), values.map((entry) => {
3482
- const optionLabel = resolveEnumLabel(caps, ns, entry.value, enumValueText(def, entry.value) ?? entry.label);
3483
- const optionDoc = resolveDoc(caps, `enum/${ns}/${entry.value}`)?.summary;
3630
+ const optionLabel = labelOf(entry);
3631
+ const optionDoc = summaryOf(entry);
3484
3632
  return jsx(SelectItem, {
3485
3633
  value: entry.value,
3486
3634
  "data-testid": `${tid}:option:${entry.value}`,
3487
- children: optionDoc === void 0 ? optionLabel : jsxs("span", {
3488
- className: "flex flex-col gap-0.5",
3489
- children: [jsx("span", { children: optionLabel }), jsx("span", {
3490
- className: "text-xs leading-snug text-muted-foreground",
3491
- "data-testid": `${tid}:option:${entry.value}:doc`,
3492
- children: optionDoc
3493
- })]
3494
- })
3635
+ description: optionDoc === void 0 ? void 0 : jsx("span", {
3636
+ "data-testid": `${tid}:option:${entry.value}:doc`,
3637
+ children: optionDoc
3638
+ }),
3639
+ children: optionLabel
3495
3640
  }, entry.value);
3496
3641
  })] })]
3497
3642
  });
3498
3643
  }
3499
3644
  //#endregion
3645
+ //#region src/enum/resolve-enum-control.ts
3646
+ const warned = new Set();
3647
+ function resolveEnumControl(fieldControl, enumDef, where) {
3648
+ if (isEnumControl(fieldControl)) return fieldControl;
3649
+ if (fieldControl !== void 0) {
3650
+ const shown = typeof fieldControl === "string" ? `'${fieldControl}'` : String(fieldControl);
3651
+ const key = `${where}\u0000${shown}`;
3652
+ if (!warned.has(key)) {
3653
+ warned.add(key);
3654
+ console.warn(`[buro/ui-shadcn] ${where}: unknown enum control ${shown}; expected one of ${ENUM_CONTROLS.map((control) => `'${control}'`).join(", ")}. Using the enum's control, else 'select'.`);
3655
+ }
3656
+ }
3657
+ return enumDef?.control ?? "select";
3658
+ }
3659
+ //#endregion
3500
3660
  //#region src/forms/issue-severity.ts
3501
3661
  function isErrorIssue(issue) {
3502
3662
  return issue.severity === "error";
3503
3663
  }
3504
3664
  //#endregion
3505
3665
  //#region src/fields/boolean.tsx
3506
- function BooleanDisplay({ value }) {
3666
+ function BooleanDisplay({ value, text }) {
3507
3667
  const t = useOptionalT();
3508
3668
  if (value == null) return jsx("span", {
3509
3669
  className: "text-muted-foreground",
3510
3670
  children: "—"
3511
3671
  });
3672
+ if (text !== void 0) return jsx("span", { children: text });
3512
3673
  return jsx("span", { children: value ? t("boolean.yes", { defaultValue: "Yes" }) : t("boolean.no", { defaultValue: "No" }) });
3513
3674
  }
3514
3675
  function BooleanInput({ name, id, value, onChange, testid, disabled, required, ariaInvalid, ariaDescribedBy, ariaErrorMessage }) {
@@ -3527,17 +3688,32 @@ function BooleanInput({ name, id, value, onChange, testid, disabled, required, a
3527
3688
  }
3528
3689
  //#endregion
3529
3690
  //#region src/fields/date.tsx
3530
- function DateDisplay({ value }) {
3691
+ function DateDisplay({ value, text }) {
3692
+ return jsx(TemporalDisplay, {
3693
+ value,
3694
+ text,
3695
+ format: formatDate
3696
+ });
3697
+ }
3698
+ function DateTimeDisplay({ value, text }) {
3699
+ return jsx(TemporalDisplay, {
3700
+ value,
3701
+ text,
3702
+ format: formatDateTime
3703
+ });
3704
+ }
3705
+ function TemporalDisplay({ value, text, format }) {
3531
3706
  const locale = useOptionalLocale();
3532
3707
  if (value == null || value === "") return jsx("span", {
3533
3708
  className: "text-muted-foreground",
3534
3709
  children: "—"
3535
3710
  });
3711
+ if (text !== void 0) return jsx("span", { children: text });
3536
3712
  const d = new Date(String(value));
3537
3713
  if (Number.isNaN(d.getTime())) return jsx("span", { children: String(value) });
3538
3714
  return jsx("span", {
3539
3715
  className: "whitespace-nowrap",
3540
- children: formatDate(d, locale)
3716
+ children: format(d, locale)
3541
3717
  });
3542
3718
  }
3543
3719
  function toIsoDate(v) {
@@ -3548,13 +3724,29 @@ function toIsoDate(v) {
3548
3724
  if (Number.isNaN(d.getTime())) return "";
3549
3725
  return d.toISOString().slice(0, 10);
3550
3726
  }
3551
- function DateInput({ name, id, value, onChange, testid, disabled, required, ariaInvalid, ariaDescribedBy, ariaErrorMessage }) {
3727
+ function DateInput(props) {
3728
+ return jsx(TemporalInput, {
3729
+ ...props,
3730
+ type: "date",
3731
+ toText: toIsoDate,
3732
+ fromText: (text) => text || null
3733
+ });
3734
+ }
3735
+ function DateTimeInput(props) {
3736
+ return jsx(TemporalInput, {
3737
+ ...props,
3738
+ type: "datetime-local",
3739
+ toText: toLocalDateTimeText,
3740
+ fromText: (text) => fromLocalDateTimeText(text) ?? null
3741
+ });
3742
+ }
3743
+ function TemporalInput({ type, toText, fromText, name, id, value, onChange, testid, disabled, required, ariaInvalid, ariaDescribedBy, ariaErrorMessage }) {
3552
3744
  return jsx(Input, {
3553
3745
  name,
3554
3746
  id,
3555
- type: "date",
3556
- value: toIsoDate(value),
3557
- onChange: (e) => onChange(e.target.value || null),
3747
+ type,
3748
+ value: toText(value),
3749
+ onChange: (e) => onChange(fromText(e.target.value)),
3558
3750
  "data-testid": testid,
3559
3751
  disabled,
3560
3752
  required,
@@ -3566,22 +3758,6 @@ function DateInput({ name, id, value, onChange, testid, disabled, required, aria
3566
3758
  }
3567
3759
  //#endregion
3568
3760
  //#region src/fields/enum.tsx
3569
- function optionLabel(caps, field, value, inline) {
3570
- const ns = enumNamespaceOf(field);
3571
- if (ns) return resolveEnumLabel(caps, ns, value, inline);
3572
- return field ? resolveFieldOptionLabel(caps, field.name, value, inline) : inline;
3573
- }
3574
- function declaredOptionLabel(option, value, enumDef) {
3575
- return (enumDef === void 0 ? void 0 : enumValueText(enumDef, value)) ?? (typeof option?.label === "string" ? option.label : value);
3576
- }
3577
- function useBoundEnum(field) {
3578
- const app = useOptionalApp();
3579
- const namespace = enumNamespaceOf(field);
3580
- return namespace === void 0 ? void 0 : app?.registry.enums.get(namespace);
3581
- }
3582
- function useOptionCaps(resource) {
3583
- return useI18nCaps(useContext(ResourceContext).resource ?? resource);
3584
- }
3585
3761
  function EnumDisplay({ value, options, field, resource }) {
3586
3762
  const caps = useOptionCaps(resource);
3587
3763
  const enumDef = useBoundEnum(field);
@@ -3590,7 +3766,7 @@ function EnumDisplay({ value, options, field, resource }) {
3590
3766
  children: "—"
3591
3767
  });
3592
3768
  const opt = options?.find((o) => o.value === String(value));
3593
- const label = optionLabel(caps, field, String(value), declaredOptionLabel(opt, String(value), enumDef));
3769
+ const label = resolveOptionLabel(caps, field, String(value), opt, enumDef);
3594
3770
  return jsxs("span", {
3595
3771
  className: "inline-flex items-center gap-1",
3596
3772
  children: [opt?.icon ? jsx(Icon, {
@@ -3599,10 +3775,36 @@ function EnumDisplay({ value, options, field, resource }) {
3599
3775
  }) : null, label]
3600
3776
  });
3601
3777
  }
3602
- function EnumInput({ name, id, value, onChange, testid, options, field, placeholder, disabled, required, ariaInvalid, ariaDescribedBy, ariaErrorMessage, resource }) {
3778
+ function EnumInput({ name, id, value, onChange, testid, options, field, placeholder, disabled, required, ariaInvalid, ariaDescribedBy, ariaErrorMessage, ariaLabelledBy, resource }) {
3603
3779
  const t = useOptionalT();
3604
3780
  const caps = useOptionCaps(resource);
3605
3781
  const enumDef = useBoundEnum(field);
3782
+ const ns = enumNamespaceOf(field);
3783
+ const control = resolveEnumControl(field?.ui?.control, enumDef, `field ${field?.name ?? name}`);
3784
+ const resolved = (options ?? []).map((o) => {
3785
+ const summary = ns === void 0 ? void 0 : resolveDoc(caps, `enum/${ns}/${o.value}`)?.summary;
3786
+ return {
3787
+ value: o.value,
3788
+ label: resolveOptionLabel(caps, field, o.value, o, enumDef),
3789
+ ...o.icon === void 0 ? {} : { icon: o.icon },
3790
+ ...summary === void 0 ? {} : { summary }
3791
+ };
3792
+ });
3793
+ if (control !== "select") return jsx(EnumChoiceGroup, {
3794
+ control,
3795
+ options: resolved,
3796
+ value,
3797
+ onChange,
3798
+ testid: testid ?? name,
3799
+ name,
3800
+ id,
3801
+ required,
3802
+ disabled,
3803
+ ariaInvalid,
3804
+ ariaDescribedBy,
3805
+ ariaErrorMessage,
3806
+ ariaLabelledBy
3807
+ });
3606
3808
  return jsxs(Select, {
3607
3809
  value: value ?? "",
3608
3810
  onValueChange: onChange,
@@ -3617,14 +3819,19 @@ function EnumInput({ name, id, value, onChange, testid, options, field, placehol
3617
3819
  "aria-describedby": ariaDescribedBy,
3618
3820
  ...ariaErrorMessage ? { "aria-errormessage": ariaErrorMessage } : {},
3619
3821
  children: jsx(SelectValue, { placeholder: placeholder ?? t("field.select", { defaultValue: "Select…" }) })
3620
- }), jsx(SelectContent, { children: options?.map((o) => jsx(SelectItem, {
3822
+ }), jsx(SelectContent, { children: resolved.map((o) => jsx(SelectItem, {
3621
3823
  value: o.value,
3824
+ "data-testid": testid === void 0 ? void 0 : `${testid}:option:${o.value}`,
3825
+ description: o.summary === void 0 ? void 0 : jsx("span", {
3826
+ "data-testid": testid === void 0 ? void 0 : `${testid}:option:${o.value}:doc`,
3827
+ children: o.summary
3828
+ }),
3622
3829
  children: jsxs("span", {
3623
3830
  className: "inline-flex items-center gap-1.5",
3624
3831
  children: [o.icon ? jsx(Icon, {
3625
3832
  name: o.icon,
3626
3833
  className: "size-3.5 shrink-0 text-muted-foreground"
3627
- }) : null, optionLabel(caps, field, o.value, declaredOptionLabel(o, o.value, enumDef))]
3834
+ }) : null, o.label]
3628
3835
  })
3629
3836
  }, o.value)) })]
3630
3837
  });
@@ -4047,7 +4254,7 @@ function JsonInput({ name, id, value, onChange, testid, disabled, required, aria
4047
4254
  }
4048
4255
  //#endregion
4049
4256
  //#region src/fields/lazy-relation-many.tsx
4050
- const RelationManyPickerInput = lazy(() => import("./relation-many-picker-bvkjkv-k.js").then((module) => ({ default: module.RelationManyPickerInput })));
4257
+ const RelationManyPickerInput = lazy(() => import("./relation-many-picker-BJhaEqxz.js").then((module) => ({ default: module.RelationManyPickerInput })));
4051
4258
  function LazyRelationManyInput(props) {
4052
4259
  return jsx(Suspense, {
4053
4260
  fallback: jsx(Skeleton, {
@@ -4060,8 +4267,8 @@ function LazyRelationManyInput(props) {
4060
4267
  }
4061
4268
  //#endregion
4062
4269
  //#region src/fields/lazy-rich-text.tsx
4063
- const RichTextDisplay = lazy(() => import("./rich-text-DFerywgz.js").then((module) => ({ default: module.RichTextDisplay })));
4064
- const RichTextInput = lazy(() => import("./rich-text-DFerywgz.js").then((module) => ({ default: module.RichTextInput })));
4270
+ const RichTextDisplay = lazy(() => import("./rich-text-RcPBf6hr.js").then((module) => ({ default: module.RichTextDisplay })));
4271
+ const RichTextInput = lazy(() => import("./rich-text-RcPBf6hr.js").then((module) => ({ default: module.RichTextInput })));
4065
4272
  function RichTextDisplayLoading() {
4066
4273
  const t = useOptionalT();
4067
4274
  return jsx("div", {
@@ -4118,12 +4325,13 @@ function isIdentifier(field) {
4118
4325
  const n = field?.name;
4119
4326
  return n === "id" || typeof n === "string" && n.endsWith("_id");
4120
4327
  }
4121
- function NumberDisplay({ value, field }) {
4328
+ function NumberDisplay({ value, field, text }) {
4122
4329
  const locale = useOptionalLocale();
4123
4330
  if (value == null || value === "") return jsx("span", {
4124
4331
  className: "text-muted-foreground",
4125
4332
  children: "—"
4126
4333
  });
4334
+ if (text !== void 0) return jsx("span", { children: text });
4127
4335
  let raw = value;
4128
4336
  if (typeof raw === "string") raw = unquote(raw);
4129
4337
  const n = typeof raw === "number" ? raw : Number(raw);
@@ -4160,10 +4368,9 @@ function NumberInput({ name, id, value, onChange, testid, placeholder, disabled,
4160
4368
  //#endregion
4161
4369
  //#region src/fields/link-keys-display.tsx
4162
4370
  const isRecord$1 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
4163
- function qualify(name, owner) {
4371
+ function qualify(name) {
4164
4372
  try {
4165
- const namespace = normalizeEntityRef(owner).namespace;
4166
- const ref = normalizeEntityRef(name, { defaultNamespace: namespace });
4373
+ const ref = normalizeEntityRef(name);
4167
4374
  return ref.namespace === "default" ? ref.id : `${ref.namespace}:${ref.id}`;
4168
4375
  } catch {
4169
4376
  return;
@@ -4188,7 +4395,7 @@ function LinkKeysDisplay(props) {
4188
4395
  const ownerDef = owner === "" ? void 0 : app.registry.get(owner);
4189
4396
  const declaration = ownerDef === void 0 ? void 0 : declaredField(ownerDef, name);
4190
4397
  const link = isRecord$1(declaration) ? linkOf(declaration) : void 0;
4191
- const junctionName = link === void 0 ? void 0 : qualify(link.junction, owner);
4398
+ const junctionName = link === void 0 ? void 0 : qualify(link.junction);
4192
4399
  const junctionDef = junctionName === void 0 ? void 0 : app.registry.get(junctionName);
4193
4400
  const junctionField = (key) => junctionDef === void 0 ? void 0 : declaredField(junctionDef, key);
4194
4401
  const ownerField = link === void 0 ? idFieldOf(ownerDef) : byOf(junctionField(link.sourceKey)) ?? idFieldOf(ownerDef);
@@ -4196,11 +4403,11 @@ function LinkKeysDisplay(props) {
4196
4403
  const ownerKey = record?.[ownerField];
4197
4404
  const { keys, complete, isLoading, error } = useLinkKeys(owner, name, ownerKey);
4198
4405
  const [missed, setMissed] = useState(() => new Set());
4199
- const onMiss = useCallback((key, miss) => {
4406
+ const onMiss = useCallback((key, isMiss) => {
4200
4407
  setMissed((current) => {
4201
- if (current.has(key) === miss) return current;
4408
+ if (current.has(key) === isMiss) return current;
4202
4409
  const next = new Set(current);
4203
- if (miss) next.add(key);
4410
+ if (isMiss) next.add(key);
4204
4411
  else next.delete(key);
4205
4412
  return next;
4206
4413
  });
@@ -4220,12 +4427,17 @@ function LinkKeysDisplay(props) {
4220
4427
  targetBy
4221
4428
  ]);
4222
4429
  const chipsId = tid.linkChips(owner, name);
4223
- if (error) return jsx("span", {
4224
- "data-testid": tid.linkError(owner, name),
4225
- role: "status",
4430
+ if (error) return jsx(LoadError, {
4431
+ surface: "relation",
4432
+ error,
4433
+ ...typeof target === "string" ? { resource: target } : {},
4434
+ testId: tid.linkError(owner, name),
4226
4435
  className: "text-destructive text-xs",
4227
- title: error.message,
4228
- children: t("fields.link.failed", { defaultValue: "Links could not be loaded" })
4436
+ attributes: { role: "status" },
4437
+ fallback: {
4438
+ key: "field.link.failed",
4439
+ default: "Links could not be loaded"
4440
+ }
4229
4441
  });
4230
4442
  if (keys === void 0) {
4231
4443
  if (!isLoading) return jsx("span", {
@@ -4245,7 +4457,7 @@ function LinkKeysDisplay(props) {
4245
4457
  children: jsx("span", {
4246
4458
  "data-testid": tid.linkIncomplete(owner, name),
4247
4459
  className: "text-muted-foreground",
4248
- children: t("fields.link.incomplete", {
4460
+ children: t("field.link.incomplete", {
4249
4461
  count: keys.length,
4250
4462
  defaultValue: "More than {{count}} links"
4251
4463
  })
@@ -4267,7 +4479,7 @@ function LinkKeysDisplay(props) {
4267
4479
  }, String(key))), hidden > 0 ? jsx("span", {
4268
4480
  "data-testid": tid.linkHidden(owner, name),
4269
4481
  className: `${chipClassName} text-muted-foreground`,
4270
- children: t("fields.link.hidden", {
4482
+ children: t("field.link.hidden", {
4271
4483
  count: hidden,
4272
4484
  defaultValue: "{{count}} not visible"
4273
4485
  })
@@ -4355,7 +4567,7 @@ const relationMetaSchema = Object.freeze({ "~standard": Object.freeze({
4355
4567
  path: []
4356
4568
  }] };
4357
4569
  const issues = [];
4358
- const { to, by, resolve, searchField, candidates } = value;
4570
+ const { to, by, resolve, searchField, candidates, scope } = value;
4359
4571
  if (to !== void 0 && !(typeof to === "string" && to.length > 0) && !(isRecord(to) && (typeof to.id === "string" || isRecord(to.ref)))) issues.push({
4360
4572
  message: "must be a resource name or reference",
4361
4573
  path: ["to"]
@@ -4376,16 +4588,21 @@ const relationMetaSchema = Object.freeze({ "~standard": Object.freeze({
4376
4588
  message: "must be an array of conditions",
4377
4589
  path: ["candidates"]
4378
4590
  });
4591
+ if (scope !== void 0 && scope !== "context" && scope !== "session" && scope !== "none") issues.push({
4592
+ message: "must be 'context', 'session' or 'none'",
4593
+ path: ["scope"]
4594
+ });
4379
4595
  return issues.length > 0 ? { issues } : { value };
4380
4596
  }
4381
4597
  }) });
4382
4598
  //#endregion
4383
4599
  //#region src/fields/text.tsx
4384
- function TextDisplay({ value }) {
4600
+ function TextDisplay({ value, text: formatted }) {
4385
4601
  if (value == null || value === "") return jsx("span", {
4386
4602
  className: "text-muted-foreground",
4387
4603
  children: "—"
4388
4604
  });
4605
+ if (formatted !== void 0) return jsx("span", { children: formatted });
4389
4606
  const { text, isStructured } = toDisplayText(value);
4390
4607
  return isStructured ? jsx("span", {
4391
4608
  className: "font-mono text-xs break-all",
@@ -4414,23 +4631,26 @@ function TextInput({ name, id, value, onChange, testid, placeholder, disabled, r
4414
4631
  }
4415
4632
  //#endregion
4416
4633
  //#region src/fields/textarea.tsx
4417
- function TextareaDisplay({ value }) {
4634
+ function TextareaDisplay({ value, text: formatted }) {
4418
4635
  if (value == null || value === "") return jsx("span", {
4419
4636
  className: "text-muted-foreground",
4420
4637
  children: "—"
4421
4638
  });
4422
- const { text, isStructured } = toDisplayText(value);
4639
+ const { text, isStructured } = formatted === void 0 ? toDisplayText(value) : {
4640
+ text: formatted,
4641
+ isStructured: false
4642
+ };
4423
4643
  return jsx("pre", {
4424
4644
  className: isStructured ? "whitespace-pre-wrap break-all font-mono text-xs" : "whitespace-pre-wrap font-sans text-sm",
4425
4645
  children: text
4426
4646
  });
4427
4647
  }
4428
- function CodeDisplay({ value, presentation, testid }) {
4648
+ function CodeDisplay({ value, text: formatted, presentation, testid }) {
4429
4649
  if (value == null || value === "") return jsx("span", {
4430
4650
  className: "text-muted-foreground",
4431
4651
  children: "—"
4432
4652
  });
4433
- const { text } = toDisplayText(value);
4653
+ const text = formatted ?? toDisplayText(value).text;
4434
4654
  return jsx("pre", {
4435
4655
  "data-testid": testid,
4436
4656
  className: presentation === "plain" ? "overflow-x-auto whitespace-pre font-mono text-xs leading-relaxed" : "overflow-x-auto whitespace-pre rounded-md border bg-muted/40 p-3 font-mono text-xs leading-relaxed",
@@ -4474,13 +4694,12 @@ function TextareaInput({ name, id, value, onChange, testid, placeholder, disable
4474
4694
  //#endregion
4475
4695
  //#region src/fields/default-renderers.ts
4476
4696
  function legacyField(props) {
4477
- const name = typeof props.path.at(-1) === "string" ? props.path.at(-1) : "field";
4697
+ const name = optionFieldName(props.path);
4478
4698
  const texts = props.field.texts;
4479
4699
  return Object.freeze({
4480
4700
  name,
4481
4701
  meta: props.meta,
4482
4702
  ui: props.ui,
4483
- codec: props.field.codec,
4484
4703
  ...texts === void 0 ? {} : { texts }
4485
4704
  });
4486
4705
  }
@@ -4502,6 +4721,7 @@ function display(renderer) {
4502
4721
  return function ShadcnDisplay(props) {
4503
4722
  return createElement(renderer, {
4504
4723
  value: props.value,
4724
+ ...props.text === void 0 ? {} : { text: props.text },
4505
4725
  multiple: props.multiple,
4506
4726
  field: legacyField(props),
4507
4727
  options: legacyOptions(props.options, props.field),
@@ -4539,12 +4759,14 @@ function input(renderer) {
4539
4759
  ariaInvalid: props.issues.some(isErrorIssue),
4540
4760
  ariaDescribedBy: props.accessibility.description,
4541
4761
  ariaErrorMessage: props.accessibility.error,
4762
+ ariaLabelledBy: props.accessibility.label,
4542
4763
  field: legacyField(props),
4543
4764
  resource: props.resource.id,
4544
4765
  record: props.record,
4545
4766
  relationSeeds: props.relationSeeds,
4546
4767
  fixedFilters: props.fixedFilters,
4547
- metaSources: props.metaSources
4768
+ metaSources: props.metaSources,
4769
+ link: props.link
4548
4770
  });
4549
4771
  };
4550
4772
  }
@@ -4592,9 +4814,27 @@ function scalarOrCollection(renderer, layout) {
4592
4814
  });
4593
4815
  }
4594
4816
  function enumName(ui) {
4595
- const value = ui.enum;
4596
- if (typeof value === "string" && value.length > 0) return value;
4597
- if (value !== null && typeof value === "object" && typeof value.id === "string") return value.id;
4817
+ return enumBindingKey(ui.enum);
4818
+ }
4819
+ function RegistryEnumInput(props) {
4820
+ const app = useOptionalApp();
4821
+ const control = resolveEnumControl(props.ui.control, app?.registry.enums.get(props.enumName), `field ${typeof props.path.at(-1) === "string" ? String(props.path.at(-1)) : props.enumName}`);
4822
+ return createElement(EnumPicker, {
4823
+ enumName: props.enumName,
4824
+ control,
4825
+ value: props.value == null ? void 0 : String(props.value),
4826
+ onChange: props.onChange ?? (() => void 0),
4827
+ name: props.accessibility.input,
4828
+ id: props.accessibility.input,
4829
+ testid: props.testIds.input,
4830
+ placeholder: typeof props.ui.placeholder === "string" ? props.ui.placeholder : void 0,
4831
+ disabled: props.disabled,
4832
+ required: props.field.required === true,
4833
+ ariaInvalid: props.issues.some(isErrorIssue),
4834
+ ariaDescribedBy: props.accessibility.description,
4835
+ ariaErrorMessage: props.accessibility.error,
4836
+ ariaLabelledBy: props.accessibility.label
4837
+ });
4598
4838
  }
4599
4839
  function enumAware(renderer, layout) {
4600
4840
  const FallbackInput = input(renderer.Input);
@@ -4604,19 +4844,9 @@ function enumAware(renderer, layout) {
4604
4844
  return Object.freeze({
4605
4845
  Input: (props) => {
4606
4846
  const name = enumName(props.ui);
4607
- if (name !== void 0) return createElement(EnumPicker, {
4608
- enumName: name,
4609
- value: props.value == null ? void 0 : String(props.value),
4610
- onChange: props.onChange ?? (() => void 0),
4611
- name: props.accessibility.input,
4612
- id: props.accessibility.input,
4613
- testid: props.testIds.input,
4614
- placeholder: typeof props.ui.placeholder === "string" ? props.ui.placeholder : void 0,
4615
- disabled: props.disabled,
4616
- required: props.field.required === true,
4617
- ariaInvalid: props.issues.some(isErrorIssue),
4618
- ariaDescribedBy: props.accessibility.description,
4619
- ariaErrorMessage: props.accessibility.error
4847
+ if (name !== void 0) return createElement(RegistryEnumInput, {
4848
+ ...props,
4849
+ enumName: name
4620
4850
  });
4621
4851
  if (props.options.length > 0) return createElement(OptionedInput, props);
4622
4852
  return createElement(FallbackInput, props);
@@ -4651,6 +4881,10 @@ const date = {
4651
4881
  Display: DateDisplay,
4652
4882
  Input: DateInput
4653
4883
  };
4884
+ const dateTime = {
4885
+ Display: DateTimeDisplay,
4886
+ Input: DateTimeInput
4887
+ };
4654
4888
  const en = {
4655
4889
  Display: EnumDisplay,
4656
4890
  Input: EnumInput
@@ -4686,9 +4920,9 @@ const shadcnFieldImplementations = Object.freeze({
4686
4920
  number: scalar(num),
4687
4921
  boolean: scalar(bool),
4688
4922
  date: scalar(date),
4689
- dateTime: scalar(date),
4690
- "date-time": scalar(date),
4691
- "default:date-time": scalar(date),
4923
+ dateTime: scalar(dateTime),
4924
+ "date-time": scalar(dateTime),
4925
+ "default:date-time": scalar(dateTime),
4692
4926
  enum: enumAware(en),
4693
4927
  json: scalar({
4694
4928
  Display: JsonDisplay,
@@ -4705,313 +4939,6 @@ const shadcnFieldImplementations = Object.freeze({
4705
4939
  file: scalarOrCollection(file, { size: "full" })
4706
4940
  });
4707
4941
  //#endregion
4708
- //#region src/fields/use-relation-picker.tsx
4709
- const noop = () => void 0;
4710
- function safeKey(input) {
4711
- if (input === void 0 || input === null) return void 0;
4712
- try {
4713
- return resourceKey(input);
4714
- } catch {
4715
- return;
4716
- }
4717
- }
4718
- function sessionIdentity(runtime) {
4719
- const state = runtime.dataSession.getState();
4720
- const snapshot = state.status === "ready" ? state.snapshot : state.target;
4721
- let scopeKey;
4722
- try {
4723
- scopeKey = JSON.stringify(snapshot.scopeKey) ?? "";
4724
- } catch {
4725
- scopeKey = String(snapshot.scopeKey);
4726
- }
4727
- return {
4728
- sessionKey: snapshot.sessionKey,
4729
- scopeKey
4730
- };
4731
- }
4732
- function PickerHost(props) {
4733
- const { register } = props;
4734
- React.useEffect(() => register(), [register]);
4735
- return jsx(Fragment$1, { children: props.children });
4736
- }
4737
- function useRelationPicker(options) {
4738
- const app = useApp();
4739
- const runtime = useDataRuntime();
4740
- const frame = useOptionalRecordFrame();
4741
- const frames = useRecordScopeFrames();
4742
- const multiple = options.multiple === true;
4743
- const fieldName = options.field;
4744
- let to;
4745
- let declaredBy;
4746
- let declaredCandidates;
4747
- if (fieldName !== void 0) {
4748
- const meta = ((frame === null ? void 0 : app.registry.get(frame.resource)?.fields)?.[fieldName])?.meta;
4749
- to = safeKey(meta?.to);
4750
- declaredBy = typeof meta?.by === "string" ? meta.by : void 0;
4751
- declaredCandidates = Array.isArray(meta?.candidates) ? meta.candidates : void 0;
4752
- } else to = safeKey(options.to);
4753
- const target = to ?? "";
4754
- const by = options.valueField ?? declaredBy;
4755
- const scope = options.scope ?? "context";
4756
- const selection = useCandidateSelection({
4757
- to,
4758
- candidates: options.candidates ?? declaredCandidates,
4759
- sources: frame?.controller.sources,
4760
- resource: frame?.resource ?? "",
4761
- fieldName: fieldName ?? target,
4762
- fixedFilters: options.fixedFilters
4763
- });
4764
- const held = selection.gate !== void 0;
4765
- const pendingRef = React.useRef(null);
4766
- const [active, setActive] = React.useState(null);
4767
- const activeRef = React.useRef(null);
4768
- activeRef.current = active;
4769
- const rowsRef = React.useRef(new Map());
4770
- const createdRowRef = React.useRef(void 0);
4771
- const alive = React.useRef(true);
4772
- const mounts = React.useRef(0);
4773
- const sequence = React.useRef(0);
4774
- const latest = React.useRef({
4775
- multiple,
4776
- select: options.select,
4777
- idField: "id",
4778
- valueField: "id",
4779
- available: false,
4780
- frames
4781
- });
4782
- const project = React.useCallback((row) => {
4783
- const select = latest.current.select;
4784
- if (select === void 0) return { ...row };
4785
- const out = {};
4786
- const key = row.id !== void 0 ? row.id : row[latest.current.idField];
4787
- if (key !== void 0) out.id = key;
4788
- const { valueField } = latest.current;
4789
- if (Object.hasOwn(row, valueField)) out[valueField] = row[valueField];
4790
- for (const name of select) if (Object.hasOwn(row, name)) out[name] = row[name];
4791
- return out;
4792
- }, []);
4793
- const settle = React.useCallback((result) => {
4794
- const pending = pendingRef.current;
4795
- if (pending === null) return;
4796
- pendingRef.current = null;
4797
- pending.detach();
4798
- if (alive.current) setActive(null);
4799
- pending.resolve(result);
4800
- }, []);
4801
- const toggle = React.useCallback((key, row) => {
4802
- setActive((current) => {
4803
- if (current === null) return current;
4804
- const has = current.selected.some((k) => String(k) === String(key));
4805
- if (has) rowsRef.current.delete(String(key));
4806
- else if (row !== void 0) rowsRef.current.set(String(key), row);
4807
- const selected = has ? current.selected.filter((k) => String(k) !== String(key)) : [...current.selected, key];
4808
- const next = {
4809
- ...current,
4810
- selected
4811
- };
4812
- activeRef.current = next;
4813
- return next;
4814
- });
4815
- }, []);
4816
- const onValue = React.useCallback((value) => {
4817
- const row = createdRowRef.current;
4818
- createdRowRef.current = void 0;
4819
- if (latest.current.multiple) {
4820
- const current = activeRef.current;
4821
- if (current !== null && !current.selected.some((k) => String(k) === String(value))) toggle(value, row);
4822
- return;
4823
- }
4824
- settle({
4825
- kind: "selected",
4826
- keys: [value],
4827
- rows: row === void 0 ? [] : [project(row)]
4828
- });
4829
- }, [
4830
- project,
4831
- settle,
4832
- toggle
4833
- ]);
4834
- const wiring = useRelationSelect({
4835
- to: target,
4836
- by,
4837
- fixedFilters: selection.fixedFilters,
4838
- scope,
4839
- ...fieldName === void 0 ? {} : { scopeField: fieldName },
4840
- held,
4841
- onValue
4842
- });
4843
- latest.current = {
4844
- multiple,
4845
- select: options.select,
4846
- idField: wiring.idField,
4847
- valueField: wiring.valueField,
4848
- available: to !== void 0 && wiring.targetDef !== void 0 && !held,
4849
- frames
4850
- };
4851
- const { create: shared } = wiring;
4852
- const create = React.useMemo(() => ({
4853
- ...shared,
4854
- start: (openCreate) => shared.start(() => {
4855
- const opened = openCreate();
4856
- opened.then((row) => {
4857
- createdRowRef.current = row === null ? void 0 : { ...row };
4858
- }, noop);
4859
- return opened;
4860
- })
4861
- }), [shared]);
4862
- React.useEffect(() => runtime.dataSession.subscribe(() => {
4863
- const pending = pendingRef.current;
4864
- if (pending === null) return;
4865
- const now = sessionIdentity(runtime);
4866
- if (now.sessionKey !== pending.sessionKey || now.scopeKey !== pending.scopeKey) settle({
4867
- kind: "cancelled",
4868
- reason: "session-changed"
4869
- });
4870
- }), [runtime, settle]);
4871
- React.useEffect(() => {
4872
- alive.current = true;
4873
- return () => {
4874
- alive.current = false;
4875
- settle({
4876
- kind: "cancelled",
4877
- reason: "unmounted"
4878
- });
4879
- };
4880
- }, [settle]);
4881
- React.useEffect(() => {
4882
- if (held) settle({
4883
- kind: "cancelled",
4884
- reason: "unavailable"
4885
- });
4886
- }, [held, settle]);
4887
- const register = React.useCallback(() => {
4888
- mounts.current += 1;
4889
- return () => {
4890
- mounts.current -= 1;
4891
- if (mounts.current === 0) settle({
4892
- kind: "cancelled",
4893
- reason: "unmounted"
4894
- });
4895
- };
4896
- }, [settle]);
4897
- const open = React.useCallback((opts = {}) => new Promise((resolve) => {
4898
- settle({
4899
- kind: "cancelled",
4900
- reason: "superseded"
4901
- });
4902
- if (mounts.current === 0) {
4903
- if (process.env.NODE_ENV !== "production") console.error("[burojs] useRelationPicker: open() was called but its element is not rendered — render `handle.element` once in your tree.");
4904
- resolve({
4905
- kind: "cancelled",
4906
- reason: "not-mounted"
4907
- });
4908
- return;
4909
- }
4910
- const { signal } = opts;
4911
- if (signal?.aborted === true) {
4912
- resolve({
4913
- kind: "cancelled",
4914
- reason: "aborted"
4915
- });
4916
- return;
4917
- }
4918
- if (!latest.current.available) {
4919
- resolve({
4920
- kind: "cancelled",
4921
- reason: "unavailable"
4922
- });
4923
- return;
4924
- }
4925
- sequence.current += 1;
4926
- const id = sequence.current;
4927
- const onAbort = () => {
4928
- if (pendingRef.current?.id === id) settle({
4929
- kind: "cancelled",
4930
- reason: "aborted"
4931
- });
4932
- };
4933
- signal?.addEventListener("abort", onAbort, { once: true });
4934
- pendingRef.current = {
4935
- id,
4936
- ...sessionIdentity(runtime),
4937
- resolve,
4938
- detach: () => signal?.removeEventListener("abort", onAbort)
4939
- };
4940
- rowsRef.current = new Map();
4941
- createdRowRef.current = void 0;
4942
- const next = {
4943
- id,
4944
- frames: latest.current.frames,
4945
- selected: opts.selected ?? []
4946
- };
4947
- activeRef.current = next;
4948
- setActive(next);
4949
- }), [runtime, settle]);
4950
- const onSelectRow = React.useCallback((row) => {
4951
- const field = wiring.valueField;
4952
- const value = field === "id" ? row.id : row[field];
4953
- if (typeof value !== "string" && typeof value !== "number") return;
4954
- settle({
4955
- kind: "selected",
4956
- keys: [value],
4957
- rows: [project(row)]
4958
- });
4959
- }, [
4960
- wiring.valueField,
4961
- settle,
4962
- project
4963
- ]);
4964
- const onDone = React.useCallback(() => {
4965
- const keys = activeRef.current?.selected ?? [];
4966
- const rows = keys.flatMap((key) => {
4967
- const row = rowsRef.current.get(String(key));
4968
- return row === void 0 ? [] : [project(row)];
4969
- });
4970
- settle({
4971
- kind: "selected",
4972
- keys,
4973
- rows
4974
- });
4975
- }, [settle, project]);
4976
- const onOpenChange = React.useCallback((next) => {
4977
- if (!next) settle({
4978
- kind: "cancelled",
4979
- reason: "dismissed"
4980
- });
4981
- }, [settle]);
4982
- return {
4983
- open,
4984
- element: jsx(PickerHost, {
4985
- register,
4986
- children: active === null || held ? null : jsxs(RecordScopeChain, {
4987
- frames: active.frames,
4988
- children: [jsx(LazyRelationPickerDialog, {
4989
- to: target,
4990
- open: true,
4991
- onOpenChange,
4992
- onSelect: noop,
4993
- onSelectRow,
4994
- valueField: wiring.valueField,
4995
- ...selection.fixedFilters === void 0 ? {} : { fixedFilters: selection.fixedFilters },
4996
- scope,
4997
- ...fieldName === void 0 ? {} : { scopeField: fieldName },
4998
- ...options.create === void 0 ? {} : {
4999
- create,
5000
- ...options.create.seeds === void 0 ? {} : { createSeeds: options.create.seeds }
5001
- },
5002
- fieldName: fieldName ?? target,
5003
- ...multiple ? {
5004
- multiple: true,
5005
- selected: active.selected,
5006
- onToggle: (value, row) => toggle(value, row),
5007
- onDone
5008
- } : {}
5009
- }), wiring.reader]
5010
- }, active.id)
5011
- })
5012
- };
5013
- }
5014
- //#endregion
5015
4942
  //#region src/forms/declarative-display.tsx
5016
4943
  function DeclarativeDisplay(props) {
5017
4944
  return jsx(ScreenStateProvider, { children: jsx(DisplayBody, { ...props }) });
@@ -5037,7 +4964,8 @@ function DisplayBody(props) {
5037
4964
  }
5038
4965
  //#endregion
5039
4966
  //#region src/enum/enum-display.tsx
5040
- function EnumDisplay$1({ enumName, value, variant = "badge", testid, className }) {
4967
+ function EnumDisplay$1({ enumName: enumInput, value, variant = "badge", testid, className }) {
4968
+ const enumName = enumBindingKey(enumInput) ?? "";
5041
4969
  const app = useApp();
5042
4970
  const caps = useI18nCaps();
5043
4971
  const def = app.registry.enums.get(enumName);
@@ -5085,159 +5013,6 @@ function EnumDisplay$1({ enumName, value, variant = "badge", testid, className }
5085
5013
  });
5086
5014
  }
5087
5015
  //#endregion
5088
- //#region src/data-table/data-table-faceted-filter.tsx
5089
- function DataTableFacetedFilter({ column, title, options = [], loadOptions, selectedLabelFor, searchPlaceholder, emptyText, getTestId, className }) {
5090
- const t = useOptionalT();
5091
- const filterValue = column.getFilterValue();
5092
- const selected = useMemo(() => {
5093
- if (Array.isArray(filterValue)) return new Set(filterValue.map(String));
5094
- return new Set();
5095
- }, [filterValue]);
5096
- const [search, setSearch] = useState("");
5097
- const [asyncOptions, setAsyncOptions] = useState([]);
5098
- const [loading, setLoading] = useState(false);
5099
- const debounceRef = useRef(null);
5100
- const loadOptionsRef = useRef(loadOptions);
5101
- useEffect(() => {
5102
- loadOptionsRef.current = loadOptions;
5103
- });
5104
- useEffect(() => {
5105
- if (!loadOptionsRef.current) return;
5106
- setLoading(true);
5107
- if (debounceRef.current !== null) clearTimeout(debounceRef.current);
5108
- let cancelled = false;
5109
- debounceRef.current = setTimeout(() => {
5110
- const loader = loadOptionsRef.current;
5111
- if (!loader) return;
5112
- loader(search).then((results) => {
5113
- if (!cancelled) {
5114
- setAsyncOptions(results);
5115
- setLoading(false);
5116
- }
5117
- }).catch(() => {
5118
- if (!cancelled) setLoading(false);
5119
- });
5120
- }, 250);
5121
- return () => {
5122
- cancelled = true;
5123
- if (debounceRef.current !== null) clearTimeout(debounceRef.current);
5124
- };
5125
- }, [search]);
5126
- const effectiveOptions = loadOptions ? asyncOptions : options;
5127
- const labelFor = (value) => {
5128
- const opt = effectiveOptions.find((o) => o.value === value);
5129
- if (opt) return opt.label;
5130
- return selectedLabelFor?.(value) ?? value;
5131
- };
5132
- const toggle = (value) => {
5133
- const next = new Set(selected);
5134
- if (next.has(value)) next.delete(value);
5135
- else next.add(value);
5136
- column.setFilterValue(next.size === 0 ? void 0 : Array.from(next));
5137
- };
5138
- const selectedValues = Array.from(selected);
5139
- return jsxs(Popover, { children: [jsx(PopoverTrigger, {
5140
- asChild: true,
5141
- children: jsxs(Button, {
5142
- type: "button",
5143
- variant: "outline",
5144
- size: "sm",
5145
- "data-testid": getTestId?.("trigger"),
5146
- className: cn("h-8 border-dashed", className),
5147
- children: [
5148
- jsx(IconCirclePlus, {
5149
- className: "mr-2 h-4 w-4",
5150
- "aria-hidden": "true"
5151
- }),
5152
- title,
5153
- selected.size > 0 && jsxs(Fragment$1, { children: [
5154
- jsx("span", {
5155
- className: "mx-2 h-4 w-px bg-border",
5156
- "aria-hidden": "true"
5157
- }),
5158
- jsx(Badge, {
5159
- variant: "secondary",
5160
- className: "rounded-sm px-1 font-normal lg:hidden",
5161
- children: selected.size
5162
- }),
5163
- jsx("div", {
5164
- className: "hidden gap-1 lg:flex",
5165
- children: selected.size > 2 ? jsx(Badge, {
5166
- variant: "secondary",
5167
- className: "rounded-sm px-1 font-normal",
5168
- children: t("table.selectedCount", {
5169
- count: selected.size,
5170
- defaultValue: "{{count}} selected"
5171
- })
5172
- }) : selectedValues.map((value) => jsx(Badge, {
5173
- variant: "secondary",
5174
- className: "rounded-sm px-1 font-normal",
5175
- children: labelFor(value)
5176
- }, value))
5177
- })
5178
- ] })
5179
- ]
5180
- })
5181
- }), jsx(PopoverContent, {
5182
- className: "w-[220px] p-0",
5183
- align: "start",
5184
- children: jsxs(Command, {
5185
- shouldFilter: !loadOptions,
5186
- children: [
5187
- jsx(CommandInput, {
5188
- placeholder: searchPlaceholder ?? title,
5189
- "data-testid": getTestId?.("search"),
5190
- ...loadOptions ? {
5191
- value: search,
5192
- onValueChange: setSearch
5193
- } : {}
5194
- }),
5195
- jsxs(CommandList, { children: [
5196
- loading && jsx("div", {
5197
- className: "py-6 text-center text-sm text-muted-foreground",
5198
- children: t("list.loadingShort", { defaultValue: "Loading…" })
5199
- }),
5200
- jsx(CommandEmpty, { children: emptyText ?? t("relation.noResults", { defaultValue: "No results." }) }),
5201
- jsx(CommandGroup, { children: effectiveOptions.map((opt) => {
5202
- const isSelected = selected.has(opt.value);
5203
- const Icon = opt.icon;
5204
- return jsxs(CommandItem, {
5205
- value: opt.label,
5206
- "data-testid": getTestId?.("option", opt.value),
5207
- role: "option",
5208
- "aria-selected": isSelected,
5209
- "aria-checked": isSelected,
5210
- onSelect: () => toggle(opt.value),
5211
- children: [
5212
- jsx("span", {
5213
- className: cn("mr-2 flex h-4 w-4 shrink-0 items-center justify-center rounded-sm border", isSelected ? "border-primary bg-primary text-primary-foreground" : "border-input opacity-50"),
5214
- "aria-hidden": "true",
5215
- children: isSelected && jsx(IconCheck, { className: "h-3.5 w-3.5" })
5216
- }),
5217
- Icon && jsx(Icon, {
5218
- className: "mr-2 h-4 w-4 text-muted-foreground",
5219
- "aria-hidden": "true"
5220
- }),
5221
- jsx("span", {
5222
- className: "flex-1 text-left",
5223
- children: opt.label
5224
- })
5225
- ]
5226
- }, opt.value);
5227
- }) })
5228
- ] }),
5229
- selected.size > 0 && jsx("button", {
5230
- type: "button",
5231
- "data-testid": getTestId?.("clear"),
5232
- onClick: () => column.setFilterValue(void 0),
5233
- className: "flex w-full items-center justify-center border-t px-2 py-1.5 text-sm hover:bg-accent hover:text-accent-foreground",
5234
- children: t("filters.clearAll", { defaultValue: "Clear filters" })
5235
- })
5236
- ]
5237
- })
5238
- })] });
5239
- }
5240
- //#endregion
5241
5016
  //#region src/data-table/data-table-text-filter.tsx
5242
5017
  function DataTableTextFilter({ column, placeholder, testid, className }) {
5243
5018
  const external = column.getFilterValue() ?? "";
@@ -5393,12 +5168,12 @@ const OPERATOR_LABELS = {
5393
5168
  hasAll: "has all of",
5394
5169
  hasNone: "has none of"
5395
5170
  };
5396
- function formatOperatorLabel(op, t) {
5397
- return t ? t(`filters.operators.${op}`, { defaultValue: OPERATOR_LABELS[op] }) : OPERATOR_LABELS[op];
5171
+ function formatOperatorLabel(op, chromeT) {
5172
+ return chromeT ? chromeT(`filters.operators.${op}`, { defaultValue: OPERATOR_LABELS[op] }) : OPERATOR_LABELS[op];
5398
5173
  }
5399
5174
  function useOperatorLabel() {
5400
- const t = useOptionalT();
5401
- return (op) => formatOperatorLabel(op, t);
5175
+ const chromeT = useChromeT();
5176
+ return (op) => formatOperatorLabel(op, chromeT);
5402
5177
  }
5403
5178
  function isEmpty(v) {
5404
5179
  return v === void 0 || v === null || v === "";
@@ -5492,7 +5267,7 @@ function DataTableOperatorFilter({ column, operators, defaultOperator, valueKind
5492
5267
  //#region src/data-table/data-table-row-actions.tsx
5493
5268
  function DataTableRowActions({ row, actions, getTestId, className }) {
5494
5269
  const [open, setOpen] = useState(false);
5495
- const t = useOptionalT();
5270
+ const chromeT = useChromeT();
5496
5271
  if (actions.length === 0) return null;
5497
5272
  return jsxs(Popover, {
5498
5273
  open,
@@ -5510,7 +5285,7 @@ function DataTableRowActions({ row, actions, getTestId, className }) {
5510
5285
  "aria-hidden": "true"
5511
5286
  }), jsx("span", {
5512
5287
  className: "sr-only",
5513
- children: t("actions.openMenu", { defaultValue: "Open row actions menu" })
5288
+ children: chromeT("actions.openMenu", { defaultValue: "Open row actions menu" })
5514
5289
  })]
5515
5290
  })
5516
5291
  }), jsx(PopoverContent, {
@@ -5631,7 +5406,8 @@ function BlockScreen({ block, props, resource, record, label }) {
5631
5406
  children: jsx(PlannedBody, {
5632
5407
  screen: compiled,
5633
5408
  name: "modal",
5634
- label: label ?? ""
5409
+ label: label ?? "",
5410
+ ...needsRow && row !== null ? { record: row } : {}
5635
5411
  })
5636
5412
  })
5637
5413
  });
@@ -5640,13 +5416,20 @@ function relation(field) {
5640
5416
  if (field === null || typeof field !== "object") return false;
5641
5417
  return isRelationField(field);
5642
5418
  }
5419
+ const resolveOf = (bag) => bag !== null && typeof bag === "object" ? bag.resolve : void 0;
5420
+ function lazyToOne(field) {
5421
+ const entry = field;
5422
+ if (entry.kind === "relationMany" || entry.type === "array") return false;
5423
+ return (resolveOf(entry.meta) ?? resolveOf(entry.opts)) === "lazy";
5424
+ }
5643
5425
  function peekFields(def, columns, capabilityFor, fieldVisible = () => true) {
5644
5426
  const record = new Set(dtoFields(def, "record"));
5645
5427
  const out = [];
5646
5428
  for (const name of columns) {
5647
5429
  if (out.length === 5) break;
5648
5430
  if (name === def.displayField || out.includes(name) || !record.has(name)) continue;
5649
- if (!peekLeafAllowed(def, name, capabilityFor, fieldVisible) || relation(peekFieldDefinition(def, name))) continue;
5431
+ const field = peekFieldDefinition(def, name);
5432
+ if (!peekLeafAllowed(def, name, capabilityFor, fieldVisible) || relation(field) && !lazyToOne(field)) continue;
5650
5433
  out.push(name);
5651
5434
  }
5652
5435
  return Object.freeze(out);
@@ -5729,7 +5512,7 @@ function PeekByKey({ target, by }) {
5729
5512
  } else if (query.error != null) read = failure(query.error, () => void query.refetch());
5730
5513
  else read = { state: "pending" };
5731
5514
  useEffect(() => {
5732
- if (read.state === "ambiguous" && process.env.NODE_ENV !== "production") console.error(`[burojs] ${relationAmbiguousError(target, by.field, by.key).message}`);
5515
+ if (read.state === "ambiguous" && process.env.NODE_ENV !== "production") console.error(`[burojs] ${technicalText(relationAmbiguousError(target, by.field, by.key))}`);
5733
5516
  }, [
5734
5517
  read.state,
5735
5518
  target,
@@ -5745,6 +5528,7 @@ function PeekByKey({ target, by }) {
5745
5528
  function PeekBody({ target, peekKey, read }) {
5746
5529
  const tid = useTestIds();
5747
5530
  const t = useOptionalT();
5531
+ const chromeT = useChromeT();
5748
5532
  const testid = tid.peek(target, peekKey);
5749
5533
  if (read.state === "pending") return jsx("div", {
5750
5534
  "data-testid": testid,
@@ -5772,7 +5556,7 @@ function PeekBody({ target, peekKey, read }) {
5772
5556
  variant: "outline",
5773
5557
  "data-testid": `${testid}:retry`,
5774
5558
  onClick: read.retry,
5775
- children: t("actions.retry", { defaultValue: "Retry" })
5559
+ children: chromeT("actions.retry", { defaultValue: "Retry" })
5776
5560
  })]
5777
5561
  });
5778
5562
  if (read.state === "unavailable") return jsx("p", {
@@ -6000,7 +5784,7 @@ function DefaultPeekBody({ target, testid, row, open }) {
6000
5784
  const columns = useMemo(() => {
6001
5785
  if (def === void 0) return [];
6002
5786
  const listed = def.views?.list?.columns;
6003
- return peekFields(def, listed ?? Object.keys(def.fields), capabilityFor, (name) => access[name]?.view === "visible");
5787
+ return peekFields(def, listed?.map(columnName) ?? Object.keys(def.fields), capabilityFor, (name) => access[name]?.view === "visible");
6004
5788
  }, [
6005
5789
  def,
6006
5790
  capabilityFor,
@@ -6040,13 +5824,21 @@ function DefaultPeekBody({ target, testid, row, open }) {
6040
5824
  children: resolveFieldLabel(caps, name, declaredText("field", field, "label"))
6041
5825
  }), jsx("dd", {
6042
5826
  className: "min-w-0 break-words",
6043
- children: jsx(ResolvedFieldDisplay, {
6044
- resource: ref,
6045
- name,
6046
- field,
5827
+ children: jsx(FieldValueFrame, {
5828
+ field: {
5829
+ ...field,
5830
+ name
5831
+ },
6047
5832
  value,
6048
- record,
6049
- fallback: toDisplayText(value).text
5833
+ surface: "display",
5834
+ children: jsx(ResolvedFieldDisplay, {
5835
+ resource: ref,
5836
+ name,
5837
+ field,
5838
+ value,
5839
+ record,
5840
+ fallback: toDisplayText(value).text
5841
+ })
6050
5842
  })
6051
5843
  })]
6052
5844
  }, name);
@@ -6069,16 +5861,25 @@ function QuickBodyOf({ entry }) {
6069
5861
  route: EMPTY_ROUTE
6070
5862
  });
6071
5863
  if (entry.recordId === void 0 || entry.recordId === "") return jsx(RecordState, { state: "not-found" });
6072
- return jsx(QuickRead, {
5864
+ return jsx(QuickReadRoute, {
6073
5865
  entry,
6074
5866
  recordId: entry.recordId
6075
5867
  });
6076
5868
  }
6077
- function QuickRead({ entry, recordId }) {
5869
+ function QuickReadRoute({ entry, recordId }) {
5870
+ const typed = useRouteRecordId(entry.resource, recordId);
5871
+ if (typed === void 0) return jsx(InvalidRouteId, { resource: entry.resource });
5872
+ return jsx(QuickRead, {
5873
+ entry,
5874
+ recordId,
5875
+ typedId: typed
5876
+ });
5877
+ }
5878
+ function QuickRead({ entry, recordId, typedId }) {
6078
5879
  const def = useApp().registry.get(entry.resource);
6079
5880
  const projection = useMemo(() => def === void 0 ? void 0 : dtoFields(def, "record"), [def]);
6080
5881
  const query = useOne(entry.resource, {
6081
- id: recordId,
5882
+ id: typedId,
6082
5883
  retry: retryRecordRead,
6083
5884
  ...projection === void 0 ? {} : { projection }
6084
5885
  });
@@ -6089,20 +5890,20 @@ function QuickRead({ entry, recordId }) {
6089
5890
  return jsx(QuickLoaded, {
6090
5891
  entry,
6091
5892
  recordId,
5893
+ typedId,
6092
5894
  row,
6093
5895
  isCurrentData: !query.isPlaceholderData
6094
5896
  });
6095
5897
  }
6096
- if (query.error != null) {
6097
- const state = recordErrorState(query.error);
6098
- return jsx(RecordState, {
6099
- state,
6100
- ...state === "error" ? { onRetry: () => void query.refetch() } : {}
6101
- });
6102
- }
5898
+ if (query.error != null) return jsx(LoadError, {
5899
+ surface: "record",
5900
+ resource: entry.resource,
5901
+ error: query.error,
5902
+ retry: () => void query.refetch()
5903
+ });
6103
5904
  return jsx(RecordState, { state: "loading" });
6104
5905
  }
6105
- function QuickLoaded({ entry, recordId, row, isCurrentData }) {
5906
+ function QuickLoaded({ entry, recordId, typedId, row, isCurrentData }) {
6106
5907
  const gate = useEntryGate();
6107
5908
  const quick = useQuickEntry();
6108
5909
  const answer = gate(entry.resource, entry.mode === "edit" ? "edit" : "show", row);
@@ -6122,16 +5923,16 @@ function QuickLoaded({ entry, recordId, row, isCurrentData }) {
6122
5923
  if (!open) return jsx(RecordState, { state: "not-found" });
6123
5924
  return jsx(QuickScreenOf, {
6124
5925
  entry,
6125
- route
5926
+ route,
5927
+ recordId: typedId
6126
5928
  });
6127
5929
  }
6128
5930
  function canonicalOrNull(name) {
6129
- if (typeof name !== "string") return null;
6130
5931
  try {
6131
- return canonicalResourceName(name);
6132
- } catch {
6133
- return null;
6134
- }
5932
+ if (typeof name === "string") return canonicalResourceName(name);
5933
+ if (name !== null && typeof name === "object") return routeResourceKey(name);
5934
+ } catch {}
5935
+ return null;
6135
5936
  }
6136
5937
  function absorbedRedirect(to, entry) {
6137
5938
  if (typeof to !== "object" || to === null) return null;
@@ -6145,7 +5946,7 @@ function closeEntry(quick, dismiss) {
6145
5946
  if (quick.stack.entries.length > 1) quick.stack.pop();
6146
5947
  else dismiss(quick.presentationId);
6147
5948
  }
6148
- function QuickScreenOf({ entry, route }) {
5949
+ function QuickScreenOf({ entry, route, recordId }) {
6149
5950
  const quick = useQuickEntry();
6150
5951
  const instance = useUIInstance();
6151
5952
  const runtime = useUIPresentationRuntime();
@@ -6197,7 +5998,7 @@ function QuickScreenOf({ entry, route }) {
6197
5998
  children: jsx(RecordScreen, {
6198
5999
  resource: entry.resource,
6199
6000
  mode: entry.mode,
6200
- ...entry.recordId === void 0 ? {} : { recordId: entry.recordId },
6001
+ ...recordId === void 0 ? {} : { recordId },
6201
6002
  ...entry.defaults === void 0 ? {} : { defaults: entry.defaults },
6202
6003
  ...entry.input === void 0 ? {} : { input: entry.input },
6203
6004
  ...callbacks
@@ -6219,7 +6020,7 @@ function useEntryTitle(entry) {
6219
6020
  const caps = useI18nCaps(entry.resource);
6220
6021
  const t = useOptionalT();
6221
6022
  if (entry.mode !== "create") return entry.title ?? "";
6222
- return t("pageHeader.createTitle", { params: { label: resolveResourceLabel(caps, entry.resource, "single", app.registry.get(entry.resource)) } });
6023
+ return resolveResourceTitle(caps, t, entry.resource, "createTitle", { label: resolveResourceLabel(caps, entry.resource, "single", app.registry.get(entry.resource)) });
6223
6024
  }
6224
6025
  const HEADING_CLASS = "min-w-0 flex-1 break-words text-lg font-semibold tracking-tight focus-visible:outline-hidden";
6225
6026
  function QuickHeader({ entries }) {
@@ -6476,11 +6277,25 @@ SheetPresentationHost.optionsSchema = Object.freeze({
6476
6277
  //#region src/ui-presentations/index.tsx
6477
6278
  function FlowScreen(props) {
6478
6279
  const loaded = useLoaded(loadFlowScreen);
6479
- if (loaded.error !== void 0) return jsx(FlowLoadFailed, { onRetry: loaded.retry });
6480
- if (loaded.module === void 0) return null;
6280
+ if (loaded.error !== void 0) return jsx(FlowLoadFailed, {
6281
+ label: props.label,
6282
+ onRetry: loaded.retry
6283
+ });
6284
+ if (loaded.module === void 0) return jsxs("div", {
6285
+ "data-buro-flow-step": "loading",
6286
+ "aria-busy": "true",
6287
+ className: "flex flex-col gap-4",
6288
+ children: [jsx(OwnTitleHeading, { label: props.label }), jsx(IconLoader2, {
6289
+ className: "h-5 w-5 animate-spin self-center",
6290
+ "aria-hidden": "true"
6291
+ })]
6292
+ });
6481
6293
  const Screen = loaded.module.FlowScreen;
6482
6294
  return jsx(FlowBoundary, {
6483
- fallback: (_error, reset) => jsx(FlowLoadFailed, { onRetry: reset }),
6295
+ fallback: (_error, reset) => jsx(FlowLoadFailed, {
6296
+ label: props.label,
6297
+ onRetry: reset
6298
+ }),
6484
6299
  children: jsx(Screen, { ...props })
6485
6300
  });
6486
6301
  }
@@ -6755,9 +6570,13 @@ function DefaultCommandPalette({ open, onOpenChange, actions, children }) {
6755
6570
  }
6756
6571
  //#endregion
6757
6572
  //#region src/shell/app-shell.tsx
6758
- function AppShell({ brand, user, loginPath, sidebar, header, palette, docPanel, children }) {
6573
+ function AppShell({ brand, user, loginPath, sidebar, header, palette, docPanel, navChrome, children }) {
6759
6574
  const enabled = palette !== false;
6760
- const { open, setOpen } = useCommandPalette({ disableShortcut: !enabled });
6575
+ const { open, setOpen, toggle } = useCommandPalette();
6576
+ useGlobalShortcut({
6577
+ key: "k",
6578
+ mod: true
6579
+ }, toggle, { enabled });
6761
6580
  const paletteState = useMemo(() => ({
6762
6581
  open,
6763
6582
  setOpen
@@ -6775,7 +6594,7 @@ function AppShell({ brand, user, loginPath, sidebar, header, palette, docPanel,
6775
6594
  sidebar: fill(sidebar, () => jsx(AppSidebar, {})),
6776
6595
  header: fill(header, () => jsx(AppHeader, {})),
6777
6596
  ...docPanel !== void 0 ? { docPanel } : {},
6778
- children
6597
+ children: navChrome === false ? children : jsx(NavChrome, { children })
6779
6598
  }), paletteNode]
6780
6599
  });
6781
6600
  }
@@ -6883,6 +6702,6 @@ function ScopeSwitcher({ options, value, onChange, label, extra, placeholder })
6883
6702
  const PACKAGE_NAME = "@burojs/ui-shadcn";
6884
6703
  const PACKAGE_VERSION = "0.0.0";
6885
6704
  //#endregion
6886
- 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, 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, NavAreaLayout, NavAreaPage, NavChrome, NavChromeBoundaryProvider, NavMain, NavigationGuardDialog, NumberDisplay, NumberInput, PACKAGE_NAME, PACKAGE_VERSION, PageHeader, PinnedFilterControls, Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverPresentationHost, PopoverTrigger, Progress, RecordActions, RecordBreadcrumbs, RecordPage, RecordScreen, RecordTitle, RefreshButton, RelationDisplay, RelationField, RelationManyDisplay, RelationPicker, LazyRelationPickerDialog as RelationPickerDialog, RelationPickerInput, ResourceList, ResourceListPage, ResourcePageRouter, SavedViewsDropdown, 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, useNavChromeBoundary, useNavIcon, useNavTree, useNavVisible, useOptionalSidebar, usePaletteState, usePresentationCopy, useRelationPicker, useShell, useSidebar, useTheme, useThemePaletteActions, wrapperEnabled };
6705
+ 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, 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 };
6887
6706
 
6888
6707
  //# sourceMappingURL=index.js.map