@burojs/ui-shadcn 0.4.0 → 0.6.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 (131) hide show
  1. package/README.md +22 -5
  2. package/dist/bulk-summary-CwSd6Yjb.cjs +108 -0
  3. package/dist/bulk-summary-CwSd6Yjb.cjs.map +1 -0
  4. package/dist/bulk-summary-GxMDP4bw.js +108 -0
  5. package/dist/bulk-summary-GxMDP4bw.js.map +1 -0
  6. package/dist/button-BxnnE28H.cjs +55 -0
  7. package/dist/button-BxnnE28H.cjs.map +1 -0
  8. package/dist/button-MWVeZaqj.js +44 -0
  9. package/dist/button-MWVeZaqj.js.map +1 -0
  10. package/dist/candidates-gate-Bb70LPAy.js +135 -0
  11. package/dist/candidates-gate-Bb70LPAy.js.map +1 -0
  12. package/dist/candidates-gate-D33jXLHO.cjs +153 -0
  13. package/dist/candidates-gate-D33jXLHO.cjs.map +1 -0
  14. package/dist/candidates-relation-picker-B116Bmqi.js +31 -0
  15. package/dist/candidates-relation-picker-B116Bmqi.js.map +1 -0
  16. package/dist/candidates-relation-picker-Cy0rTxvI.cjs +31 -0
  17. package/dist/candidates-relation-picker-Cy0rTxvI.cjs.map +1 -0
  18. package/dist/check-confirm-dialog--gPFnEeg.cjs +1547 -0
  19. package/dist/check-confirm-dialog--gPFnEeg.cjs.map +1 -0
  20. package/dist/check-confirm-dialog-bRT8lt0d.js +1245 -0
  21. package/dist/check-confirm-dialog-bRT8lt0d.js.map +1 -0
  22. package/dist/dialog-B_rt9S1c.js +63 -0
  23. package/dist/dialog-B_rt9S1c.js.map +1 -0
  24. package/dist/dialog-DRNUq9EA.cjs +112 -0
  25. package/dist/dialog-DRNUq9EA.cjs.map +1 -0
  26. package/dist/filter-builder-Bhn-dhZV.js +1621 -0
  27. package/dist/filter-builder-Bhn-dhZV.js.map +1 -0
  28. package/dist/filter-builder-nXqtM_h4.cjs +1789 -0
  29. package/dist/filter-builder-nXqtM_h4.cjs.map +1 -0
  30. package/dist/flow-runtime-D3avVH0I.cjs +255 -0
  31. package/dist/flow-runtime-D3avVH0I.cjs.map +1 -0
  32. package/dist/flow-runtime-s6lkRPKF.js +252 -0
  33. package/dist/flow-runtime-s6lkRPKF.js.map +1 -0
  34. package/dist/flow-screen-CCvgDI9G.js +704 -0
  35. package/dist/flow-screen-CCvgDI9G.js.map +1 -0
  36. package/dist/flow-screen-Ci_Sik4Y.cjs +708 -0
  37. package/dist/flow-screen-Ci_Sik4Y.cjs.map +1 -0
  38. package/dist/index.cjs +3420 -11986
  39. package/dist/index.cjs.map +1 -1
  40. package/dist/index.d.cts +1843 -2015
  41. package/dist/index.d.ts +1849 -2021
  42. package/dist/index.js +3090 -11675
  43. package/dist/index.js.map +1 -1
  44. package/dist/inline-flow-host-B6FI0ctQ.js +112 -0
  45. package/dist/inline-flow-host-B6FI0ctQ.js.map +1 -0
  46. package/dist/inline-flow-host-DV1et3c6.cjs +112 -0
  47. package/dist/inline-flow-host-DV1et3c6.cjs.map +1 -0
  48. package/dist/input-BI0czGyI.cjs +23 -0
  49. package/dist/input-BI0czGyI.cjs.map +1 -0
  50. package/dist/input-CUPStzZO.js +17 -0
  51. package/dist/input-CUPStzZO.js.map +1 -0
  52. package/dist/label-66W1qbke.js +29 -0
  53. package/dist/label-66W1qbke.js.map +1 -0
  54. package/dist/label-w6JYf2cF.cjs +36 -0
  55. package/dist/label-w6JYf2cF.cjs.map +1 -0
  56. package/dist/markdown/index.cjs +1 -1
  57. package/dist/markdown/index.d.cts +2 -3
  58. package/dist/markdown/index.d.ts +2 -3
  59. package/dist/markdown/index.js +1 -1
  60. package/dist/page-flow-route-hdnULWqd.cjs +277 -0
  61. package/dist/page-flow-route-hdnULWqd.cjs.map +1 -0
  62. package/dist/page-flow-route-i3ZfJ1sd.js +277 -0
  63. package/dist/page-flow-route-i3ZfJ1sd.js.map +1 -0
  64. package/dist/place-node-C5SmIAYU.cjs +8139 -0
  65. package/dist/place-node-C5SmIAYU.cjs.map +1 -0
  66. package/dist/place-node-NraNYKPx.js +7597 -0
  67. package/dist/place-node-NraNYKPx.js.map +1 -0
  68. package/dist/related-list-cards-BWZ9GfOG.js +42 -0
  69. package/dist/related-list-cards-BWZ9GfOG.js.map +1 -0
  70. package/dist/related-list-cards-CFq3meUn.cjs +42 -0
  71. package/dist/related-list-cards-CFq3meUn.cjs.map +1 -0
  72. package/dist/related-list-timeline-CCzl71aA.cjs +142 -0
  73. package/dist/related-list-timeline-CCzl71aA.cjs.map +1 -0
  74. package/dist/related-list-timeline-yrPsjA3F.js +142 -0
  75. package/dist/related-list-timeline-yrPsjA3F.js.map +1 -0
  76. package/dist/related-rows-ea43qhhy.cjs +208 -0
  77. package/dist/related-rows-ea43qhhy.cjs.map +1 -0
  78. package/dist/related-rows-o0_t-Yce.js +185 -0
  79. package/dist/related-rows-o0_t-Yce.js.map +1 -0
  80. package/dist/relation-create-IA40t1hi.cjs +364 -0
  81. package/dist/relation-create-IA40t1hi.cjs.map +1 -0
  82. package/dist/relation-create-h6F9B4C4.js +339 -0
  83. package/dist/relation-create-h6F9B4C4.js.map +1 -0
  84. package/dist/relation-many-picker-C8zFEjwd.cjs +467 -0
  85. package/dist/relation-many-picker-C8zFEjwd.cjs.map +1 -0
  86. package/dist/relation-many-picker-bvkjkv-k.js +466 -0
  87. package/dist/relation-many-picker-bvkjkv-k.js.map +1 -0
  88. package/dist/relation-picker-Z0ZJJ5uS.js +493 -0
  89. package/dist/relation-picker-Z0ZJJ5uS.js.map +1 -0
  90. package/dist/relation-picker-dialog-0IzkjmiA.cjs +304 -0
  91. package/dist/relation-picker-dialog-0IzkjmiA.cjs.map +1 -0
  92. package/dist/relation-picker-dialog-B6nIiJBf.js +303 -0
  93. package/dist/relation-picker-dialog-B6nIiJBf.js.map +1 -0
  94. package/dist/relation-picker-gag0qSR5.cjs +516 -0
  95. package/dist/relation-picker-gag0qSR5.cjs.map +1 -0
  96. package/dist/resource-page-router-3RUf9d1j.js +1588 -0
  97. package/dist/resource-page-router-3RUf9d1j.js.map +1 -0
  98. package/dist/resource-page-router-PXfMW9nh.cjs +1785 -0
  99. package/dist/resource-page-router-PXfMW9nh.cjs.map +1 -0
  100. package/dist/{rich-text-IDFvyvRE.js → rich-text-DFerywgz.js} +7 -4
  101. package/dist/{rich-text-IDFvyvRE.js.map → rich-text-DFerywgz.js.map} +1 -1
  102. package/dist/{rich-text-lndbYqzR.cjs → rich-text-vTyVjDoa.cjs} +25 -22
  103. package/dist/{rich-text-lndbYqzR.cjs.map → rich-text-vTyVjDoa.cjs.map} +1 -1
  104. package/dist/search-access-CPPmfuvy.js +654 -0
  105. package/dist/search-access-CPPmfuvy.js.map +1 -0
  106. package/dist/search-access-Dugvttlg.cjs +791 -0
  107. package/dist/search-access-Dugvttlg.cjs.map +1 -0
  108. package/dist/shell-BPlk8hEa.js +205 -0
  109. package/dist/shell-BPlk8hEa.js.map +1 -0
  110. package/dist/shell-DxhlsPwm.cjs +271 -0
  111. package/dist/shell-DxhlsPwm.cjs.map +1 -0
  112. package/dist/skeleton-U2noefj5.js +13 -0
  113. package/dist/skeleton-U2noefj5.js.map +1 -0
  114. package/dist/skeleton-_1gP7wan.cjs +18 -0
  115. package/dist/skeleton-_1gP7wan.cjs.map +1 -0
  116. package/dist/styles.css +241 -9
  117. package/dist/toaster-C02XbB9r.js +135 -0
  118. package/dist/toaster-C02XbB9r.js.map +1 -0
  119. package/dist/toaster-Cr51X7bz.cjs +195 -0
  120. package/dist/toaster-Cr51X7bz.cjs.map +1 -0
  121. package/dist/use-dialog-filter-state-C--oMAZG.js +87 -0
  122. package/dist/use-dialog-filter-state-C--oMAZG.js.map +1 -0
  123. package/dist/use-dialog-filter-state-Dhe8PcB5.cjs +92 -0
  124. package/dist/use-dialog-filter-state-Dhe8PcB5.cjs.map +1 -0
  125. package/dist/{use-theme-BwPWinB2.cjs → use-theme-DFlpXils.cjs} +12 -1
  126. package/dist/use-theme-DFlpXils.cjs.map +1 -0
  127. package/dist/{use-theme-IHmtrhEt.js → use-theme-dnE3Od3I.js} +7 -2
  128. package/dist/use-theme-dnE3Od3I.js.map +1 -0
  129. package/package.json +16 -14
  130. package/dist/use-theme-BwPWinB2.cjs.map +0 -1
  131. package/dist/use-theme-IHmtrhEt.js.map +0 -1
@@ -0,0 +1,1245 @@
1
+ import { l as cn } from "./use-theme-dnE3Od3I.js";
2
+ import { d as PopoverTrigger, n as toast, o as useLinkComponent, s as Popover, u as PopoverContent } from "./toaster-C02XbB9r.js";
3
+ import { t as Button } from "./button-MWVeZaqj.js";
4
+ import { a as DialogFooter, i as DialogDescription, o as DialogHeader, r as DialogContent, s as DialogTitle, t as Dialog } from "./dialog-B_rt9S1c.js";
5
+ import { FRAMEWORK_TEXT_KEYS, canonicalEntityNodeKey, checkFailedDefault, compileFlow, declaredText, docAddressToArticle, hasRecordPage, hrefFor, humanizeKey, isBuiltinItemAction, normalizeEntityRef, recordEntries, resolveContentSlot, resolveDocSee } from "@burojs/core";
6
+ import { buildDI, conjoinHostPage, modeForSurface, resolveRoute, useApp, useAvailabilityResolver, useComponent, useDoc, useDocPanel, useDocTopics, useEntryGate, useFlowRowResolver, useHostPage, useI18nCaps, useOptionalRouterAdapter, useOptionalT, usePresentBlock, usePresentFlow, useProjectedTitle, useQuick, useQuickEntry, useTestIds, useUIInstance } from "@burojs/react";
7
+ import { IconArrowRight, IconArrowUpRight, IconArrowsLeftRight, IconBan, IconBell, IconBox, IconBoxMultiple, IconBuilding, IconCheck, IconChevronRight, IconCircle, IconCircleCaretRight, IconCircleCheck, IconCircleX, IconClipboardList, IconClock, IconCopy, IconDots, IconEye, IconFileOff, IconFilePencil, IconFileText, IconFileX, IconGitBranch, IconHammer, IconHash, IconHistory, IconInfoHexagon, IconKey, IconKeyOff, IconLink, IconList, IconLoader2, IconMapPin, IconNetwork, IconPackage, IconPackageExport, IconPackageImport, IconPackageOff, IconPackages, IconPencil, IconPlayerPlay, IconPlayerTrackNext, IconPlus, IconQrcode, IconRefresh, IconRotate, IconScript, IconSettings, IconShieldCheck, IconTag, IconTool, IconTrash, IconTruck, IconUserPlus, IconUsers, IconX } from "@tabler/icons-react";
8
+ import * as React from "react";
9
+ import { Component, useCallback, useEffect, useMemo, useRef, useState } from "react";
10
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
11
+ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
12
+ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
13
+ import { evaluateCondition, isFlowAction } from "@burojs/core/internal";
14
+ //#region src/doc/doc-info.tsx
15
+ function DocInfo({ address, name, testId, className }) {
16
+ const doc = useDoc(address);
17
+ const caps = useI18nCaps();
18
+ const t = useOptionalT();
19
+ const { openPanel } = useDocPanel();
20
+ const [open, setOpen] = useState(false);
21
+ const see = resolveDocSee(caps, address);
22
+ const { scope: articleScope, topicId: ownTopicId } = docAddressToArticle(see ?? address);
23
+ const topics = useDocTopics(articleScope);
24
+ const hasOwnArticle = ownTopicId === void 0 ? topics.length > 0 : topics.some((x) => x.id === ownTopicId);
25
+ if (!doc && !hasOwnArticle) return null;
26
+ const id = testId ?? `doc-info:${address}`;
27
+ const newTabNote = t("docPanel.opensInNewTab", { defaultValue: "(opens in a new tab)" });
28
+ const hasSummary = doc?.summary !== void 0;
29
+ const hasLinks = doc?.links !== void 0 && doc.links.length > 0;
30
+ return jsxs(Popover, {
31
+ open,
32
+ onOpenChange: setOpen,
33
+ children: [jsx(PopoverTrigger, {
34
+ asChild: true,
35
+ children: jsx("button", {
36
+ type: "button",
37
+ "aria-haspopup": "dialog",
38
+ "aria-label": t("docPanel.openFor", {
39
+ params: { name },
40
+ defaultValue: `Help: ${name}`
41
+ }),
42
+ "data-testid": id,
43
+ className: cn("inline-flex size-6 min-h-[24px] min-w-[24px] shrink-0 items-center justify-center rounded-full", "text-muted-foreground", "transition-colors duration-150", "hover:bg-muted hover:text-foreground", "data-[state=open]:bg-muted data-[state=open]:text-foreground", "focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background", className),
44
+ children: jsx(IconInfoHexagon, {
45
+ className: "size-3.5",
46
+ "aria-hidden": "true"
47
+ })
48
+ })
49
+ }), jsxs(PopoverContent, {
50
+ role: "dialog",
51
+ "aria-label": name,
52
+ className: cn("w-auto min-w-[16rem] max-w-[22rem]", "max-h-[min(24rem,60vh)] overflow-y-auto overscroll-contain", "space-y-2.5"),
53
+ "data-testid": `${id}:content`,
54
+ children: [
55
+ hasSummary && jsx("p", {
56
+ className: "text-[0.8125rem] leading-[1.6] text-foreground",
57
+ children: doc?.summary
58
+ }),
59
+ hasOwnArticle && jsxs("button", {
60
+ type: "button",
61
+ "data-testid": `${id}:more`,
62
+ onClick: () => {
63
+ setOpen(false);
64
+ openPanel(ownTopicId === void 0 ? { scopes: [articleScope] } : {
65
+ scopes: [articleScope],
66
+ topicId: ownTopicId
67
+ }, id);
68
+ },
69
+ className: cn("inline-flex items-center gap-1 rounded-sm text-[0.8125rem] font-medium text-primary", "hover:underline underline-offset-2", "focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"),
70
+ children: [t("docPanel.readMore", { defaultValue: "Read more" }), jsx(IconArrowRight, {
71
+ className: "size-3.5 shrink-0",
72
+ "aria-hidden": "true"
73
+ })]
74
+ }),
75
+ hasLinks && jsx("div", {
76
+ className: cn("flex flex-col items-start gap-1.5", hasSummary && "border-t border-border/60 pt-2.5"),
77
+ children: doc?.links?.map((link) => jsxs("a", {
78
+ href: link.href,
79
+ target: "_blank",
80
+ rel: "noopener noreferrer",
81
+ className: cn("group inline-flex max-w-full items-center gap-1 rounded-sm", "text-[0.8125rem] font-medium text-primary", "hover:underline underline-offset-2", "focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"),
82
+ children: [
83
+ jsx("span", {
84
+ className: "min-w-0 truncate",
85
+ children: link.label
86
+ }),
87
+ jsx(IconArrowUpRight, {
88
+ className: "size-3.5 shrink-0 transition-transform duration-150 group-hover:-translate-y-px group-hover:translate-x-px",
89
+ "aria-hidden": "true"
90
+ }),
91
+ jsx("span", {
92
+ className: "sr-only",
93
+ children: newTabNote
94
+ })
95
+ ]
96
+ }, link.href))
97
+ })
98
+ ]
99
+ })]
100
+ });
101
+ }
102
+ //#endregion
103
+ //#region src/primitives/tooltip.tsx
104
+ const TooltipProvider = TooltipPrimitive.Provider;
105
+ const Tooltip = TooltipPrimitive.Root;
106
+ const TooltipTrigger = TooltipPrimitive.Trigger;
107
+ const TooltipContent = React.forwardRef(({ className, sideOffset = 4, ...props }, ref) => jsx(TooltipPrimitive.Portal, { children: jsx(TooltipPrimitive.Content, {
108
+ ref,
109
+ sideOffset,
110
+ className: cn("z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md duration-[var(--duration-overlay)] ease-[var(--ease-overlay)] animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", className),
111
+ ...props
112
+ }) }));
113
+ TooltipContent.displayName = TooltipPrimitive.Content.displayName;
114
+ //#endregion
115
+ //#region src/primitives/dropdown-menu.tsx
116
+ const DropdownMenu = DropdownMenuPrimitive.Root;
117
+ const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
118
+ const DropdownMenuGroup = DropdownMenuPrimitive.Group;
119
+ const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
120
+ const DropdownMenuSub = DropdownMenuPrimitive.Sub;
121
+ const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
122
+ const DropdownMenuSubTrigger = React.forwardRef(({ className, inset, children, ...props }, ref) => jsxs(DropdownMenuPrimitive.SubTrigger, {
123
+ ref,
124
+ className: cn("flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", inset && "pl-8", className),
125
+ ...props,
126
+ children: [children, jsx(IconChevronRight, { className: "ml-auto" })]
127
+ }));
128
+ DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
129
+ const DropdownMenuSubContent = React.forwardRef(({ className, ...props }, ref) => jsx(DropdownMenuPrimitive.SubContent, {
130
+ ref,
131
+ className: cn("z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg duration-[var(--duration-overlay)] ease-[var(--ease-overlay)] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", className),
132
+ ...props
133
+ }));
134
+ DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
135
+ const DropdownMenuContent = React.forwardRef(({ className, sideOffset = 4, ...props }, ref) => jsx(DropdownMenuPrimitive.Portal, { children: jsx(DropdownMenuPrimitive.Content, {
136
+ ref,
137
+ sideOffset,
138
+ className: cn("z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md duration-[var(--duration-overlay)] ease-[var(--ease-overlay)] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", className),
139
+ ...props
140
+ }) }));
141
+ DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
142
+ const DropdownMenuItem = React.forwardRef(({ className, inset, ...props }, ref) => jsx(DropdownMenuPrimitive.Item, {
143
+ ref,
144
+ className: cn("relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", inset && "pl-8", className),
145
+ ...props
146
+ }));
147
+ DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
148
+ const DropdownMenuCheckboxItem = React.forwardRef(({ className, children, checked, ...props }, ref) => jsxs(DropdownMenuPrimitive.CheckboxItem, {
149
+ ref,
150
+ className: cn("relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-hidden transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className),
151
+ checked,
152
+ ...props,
153
+ children: [jsx("span", {
154
+ className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center",
155
+ children: jsx(DropdownMenuPrimitive.ItemIndicator, { children: jsx(IconCheck, { className: "h-4 w-4" }) })
156
+ }), children]
157
+ }));
158
+ DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
159
+ const DropdownMenuRadioItem = React.forwardRef(({ className, children, ...props }, ref) => jsxs(DropdownMenuPrimitive.RadioItem, {
160
+ ref,
161
+ className: cn("relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-hidden transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className),
162
+ ...props,
163
+ children: [jsx("span", {
164
+ className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center",
165
+ children: jsx(DropdownMenuPrimitive.ItemIndicator, { children: jsx(IconCircle, { className: "h-2 w-2 fill-current" }) })
166
+ }), children]
167
+ }));
168
+ DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
169
+ const DropdownMenuLabel = React.forwardRef(({ className, inset, ...props }, ref) => jsx(DropdownMenuPrimitive.Label, {
170
+ ref,
171
+ className: cn("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className),
172
+ ...props
173
+ }));
174
+ DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
175
+ const DropdownMenuSeparator = React.forwardRef(({ className, ...props }, ref) => jsx(DropdownMenuPrimitive.Separator, {
176
+ ref,
177
+ className: cn("-mx-1 my-1 h-px bg-muted", className),
178
+ ...props
179
+ }));
180
+ DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
181
+ function DropdownMenuShortcut({ className, ...props }) {
182
+ return jsx("span", {
183
+ className: cn("ml-auto text-xs tracking-widest opacity-60", className),
184
+ ...props
185
+ });
186
+ }
187
+ DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
188
+ //#endregion
189
+ //#region src/primitives/icon.tsx
190
+ const REGISTRY = {
191
+ Play: IconPlayerPlay,
192
+ PlayCircle: IconCircleCaretRight,
193
+ StepForward: IconPlayerTrackNext,
194
+ RotateCcw: IconRotate,
195
+ RefreshCw: IconRefresh,
196
+ Ban: IconBan,
197
+ XCircle: IconCircleX,
198
+ Trash2: IconTrash,
199
+ Copy: IconCopy,
200
+ Hash: IconHash,
201
+ QrCode: IconQrcode,
202
+ Network: IconNetwork,
203
+ GitBranch: IconGitBranch,
204
+ Link: IconLink,
205
+ Link2: IconLink,
206
+ Pencil: IconPencil,
207
+ Plus: IconPlus,
208
+ Eye: IconEye,
209
+ ScrollText: IconScript,
210
+ History: IconHistory,
211
+ MoreHorizontal: IconDots,
212
+ Circle: IconCircle,
213
+ CircleCheck: IconCircleCheck,
214
+ Clock: IconClock,
215
+ Package: IconPackage,
216
+ PackagePlus: IconPackageImport,
217
+ PackageMinus: IconPackageExport,
218
+ PackageCheck: IconPackages,
219
+ PackageX: IconPackageOff,
220
+ PackageOpen: IconBox,
221
+ ArrowRightLeft: IconArrowsLeftRight,
222
+ FileText: IconFileText,
223
+ FileEdit: IconFilePencil,
224
+ FileX: IconFileX,
225
+ FileX2: IconFileOff,
226
+ Truck: IconTruck,
227
+ Wrench: IconTool,
228
+ Hammer: IconHammer,
229
+ Settings: IconSettings,
230
+ Bell: IconBell,
231
+ Building2: IconBuilding,
232
+ MapPin: IconMapPin,
233
+ Users: IconUsers,
234
+ UserPlus: IconUserPlus,
235
+ Boxes: IconBoxMultiple,
236
+ Tag: IconTag,
237
+ ShieldCheck: IconShieldCheck,
238
+ Key: IconKey,
239
+ KeyOff: IconKeyOff,
240
+ ClipboardList: IconClipboardList,
241
+ List: IconList,
242
+ Check: IconCheck,
243
+ X: IconX
244
+ };
245
+ function registerIcons(map) {
246
+ Object.assign(REGISTRY, map);
247
+ }
248
+ function hasIcon(name) {
249
+ return Object.hasOwn(REGISTRY, name);
250
+ }
251
+ function Icon({ name, className }) {
252
+ const Cmp = (name ? REGISTRY[name] : void 0) ?? IconCircle;
253
+ return jsx(Cmp, {
254
+ className: cn("h-4 w-4", className),
255
+ "aria-hidden": "true"
256
+ });
257
+ }
258
+ //#endregion
259
+ //#region src/flows/load-runtime.tsx
260
+ function retrying(importer) {
261
+ let loading;
262
+ return () => {
263
+ loading ??= importer().catch((error) => {
264
+ loading = void 0;
265
+ throw error;
266
+ });
267
+ return loading;
268
+ };
269
+ }
270
+ const loadFlowRuntime = retrying(() => import("./flow-runtime-s6lkRPKF.js"));
271
+ const loadFlowScreen = retrying(() => import("./flow-screen-CCvgDI9G.js"));
272
+ const loadPageFlowRoute = retrying(() => import("./page-flow-route-i3ZfJ1sd.js"));
273
+ const loadInlineFlowHost = retrying(() => import("./inline-flow-host-B6FI0ctQ.js"));
274
+ const loadBulkSummary = retrying(() => import("./bulk-summary-GxMDP4bw.js"));
275
+ function preloadFlowRuntime() {
276
+ loadFlowRuntime().catch(() => void 0);
277
+ }
278
+ function useLoaded(loader) {
279
+ const [attempt, setAttempt] = useState(0);
280
+ const [state, setState] = useState({});
281
+ useEffect(() => {
282
+ let live = true;
283
+ loader().then((module) => {
284
+ if (live) setState({ module });
285
+ }, (error) => {
286
+ if (live) setState({ error });
287
+ });
288
+ return () => {
289
+ live = false;
290
+ };
291
+ }, [loader, attempt]);
292
+ const retry = useCallback(() => {
293
+ setState({});
294
+ setAttempt((value) => value + 1);
295
+ }, []);
296
+ return {
297
+ ...state,
298
+ retry
299
+ };
300
+ }
301
+ var FlowBoundary = class extends Component {
302
+ state = { error: void 0 };
303
+ static getDerivedStateFromError(error) {
304
+ return { error: error ?? new Error("unknown") };
305
+ }
306
+ componentDidCatch(error, info) {
307
+ if (process.env.NODE_ENV !== "production") console.error("[burojs] A flow failed to render.", error, info.componentStack);
308
+ }
309
+ render() {
310
+ if (this.state.error !== void 0) return this.props.fallback(this.state.error, () => this.setState({ error: void 0 }));
311
+ return this.props.children;
312
+ }
313
+ };
314
+ function loadFailedText(t) {
315
+ const value = t("block.failed");
316
+ return value === "block.failed" ? "This section could not be loaded." : value;
317
+ }
318
+ function FailedRun({ onDone }) {
319
+ const t = useOptionalT();
320
+ useEffect(() => {
321
+ toast(loadFailedText(t));
322
+ onDone();
323
+ }, [t, onDone]);
324
+ return null;
325
+ }
326
+ function RuntimeFlowRunner(props) {
327
+ const loaded = useLoaded(loadFlowRuntime);
328
+ if (loaded.error !== void 0) return jsx(FailedRun, { onDone: props.onClose });
329
+ if (loaded.module === void 0) return null;
330
+ const Runner = loaded.module.FlowRunner;
331
+ return jsx(FlowBoundary, {
332
+ fallback: () => jsx(FailedRun, { onDone: props.onClose }),
333
+ children: jsx(Runner, { ...props })
334
+ });
335
+ }
336
+ function RuntimeAppFlowRunner(props) {
337
+ const loaded = useLoaded(loadFlowRuntime);
338
+ if (loaded.error !== void 0) return jsx(FailedRun, { onDone: props.onClose });
339
+ if (loaded.module === void 0) return null;
340
+ const Runner = loaded.module.AppFlowRunner;
341
+ return jsx(FlowBoundary, {
342
+ fallback: () => jsx(FailedRun, { onDone: props.onClose }),
343
+ children: jsx(Runner, { ...props })
344
+ });
345
+ }
346
+ function RuntimeBulkFlowRunner(props) {
347
+ const loaded = useLoaded(loadFlowRuntime);
348
+ const done = useCallback(() => props.onFinish(Object.freeze({ outcome: "failed" }), void 0), [props.onFinish]);
349
+ if (loaded.error !== void 0) return jsx(FailedRun, { onDone: done });
350
+ if (loaded.module === void 0) return null;
351
+ const Runner = loaded.module.BulkFlowRunner;
352
+ return jsx(FlowBoundary, {
353
+ fallback: () => jsx(FailedRun, { onDone: done }),
354
+ children: jsx(Runner, { ...props })
355
+ });
356
+ }
357
+ function FlowLoadFailed({ onRetry }) {
358
+ const t = useOptionalT();
359
+ const instance = useUIInstance();
360
+ const retryText = t("actions.retry") === "actions.retry" ? "Retry" : t("actions.retry");
361
+ const closeText = t("flow.close") === "flow.close" ? "Close" : t("flow.close");
362
+ return jsxs("div", {
363
+ role: "alert",
364
+ "data-buro-flow-load": "failed",
365
+ className: "flex flex-col gap-3 text-sm",
366
+ children: [jsx("p", { children: loadFailedText(t) }), jsxs("div", {
367
+ className: "flex justify-end gap-2",
368
+ children: [jsx(Button, {
369
+ type: "button",
370
+ variant: "ghost",
371
+ onClick: () => instance.dismiss(),
372
+ children: closeText
373
+ }), jsx(Button, {
374
+ type: "button",
375
+ onClick: onRetry,
376
+ children: retryText
377
+ })]
378
+ })]
379
+ });
380
+ }
381
+ //#endregion
382
+ //#region src/actions/action-inner.tsx
383
+ function ActionInner({ icon, label }) {
384
+ return jsxs(Fragment$1, { children: [icon ? jsx(Icon, { name: icon }) : null, label] });
385
+ }
386
+ //#endregion
387
+ //#region src/actions/action-control.tsx
388
+ const warned = new Set();
389
+ function resolveControlChrome(args) {
390
+ const { density, icon, label, actionName, surface } = args;
391
+ if (density === "compact" && icon == null) {
392
+ const key = `${actionName}@${surface}`;
393
+ if (!warned.has(key)) {
394
+ warned.add(key);
395
+ console.warn(`[buro] action "${actionName}" is declared 'compact' on surface "${surface}" but has no icon; rendering it with its label instead. Give the action an \`icon\`, or declare 'regular'.`);
396
+ }
397
+ return {
398
+ compact: false,
399
+ size: "sm",
400
+ className: void 0,
401
+ ariaLabel: void 0,
402
+ content: jsx(ActionInner, {
403
+ icon,
404
+ label
405
+ })
406
+ };
407
+ }
408
+ if (density === "compact") return {
409
+ compact: true,
410
+ size: "icon",
411
+ className: surface === "row" ? "size-7" : "h-8 w-8",
412
+ ariaLabel: typeof label === "string" ? label : humanizeKey(actionName),
413
+ content: jsx(Icon, { name: icon })
414
+ };
415
+ return {
416
+ compact: false,
417
+ size: "sm",
418
+ className: void 0,
419
+ ariaLabel: void 0,
420
+ content: jsx(ActionInner, {
421
+ icon,
422
+ label
423
+ })
424
+ };
425
+ }
426
+ function withActionTooltip(control, label, compact, reason) {
427
+ if (!compact && reason === void 0) return control;
428
+ const tooltip = jsxs(Tooltip, { children: [jsx(TooltipTrigger, {
429
+ asChild: true,
430
+ children: control
431
+ }), jsxs(TooltipContent, { children: [label, reason === void 0 ? null : jsx("span", {
432
+ className: "block opacity-80",
433
+ children: reason
434
+ })] })] });
435
+ return compact ? tooltip : jsx(TooltipProvider, { children: tooltip });
436
+ }
437
+ //#endregion
438
+ //#region src/flows/chrome.ts
439
+ const text = (t, key, fallback, params) => {
440
+ const value = t(key, params === void 0 ? void 0 : { params });
441
+ return value === key ? fallback : value;
442
+ };
443
+ function findDeclared(def, name) {
444
+ const actions = def?.actions ?? {};
445
+ for (const place of [
446
+ "item",
447
+ "resource",
448
+ "bulk"
449
+ ]) {
450
+ const list = actions[place];
451
+ if (!Array.isArray(list)) continue;
452
+ const found = list.find((entry) => entry.name === name);
453
+ if (found !== void 0) return found;
454
+ }
455
+ }
456
+ function useFlowChrome(resource, actionName, children) {
457
+ const app = useApp();
458
+ const declared = (resource === "" ? void 0 : findDeclared(app.registry.get(resource), actionName)) ?? {};
459
+ const label = useResolvedLabel(declared, actionName, children, resource);
460
+ return {
461
+ label,
462
+ labelText: typeof label === "string" ? label : humanizeKey(actionName),
463
+ icon: resolveActionIcon(declared, actionName),
464
+ destructive: declared.variant === "destructive"
465
+ };
466
+ }
467
+ //#endregion
468
+ //#region src/flows/flow-action-button.tsx
469
+ const DESTRUCTIVE_ITEM$1 = "text-destructive focus:bg-destructive/10 focus:text-destructive data-[highlighted]:text-destructive";
470
+ function FlowControl(props) {
471
+ const { state, chrome, testid, resource, actionName, scope, asMenuItem, density } = props;
472
+ const Anchor = useLinkComponent();
473
+ if (state === "absent") return null;
474
+ const buttonVariant = props.variant ?? (chrome.destructive ? "destructive" : "outline");
475
+ if (state === "disabled") return jsx(DisabledAction, {
476
+ reason: props.reason,
477
+ label: chrome.label,
478
+ icon: chrome.icon,
479
+ testid,
480
+ size: props.size,
481
+ variant: buttonVariant,
482
+ className: props.className,
483
+ asMenuItem,
484
+ resource,
485
+ density,
486
+ actionName,
487
+ surface: scope
488
+ });
489
+ const running = state === "running" || props.active === true;
490
+ const busy = state === "undecided" || state === "pending" || running;
491
+ if (props.href !== void 0 && !busy) {
492
+ if (asMenuItem === true) return jsx(DropdownMenuItem, {
493
+ asChild: true,
494
+ className: cn(chrome.destructive && DESTRUCTIVE_ITEM$1),
495
+ children: jsx(Anchor, {
496
+ href: props.href,
497
+ "data-testid": testid,
498
+ "data-buro-flow-state": state,
499
+ onClick: (event) => event.stopPropagation(),
500
+ children: jsx(ActionInner, {
501
+ icon: chrome.icon,
502
+ label: chrome.label
503
+ })
504
+ })
505
+ });
506
+ const linkChrome = resolveControlChrome({
507
+ density: density ?? "regular",
508
+ icon: chrome.icon,
509
+ label: chrome.label,
510
+ actionName,
511
+ surface: scope
512
+ });
513
+ return withActionTooltip(jsx(Button, {
514
+ asChild: true,
515
+ variant: buttonVariant,
516
+ size: linkChrome.size,
517
+ "aria-label": linkChrome.ariaLabel,
518
+ className: cn(linkChrome.className, props.className),
519
+ children: jsx(Anchor, {
520
+ href: props.href,
521
+ "data-testid": testid,
522
+ "data-buro-flow-state": state,
523
+ onClick: (event) => event.stopPropagation(),
524
+ children: linkChrome.content
525
+ })
526
+ }), chrome.label, linkChrome.compact);
527
+ }
528
+ if (asMenuItem === true) return jsx(DropdownMenuItem, {
529
+ "data-testid": testid,
530
+ "data-buro-flow-state": state,
531
+ disabled: busy,
532
+ "aria-busy": busy ? "true" : void 0,
533
+ className: cn(chrome.destructive && DESTRUCTIVE_ITEM$1),
534
+ onFocus: props.onIntent,
535
+ onPointerEnter: props.onIntent,
536
+ onSelect: () => {
537
+ if (!busy) props.onRun();
538
+ },
539
+ children: jsx(ActionInner, {
540
+ icon: chrome.icon,
541
+ label: chrome.label
542
+ })
543
+ });
544
+ const controlChrome = resolveControlChrome({
545
+ density: density ?? "regular",
546
+ icon: chrome.icon,
547
+ label: chrome.label,
548
+ actionName,
549
+ surface: scope
550
+ });
551
+ return jsxs(Fragment$1, { children: [withActionTooltip(jsxs(Button, {
552
+ type: "button",
553
+ variant: buttonVariant,
554
+ size: controlChrome.size,
555
+ "aria-label": controlChrome.ariaLabel,
556
+ "data-testid": testid,
557
+ "data-buro-flow-state": state,
558
+ disabled: busy,
559
+ "aria-busy": busy ? "true" : void 0,
560
+ onPointerEnter: props.onIntent,
561
+ onFocus: props.onIntent,
562
+ onClick: () => {
563
+ if (!busy) props.onRun();
564
+ },
565
+ className: cn(controlChrome.className, props.className),
566
+ children: [running ? jsx(IconLoader2, {
567
+ className: "h-4 w-4 animate-spin",
568
+ "aria-hidden": "true"
569
+ }) : null, controlChrome.content]
570
+ }), chrome.label, controlChrome.compact), jsx(DocInfo, {
571
+ address: `${resource}/actions/${actionName}`,
572
+ name: chrome.labelText,
573
+ testId: `${testid}:info`
574
+ })] });
575
+ }
576
+ function FlowActionButton(props) {
577
+ const { resource, actionName, record, scope = "row", children } = props;
578
+ const control = useFlowRowResolver(resource)(actionName, record);
579
+ const chrome = useFlowChrome(resource, actionName, children);
580
+ const tid = useTestIds();
581
+ const testid = makeTestId(scope, resource, actionName, record?.id ?? "", tid);
582
+ const [running, setRunning] = useState(false);
583
+ const runRecord = control.record ?? record;
584
+ const hosted = useHostedFlow(resource, actionName, runRecord, chrome.labelText);
585
+ const onRun = () => {
586
+ if (running) return;
587
+ if (hosted.pageHref !== void 0) return;
588
+ const closed = hosted.present();
589
+ if (closed !== null) {
590
+ setRunning(true);
591
+ closed.finally(() => setRunning(false));
592
+ return;
593
+ }
594
+ if (!hosted.hasHost) setRunning(true);
595
+ };
596
+ return jsxs(Fragment$1, { children: [jsx(FlowControl, {
597
+ ...props,
598
+ state: conjoinHostPage(control.state, hosted.hostPage),
599
+ ...control.reason === void 0 ? {} : { reason: control.reason },
600
+ testid,
601
+ scope,
602
+ chrome,
603
+ active: running,
604
+ ...hosted.pageHref === void 0 ? {} : { href: hosted.pageHref },
605
+ onRun,
606
+ onIntent: preloadFlowRuntime
607
+ }), running && !hosted.hasHost && hosted.pageHref === void 0 ? jsx(RuntimeFlowRunner, {
608
+ resource,
609
+ actionName,
610
+ ...runRecord === void 0 ? {} : { record: runRecord },
611
+ scope,
612
+ onClose: () => setRunning(false)
613
+ }) : null] });
614
+ }
615
+ function useHostedFlow(resource, actionName, record, label) {
616
+ const app = useApp();
617
+ const def = app.registry.get(resource);
618
+ const compiled = useMemo(() => {
619
+ try {
620
+ return def === void 0 ? null : compileFlow(def, actionName);
621
+ } catch {
622
+ return null;
623
+ }
624
+ }, [def, actionName]);
625
+ const title = useProjectedTitle(resource, record?.id, record);
626
+ const presentFlow = usePresentFlow();
627
+ const hasHost = compiled?.hasHost === true;
628
+ const recordId = record?.[compiled?.idField ?? "id"] ?? record?.id;
629
+ const hostPage = useHostPage(compiled?.flow.host);
630
+ const pageHref = hostPage !== void 0 ? hostPage.access === "allowed" ? hostPage.href : void 0 : compiled?.flow.host === "page" && (typeof recordId === "string" || typeof recordId === "number") && String(recordId) !== "" ? hrefFor(app.registry, resource, {
631
+ action: "flow",
632
+ id: String(recordId),
633
+ flow: actionName
634
+ }) : void 0;
635
+ return {
636
+ hasHost,
637
+ pageHref,
638
+ hostPage,
639
+ present: () => !hasHost || compiled === null || pageHref !== void 0 ? null : presentFlow({
640
+ target: {
641
+ resource,
642
+ action: actionName
643
+ },
644
+ host: compiled.flow.host === "sheet" ? "sheet" : "dialog",
645
+ label,
646
+ ...record === void 0 ? {} : { record },
647
+ ...record === void 0 || title === "" ? {} : { title }
648
+ })
649
+ };
650
+ }
651
+ function FlowMenuItem(props) {
652
+ const chrome = useFlowChrome(props.resource, props.actionName);
653
+ const tid = useTestIds();
654
+ const testid = makeTestId(props.scope, props.resource, props.actionName, props.record?.id ?? "", tid);
655
+ const runRecord = props.control.record ?? props.record;
656
+ const hosted = useHostedFlow(props.resource, props.actionName, runRecord, chrome.labelText);
657
+ return jsx(FlowControl, {
658
+ state: conjoinHostPage(props.control.state, hosted.hostPage),
659
+ ...props.control.reason === void 0 ? {} : { reason: props.control.reason },
660
+ resource: props.resource,
661
+ actionName: props.actionName,
662
+ testid,
663
+ scope: props.scope,
664
+ chrome,
665
+ asMenuItem: true,
666
+ ...props.active === true ? { active: true } : {},
667
+ ...hosted.pageHref === void 0 ? {} : { href: hosted.pageHref },
668
+ onRun: () => {
669
+ if (hosted.pageHref !== void 0) return;
670
+ if (hosted.present() === null && !hosted.hasHost) props.onRun();
671
+ },
672
+ onIntent: preloadFlowRuntime
673
+ });
674
+ }
675
+ //#endregion
676
+ //#region src/lib/external-href.ts
677
+ const EXTERNAL_HREF = /^(?:https?:|mailto:)/i;
678
+ function isExternalHref(href) {
679
+ return EXTERNAL_HREF.test(href);
680
+ }
681
+ function openExternal(href) {
682
+ window.open(href, "_blank", "noopener noreferrer");
683
+ }
684
+ function toBrowserHref(appPath, currentPath) {
685
+ if (typeof window === "undefined" || isExternalHref(appPath) || !appPath.startsWith("/")) return appPath;
686
+ const here = window.location.pathname;
687
+ if (currentPath === "") return appPath;
688
+ const basename = currentPath === "/" ? here.replace(/\/$/u, "") : here.endsWith(currentPath) ? here.slice(0, here.length - currentPath.length).replace(/\/$/u, "") : void 0;
689
+ if (basename === void 0) return appPath;
690
+ if (basename === "") return appPath;
691
+ return `${basename}${appPath}`;
692
+ }
693
+ function useToBrowserHref() {
694
+ const pathname = useOptionalRouterAdapter()?.pathname;
695
+ return useCallback((appPath) => pathname === void 0 ? appPath : toBrowserHref(appPath, pathname), [pathname]);
696
+ }
697
+ //#endregion
698
+ //#region src/list-kit/list-slots.ts
699
+ function canonicalResourceName(resource) {
700
+ return canonicalEntityNodeKey({
701
+ name: resource,
702
+ ref: normalizeEntityRef(resource)
703
+ });
704
+ }
705
+ function listSlot(region, resource) {
706
+ return `list.${region}.${canonicalResourceName(resource)}`;
707
+ }
708
+ function useListSlot(region, resource) {
709
+ return useComponent(listSlot(region, resource));
710
+ }
711
+ //#endregion
712
+ //#region src/actions/builtin-edit-route.ts
713
+ const LINK = Object.freeze({ kind: "link" });
714
+ const NONE = Object.freeze({ kind: "none" });
715
+ function sameResource(a, b) {
716
+ try {
717
+ return canonicalResourceName(a) === canonicalResourceName(b);
718
+ } catch {
719
+ return false;
720
+ }
721
+ }
722
+ function useBuiltinEditRoute(action, resource, recordId) {
723
+ const app = useApp();
724
+ const entry = useQuickEntry();
725
+ const quick = useQuick();
726
+ const gate = useEntryGate();
727
+ if (!isBuiltinItemAction(action, "edit")) return LINK;
728
+ const def = app.registry.get(resource);
729
+ if (def === void 0) return LINK;
730
+ const entries = recordEntries(def);
731
+ const id = recordId === null || recordId === void 0 ? "" : String(recordId);
732
+ const top = entry?.stack.top;
733
+ if (entry !== null && top !== void 0 && top.mode === "show" && top.recordId === id && sameResource(top.resource, resource) && entries.quick.edit !== null) {
734
+ if (entries.quick.edit === entry.host) return {
735
+ kind: "quick",
736
+ open: () => {
737
+ if (gate(resource, "edit").state !== "open") return;
738
+ entry.scope.request(() => entry.stack.replaceTop({
739
+ ...top,
740
+ mode: "edit"
741
+ }));
742
+ }
743
+ };
744
+ return {
745
+ kind: "quick",
746
+ open: () => void quick.edit(resource, id)
747
+ };
748
+ }
749
+ if (entries.page.edit) return LINK;
750
+ if (entries.quick.edit === null) return NONE;
751
+ return {
752
+ kind: "quick",
753
+ open: () => void quick.edit(resource, id)
754
+ };
755
+ }
756
+ //#endregion
757
+ //#region src/actions/action-button.tsx
758
+ function DisabledAction({ reason, label, icon, testid, size, variant, className, asMenuItem, resource, density = "regular", actionName, surface }) {
759
+ const i18nCaps = useI18nCaps(resource);
760
+ const text = reason ? resolveContentSlot(i18nCaps, [reason], {
761
+ resource,
762
+ default: reason
763
+ }) : resolveContentSlot(i18nCaps, ["availability.denied"], {
764
+ resource,
765
+ default: "This action isn't available"
766
+ });
767
+ const onClick = (e) => {
768
+ e.preventDefault();
769
+ e.stopPropagation();
770
+ toast(text);
771
+ };
772
+ if (asMenuItem) return jsx(DropdownMenuItem, {
773
+ "aria-disabled": "true",
774
+ "data-testid": testid,
775
+ onSelect: (e) => e.preventDefault(),
776
+ onClick,
777
+ className: "opacity-60",
778
+ children: jsx(ActionInner, {
779
+ icon,
780
+ label
781
+ })
782
+ });
783
+ const chrome = resolveControlChrome({
784
+ density,
785
+ icon,
786
+ label,
787
+ actionName: actionName ?? testid ?? "",
788
+ surface: surface ?? "unknown"
789
+ });
790
+ return withActionTooltip(jsx(Button, {
791
+ type: "button",
792
+ size: size ?? chrome.size,
793
+ variant: variant ?? "outline",
794
+ className: cn(chrome.className, className),
795
+ "data-testid": testid,
796
+ "aria-disabled": "true",
797
+ "aria-label": chrome.ariaLabel,
798
+ onClick,
799
+ children: chrome.content
800
+ }), label, chrome.compact, text);
801
+ }
802
+ const DESTRUCTIVE_ITEM = "text-destructive focus:bg-destructive/10 focus:text-destructive data-[highlighted]:text-destructive";
803
+ const DEFAULT_ACTION_ICONS = {
804
+ create: "Plus",
805
+ edit: "Pencil",
806
+ delete: "Trash2",
807
+ show: "Eye",
808
+ auditLog: "ScrollText",
809
+ refresh: "RefreshCw",
810
+ copy: "Copy",
811
+ cancel: "X"
812
+ };
813
+ function resolveActionIcon(action, actionName) {
814
+ return action.icon ?? DEFAULT_ACTION_ICONS[camelizeActionName(actionName)];
815
+ }
816
+ function camelizeActionName(actionName) {
817
+ return actionName.replace(/[-_]+([a-zA-Z0-9])/g, (_m, c) => c.toUpperCase());
818
+ }
819
+ function useResolvedLabel(action, actionName, children, resource) {
820
+ const caps = useI18nCaps(resource);
821
+ if (children != null) return children;
822
+ const raw = `actions.${actionName}`;
823
+ const own = `resources.${resource}.${raw}`;
824
+ const ownLabel = resolveContentSlot(caps, [[`${own}.label`, own]]);
825
+ if (ownLabel !== void 0) return ownLabel;
826
+ const declared = declaredText(action.kind === "flow" ? "flow" : "action", action, "label");
827
+ if (declared !== void 0) return declared;
828
+ const sharedLabel = resolveContentSlot(caps, [[`${raw}.label`, raw]]);
829
+ if (sharedLabel !== void 0) return sharedLabel;
830
+ const camel = `actions.${camelizeActionName(actionName)}`;
831
+ if (caps.has(camel)) return caps.t(camel);
832
+ return humanizeKey(actionName);
833
+ }
834
+ function findAction(actions, name) {
835
+ if (!Array.isArray(actions)) return void 0;
836
+ return actions.find((a) => "name" in a && a.name === name);
837
+ }
838
+ function actionResourceHandle(resource) {
839
+ return {
840
+ kind: "resource",
841
+ ref: normalizeEntityRef(resource)
842
+ };
843
+ }
844
+ function ActionButton(props) {
845
+ const def = useApp().registry.get(props.resource);
846
+ const scope = props.scope ?? "row";
847
+ const availability = useAvailabilityResolver(props.resource, modeForSurface(scope))(props.actionName, props.record);
848
+ const action = findAction(def?.actions?.item, props.actionName) ?? findAction(def?.actions?.resource, props.actionName);
849
+ if (!action) return null;
850
+ if (isFlowAction(action)) return jsx(FlowActionButton, { ...props });
851
+ if (availability.state === "absent" || availability.state === "hidden") return null;
852
+ if (!actionWhenHolds(action, props.record)) return null;
853
+ if (action.kind === "link") return jsx(LinkActionButton, {
854
+ ...props,
855
+ action,
856
+ availability
857
+ });
858
+ if (action.kind === "modal") return jsx(ModalActionButton, {
859
+ ...props,
860
+ action,
861
+ availability
862
+ });
863
+ return null;
864
+ }
865
+ function actionWhenHolds(action, record) {
866
+ const when = action.when;
867
+ if (when === void 0) return true;
868
+ return evaluateCondition(when, record === void 0 ? {} : { record: {
869
+ status: "ready",
870
+ value: record,
871
+ refreshing: false
872
+ } }, { mode: "show" }) === true;
873
+ }
874
+ function presentModalAction(args) {
875
+ const { present, action, resource, actionName, record, recordId, label } = args;
876
+ const result = present({
877
+ block: action.block,
878
+ props: action.props ?? {},
879
+ resource,
880
+ record,
881
+ host: action.host === "sheet" ? "sheet" : "dialog",
882
+ ...typeof label === "string" ? { label } : {},
883
+ activation: { surface: {
884
+ type: "item",
885
+ resource: normalizeEntityRef(resource),
886
+ recordId,
887
+ record
888
+ } }
889
+ });
890
+ if (!result.ok) console.error(`[buro/ui-shadcn] modal action "${actionName}" failed to open block "${action.block.namespace}:${action.block.id}": ${result.code}`);
891
+ }
892
+ function makeTestId(scope, resource, actionName, recordId, tid) {
893
+ if (scope === "row") return tid.listRowAction(resource, recordId, actionName);
894
+ if (scope === "list" && recordId === "") return tid.listFlow(resource, actionName);
895
+ return tid.formAction(resource, scope, actionName);
896
+ }
897
+ const reportedDeadRoutes = new Set();
898
+ function deadRecordRoute(registry, action, to) {
899
+ if (isBuiltinItemAction(action) || to === null || typeof to !== "object") return null;
900
+ const target = to;
901
+ if (typeof target.resource !== "string") return null;
902
+ if (target.action !== "show" && target.action !== "edit" && target.action !== "create") return null;
903
+ let def;
904
+ try {
905
+ def = registry.get(target.resource);
906
+ } catch {
907
+ return null;
908
+ }
909
+ if (def === void 0 || hasRecordPage(def, target.action)) return null;
910
+ return {
911
+ resource: target.resource,
912
+ action: target.action
913
+ };
914
+ }
915
+ function reportDeadRecordRoute(name, resource, action) {
916
+ if (process.env.NODE_ENV === "production") return;
917
+ const key = `${name}\u0000${resource}\u0000${action}`;
918
+ if (reportedDeadRoutes.has(key)) return;
919
+ reportedDeadRoutes.add(key);
920
+ console.error(`[burojs] The action "${name}" links to ${resource}'s ${action} page, and ${resource} has none (views.show.page: false).`);
921
+ }
922
+ function LinkActionButton({ resource, actionName, record, scope = "row", variant, size, density, className, children, asMenuItem, action, availability }) {
923
+ const tid = useTestIds();
924
+ const app = useApp();
925
+ const toBrowser = useToBrowserHref();
926
+ const safeRecord = record ?? { id: "" };
927
+ const isDestructive = action.variant === "destructive";
928
+ const buttonVariant = variant ?? (isDestructive ? "destructive" : "outline");
929
+ const recordId = record?.id ?? "";
930
+ const testid = makeTestId(scope, resource, actionName, recordId, tid);
931
+ const label = useResolvedLabel(action, actionName, children, resource);
932
+ const editRoute = useBuiltinEditRoute(action, resource, recordId);
933
+ const to = typeof action.to === "function" ? action.to(buildDI(actionResourceHandle(resource), safeRecord)) : action.to;
934
+ const href = resolveRoute(to, app.registry);
935
+ const target = action.target ?? "_self";
936
+ const deadPage = deadRecordRoute(app.registry, action, to);
937
+ const deadResource = deadPage?.resource;
938
+ const deadAction = deadPage?.action;
939
+ useEffect(() => {
940
+ if (deadResource !== void 0 && deadAction !== void 0) reportDeadRecordRoute(actionName, deadResource, deadAction);
941
+ }, [
942
+ deadResource,
943
+ deadAction,
944
+ actionName
945
+ ]);
946
+ const rel = target === "_blank" ? "noopener noreferrer" : void 0;
947
+ const RouterLink = useLinkComponent();
948
+ const Anchor = target === "_blank" || isExternalHref(href) ? "a" : RouterLink;
949
+ const anchorHref = target === "_blank" ? toBrowser(href) : href;
950
+ if (editRoute.kind === "none") return null;
951
+ if (availability.state === "disabled") return jsx(DisabledAction, {
952
+ reason: availability.reason,
953
+ label,
954
+ icon: resolveActionIcon(action, actionName),
955
+ testid,
956
+ size,
957
+ variant: buttonVariant,
958
+ className,
959
+ asMenuItem,
960
+ resource,
961
+ density,
962
+ actionName,
963
+ surface: scope
964
+ });
965
+ if (editRoute.kind === "quick") {
966
+ if (asMenuItem) return jsx(DropdownMenuItem, {
967
+ "data-testid": testid,
968
+ onSelect: () => editRoute.open(),
969
+ children: jsx(ActionInner, {
970
+ icon: resolveActionIcon(action, actionName),
971
+ label
972
+ })
973
+ });
974
+ const quickChrome = resolveControlChrome({
975
+ density: density ?? "regular",
976
+ icon: resolveActionIcon(action, actionName),
977
+ label,
978
+ actionName,
979
+ surface: scope
980
+ });
981
+ return withActionTooltip(jsx(Button, {
982
+ type: "button",
983
+ variant: buttonVariant,
984
+ size: quickChrome.size,
985
+ "aria-label": quickChrome.ariaLabel,
986
+ className: cn(quickChrome.className, className),
987
+ "data-testid": testid,
988
+ onClick: (e) => {
989
+ e.stopPropagation();
990
+ editRoute.open();
991
+ },
992
+ children: quickChrome.content
993
+ }), label, quickChrome.compact);
994
+ }
995
+ if (asMenuItem) return jsx(DropdownMenuItem, {
996
+ asChild: true,
997
+ className: cn(isDestructive && DESTRUCTIVE_ITEM),
998
+ children: jsx(Anchor, {
999
+ href: anchorHref,
1000
+ target,
1001
+ rel,
1002
+ "data-testid": testid,
1003
+ onClick: (e) => e.stopPropagation(),
1004
+ children: jsx(ActionInner, {
1005
+ icon: resolveActionIcon(action, actionName),
1006
+ label
1007
+ })
1008
+ })
1009
+ });
1010
+ const chrome = resolveControlChrome({
1011
+ density: density ?? "regular",
1012
+ icon: resolveActionIcon(action, actionName),
1013
+ label,
1014
+ actionName,
1015
+ surface: scope
1016
+ });
1017
+ return withActionTooltip(jsx(Button, {
1018
+ asChild: true,
1019
+ variant: buttonVariant,
1020
+ size: chrome.size,
1021
+ "aria-label": chrome.ariaLabel,
1022
+ className: cn(chrome.className, className),
1023
+ children: jsx(Anchor, {
1024
+ href: anchorHref,
1025
+ target,
1026
+ rel,
1027
+ "data-testid": testid,
1028
+ onClick: (e) => e.stopPropagation(),
1029
+ children: chrome.content
1030
+ })
1031
+ }), label, chrome.compact);
1032
+ }
1033
+ function ModalActionButton({ resource, actionName, record, scope = "row", variant, size, density, className, children, asMenuItem, action, availability }) {
1034
+ const tid = useTestIds();
1035
+ const present = usePresentBlock();
1036
+ const safeRecord = record ?? { id: "" };
1037
+ const isDestructive = action.variant === "destructive";
1038
+ const buttonVariant = variant ?? (isDestructive ? "destructive" : "outline");
1039
+ const recordId = record?.id ?? "";
1040
+ const testid = makeTestId(scope, resource, actionName, recordId, tid);
1041
+ const label = useResolvedLabel(action, actionName, children, resource);
1042
+ if (availability.state === "disabled") return jsx(DisabledAction, {
1043
+ reason: availability.reason,
1044
+ label,
1045
+ icon: resolveActionIcon(action, actionName),
1046
+ testid,
1047
+ size,
1048
+ variant: buttonVariant,
1049
+ className,
1050
+ asMenuItem,
1051
+ resource,
1052
+ density,
1053
+ actionName,
1054
+ surface: scope
1055
+ });
1056
+ function openModal() {
1057
+ presentModalAction({
1058
+ present,
1059
+ action,
1060
+ resource,
1061
+ actionName,
1062
+ record: safeRecord,
1063
+ recordId,
1064
+ label
1065
+ });
1066
+ }
1067
+ if (asMenuItem) return jsx(DropdownMenuItem, {
1068
+ "data-testid": testid,
1069
+ className: cn(isDestructive && DESTRUCTIVE_ITEM),
1070
+ onSelect: openModal,
1071
+ children: jsx(ActionInner, {
1072
+ icon: resolveActionIcon(action, actionName),
1073
+ label
1074
+ })
1075
+ });
1076
+ const chrome = resolveControlChrome({
1077
+ density: density ?? "regular",
1078
+ icon: resolveActionIcon(action, actionName),
1079
+ label,
1080
+ actionName,
1081
+ surface: scope
1082
+ });
1083
+ return withActionTooltip(jsx(Button, {
1084
+ type: "button",
1085
+ variant: buttonVariant,
1086
+ size: chrome.size,
1087
+ "aria-label": chrome.ariaLabel,
1088
+ "data-testid": testid,
1089
+ onClick: (e) => {
1090
+ e.stopPropagation();
1091
+ openModal();
1092
+ },
1093
+ className: cn(chrome.className, className),
1094
+ children: chrome.content
1095
+ }), label, chrome.compact);
1096
+ }
1097
+ //#endregion
1098
+ //#region src/checks/check-confirm-dialog.tsx
1099
+ function translateOrFallback(t, key, fallback, params, resource) {
1100
+ const translated = t(key, {
1101
+ params,
1102
+ ...resource === void 0 ? {} : { resource }
1103
+ });
1104
+ return translated === key ? fallback : translated;
1105
+ }
1106
+ function issueText(issue, t, resource) {
1107
+ const params = issue.params;
1108
+ const checkId = params?.checkId;
1109
+ const ownCheck = typeof checkId === "string" && issue.message.key === `checks.${checkId}`;
1110
+ const declared = typeof issue.message.default === "string" ? issue.message.default : ownCheck ? void 0 : issue.message.key;
1111
+ if (issue.params?.resolved === true) return declared ?? issue.message.key;
1112
+ if (!ownCheck) return translateOrFallback(t, issue.message.key, declared ?? "", params, resource);
1113
+ const miss = "\0";
1114
+ const bundled = [`${issue.message.key}.message`, issue.message.key].map((key) => translateOrFallback(t, key, miss, params, resource)).find((text) => text !== miss);
1115
+ if (bundled !== void 0) return bundled;
1116
+ if (declared !== void 0) return declared;
1117
+ const name = String(params?.name ?? checkId);
1118
+ return translateOrFallback(t, FRAMEWORK_TEXT_KEYS.checkFailed, checkFailedDefault(name), {
1119
+ ...params,
1120
+ name
1121
+ }, void 0);
1122
+ }
1123
+ function checkIdOf(issue, index) {
1124
+ const id = issue.params?.checkId;
1125
+ return typeof id === "string" ? id : `${index}`;
1126
+ }
1127
+ const SEVERITY_CLASSNAME = {
1128
+ error: "text-destructive",
1129
+ warning: "text-warning-emphasis",
1130
+ info: "text-muted-foreground"
1131
+ };
1132
+ function ChecksList({ issues, testid, onRowClick, resource }) {
1133
+ const t = useOptionalT();
1134
+ return issues.map((issue, index) => {
1135
+ const checkId = checkIdOf(issue, index);
1136
+ const anchor = issue.path[0];
1137
+ const anchorable = typeof anchor === "string";
1138
+ const text = issueText(issue, t, resource);
1139
+ const className = cn("text-sm", SEVERITY_CLASSNAME[issue.severity]);
1140
+ return anchorable ? jsx("li", { children: jsx("button", {
1141
+ type: "button",
1142
+ "data-testid": `${testid}:item:${checkId}`,
1143
+ className: cn(className, "text-left underline-offset-2 hover:underline"),
1144
+ onClick: () => onRowClick(anchor),
1145
+ children: text
1146
+ }) }, `${checkId}-${index}`) : jsx("li", {
1147
+ "data-testid": `${testid}:item:${checkId}`,
1148
+ className,
1149
+ children: text
1150
+ }, `${checkId}-${index}`);
1151
+ });
1152
+ }
1153
+ function CheckConfirmDialog({ state, testid, onAnchorFocus, title, proceedLabel, tone }) {
1154
+ const t = useOptionalT();
1155
+ const { resource, open, busy, header, blockers, confirmable, proceed, cancel } = state;
1156
+ const blocked = blockers.length > 0;
1157
+ const bound = resource === void 0 ? {} : { resource };
1158
+ const heading = title ?? t("checks.dialogTitle", {
1159
+ defaultValue: "Please review",
1160
+ ...bound
1161
+ });
1162
+ const restoreFocusRef = useRef(null);
1163
+ useEffect(() => {
1164
+ if (typeof document === "undefined") return;
1165
+ if (open) {
1166
+ const active = document.activeElement;
1167
+ if (active instanceof HTMLElement && active !== document.body) restoreFocusRef.current = active;
1168
+ return;
1169
+ }
1170
+ const target = restoreFocusRef.current;
1171
+ restoreFocusRef.current = null;
1172
+ if (!target || !document.contains(target)) return;
1173
+ const id = requestAnimationFrame(() => target.focus());
1174
+ return () => cancelAnimationFrame(id);
1175
+ }, [open]);
1176
+ const onRowClick = (field) => {
1177
+ onAnchorFocus?.(field);
1178
+ cancel();
1179
+ };
1180
+ return jsx(Dialog, {
1181
+ open,
1182
+ onOpenChange: (next) => {
1183
+ if (!next) cancel();
1184
+ },
1185
+ children: jsxs(DialogContent, {
1186
+ "data-testid": `${testid}:dialog`,
1187
+ className: "flex max-h-[85vh] flex-col overflow-hidden",
1188
+ children: [
1189
+ jsxs(DialogHeader, { children: [jsx(DialogTitle, { children: heading }), header !== null ? jsx(DialogDescription, { children: header }) : jsx(DialogDescription, {
1190
+ className: "sr-only",
1191
+ children: heading
1192
+ })] }),
1193
+ jsxs("ul", {
1194
+ className: "flex min-h-0 flex-1 flex-col gap-2 overflow-y-auto overscroll-contain",
1195
+ children: [
1196
+ blocked && jsx("li", {
1197
+ className: "text-xs font-semibold uppercase tracking-wider text-destructive",
1198
+ children: t("checks.blocked", {
1199
+ defaultValue: "Cannot continue",
1200
+ ...bound
1201
+ })
1202
+ }),
1203
+ jsx(ChecksList, {
1204
+ issues: blockers,
1205
+ testid,
1206
+ onRowClick,
1207
+ resource
1208
+ }),
1209
+ jsx(ChecksList, {
1210
+ issues: confirmable,
1211
+ testid,
1212
+ onRowClick,
1213
+ resource
1214
+ })
1215
+ ]
1216
+ }),
1217
+ jsxs(DialogFooter, { children: [jsx(Button, {
1218
+ type: "button",
1219
+ variant: "outline",
1220
+ onClick: cancel,
1221
+ "data-testid": `${testid}:cancel`,
1222
+ disabled: busy,
1223
+ children: t("checks.back", {
1224
+ defaultValue: "Go back",
1225
+ ...bound
1226
+ })
1227
+ }), !blocked && jsx(Button, {
1228
+ type: "button",
1229
+ variant: tone === "destructive" ? "destructive" : "default",
1230
+ onClick: proceed,
1231
+ "data-testid": `${testid}:proceed`,
1232
+ disabled: busy,
1233
+ children: proceedLabel ?? t("checks.proceed", {
1234
+ defaultValue: "Continue anyway",
1235
+ ...bound
1236
+ })
1237
+ })] })
1238
+ ]
1239
+ })
1240
+ });
1241
+ }
1242
+ //#endregion
1243
+ export { hasIcon as A, DropdownMenuRadioItem as B, loadFailedText as C, preloadFlowRuntime as D, loadPageFlowRoute as E, DropdownMenuGroup as F, DropdownMenuSubTrigger as G, DropdownMenuShortcut as H, DropdownMenuItem as I, TooltipContent as J, DropdownMenuTrigger as K, DropdownMenuLabel as L, DropdownMenu as M, DropdownMenuCheckboxItem as N, useLoaded as O, DropdownMenuContent as P, DropdownMenuPortal as R, loadBulkSummary as S, loadInlineFlowHost as T, DropdownMenuSub as U, DropdownMenuSeparator as V, DropdownMenuSubContent as W, TooltipTrigger as X, TooltipProvider as Y, DocInfo as Z, FlowBoundary as _, modeForSurface as a, RuntimeBulkFlowRunner as b, useListSlot as c, useToBrowserHref as d, FlowActionButton as f, ActionInner as g, useFlowChrome as h, makeTestId as i, registerIcons as j, Icon as k, isExternalHref as l, text as m, ActionButton as n, canonicalResourceName as o, FlowMenuItem as p, Tooltip as q, DisabledAction as r, listSlot as s, CheckConfirmDialog as t, openExternal as u, FlowLoadFailed as v, loadFlowScreen as w, RuntimeFlowRunner as x, RuntimeAppFlowRunner as y, DropdownMenuRadioGroup as z };
1244
+
1245
+ //# sourceMappingURL=check-confirm-dialog-bRT8lt0d.js.map