@burojs/ui-shadcn 0.3.0 → 0.5.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 (179) hide show
  1. package/README.md +26 -7
  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-CX2PBu6l.js +63 -0
  11. package/dist/candidates-gate-CX2PBu6l.js.map +1 -0
  12. package/dist/candidates-gate-DiFI52r7.cjs +70 -0
  13. package/dist/candidates-gate-DiFI52r7.cjs.map +1 -0
  14. package/dist/candidates-relation-picker-CBsVcnPR.js +82 -0
  15. package/dist/candidates-relation-picker-CBsVcnPR.js.map +1 -0
  16. package/dist/candidates-relation-picker-Dd_GVLlu.cjs +84 -0
  17. package/dist/candidates-relation-picker-Dd_GVLlu.cjs.map +1 -0
  18. package/dist/check-confirm-dialog-BRByTFpg.cjs +1534 -0
  19. package/dist/check-confirm-dialog-BRByTFpg.cjs.map +1 -0
  20. package/dist/check-confirm-dialog-CkaVTPT9.js +1232 -0
  21. package/dist/check-confirm-dialog-CkaVTPT9.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-B3mZFL-K.cjs +1761 -0
  27. package/dist/filter-builder-B3mZFL-K.cjs.map +1 -0
  28. package/dist/filter-builder-DOnaXNfP.js +1605 -0
  29. package/dist/filter-builder-DOnaXNfP.js.map +1 -0
  30. package/dist/flow-runtime-B6zOHYqI.cjs +255 -0
  31. package/dist/flow-runtime-B6zOHYqI.cjs.map +1 -0
  32. package/dist/flow-runtime-D8h99FSg.js +252 -0
  33. package/dist/flow-runtime-D8h99FSg.js.map +1 -0
  34. package/dist/flow-screen-CX05b3G9.cjs +705 -0
  35. package/dist/flow-screen-CX05b3G9.cjs.map +1 -0
  36. package/dist/flow-screen-CmbARSqg.js +701 -0
  37. package/dist/flow-screen-CmbARSqg.js.map +1 -0
  38. package/dist/index.cjs +6453 -17494
  39. package/dist/index.cjs.map +1 -1
  40. package/dist/index.d.cts +3754 -3621
  41. package/dist/index.d.ts +3754 -3621
  42. package/dist/index.js +6217 -17219
  43. package/dist/index.js.map +1 -1
  44. package/dist/inline-flow-host-B7U1OJUe.cjs +112 -0
  45. package/dist/inline-flow-host-B7U1OJUe.cjs.map +1 -0
  46. package/dist/inline-flow-host-C3H2UpSA.js +112 -0
  47. package/dist/inline-flow-host-C3H2UpSA.js.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/layout/theme-storage-key.cjs +5 -10
  57. package/dist/layout/theme-storage-key.cjs.map +1 -1
  58. package/dist/layout/theme-storage-key.d.cts +2 -23
  59. package/dist/layout/theme-storage-key.d.ts +2 -23
  60. package/dist/layout/theme-storage-key.js +5 -2
  61. package/dist/layout/theme-storage-key.js.map +1 -1
  62. package/dist/lazy-relation-picker-dialog-2oxnA6IR.js +14 -0
  63. package/dist/lazy-relation-picker-dialog-2oxnA6IR.js.map +1 -0
  64. package/dist/lazy-relation-picker-dialog-BfAGKzUG.cjs +19 -0
  65. package/dist/lazy-relation-picker-dialog-BfAGKzUG.cjs.map +1 -0
  66. package/dist/markdown/index.cjs +424 -511
  67. package/dist/markdown/index.cjs.map +1 -1
  68. package/dist/markdown/index.d.cts +1072 -34
  69. package/dist/markdown/index.d.ts +1072 -34
  70. package/dist/markdown/index.js +411 -459
  71. package/dist/markdown/index.js.map +1 -1
  72. package/dist/page-flow-route-CQ7HsbBm.cjs +277 -0
  73. package/dist/page-flow-route-CQ7HsbBm.cjs.map +1 -0
  74. package/dist/page-flow-route-CyXSvXSE.js +277 -0
  75. package/dist/page-flow-route-CyXSvXSE.js.map +1 -0
  76. package/dist/peek-filter-CnqHwTMU.cjs +51 -0
  77. package/dist/peek-filter-CnqHwTMU.cjs.map +1 -0
  78. package/dist/peek-filter-ErLfO153.js +28 -0
  79. package/dist/peek-filter-ErLfO153.js.map +1 -0
  80. package/dist/place-node--GdsP688.js +7315 -0
  81. package/dist/place-node--GdsP688.js.map +1 -0
  82. package/dist/place-node-SIp4XYQH.cjs +7833 -0
  83. package/dist/place-node-SIp4XYQH.cjs.map +1 -0
  84. package/dist/related-list-cards-B6x9HQQp.js +42 -0
  85. package/dist/related-list-cards-B6x9HQQp.js.map +1 -0
  86. package/dist/related-list-cards-nxuODlIA.cjs +42 -0
  87. package/dist/related-list-cards-nxuODlIA.cjs.map +1 -0
  88. package/dist/related-list-timeline-BYJKEbmA.cjs +142 -0
  89. package/dist/related-list-timeline-BYJKEbmA.cjs.map +1 -0
  90. package/dist/related-list-timeline-DEdfd-rr.js +142 -0
  91. package/dist/related-list-timeline-DEdfd-rr.js.map +1 -0
  92. package/dist/related-rows-B4levHcR.js +186 -0
  93. package/dist/related-rows-B4levHcR.js.map +1 -0
  94. package/dist/related-rows-zh5f_4QR.cjs +209 -0
  95. package/dist/related-rows-zh5f_4QR.cjs.map +1 -0
  96. package/dist/relation-create-BOaUe12G.cjs +362 -0
  97. package/dist/relation-create-BOaUe12G.cjs.map +1 -0
  98. package/dist/relation-create-Bg-eEJLs.js +337 -0
  99. package/dist/relation-create-Bg-eEJLs.js.map +1 -0
  100. package/dist/relation-many-picker-B-NCEUgX.cjs +465 -0
  101. package/dist/relation-many-picker-B-NCEUgX.cjs.map +1 -0
  102. package/dist/relation-many-picker-gdAOD-qK.js +464 -0
  103. package/dist/relation-many-picker-gdAOD-qK.js.map +1 -0
  104. package/dist/relation-picker-BAY77ivO.js +462 -0
  105. package/dist/relation-picker-BAY77ivO.js.map +1 -0
  106. package/dist/relation-picker-Da_uhFvA.cjs +479 -0
  107. package/dist/relation-picker-Da_uhFvA.cjs.map +1 -0
  108. package/dist/relation-picker-dialog-M0pQaWlp.cjs +300 -0
  109. package/dist/relation-picker-dialog-M0pQaWlp.cjs.map +1 -0
  110. package/dist/relation-picker-dialog-hA9rYrZB.js +299 -0
  111. package/dist/relation-picker-dialog-hA9rYrZB.js.map +1 -0
  112. package/dist/resource-page-router-OSQyRA5b.cjs +1779 -0
  113. package/dist/resource-page-router-OSQyRA5b.cjs.map +1 -0
  114. package/dist/resource-page-router-T4vS5gbJ.js +1582 -0
  115. package/dist/resource-page-router-T4vS5gbJ.js.map +1 -0
  116. package/dist/rich-text-DFerywgz.js +457 -0
  117. package/dist/rich-text-DFerywgz.js.map +1 -0
  118. package/dist/rich-text-vTyVjDoa.cjs +460 -0
  119. package/dist/rich-text-vTyVjDoa.cjs.map +1 -0
  120. package/dist/search-access-B7G5oR8n.cjs +812 -0
  121. package/dist/search-access-B7G5oR8n.cjs.map +1 -0
  122. package/dist/search-access-CURsWn-U.js +669 -0
  123. package/dist/search-access-CURsWn-U.js.map +1 -0
  124. package/dist/shell-BPlk8hEa.js +205 -0
  125. package/dist/shell-BPlk8hEa.js.map +1 -0
  126. package/dist/shell-DxhlsPwm.cjs +271 -0
  127. package/dist/shell-DxhlsPwm.cjs.map +1 -0
  128. package/dist/skeleton-U2noefj5.js +13 -0
  129. package/dist/skeleton-U2noefj5.js.map +1 -0
  130. package/dist/skeleton-_1gP7wan.cjs +18 -0
  131. package/dist/skeleton-_1gP7wan.cjs.map +1 -0
  132. package/dist/styles.css +255 -17
  133. package/dist/theme/theme-css.cjs +95 -96
  134. package/dist/theme/theme-css.cjs.map +1 -1
  135. package/dist/theme/theme-css.d.cts +10 -8
  136. package/dist/theme/theme-css.d.ts +10 -8
  137. package/dist/theme/theme-css.js +94 -94
  138. package/dist/theme/theme-css.js.map +1 -1
  139. package/dist/theme/theme-storage.cjs +34 -39
  140. package/dist/theme/theme-storage.cjs.map +1 -1
  141. package/dist/theme/theme-storage.d.cts +3 -1
  142. package/dist/theme/theme-storage.d.ts +3 -1
  143. package/dist/theme/theme-storage.js +33 -37
  144. package/dist/theme/theme-storage.js.map +1 -1
  145. package/dist/theme-storage-key-pYlp4aDS.d.cts +31 -0
  146. package/dist/theme-storage-key-pYlp4aDS.d.ts +31 -0
  147. package/dist/toaster-C7CiYA4Z.cjs +248 -0
  148. package/dist/toaster-C7CiYA4Z.cjs.map +1 -0
  149. package/dist/toaster-CfCRLgR-.js +164 -0
  150. package/dist/toaster-CfCRLgR-.js.map +1 -0
  151. package/dist/use-dialog-filter-state-BBCC0OEK.cjs +92 -0
  152. package/dist/use-dialog-filter-state-BBCC0OEK.cjs.map +1 -0
  153. package/dist/use-dialog-filter-state-BDcgS5Oz.js +87 -0
  154. package/dist/use-dialog-filter-state-BDcgS5Oz.js.map +1 -0
  155. package/dist/use-theme-DFlpXils.cjs +257 -0
  156. package/dist/use-theme-DFlpXils.cjs.map +1 -0
  157. package/dist/use-theme-dnE3Od3I.js +175 -0
  158. package/dist/use-theme-dnE3Od3I.js.map +1 -0
  159. package/package.json +18 -17
  160. package/dist/chunk-ABUQPOOE.js +0 -11
  161. package/dist/chunk-ABUQPOOE.js.map +0 -1
  162. package/dist/chunk-DBGGWBFG.cjs +0 -199
  163. package/dist/chunk-DBGGWBFG.cjs.map +0 -1
  164. package/dist/chunk-FMX4GLCQ.js +0 -6
  165. package/dist/chunk-FMX4GLCQ.js.map +0 -1
  166. package/dist/chunk-UC57Z243.js +0 -143
  167. package/dist/chunk-UC57Z243.js.map +0 -1
  168. package/dist/chunk-UPGPO75B.js +0 -164
  169. package/dist/chunk-UPGPO75B.js.map +0 -1
  170. package/dist/chunk-VXJAXJ3U.cjs +0 -8
  171. package/dist/chunk-VXJAXJ3U.cjs.map +0 -1
  172. package/dist/chunk-W7AEYE7A.cjs +0 -13
  173. package/dist/chunk-W7AEYE7A.cjs.map +0 -1
  174. package/dist/chunk-YF5IW525.cjs +0 -155
  175. package/dist/chunk-YF5IW525.cjs.map +0 -1
  176. package/dist/rich-text-6V7WZ3WV.cjs +0 -518
  177. package/dist/rich-text-6V7WZ3WV.cjs.map +0 -1
  178. package/dist/rich-text-N2FZEJJV.js +0 -491
  179. package/dist/rich-text-N2FZEJJV.js.map +0 -1
@@ -0,0 +1,1232 @@
1
+ import { l as cn } from "./use-theme-dnE3Od3I.js";
2
+ import { d as useLinkComponent, f as Popover, g as PopoverTrigger, h as PopoverContent, n as toast } from "./toaster-CfCRLgR-.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 { canonicalEntityNodeKey, compileFlow, 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-D8h99FSg.js"));
271
+ const loadFlowScreen = retrying(() => import("./flow-screen-CmbARSqg.js"));
272
+ const loadPageFlowRoute = retrying(() => import("./page-flow-route-CyXSvXSE.js"));
273
+ const loadInlineFlowHost = retrying(() => import("./inline-flow-host-C3H2UpSA.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
+ if (caps.has(`${own}.label`)) return caps.t(`${own}.label`);
825
+ if (caps.has(own)) return caps.t(own);
826
+ if (action.label != null) return action.label;
827
+ if (caps.has(`${raw}.label`)) return caps.t(`${raw}.label`);
828
+ if (caps.has(raw)) return caps.t(raw);
829
+ const camel = `actions.${camelizeActionName(actionName)}`;
830
+ if (caps.has(camel)) return caps.t(camel);
831
+ return humanizeKey(actionName);
832
+ }
833
+ function findAction(actions, name) {
834
+ if (!Array.isArray(actions)) return void 0;
835
+ return actions.find((a) => "name" in a && a.name === name);
836
+ }
837
+ function actionResourceHandle(resource) {
838
+ return {
839
+ kind: "resource",
840
+ ref: normalizeEntityRef(resource)
841
+ };
842
+ }
843
+ function ActionButton(props) {
844
+ const def = useApp().registry.get(props.resource);
845
+ const scope = props.scope ?? "row";
846
+ const availability = useAvailabilityResolver(props.resource, modeForSurface(scope))(props.actionName, props.record);
847
+ const action = findAction(def?.actions?.item, props.actionName) ?? findAction(def?.actions?.resource, props.actionName);
848
+ if (!action) return null;
849
+ if (isFlowAction(action)) return jsx(FlowActionButton, { ...props });
850
+ if (availability.state === "absent" || availability.state === "hidden") return null;
851
+ if (!actionWhenHolds(action, props.record)) return null;
852
+ if (action.kind === "link") return jsx(LinkActionButton, {
853
+ ...props,
854
+ action,
855
+ availability
856
+ });
857
+ if (action.kind === "modal") return jsx(ModalActionButton, {
858
+ ...props,
859
+ action,
860
+ availability
861
+ });
862
+ return null;
863
+ }
864
+ function actionWhenHolds(action, record) {
865
+ const when = action.when;
866
+ if (when === void 0) return true;
867
+ return evaluateCondition(when, record === void 0 ? {} : { record: {
868
+ status: "ready",
869
+ value: record,
870
+ refreshing: false
871
+ } }, { mode: "show" }) === true;
872
+ }
873
+ function presentModalAction(args) {
874
+ const { present, action, resource, actionName, record, recordId, label } = args;
875
+ const result = present({
876
+ block: action.block,
877
+ props: action.props ?? {},
878
+ resource,
879
+ record,
880
+ host: action.host === "sheet" ? "sheet" : "dialog",
881
+ ...typeof label === "string" ? { label } : {},
882
+ activation: { surface: {
883
+ type: "item",
884
+ resource: normalizeEntityRef(resource),
885
+ recordId,
886
+ record
887
+ } }
888
+ });
889
+ if (!result.ok) console.error(`[buro/ui-shadcn] modal action "${actionName}" failed to open block "${action.block.namespace}:${action.block.id}": ${result.code}`);
890
+ }
891
+ function makeTestId(scope, resource, actionName, recordId, tid) {
892
+ if (scope === "row") return tid.listRowAction(resource, recordId, actionName);
893
+ if (scope === "list" && recordId === "") return tid.listFlow(resource, actionName);
894
+ return tid.formAction(resource, scope, actionName);
895
+ }
896
+ const reportedDeadRoutes = new Set();
897
+ function deadRecordRoute(registry, action, to) {
898
+ if (isBuiltinItemAction(action) || to === null || typeof to !== "object") return null;
899
+ const target = to;
900
+ if (typeof target.resource !== "string") return null;
901
+ if (target.action !== "show" && target.action !== "edit" && target.action !== "create") return null;
902
+ let def;
903
+ try {
904
+ def = registry.get(target.resource);
905
+ } catch {
906
+ return null;
907
+ }
908
+ if (def === void 0 || hasRecordPage(def, target.action)) return null;
909
+ return {
910
+ resource: target.resource,
911
+ action: target.action
912
+ };
913
+ }
914
+ function reportDeadRecordRoute(name, resource, action) {
915
+ if (process.env.NODE_ENV === "production") return;
916
+ const key = `${name}\u0000${resource}\u0000${action}`;
917
+ if (reportedDeadRoutes.has(key)) return;
918
+ reportedDeadRoutes.add(key);
919
+ console.error(`[burojs] The action "${name}" links to ${resource}'s ${action} page, and ${resource} has none (views.show.page: false).`);
920
+ }
921
+ function LinkActionButton({ resource, actionName, record, scope = "row", variant, size, density, className, children, asMenuItem, action, availability }) {
922
+ const tid = useTestIds();
923
+ const app = useApp();
924
+ const toBrowser = useToBrowserHref();
925
+ const safeRecord = record ?? { id: "" };
926
+ const isDestructive = action.variant === "destructive";
927
+ const buttonVariant = variant ?? (isDestructive ? "destructive" : "outline");
928
+ const recordId = record?.id ?? "";
929
+ const testid = makeTestId(scope, resource, actionName, recordId, tid);
930
+ const label = useResolvedLabel(action, actionName, children, resource);
931
+ const editRoute = useBuiltinEditRoute(action, resource, recordId);
932
+ const to = typeof action.to === "function" ? action.to(buildDI(actionResourceHandle(resource), safeRecord)) : action.to;
933
+ const href = resolveRoute(to, app.registry);
934
+ const target = action.target ?? "_self";
935
+ const deadPage = deadRecordRoute(app.registry, action, to);
936
+ const deadResource = deadPage?.resource;
937
+ const deadAction = deadPage?.action;
938
+ useEffect(() => {
939
+ if (deadResource !== void 0 && deadAction !== void 0) reportDeadRecordRoute(actionName, deadResource, deadAction);
940
+ }, [
941
+ deadResource,
942
+ deadAction,
943
+ actionName
944
+ ]);
945
+ const rel = target === "_blank" ? "noopener noreferrer" : void 0;
946
+ const RouterLink = useLinkComponent();
947
+ const Anchor = target === "_blank" || isExternalHref(href) ? "a" : RouterLink;
948
+ const anchorHref = target === "_blank" ? toBrowser(href) : href;
949
+ if (editRoute.kind === "none") return null;
950
+ if (availability.state === "disabled") return jsx(DisabledAction, {
951
+ reason: availability.reason,
952
+ label,
953
+ icon: resolveActionIcon(action, actionName),
954
+ testid,
955
+ size,
956
+ variant: buttonVariant,
957
+ className,
958
+ asMenuItem,
959
+ resource,
960
+ density,
961
+ actionName,
962
+ surface: scope
963
+ });
964
+ if (editRoute.kind === "quick") {
965
+ if (asMenuItem) return jsx(DropdownMenuItem, {
966
+ "data-testid": testid,
967
+ onSelect: () => editRoute.open(),
968
+ children: jsx(ActionInner, {
969
+ icon: resolveActionIcon(action, actionName),
970
+ label
971
+ })
972
+ });
973
+ const quickChrome = resolveControlChrome({
974
+ density: density ?? "regular",
975
+ icon: resolveActionIcon(action, actionName),
976
+ label,
977
+ actionName,
978
+ surface: scope
979
+ });
980
+ return withActionTooltip(jsx(Button, {
981
+ type: "button",
982
+ variant: buttonVariant,
983
+ size: quickChrome.size,
984
+ "aria-label": quickChrome.ariaLabel,
985
+ className: cn(quickChrome.className, className),
986
+ "data-testid": testid,
987
+ onClick: (e) => {
988
+ e.stopPropagation();
989
+ editRoute.open();
990
+ },
991
+ children: quickChrome.content
992
+ }), label, quickChrome.compact);
993
+ }
994
+ if (asMenuItem) return jsx(DropdownMenuItem, {
995
+ asChild: true,
996
+ className: cn(isDestructive && DESTRUCTIVE_ITEM),
997
+ children: jsx(Anchor, {
998
+ href: anchorHref,
999
+ target,
1000
+ rel,
1001
+ "data-testid": testid,
1002
+ onClick: (e) => e.stopPropagation(),
1003
+ children: jsx(ActionInner, {
1004
+ icon: resolveActionIcon(action, actionName),
1005
+ label
1006
+ })
1007
+ })
1008
+ });
1009
+ const chrome = resolveControlChrome({
1010
+ density: density ?? "regular",
1011
+ icon: resolveActionIcon(action, actionName),
1012
+ label,
1013
+ actionName,
1014
+ surface: scope
1015
+ });
1016
+ return withActionTooltip(jsx(Button, {
1017
+ asChild: true,
1018
+ variant: buttonVariant,
1019
+ size: chrome.size,
1020
+ "aria-label": chrome.ariaLabel,
1021
+ className: cn(chrome.className, className),
1022
+ children: jsx(Anchor, {
1023
+ href: anchorHref,
1024
+ target,
1025
+ rel,
1026
+ "data-testid": testid,
1027
+ onClick: (e) => e.stopPropagation(),
1028
+ children: chrome.content
1029
+ })
1030
+ }), label, chrome.compact);
1031
+ }
1032
+ function ModalActionButton({ resource, actionName, record, scope = "row", variant, size, density, className, children, asMenuItem, action, availability }) {
1033
+ const tid = useTestIds();
1034
+ const present = usePresentBlock();
1035
+ const safeRecord = record ?? { id: "" };
1036
+ const isDestructive = action.variant === "destructive";
1037
+ const buttonVariant = variant ?? (isDestructive ? "destructive" : "outline");
1038
+ const recordId = record?.id ?? "";
1039
+ const testid = makeTestId(scope, resource, actionName, recordId, tid);
1040
+ const label = useResolvedLabel(action, actionName, children, resource);
1041
+ if (availability.state === "disabled") return jsx(DisabledAction, {
1042
+ reason: availability.reason,
1043
+ label,
1044
+ icon: resolveActionIcon(action, actionName),
1045
+ testid,
1046
+ size,
1047
+ variant: buttonVariant,
1048
+ className,
1049
+ asMenuItem,
1050
+ resource,
1051
+ density,
1052
+ actionName,
1053
+ surface: scope
1054
+ });
1055
+ function openModal() {
1056
+ presentModalAction({
1057
+ present,
1058
+ action,
1059
+ resource,
1060
+ actionName,
1061
+ record: safeRecord,
1062
+ recordId,
1063
+ label
1064
+ });
1065
+ }
1066
+ if (asMenuItem) return jsx(DropdownMenuItem, {
1067
+ "data-testid": testid,
1068
+ className: cn(isDestructive && DESTRUCTIVE_ITEM),
1069
+ onSelect: openModal,
1070
+ children: jsx(ActionInner, {
1071
+ icon: resolveActionIcon(action, actionName),
1072
+ label
1073
+ })
1074
+ });
1075
+ const chrome = resolveControlChrome({
1076
+ density: density ?? "regular",
1077
+ icon: resolveActionIcon(action, actionName),
1078
+ label,
1079
+ actionName,
1080
+ surface: scope
1081
+ });
1082
+ return withActionTooltip(jsx(Button, {
1083
+ type: "button",
1084
+ variant: buttonVariant,
1085
+ size: chrome.size,
1086
+ "aria-label": chrome.ariaLabel,
1087
+ "data-testid": testid,
1088
+ onClick: (e) => {
1089
+ e.stopPropagation();
1090
+ openModal();
1091
+ },
1092
+ className: cn(chrome.className, className),
1093
+ children: chrome.content
1094
+ }), label, chrome.compact);
1095
+ }
1096
+ //#endregion
1097
+ //#region src/checks/check-confirm-dialog.tsx
1098
+ function translateOrFallback(t, key, fallback, params, resource) {
1099
+ const translated = t(key, {
1100
+ params,
1101
+ ...resource === void 0 ? {} : { resource }
1102
+ });
1103
+ return translated === key ? fallback : translated;
1104
+ }
1105
+ function issueText(issue, t, resource) {
1106
+ const declared = typeof issue.message.default === "string" ? issue.message.default : issue.message.key;
1107
+ if (issue.params?.resolved === true) return declared;
1108
+ return translateOrFallback(t, issue.message.key, declared, issue.params, resource);
1109
+ }
1110
+ function checkIdOf(issue, index) {
1111
+ const id = issue.params?.checkId;
1112
+ return typeof id === "string" ? id : `${index}`;
1113
+ }
1114
+ const SEVERITY_CLASSNAME = {
1115
+ error: "text-destructive",
1116
+ warning: "text-warning-emphasis",
1117
+ info: "text-muted-foreground"
1118
+ };
1119
+ function ChecksList({ issues, testid, onRowClick, resource }) {
1120
+ const t = useOptionalT();
1121
+ return issues.map((issue, index) => {
1122
+ const checkId = checkIdOf(issue, index);
1123
+ const anchor = issue.path[0];
1124
+ const anchorable = typeof anchor === "string";
1125
+ const text = issueText(issue, t, resource);
1126
+ const className = cn("text-sm", SEVERITY_CLASSNAME[issue.severity]);
1127
+ return anchorable ? jsx("li", { children: jsx("button", {
1128
+ type: "button",
1129
+ "data-testid": `${testid}:item:${checkId}`,
1130
+ className: cn(className, "text-left underline-offset-2 hover:underline"),
1131
+ onClick: () => onRowClick(anchor),
1132
+ children: text
1133
+ }) }, `${checkId}-${index}`) : jsx("li", {
1134
+ "data-testid": `${testid}:item:${checkId}`,
1135
+ className,
1136
+ children: text
1137
+ }, `${checkId}-${index}`);
1138
+ });
1139
+ }
1140
+ function CheckConfirmDialog({ state, testid, onAnchorFocus, title, proceedLabel, tone }) {
1141
+ const t = useOptionalT();
1142
+ const { resource, open, busy, header, blockers, confirmable, proceed, cancel } = state;
1143
+ const blocked = blockers.length > 0;
1144
+ const bound = resource === void 0 ? {} : { resource };
1145
+ const heading = title ?? t("checks.dialogTitle", {
1146
+ defaultValue: "Please review",
1147
+ ...bound
1148
+ });
1149
+ const restoreFocusRef = useRef(null);
1150
+ useEffect(() => {
1151
+ if (typeof document === "undefined") return;
1152
+ if (open) {
1153
+ const active = document.activeElement;
1154
+ if (active instanceof HTMLElement && active !== document.body) restoreFocusRef.current = active;
1155
+ return;
1156
+ }
1157
+ const target = restoreFocusRef.current;
1158
+ restoreFocusRef.current = null;
1159
+ if (!target || !document.contains(target)) return;
1160
+ const id = requestAnimationFrame(() => target.focus());
1161
+ return () => cancelAnimationFrame(id);
1162
+ }, [open]);
1163
+ const onRowClick = (field) => {
1164
+ onAnchorFocus?.(field);
1165
+ cancel();
1166
+ };
1167
+ return jsx(Dialog, {
1168
+ open,
1169
+ onOpenChange: (next) => {
1170
+ if (!next) cancel();
1171
+ },
1172
+ children: jsxs(DialogContent, {
1173
+ "data-testid": `${testid}:dialog`,
1174
+ className: "flex max-h-[85vh] flex-col overflow-hidden",
1175
+ children: [
1176
+ jsxs(DialogHeader, { children: [jsx(DialogTitle, { children: heading }), header !== null ? jsx(DialogDescription, { children: header }) : jsx(DialogDescription, {
1177
+ className: "sr-only",
1178
+ children: heading
1179
+ })] }),
1180
+ jsxs("ul", {
1181
+ className: "flex min-h-0 flex-1 flex-col gap-2 overflow-y-auto overscroll-contain",
1182
+ children: [
1183
+ blocked && jsx("li", {
1184
+ className: "text-xs font-semibold uppercase tracking-wider text-destructive",
1185
+ children: t("checks.blocked", {
1186
+ defaultValue: "Cannot continue",
1187
+ ...bound
1188
+ })
1189
+ }),
1190
+ jsx(ChecksList, {
1191
+ issues: blockers,
1192
+ testid,
1193
+ onRowClick,
1194
+ resource
1195
+ }),
1196
+ jsx(ChecksList, {
1197
+ issues: confirmable,
1198
+ testid,
1199
+ onRowClick,
1200
+ resource
1201
+ })
1202
+ ]
1203
+ }),
1204
+ jsxs(DialogFooter, { children: [jsx(Button, {
1205
+ type: "button",
1206
+ variant: "outline",
1207
+ onClick: cancel,
1208
+ "data-testid": `${testid}:cancel`,
1209
+ disabled: busy,
1210
+ children: t("checks.back", {
1211
+ defaultValue: "Go back",
1212
+ ...bound
1213
+ })
1214
+ }), !blocked && jsx(Button, {
1215
+ type: "button",
1216
+ variant: tone === "destructive" ? "destructive" : "default",
1217
+ onClick: proceed,
1218
+ "data-testid": `${testid}:proceed`,
1219
+ disabled: busy,
1220
+ children: proceedLabel ?? t("checks.proceed", {
1221
+ defaultValue: "Continue anyway",
1222
+ ...bound
1223
+ })
1224
+ })] })
1225
+ ]
1226
+ })
1227
+ });
1228
+ }
1229
+ //#endregion
1230
+ 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 };
1231
+
1232
+ //# sourceMappingURL=check-confirm-dialog-CkaVTPT9.js.map