@burojs/ui-shadcn 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. package/README.md +9 -0
  2. package/dist/bulk-summary-BWSAS7k2.js +143 -0
  3. package/dist/bulk-summary-BWSAS7k2.js.map +1 -0
  4. package/dist/bulk-summary-CrEij5vq.cjs +143 -0
  5. package/dist/bulk-summary-CrEij5vq.cjs.map +1 -0
  6. package/dist/candidates-relation-picker-CS_JZ4Fd.js +31 -0
  7. package/dist/candidates-relation-picker-CS_JZ4Fd.js.map +1 -0
  8. package/dist/candidates-relation-picker-y5M6_oe4.cjs +31 -0
  9. package/dist/candidates-relation-picker-y5M6_oe4.cjs.map +1 -0
  10. package/dist/{check-confirm-dialog-CkaVTPT9.js → check-confirm-dialog-2j0gOd7x.js} +392 -103
  11. package/dist/check-confirm-dialog-2j0gOd7x.js.map +1 -0
  12. package/dist/{check-confirm-dialog-BRByTFpg.cjs → check-confirm-dialog-C-NHgMST.cjs} +476 -102
  13. package/dist/check-confirm-dialog-C-NHgMST.cjs.map +1 -0
  14. package/dist/{dialog-B_rt9S1c.js → dialog-C123sVQ8.js} +4 -4
  15. package/dist/dialog-C123sVQ8.js.map +1 -0
  16. package/dist/{dialog-DRNUq9EA.cjs → dialog-vmMdfUWs.cjs} +3 -3
  17. package/dist/dialog-vmMdfUWs.cjs.map +1 -0
  18. package/dist/{filter-builder-B3mZFL-K.cjs → filter-builder-DFu0JP-1.cjs} +959 -128
  19. package/dist/filter-builder-DFu0JP-1.cjs.map +1 -0
  20. package/dist/{filter-builder-DOnaXNfP.js → filter-builder-DaWHUZuV.js} +863 -116
  21. package/dist/filter-builder-DaWHUZuV.js.map +1 -0
  22. package/dist/{flow-runtime-B6zOHYqI.cjs → flow-runtime-BpmrIUb6.cjs} +61 -29
  23. package/dist/flow-runtime-BpmrIUb6.cjs.map +1 -0
  24. package/dist/{flow-runtime-D8h99FSg.js → flow-runtime-DyqTmK3H.js} +62 -30
  25. package/dist/flow-runtime-DyqTmK3H.js.map +1 -0
  26. package/dist/{flow-screen-CX05b3G9.cjs → flow-screen-Bcz9NF2V.cjs} +132 -88
  27. package/dist/flow-screen-Bcz9NF2V.cjs.map +1 -0
  28. package/dist/{flow-screen-CmbARSqg.js → flow-screen-DCdli6Ha.js} +132 -88
  29. package/dist/flow-screen-DCdli6Ha.js.map +1 -0
  30. package/dist/index.cjs +951 -605
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.d.cts +618 -332
  33. package/dist/index.d.ts +618 -332
  34. package/dist/index.js +863 -522
  35. package/dist/index.js.map +1 -1
  36. package/dist/{inline-flow-host-B7U1OJUe.cjs → inline-flow-host-3vw7LzzD.cjs} +5 -5
  37. package/dist/inline-flow-host-3vw7LzzD.cjs.map +1 -0
  38. package/dist/{inline-flow-host-C3H2UpSA.js → inline-flow-host-C0rI9B7f.js} +5 -5
  39. package/dist/inline-flow-host-C0rI9B7f.js.map +1 -0
  40. package/dist/label-66W1qbke.js.map +1 -1
  41. package/dist/label-w6JYf2cF.cjs.map +1 -1
  42. package/dist/lazy-relation-picker-dialog-Bt8lrEIu.cjs +153 -0
  43. package/dist/lazy-relation-picker-dialog-Bt8lrEIu.cjs.map +1 -0
  44. package/dist/lazy-relation-picker-dialog-CAScLPb2.js +135 -0
  45. package/dist/lazy-relation-picker-dialog-CAScLPb2.js.map +1 -0
  46. package/dist/markdown/index.d.cts +2 -3
  47. package/dist/markdown/index.d.ts +2 -3
  48. package/dist/{page-flow-route-CyXSvXSE.js → page-flow-route-BHUEpn0I.js} +36 -23
  49. package/dist/page-flow-route-BHUEpn0I.js.map +1 -0
  50. package/dist/{page-flow-route-CQ7HsbBm.cjs → page-flow-route-DS8IVTVH.cjs} +41 -28
  51. package/dist/page-flow-route-DS8IVTVH.cjs.map +1 -0
  52. package/dist/{place-node-SIp4XYQH.cjs → place-node-CNb3w-c7.cjs} +2227 -999
  53. package/dist/place-node-CNb3w-c7.cjs.map +1 -0
  54. package/dist/{place-node--GdsP688.js → place-node-CfzQvh4Y.js} +2164 -984
  55. package/dist/place-node-CfzQvh4Y.js.map +1 -0
  56. package/dist/{related-list-cards-B6x9HQQp.js → related-list-cards-BIqqY69Y.js} +9 -4
  57. package/dist/{related-list-cards-B6x9HQQp.js.map → related-list-cards-BIqqY69Y.js.map} +1 -1
  58. package/dist/{related-list-cards-nxuODlIA.cjs → related-list-cards-CelMxl4q.cjs} +9 -4
  59. package/dist/{related-list-cards-nxuODlIA.cjs.map → related-list-cards-CelMxl4q.cjs.map} +1 -1
  60. package/dist/{related-list-timeline-DEdfd-rr.js → related-list-timeline-CRh7xwLD.js} +6 -7
  61. package/dist/related-list-timeline-CRh7xwLD.js.map +1 -0
  62. package/dist/{related-list-timeline-BYJKEbmA.cjs → related-list-timeline-DsLdi8sv.cjs} +5 -6
  63. package/dist/related-list-timeline-DsLdi8sv.cjs.map +1 -0
  64. package/dist/{related-rows-B4levHcR.js → related-rows--uP2iKQC.js} +27 -17
  65. package/dist/related-rows--uP2iKQC.js.map +1 -0
  66. package/dist/{related-rows-zh5f_4QR.cjs → related-rows-MPnLCmPF.cjs} +32 -22
  67. package/dist/related-rows-MPnLCmPF.cjs.map +1 -0
  68. package/dist/{search-access-CURsWn-U.js → relation-create-C43cdPQt.js} +596 -29
  69. package/dist/relation-create-C43cdPQt.js.map +1 -0
  70. package/dist/{search-access-B7G5oR8n.cjs → relation-create-DDEYcKfw.cjs} +630 -32
  71. package/dist/relation-create-DDEYcKfw.cjs.map +1 -0
  72. package/dist/{relation-many-picker-gdAOD-qK.js → relation-many-picker-BJhaEqxz.js} +210 -107
  73. package/dist/relation-many-picker-BJhaEqxz.js.map +1 -0
  74. package/dist/{relation-many-picker-B-NCEUgX.cjs → relation-many-picker-DzuGJpEl.cjs} +218 -115
  75. package/dist/relation-many-picker-DzuGJpEl.cjs.map +1 -0
  76. package/dist/{relation-picker-BAY77ivO.js → relation-picker-D-tBBZW_.js} +40 -45
  77. package/dist/relation-picker-D-tBBZW_.js.map +1 -0
  78. package/dist/{relation-picker-Da_uhFvA.cjs → relation-picker-DaIMzf2H.cjs} +45 -50
  79. package/dist/relation-picker-DaIMzf2H.cjs.map +1 -0
  80. package/dist/{relation-picker-dialog-M0pQaWlp.cjs → relation-picker-dialog-9Vg5vvR1.cjs} +142 -40
  81. package/dist/relation-picker-dialog-9Vg5vvR1.cjs.map +1 -0
  82. package/dist/{relation-picker-dialog-hA9rYrZB.js → relation-picker-dialog-DoEY8EkH.js} +143 -41
  83. package/dist/relation-picker-dialog-DoEY8EkH.js.map +1 -0
  84. package/dist/relation-select-B8Fq4o-t.js +48 -0
  85. package/dist/relation-select-B8Fq4o-t.js.map +1 -0
  86. package/dist/relation-select-Cr3CfNLy.cjs +55 -0
  87. package/dist/relation-select-Cr3CfNLy.cjs.map +1 -0
  88. package/dist/{resource-page-router-OSQyRA5b.cjs → resource-page-router-C_kGW2o_.cjs} +552 -303
  89. package/dist/resource-page-router-C_kGW2o_.cjs.map +1 -0
  90. package/dist/{resource-page-router-T4vS5gbJ.js → resource-page-router-Diw6S6TK.js} +507 -258
  91. package/dist/resource-page-router-Diw6S6TK.js.map +1 -0
  92. package/dist/{rich-text-vTyVjDoa.cjs → rich-text-C_7JCvRo.cjs} +2 -2
  93. package/dist/{rich-text-vTyVjDoa.cjs.map → rich-text-C_7JCvRo.cjs.map} +1 -1
  94. package/dist/{rich-text-DFerywgz.js → rich-text-RcPBf6hr.js} +2 -2
  95. package/dist/{rich-text-DFerywgz.js.map → rich-text-RcPBf6hr.js.map} +1 -1
  96. package/dist/success-notices-Dl3M1fZP.cjs +46 -0
  97. package/dist/success-notices-Dl3M1fZP.cjs.map +1 -0
  98. package/dist/success-notices-LDEgEkc4.js +41 -0
  99. package/dist/success-notices-LDEgEkc4.js.map +1 -0
  100. package/dist/{toaster-C7CiYA4Z.cjs → toaster-BbByOytP.cjs} +72 -80
  101. package/dist/toaster-BbByOytP.cjs.map +1 -0
  102. package/dist/{toaster-CfCRLgR-.js → toaster-Ct_YHGs6.js} +66 -68
  103. package/dist/toaster-Ct_YHGs6.js.map +1 -0
  104. package/dist/{use-dialog-filter-state-BDcgS5Oz.js → use-dialog-filter-state-B_MqzHaT.js} +5 -4
  105. package/dist/use-dialog-filter-state-B_MqzHaT.js.map +1 -0
  106. package/dist/{use-dialog-filter-state-BBCC0OEK.cjs → use-dialog-filter-state-tNvqAAjh.cjs} +6 -5
  107. package/dist/use-dialog-filter-state-tNvqAAjh.cjs.map +1 -0
  108. package/dist/use-theme-DFlpXils.cjs.map +1 -1
  109. package/dist/use-theme-dnE3Od3I.js.map +1 -1
  110. package/package.json +11 -11
  111. package/dist/bulk-summary-CwSd6Yjb.cjs +0 -108
  112. package/dist/bulk-summary-CwSd6Yjb.cjs.map +0 -1
  113. package/dist/bulk-summary-GxMDP4bw.js +0 -108
  114. package/dist/bulk-summary-GxMDP4bw.js.map +0 -1
  115. package/dist/candidates-gate-CX2PBu6l.js +0 -63
  116. package/dist/candidates-gate-CX2PBu6l.js.map +0 -1
  117. package/dist/candidates-gate-DiFI52r7.cjs +0 -70
  118. package/dist/candidates-gate-DiFI52r7.cjs.map +0 -1
  119. package/dist/candidates-relation-picker-CBsVcnPR.js +0 -82
  120. package/dist/candidates-relation-picker-CBsVcnPR.js.map +0 -1
  121. package/dist/candidates-relation-picker-Dd_GVLlu.cjs +0 -84
  122. package/dist/candidates-relation-picker-Dd_GVLlu.cjs.map +0 -1
  123. package/dist/check-confirm-dialog-BRByTFpg.cjs.map +0 -1
  124. package/dist/check-confirm-dialog-CkaVTPT9.js.map +0 -1
  125. package/dist/dialog-B_rt9S1c.js.map +0 -1
  126. package/dist/dialog-DRNUq9EA.cjs.map +0 -1
  127. package/dist/filter-builder-B3mZFL-K.cjs.map +0 -1
  128. package/dist/filter-builder-DOnaXNfP.js.map +0 -1
  129. package/dist/flow-runtime-B6zOHYqI.cjs.map +0 -1
  130. package/dist/flow-runtime-D8h99FSg.js.map +0 -1
  131. package/dist/flow-screen-CX05b3G9.cjs.map +0 -1
  132. package/dist/flow-screen-CmbARSqg.js.map +0 -1
  133. package/dist/inline-flow-host-B7U1OJUe.cjs.map +0 -1
  134. package/dist/inline-flow-host-C3H2UpSA.js.map +0 -1
  135. package/dist/lazy-relation-picker-dialog-2oxnA6IR.js +0 -14
  136. package/dist/lazy-relation-picker-dialog-2oxnA6IR.js.map +0 -1
  137. package/dist/lazy-relation-picker-dialog-BfAGKzUG.cjs +0 -19
  138. package/dist/lazy-relation-picker-dialog-BfAGKzUG.cjs.map +0 -1
  139. package/dist/page-flow-route-CQ7HsbBm.cjs.map +0 -1
  140. package/dist/page-flow-route-CyXSvXSE.js.map +0 -1
  141. package/dist/peek-filter-CnqHwTMU.cjs +0 -51
  142. package/dist/peek-filter-CnqHwTMU.cjs.map +0 -1
  143. package/dist/peek-filter-ErLfO153.js +0 -28
  144. package/dist/peek-filter-ErLfO153.js.map +0 -1
  145. package/dist/place-node--GdsP688.js.map +0 -1
  146. package/dist/place-node-SIp4XYQH.cjs.map +0 -1
  147. package/dist/related-list-timeline-BYJKEbmA.cjs.map +0 -1
  148. package/dist/related-list-timeline-DEdfd-rr.js.map +0 -1
  149. package/dist/related-rows-B4levHcR.js.map +0 -1
  150. package/dist/related-rows-zh5f_4QR.cjs.map +0 -1
  151. package/dist/relation-create-BOaUe12G.cjs +0 -362
  152. package/dist/relation-create-BOaUe12G.cjs.map +0 -1
  153. package/dist/relation-create-Bg-eEJLs.js +0 -337
  154. package/dist/relation-create-Bg-eEJLs.js.map +0 -1
  155. package/dist/relation-many-picker-B-NCEUgX.cjs.map +0 -1
  156. package/dist/relation-many-picker-gdAOD-qK.js.map +0 -1
  157. package/dist/relation-picker-BAY77ivO.js.map +0 -1
  158. package/dist/relation-picker-Da_uhFvA.cjs.map +0 -1
  159. package/dist/relation-picker-dialog-M0pQaWlp.cjs.map +0 -1
  160. package/dist/relation-picker-dialog-hA9rYrZB.js.map +0 -1
  161. package/dist/resource-page-router-OSQyRA5b.cjs.map +0 -1
  162. package/dist/resource-page-router-T4vS5gbJ.js.map +0 -1
  163. package/dist/search-access-B7G5oR8n.cjs.map +0 -1
  164. package/dist/search-access-CURsWn-U.js.map +0 -1
  165. package/dist/shell-BPlk8hEa.js +0 -205
  166. package/dist/shell-BPlk8hEa.js.map +0 -1
  167. package/dist/shell-DxhlsPwm.cjs +0 -271
  168. package/dist/shell-DxhlsPwm.cjs.map +0 -1
  169. package/dist/toaster-C7CiYA4Z.cjs.map +0 -1
  170. package/dist/toaster-CfCRLgR-.js.map +0 -1
  171. package/dist/use-dialog-filter-state-BBCC0OEK.cjs.map +0 -1
  172. package/dist/use-dialog-filter-state-BDcgS5Oz.js.map +0 -1
@@ -1,271 +0,0 @@
1
- const require_use_theme = require("./use-theme-DFlpXils.cjs");
2
- const require_dialog = require("./dialog-DRNUq9EA.cjs");
3
- let _burojs_react = require("@burojs/react");
4
- let _tabler_icons_react = require("@tabler/icons-react");
5
- let react = require("react");
6
- react = require_use_theme.__toESM(react, 1);
7
- let react_jsx_runtime = require("react/jsx-runtime");
8
- let class_variance_authority = require("class-variance-authority");
9
- let _radix_ui_react_dialog = require("@radix-ui/react-dialog");
10
- _radix_ui_react_dialog = require_use_theme.__toESM(_radix_ui_react_dialog, 1);
11
- //#region src/primitives/sheet.tsx
12
- const Sheet = _radix_ui_react_dialog.Root;
13
- const SheetTrigger = _radix_ui_react_dialog.Trigger;
14
- const SheetClose = _radix_ui_react_dialog.Close;
15
- const SheetPortal = _radix_ui_react_dialog.Portal;
16
- const SheetOverlay = react.forwardRef(({ className, ...props }, ref) => (0, react_jsx_runtime.jsx)(_radix_ui_react_dialog.Overlay, {
17
- className: require_use_theme.cn("fixed inset-0 z-50 bg-overlay/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 duration-[var(--duration-panel)] ease-[var(--ease-overlay)]", className),
18
- ...props,
19
- ref
20
- }));
21
- SheetOverlay.displayName = _radix_ui_react_dialog.Overlay.displayName;
22
- const sheetVariants = (0, class_variance_authority.cva)("fixed z-50 gap-4 bg-background text-foreground p-6 shadow-lg duration-[var(--duration-panel)] ease-[var(--ease-overlay)] data-[state=open]:animate-in data-[state=closed]:animate-out", {
23
- variants: { side: {
24
- top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
25
- bottom: "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
26
- left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
27
- right: "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm"
28
- } },
29
- defaultVariants: { side: "right" }
30
- });
31
- const SheetContent = react.forwardRef(({ side = "right", className, children, showClose = true, ...props }, ref) => {
32
- const t = (0, _burojs_react.useOptionalT)();
33
- return (0, react_jsx_runtime.jsxs)(SheetPortal, { children: [(0, react_jsx_runtime.jsx)(SheetOverlay, {}), (0, react_jsx_runtime.jsxs)(_radix_ui_react_dialog.Content, {
34
- ref,
35
- className: require_use_theme.cn(sheetVariants({ side }), className),
36
- ...props,
37
- children: [children, showClose && (0, react_jsx_runtime.jsxs)(_radix_ui_react_dialog.Close, {
38
- className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary",
39
- children: [(0, react_jsx_runtime.jsx)(_tabler_icons_react.IconX, { className: "h-4 w-4" }), (0, react_jsx_runtime.jsx)("span", {
40
- className: "sr-only",
41
- children: t("actions.close", { defaultValue: "Close" })
42
- })]
43
- })]
44
- })] });
45
- });
46
- SheetContent.displayName = _radix_ui_react_dialog.Content.displayName;
47
- function SheetHeader({ className, ...props }) {
48
- return (0, react_jsx_runtime.jsx)("div", {
49
- className: require_use_theme.cn("flex flex-col space-y-2 text-center sm:text-left", className),
50
- ...props
51
- });
52
- }
53
- SheetHeader.displayName = "SheetHeader";
54
- function SheetFooter({ className, ...props }) {
55
- return (0, react_jsx_runtime.jsx)("div", {
56
- className: require_use_theme.cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className),
57
- ...props
58
- });
59
- }
60
- SheetFooter.displayName = "SheetFooter";
61
- const SheetTitle = react.forwardRef(({ className, ...props }, ref) => (0, react_jsx_runtime.jsx)(_radix_ui_react_dialog.Title, {
62
- ref,
63
- className: require_use_theme.cn("text-lg font-semibold text-foreground", className),
64
- ...props
65
- }));
66
- SheetTitle.displayName = _radix_ui_react_dialog.Title.displayName;
67
- const SheetDescription = react.forwardRef(({ className, ...props }, ref) => (0, react_jsx_runtime.jsx)(_radix_ui_react_dialog.Description, {
68
- ref,
69
- className: require_use_theme.cn("text-sm text-muted-foreground", className),
70
- ...props
71
- }));
72
- SheetDescription.displayName = _radix_ui_react_dialog.Description.displayName;
73
- //#endregion
74
- //#region src/ui-presentations/shell.tsx
75
- const OwnTitleContext = (0, react.createContext)(false);
76
- function focusOwnHeading(event) {
77
- const container = event.currentTarget;
78
- if (!(container instanceof HTMLElement)) return;
79
- const heading = container.querySelector("[data-buro-overlay-heading]");
80
- if (!(heading instanceof HTMLElement)) return;
81
- event.preventDefault();
82
- heading.focus();
83
- }
84
- function WrappedDialogContent({ wrapper, copy, children }) {
85
- return wrapper ? (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)(require_dialog.DialogHeader, { children: [(0, react_jsx_runtime.jsx)(require_dialog.DialogTitle, { children: copy.title }), (0, react_jsx_runtime.jsx)(require_dialog.DialogDescription, {
86
- className: copy.description === void 0 ? "sr-only" : void 0,
87
- children: copy.description ?? ""
88
- })] }), children] }) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
89
- (0, react_jsx_runtime.jsx)(require_dialog.DialogTitle, {
90
- className: "sr-only",
91
- children: copy.title
92
- }),
93
- (0, react_jsx_runtime.jsx)(require_dialog.DialogDescription, {
94
- className: "sr-only",
95
- children: copy.description ?? ""
96
- }),
97
- children
98
- ] });
99
- }
100
- function WrappedSheetContent({ wrapper, copy, children }) {
101
- return wrapper ? (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)(SheetHeader, { children: [(0, react_jsx_runtime.jsx)(SheetTitle, { children: copy.title }), (0, react_jsx_runtime.jsx)(SheetDescription, {
102
- className: copy.description === void 0 ? "sr-only" : void 0,
103
- children: copy.description ?? ""
104
- })] }), children] }) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
105
- (0, react_jsx_runtime.jsx)(SheetTitle, {
106
- className: "sr-only",
107
- children: copy.title
108
- }),
109
- (0, react_jsx_runtime.jsx)(SheetDescription, {
110
- className: "sr-only",
111
- children: copy.description ?? ""
112
- }),
113
- children
114
- ] });
115
- }
116
- function useFocusRestoration() {
117
- const returnFocus = (0, react.useRef)(typeof document === "undefined" || !(document.activeElement instanceof HTMLElement) ? null : document.activeElement);
118
- (0, react.useEffect)(() => () => {
119
- const element = returnFocus.current;
120
- queueMicrotask(() => {
121
- if (element?.isConnected && element !== document.body) {
122
- element.focus();
123
- return;
124
- }
125
- const main = document.querySelector("main");
126
- if (main === null) return;
127
- if (!main.hasAttribute("tabindex")) main.setAttribute("tabindex", "-1");
128
- main.focus();
129
- });
130
- }, []);
131
- }
132
- function keepForPopover(event) {
133
- const target = event.target;
134
- if (target instanceof Element && target.closest("[data-buro-popover]") !== null) event.preventDefault();
135
- }
136
- const REDUCED_MOTION = "motion-reduce:animate-none motion-reduce:transition-none";
137
- function DialogPresentationShell({ dismiss, wrapper, copy, ownTitle = false, children }) {
138
- useFocusRestoration();
139
- return (0, react_jsx_runtime.jsx)(require_dialog.Dialog, {
140
- open: true,
141
- onOpenChange: (open) => {
142
- if (!open) dismiss();
143
- },
144
- children: ownTitle ? (0, react_jsx_runtime.jsx)(require_dialog.DialogContent, {
145
- className: `flex max-h-[85vh] flex-col ${REDUCED_MOTION}`,
146
- overlayClassName: REDUCED_MOTION,
147
- showClose: wrapper,
148
- "aria-describedby": void 0,
149
- "aria-modal": "true",
150
- onOpenAutoFocus: focusOwnHeading,
151
- onPointerDownOutside: keepForPopover,
152
- children: (0, react_jsx_runtime.jsx)(OwnTitleContext.Provider, {
153
- value: true,
154
- children
155
- })
156
- }) : (0, react_jsx_runtime.jsx)(require_dialog.DialogContent, {
157
- className: REDUCED_MOTION,
158
- overlayClassName: REDUCED_MOTION,
159
- showClose: wrapper,
160
- "aria-modal": "true",
161
- onPointerDownOutside: keepForPopover,
162
- children: (0, react_jsx_runtime.jsx)(WrappedDialogContent, {
163
- wrapper,
164
- copy,
165
- children
166
- })
167
- })
168
- });
169
- }
170
- function SheetPresentationShell({ dismiss, wrapper, copy, ownTitle = false, children }) {
171
- useFocusRestoration();
172
- return (0, react_jsx_runtime.jsx)(Sheet, {
173
- open: true,
174
- onOpenChange: (open) => {
175
- if (!open) dismiss();
176
- },
177
- children: ownTitle ? (0, react_jsx_runtime.jsx)(SheetContent, {
178
- side: "right",
179
- className: `flex flex-col sm:max-w-xl ${REDUCED_MOTION}`,
180
- showClose: wrapper,
181
- "aria-describedby": void 0,
182
- "aria-modal": "true",
183
- onOpenAutoFocus: focusOwnHeading,
184
- onPointerDownOutside: keepForPopover,
185
- children: (0, react_jsx_runtime.jsx)(OwnTitleContext.Provider, {
186
- value: true,
187
- children
188
- })
189
- }) : (0, react_jsx_runtime.jsx)(SheetContent, {
190
- side: "right",
191
- className: `sm:max-w-xl ${REDUCED_MOTION}`,
192
- showClose: wrapper,
193
- "aria-modal": "true",
194
- onPointerDownOutside: keepForPopover,
195
- children: (0, react_jsx_runtime.jsx)(WrappedSheetContent, {
196
- wrapper,
197
- copy,
198
- children
199
- })
200
- })
201
- });
202
- }
203
- //#endregion
204
- Object.defineProperty(exports, "DialogPresentationShell", {
205
- enumerable: true,
206
- get: function() {
207
- return DialogPresentationShell;
208
- }
209
- });
210
- Object.defineProperty(exports, "OwnTitleContext", {
211
- enumerable: true,
212
- get: function() {
213
- return OwnTitleContext;
214
- }
215
- });
216
- Object.defineProperty(exports, "Sheet", {
217
- enumerable: true,
218
- get: function() {
219
- return Sheet;
220
- }
221
- });
222
- Object.defineProperty(exports, "SheetClose", {
223
- enumerable: true,
224
- get: function() {
225
- return SheetClose;
226
- }
227
- });
228
- Object.defineProperty(exports, "SheetContent", {
229
- enumerable: true,
230
- get: function() {
231
- return SheetContent;
232
- }
233
- });
234
- Object.defineProperty(exports, "SheetDescription", {
235
- enumerable: true,
236
- get: function() {
237
- return SheetDescription;
238
- }
239
- });
240
- Object.defineProperty(exports, "SheetFooter", {
241
- enumerable: true,
242
- get: function() {
243
- return SheetFooter;
244
- }
245
- });
246
- Object.defineProperty(exports, "SheetHeader", {
247
- enumerable: true,
248
- get: function() {
249
- return SheetHeader;
250
- }
251
- });
252
- Object.defineProperty(exports, "SheetPresentationShell", {
253
- enumerable: true,
254
- get: function() {
255
- return SheetPresentationShell;
256
- }
257
- });
258
- Object.defineProperty(exports, "SheetTitle", {
259
- enumerable: true,
260
- get: function() {
261
- return SheetTitle;
262
- }
263
- });
264
- Object.defineProperty(exports, "SheetTrigger", {
265
- enumerable: true,
266
- get: function() {
267
- return SheetTrigger;
268
- }
269
- });
270
-
271
- //# sourceMappingURL=shell-DxhlsPwm.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"shell-DxhlsPwm.cjs","names":["SheetPrimitive","React","cn","cva","useOptionalT","IconX","createContext","DialogHeader","DialogTitle","DialogDescription","useRef","Dialog","DialogContent"],"sources":["../src/primitives/sheet.tsx","../src/ui-presentations/shell.tsx"],"sourcesContent":["'use client';\nimport { useOptionalT } from '@burojs/react';\n\nimport * as React from 'react';\nimport * as SheetPrimitive from '@radix-ui/react-dialog';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { IconX } from '@tabler/icons-react';\nimport { cn } from '../lib/cn.js';\n\nconst Sheet = SheetPrimitive.Root;\nconst SheetTrigger = SheetPrimitive.Trigger;\nconst SheetClose = SheetPrimitive.Close;\nconst SheetPortal = SheetPrimitive.Portal;\n\nexport type SheetOverlayProps = React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>;\n\nconst SheetOverlay = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Overlay>,\n SheetOverlayProps\n>(({ className, ...props }, ref) => (\n <SheetPrimitive.Overlay\n className={cn(\n 'fixed inset-0 z-50 bg-overlay/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 duration-[var(--duration-panel)] ease-[var(--ease-overlay)]',\n className,\n )}\n {...props}\n ref={ref}\n />\n));\nSheetOverlay.displayName = SheetPrimitive.Overlay.displayName;\n\nconst sheetVariants = cva(\n 'fixed z-50 gap-4 bg-background text-foreground p-6 shadow-lg duration-[var(--duration-panel)] ease-[var(--ease-overlay)] data-[state=open]:animate-in data-[state=closed]:animate-out',\n {\n variants: {\n side: {\n top: 'inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top',\n bottom:\n 'inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom',\n left: 'inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm',\n right:\n 'inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm',\n },\n },\n defaultVariants: {\n side: 'right',\n },\n },\n);\n\nexport interface SheetContentProps\n extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,\n VariantProps<typeof sheetVariants> {\n /** Whether the standard visual close button is rendered. Defaults to true. */\n showClose?: boolean;\n}\n\nconst SheetContent = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Content>,\n SheetContentProps\n>(({ side = 'right', className, children, showClose = true, ...props }, ref) => {\n const t = useOptionalT();\n return (\n <SheetPortal>\n <SheetOverlay />\n <SheetPrimitive.Content\n ref={ref}\n className={cn(sheetVariants({ side }), className)}\n {...props}\n >\n {children}\n {showClose && (\n <SheetPrimitive.Close className=\"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary\">\n <IconX className=\"h-4 w-4\" />\n <span className=\"sr-only\">{t('actions.close', { defaultValue: 'Close' })}</span>\n </SheetPrimitive.Close>\n )}\n </SheetPrimitive.Content>\n </SheetPortal>\n );\n});\nSheetContent.displayName = SheetPrimitive.Content.displayName;\n\nexport type SheetHeaderProps = React.HTMLAttributes<HTMLDivElement>;\n\nfunction SheetHeader({ className, ...props }: SheetHeaderProps) {\n return (\n <div className={cn('flex flex-col space-y-2 text-center sm:text-left', className)} {...props} />\n );\n}\nSheetHeader.displayName = 'SheetHeader';\n\nexport type SheetFooterProps = React.HTMLAttributes<HTMLDivElement>;\n\nfunction SheetFooter({ className, ...props }: SheetFooterProps) {\n return (\n <div\n className={cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', className)}\n {...props}\n />\n );\n}\nSheetFooter.displayName = 'SheetFooter';\n\nexport type SheetTitleProps = React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>;\n\nconst SheetTitle = React.forwardRef<React.ElementRef<typeof SheetPrimitive.Title>, SheetTitleProps>(\n ({ className, ...props }, ref) => (\n <SheetPrimitive.Title\n ref={ref}\n className={cn('text-lg font-semibold text-foreground', className)}\n {...props}\n />\n ),\n);\nSheetTitle.displayName = SheetPrimitive.Title.displayName;\n\nexport type SheetDescriptionProps = React.ComponentPropsWithoutRef<\n typeof SheetPrimitive.Description\n>;\n\nconst SheetDescription = React.forwardRef<\n React.ElementRef<typeof SheetPrimitive.Description>,\n SheetDescriptionProps\n>(({ className, ...props }, ref) => (\n <SheetPrimitive.Description\n ref={ref}\n className={cn('text-sm text-muted-foreground', className)}\n {...props}\n />\n));\nSheetDescription.displayName = SheetPrimitive.Description.displayName;\n\nexport {\n Sheet,\n SheetTrigger,\n SheetContent,\n SheetHeader,\n SheetFooter,\n SheetTitle,\n SheetDescription,\n SheetClose,\n};\n","import { createContext, useEffect, useRef, type ReactNode } from 'react';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from '../primitives/dialog.js';\nimport {\n Sheet,\n SheetContent,\n SheetDescription,\n SheetHeader,\n SheetTitle,\n} from '../primitives/sheet.js';\n\nexport interface PresentationCopy {\n readonly title: string;\n readonly description?: string;\n}\n\ninterface PresentationShellProps {\n readonly dismiss: () => void;\n readonly wrapper: boolean;\n readonly copy: PresentationCopy;\n /**\n * The presented component renders the overlay's title itself, as the Radix `Title` (a quick\n * entry's record title, plan ruling 2): the shell renders no title and no description, and\n * focus moves to the element marked `data-buro-overlay-heading` on open.\n */\n readonly ownTitle?: boolean;\n readonly children: ReactNode;\n}\n\n/**\n * @internal True inside a kit shell asked for `ownTitle`: the presented component may render the\n * Radix `Title` (an app's host, which may not be a Radix dialog at all, leaves it `false`).\n */\nexport const OwnTitleContext = createContext(false);\n\n/** On open, focus the presented component's own heading instead of the first tabbable. */\nfunction focusOwnHeading(event: Event): void {\n const container = event.currentTarget;\n if (!(container instanceof HTMLElement)) return;\n const heading = container.querySelector('[data-buro-overlay-heading]');\n if (!(heading instanceof HTMLElement)) return;\n event.preventDefault();\n heading.focus();\n}\n\nfunction WrappedDialogContent({\n wrapper,\n copy,\n children,\n}: Pick<PresentationShellProps, 'wrapper' | 'copy' | 'children'>) {\n return wrapper ? (\n <>\n <DialogHeader>\n <DialogTitle>{copy.title}</DialogTitle>\n <DialogDescription className={copy.description === undefined ? 'sr-only' : undefined}>\n {copy.description ?? ''}\n </DialogDescription>\n </DialogHeader>\n {children}\n </>\n ) : (\n <>\n <DialogTitle className=\"sr-only\">{copy.title}</DialogTitle>\n <DialogDescription className=\"sr-only\">{copy.description ?? ''}</DialogDescription>\n {children}\n </>\n );\n}\n\nfunction WrappedSheetContent({\n wrapper,\n copy,\n children,\n}: Pick<PresentationShellProps, 'wrapper' | 'copy' | 'children'>) {\n return wrapper ? (\n <>\n <SheetHeader>\n <SheetTitle>{copy.title}</SheetTitle>\n <SheetDescription className={copy.description === undefined ? 'sr-only' : undefined}>\n {copy.description ?? ''}\n </SheetDescription>\n </SheetHeader>\n {children}\n </>\n ) : (\n <>\n <SheetTitle className=\"sr-only\">{copy.title}</SheetTitle>\n <SheetDescription className=\"sr-only\">{copy.description ?? ''}</SheetDescription>\n {children}\n </>\n );\n}\n\nfunction useFocusRestoration(): void {\n // Capture before Radix moves focus into the portal. The host may be removed\n // immediately after `dismiss`, so defer restoration until Radix cleanup has\n // completed its own focus handling.\n const returnFocus = useRef<HTMLElement | null>(\n typeof document === 'undefined' || !(document.activeElement instanceof HTMLElement)\n ? null\n : document.activeElement,\n );\n useEffect(\n () => () => {\n const element = returnFocus.current;\n queueMicrotask(() => {\n // The opener is gone (its row was deleted, say): the nearest surviving landmark instead\n // (spec 4.12), never the document body.\n if (element?.isConnected && element !== document.body) {\n element.focus();\n return;\n }\n const main = document.querySelector<HTMLElement>('main');\n if (main === null) return;\n if (!main.hasAttribute('tabindex')) main.setAttribute('tabindex', '-1');\n main.focus();\n });\n },\n [],\n );\n}\n\n/**\n * A pointer down inside a popover (a peek) is not outside the overlay. The popover is a React\n * sibling of the sheet or dialog (`<UIPresentations>` renders every presentation side by side),\n * and Radix decides \"inside\" by the React tree, so without this a click on a peek's title — which\n * pushes into this sheet — would first dismiss it (or ask about its dirty form).\n */\nfunction keepForPopover(event: { readonly target: EventTarget | null; preventDefault(): void }) {\n const target = event.target;\n if (target instanceof Element && target.closest('[data-buro-popover]') !== null)\n event.preventDefault();\n}\n\n/** No slide and no fade under `prefers-reduced-motion` (spec 4.12). */\nconst REDUCED_MOTION = 'motion-reduce:animate-none motion-reduce:transition-none';\n\n/** Shared Radix lifecycle shell for a centered temporary presentation. */\nexport function DialogPresentationShell({\n dismiss,\n wrapper,\n copy,\n ownTitle = false,\n children,\n}: PresentationShellProps) {\n useFocusRestoration();\n return (\n <Dialog\n open\n onOpenChange={(open) => {\n if (!open) dismiss();\n }}\n >\n {ownTitle ? (\n <DialogContent\n className={`flex max-h-[85vh] flex-col ${REDUCED_MOTION}`}\n overlayClassName={REDUCED_MOTION}\n showClose={wrapper}\n aria-describedby={undefined}\n aria-modal=\"true\"\n onOpenAutoFocus={focusOwnHeading}\n onPointerDownOutside={keepForPopover}\n >\n <OwnTitleContext.Provider value={true}>{children}</OwnTitleContext.Provider>\n </DialogContent>\n ) : (\n <DialogContent\n className={REDUCED_MOTION}\n overlayClassName={REDUCED_MOTION}\n showClose={wrapper}\n aria-modal=\"true\"\n onPointerDownOutside={keepForPopover}\n >\n <WrappedDialogContent wrapper={wrapper} copy={copy}>\n {children}\n </WrappedDialogContent>\n </DialogContent>\n )}\n </Dialog>\n );\n}\n\n/** Shared Radix lifecycle shell for a right-hand temporary presentation. */\nexport function SheetPresentationShell({\n dismiss,\n wrapper,\n copy,\n ownTitle = false,\n children,\n}: PresentationShellProps) {\n useFocusRestoration();\n return (\n <Sheet\n open\n onOpenChange={(open) => {\n if (!open) dismiss();\n }}\n >\n {ownTitle ? (\n <SheetContent\n side=\"right\"\n className={`flex flex-col sm:max-w-xl ${REDUCED_MOTION}`}\n showClose={wrapper}\n aria-describedby={undefined}\n aria-modal=\"true\"\n onOpenAutoFocus={focusOwnHeading}\n onPointerDownOutside={keepForPopover}\n >\n <OwnTitleContext.Provider value={true}>{children}</OwnTitleContext.Provider>\n </SheetContent>\n ) : (\n <SheetContent\n side=\"right\"\n className={`sm:max-w-xl ${REDUCED_MOTION}`}\n showClose={wrapper}\n aria-modal=\"true\"\n onPointerDownOutside={keepForPopover}\n >\n <WrappedSheetContent wrapper={wrapper} copy={copy}>\n {children}\n </WrappedSheetContent>\n </SheetContent>\n )}\n </Sheet>\n );\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"toaster-C7CiYA4Z.cjs","names":["PopoverPrimitive","React","cn","forwardRef","createContext","useContext","DEFAULT_LANGUAGE_STORAGE_KEY","toast","useOptionalT","useTheme","useOptionalLocale","useRef","useMemo","SonnerToaster"],"sources":["../src/primitives/popover.tsx","../src/layout/link-component.tsx","../src/layout/language-storage.ts","../src/lib/friendly-error.ts","../src/notification/notification-provider.ts","../src/notification/toaster.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport * as PopoverPrimitive from '@radix-ui/react-popover';\nimport { cn } from '../lib/cn.js';\n\n/**\n * Thin wrapper around Radix Popover, mirroring the structure of the\n * Dialog / Select primitives in this package so the Tailwind tokens\n * stay aligned. Re-exports `Root` / `Trigger` / `Anchor` / `Close`\n * directly (no styling needed) and styles `Content` to match the\n * shadcn Popover defaults.\n */\n\nconst Popover = PopoverPrimitive.Root;\nconst PopoverTrigger = PopoverPrimitive.Trigger;\nconst PopoverAnchor = PopoverPrimitive.Anchor;\nconst PopoverClose = PopoverPrimitive.Close;\n\nexport type PopoverContentProps = React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>;\n\nconst PopoverContent = React.forwardRef<\n React.ElementRef<typeof PopoverPrimitive.Content>,\n PopoverContentProps\n>(({ className, align = 'start', sideOffset = 4, ...props }, ref) => (\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n ref={ref}\n align={align}\n sideOffset={sideOffset}\n className={cn(\n 'z-50 w-72 rounded-md border bg-popover p-3 text-popover-foreground shadow-md outline-hidden',\n 'duration-[var(--duration-overlay)] ease-[var(--ease-overlay)]',\n 'data-[state=open]:animate-in data-[state=closed]:animate-out',\n 'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',\n 'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',\n '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',\n className,\n )}\n {...props}\n />\n </PopoverPrimitive.Portal>\n));\nPopoverContent.displayName = PopoverPrimitive.Content.displayName;\n\nexport { Popover, PopoverTrigger, PopoverAnchor, PopoverClose, PopoverContent };\n","'use client';\nimport {\n type AnchorHTMLAttributes,\n type ComponentType,\n type ReactElement,\n type ReactNode,\n createContext,\n forwardRef,\n useContext,\n} from 'react';\n\n/**\n * Props every `LinkComponent` must accept. We intentionally mirror the\n * native `<a>` API surface so adopters writing a small wrapper around\n * their router's link primitive (next/link, react-router, TanStack\n * Router, etc.) can pass them straight through.\n *\n * `next/link` already accepts these names verbatim. `react-router`'s\n * `<Link>` uses `to` instead of `href` — adopters wrap once:\n *\n * const RouterLink: LinkComponent = ({ href, ...rest }) =>\n * <Link to={href} {...rest} />;\n */\nexport type LinkComponentProps = Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> & {\n href: string;\n children?: ReactNode;\n};\n\nexport type LinkComponent = ComponentType<LinkComponentProps>;\n\n/**\n * Default fallback — a plain `<a href>` anchor. Triggers a full\n * document load. Adopters that ship a SPA router (Next.js App Router,\n * react-router) install their router's `<Link>` via\n * `<LinkComponentProvider>` so internal navigation stays client-side.\n */\nconst DefaultLinkComponent: LinkComponent = forwardRef<HTMLAnchorElement, LinkComponentProps>(\n function DefaultLinkComponent({ children, ...rest }, ref) {\n return (\n <a ref={ref} {...rest}>\n {children}\n </a>\n );\n },\n);\n\nconst LinkComponentContext = createContext<LinkComponent>(DefaultLinkComponent);\n\nexport interface LinkComponentProviderProps {\n /**\n * The router-aware Link component to use throughout `@burojs/ui-shadcn` for\n * internal navigation. Pass `Link` from `next/link` for Next.js App Router;\n * wrap your router's link primitive once for react-router / TanStack Router.\n */\n linkComponent: LinkComponent;\n children: ReactNode;\n}\n\n/**\n * Install a router-aware `LinkComponent` for every framework component that\n * renders an internal navigation link (sidebar entries, action links, relation\n * cells, the list-empty Create CTA, …). Without it the framework falls back to\n * a raw `<a>` — correct, but a full document reload on every click.\n *\n * This is a link component and nothing else: the location and imperative\n * navigation are the `RouterAdapter`'s (`RouterAdapterProvider` and\n * `useRouteNavigate` from `@burojs/react`), the one router seam.\n *\n * import Link from 'next/link';\n * <LinkComponentProvider linkComponent={Link}>\n * <App />\n * </LinkComponentProvider>\n */\nexport function LinkComponentProvider({\n linkComponent,\n children,\n}: LinkComponentProviderProps): ReactElement {\n return (\n <LinkComponentContext.Provider value={linkComponent}>{children}</LinkComponentContext.Provider>\n );\n}\n\n/**\n * Read the current `LinkComponent`. Call this from any framework\n * component that needs to render an internal-navigation link, then\n * use the returned component in JSX:\n *\n * const RouterLink = useLinkComponent();\n * return <RouterLink href={href}>{label}</RouterLink>;\n *\n * Always returns a usable component — the default fallback emits a\n * raw `<a href>` so the component never has to null-check.\n */\nexport function useLinkComponent(): LinkComponent {\n return useContext(LinkComponentContext);\n}\n","import { DEFAULT_LANGUAGE_STORAGE_KEY } from '@burojs/react';\n\n/**\n * Default localStorage key (`'buro:language'`, owned by `@burojs/react`).\n * Framework-neutral so multiple adopters on the same domain don't collide.\n * Override per-app with `<BuroProvider languageStorageKey>` and pass the same\n * key to `loadLocale(key)` when restoring the choice at boot.\n */\nexport { DEFAULT_LANGUAGE_STORAGE_KEY };\n\n/**\n * Legacy RU/EN-only pair. `<LanguageSwitch>` itself no longer uses these —\n * see its own docblock. New code that needs an arbitrary (not just 'en'/'ru')\n * locale code should use `loadLocale`/`saveLocale` instead.\n *\n * ⚠️ **THE ARGUMENT THAT FROZE THIS PAIR EXPIRED WHEN SP9 DELETED THE TWO\n * APPLICATIONS, and the replacement argument is weaker.** Until then this\n * block said that `apps/playground` and `apps/l2-web-ui` hand-rolled their own\n * two-language dropdown submenu against `loadLanguage`/`saveLanguage`/\n * `LanguageCode`/`DEFAULT_LANGUAGE` directly, so narrowing or reshaping them\n * would break real, working code outside this package. Both applications are\n * gone (`docs/departing-apps.md`). Measured again after SP9 task 10, over the\n * whole repository:\n *\n * - `loadLanguage` has exactly ONE consumer left — `fields/format.ts`, the\n * no-provider locale fallback for the `Intl` renderers, which keeps it\n * deliberately (`ru-RU` and `en-US` are both real answers for a formatter\n * and neither is neutral). Task 10 removed the other two:\n * `notification/notification-provider.ts` reads `loadLocale()` and\n * `resource/list-error-state.tsx` reads the live `useLocale()`, because an\n * app registering `en`/`es`/`fr` was served the RUSSIAN error catalogue\n * through this pair's `'ru'` default — in every locale and on every first\n * visit;\n * - `saveLanguage`, `LanguageCode` and `DEFAULT_LANGUAGE` have **no consumer\n * in any application or example**, only this package's own tests.\n *\n * They are still exported, so reshaping them is still a published-API break\n * needing a `minor` changeset that says \"breaking\" — but it is no longer\n * blocked by an in-repository consumer, which is what the old sentence\n * claimed.\n */\nexport type LanguageCode = 'en' | 'ru';\n\n/**\n * Default locale applied when the user has NOT explicitly chosen a\n * language yet (fresh visit / no stored preference / SSR). The default\n * targets a Russian-first app, so a first visit renders in\n * `'ru'`; picking `EN` in the legacy two-language submenu persists the\n * choice and it takes precedence on every subsequent load.\n */\nexport const DEFAULT_LANGUAGE: LanguageCode = 'ru';\n\n/**\n * Read the stored language preference. Returns {@link DEFAULT_LANGUAGE}\n * (`'ru'`) when nothing is stored (or when localStorage is unavailable,\n * e.g. SSR / disabled) so a fresh visit is Russian-first.\n *\n * Legacy, RU/EN-only — see {@link LanguageCode}'s docblock. Exported so\n * consumers can read the same value during provider boot (before the React\n * tree mounts) — typical use is to feed the result into\n * `createI18nextAdapter({ defaultLocale })` so the initial render is already\n * in the correct language.\n */\nexport function loadLanguage(storageKey: string = DEFAULT_LANGUAGE_STORAGE_KEY): LanguageCode {\n if (typeof window === 'undefined') return DEFAULT_LANGUAGE;\n try {\n const saved = window.localStorage.getItem(storageKey);\n if (saved === 'ru' || saved === 'en') return saved;\n } catch {\n // localStorage may be disabled — fall through to default\n }\n return DEFAULT_LANGUAGE;\n}\n\n/**\n * Persist the language preference. Legacy, RU/EN-only — see\n * {@link LanguageCode}'s docblock, which also records that its last two\n * in-repository callers (the departing applications' two-language dropdown\n * submenus) left with SP9. Exported so consumer apps can call it from custom\n * UI without importing a component; nothing in this repository calls it\n * outside this package's own tests.\n */\nexport function saveLanguage(\n code: LanguageCode,\n storageKey: string = DEFAULT_LANGUAGE_STORAGE_KEY,\n): void {\n if (typeof window === 'undefined') return;\n try {\n window.localStorage.setItem(storageKey, code);\n } catch {\n // localStorage may be disabled — silently no-op\n }\n}\n\n/**\n * Read an arbitrary locale code (not restricted to 'en'/'ru') under a\n * localStorage key. Returns `undefined` when nothing is stored, unavailable,\n * or empty — unlike {@link loadLanguage} there is no fixed two-code default\n * to fall back to, so the caller (which knows its own registry) decides what\n * \"nothing chosen yet\" means.\n */\nexport function loadLocale(storageKey: string = DEFAULT_LANGUAGE_STORAGE_KEY): string | undefined {\n if (typeof window === 'undefined') return undefined;\n try {\n return window.localStorage.getItem(storageKey) ?? undefined;\n } catch {\n return undefined;\n }\n}\n\n/** Persist an arbitrary locale code. Generic counterpart to {@link saveLanguage}. */\nexport function saveLocale(code: string, storageKey: string = DEFAULT_LANGUAGE_STORAGE_KEY): void {\n if (typeof window === 'undefined') return;\n try {\n window.localStorage.setItem(storageKey, code);\n } catch {\n // localStorage may be disabled — silently no-op\n }\n}\n","/**\n * Turn a developer-facing error string into something a user can act on.\n *\n * Two surfaces need this and they are reached by different code paths — the\n * notification provider (a legacy query adapter's default query-error\n * toast) and the inline\n * error panel a list renders in place of its rows. Fixing only the first left\n * `/document_document` still printing a raw English «Failed to fetch» under a\n * Russian heading, which is how this ended up in a second acceptance round.\n * One helper, both call sites.\n *\n * Anything we do not recognise is passed through unchanged: a message written\n * by the adopter's own `onError` is almost certainly better than a generic\n * substitute.\n */\n\n/** A legacy query adapter's own untranslated wording plus the raw fetch/network failures. */\nconst DEV_FACING =\n /^Error \\(status code:|^Failed to fetch$|^NetworkError|^Load failed$|^TypeError: (Failed to fetch|NetworkError)/i;\nconst NETWORK = /Failed to fetch|NetworkError|Load failed|ERR_INTERNET_DISCONNECTED/i;\n/**\n * A machine transport trace, e.g.\n * «Temporal GET /namespaces/default/schedules?maximumPageSize=10 -> 502»\n *\n * A data provider that reports which call failed is doing the right thing —\n * that string belongs in a bug report. It does not belong in front of an\n * operator as the entire explanation of why their page is empty, which is\n * exactly what `/schedules` did when the Temporal cluster went down.\n *\n * Recognised by an HTTP verb followed by an arrow and a status code; nothing\n * an adopter would hand-write looks like this, so the pass-through contract\n * for adopter-authored messages is preserved.\n */\nconst HTTP_TRACE = /\\b(?:GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\\b[^\\n]*->\\s*(\\d{3})\\b/;\n\nconst STRINGS = {\n ru: {\n title: 'Не удалось выполнить запрос',\n offline: 'Нет связи с сервером. Проверьте подключение и повторите.',\n unavailable: 'Сервис временно недоступен. Повторите попытку через минуту.',\n generic: 'Попробуйте повторить действие.',\n },\n en: {\n title: 'Request failed',\n offline: 'Cannot reach the server. Check your connection and try again.',\n unavailable: 'The service is temporarily unavailable. Try again in a minute.',\n generic: 'Please try again.',\n },\n} as const;\n\nexport interface FriendlyError {\n /** Short headline. Empty when the original message should be kept. */\n title: string;\n /** Explanation the user can act on. */\n detail: string;\n /** True when the input was recognised as developer-facing and replaced. */\n replaced: boolean;\n}\n\n/**\n * @param locale the ACTIVE locale code, whatever the host's registry calls it —\n * `'es'`, `'fr'`, `'pt-BR'` — or `undefined` where none is known. Narrowing\n * it to this module's two-entry catalogue happens HERE, once.\n *\n * ⚠️ It used to happen at each call site, as `locale === 'ru' ? 'ru' : 'en'`\n * written out four times, and two of those four wrote it against\n * `loadLanguage()` instead of the live locale — whose vocabulary is `'en' |\n * 'ru'` and whose default is `'ru'`, so an application registering\n * `en`/`es`/`fr` got the RUSSIAN catalogue for every error panel and every\n * error toast, including on a first visit. Widening this parameter is what\n * lets a call site hand over the locale it actually has instead of\n * pre-narrowing it, so the same mistake has nowhere left to live. Ship a new\n * catalogue by adding a key to {@link STRINGS}; call sites do not change.\n */\nexport function toFriendlyError(\n message: unknown,\n description: unknown,\n locale: string | undefined,\n): FriendlyError {\n const s =\n (locale !== undefined ? STRINGS[locale as keyof typeof STRINGS] : undefined) ?? STRINGS.en;\n const raw = `${String(message ?? '')} ${String(description ?? '')}`;\n const isDevFacing = DEV_FACING.test(String(message ?? '').trim());\n const isNetwork = NETWORK.test(raw);\n const trace = HTTP_TRACE.exec(String(message ?? '').trim());\n\n if (trace) {\n // 5xx is the server's problem and waiting is the right advice; anything\n // else is at least not something the operator can read a URL out of.\n const status = Number(trace[1]);\n return {\n title: s.title,\n detail: status >= 500 ? s.unavailable : s.generic,\n replaced: true,\n };\n }\n\n if (!isDevFacing && !isNetwork) {\n return {\n title: String(message ?? ''),\n detail: String(description ?? ''),\n replaced: false,\n };\n }\n return {\n title: s.title,\n detail: isNetwork ? s.offline : String(description ?? '') || s.generic,\n replaced: true,\n };\n}\n","import type { NotificationSinkMessage } from '@burojs/react';\nimport { toast } from 'sonner';\nimport { DEFAULT_LANGUAGE_STORAGE_KEY, loadLocale } from '../layout/language-storage.js';\nimport { toFriendlyError } from '../lib/friendly-error.js';\n\n/** `<Toaster>`'s sink: `@burojs/react`'s `NotificationSink`, plus `close`. */\nexport interface NotificationSink {\n open(args: NotificationSinkMessage): void;\n close(key: string): void;\n}\n\n/**\n * A legacy query adapter can build its default query-error notification outside\n * our i18n bundle: in a Russian-primary app the user\n * saw «Error (status code: undefined)» / «Failed to fetch», plus it duplicated\n * the inline error state a list already renders. We can't localize a string we\n * don't own, so `toFriendlyError` recognises it and substitutes plain language.\n * The SAME helper backs the list's inline panel — see friendly-error.ts for why\n * that matters.\n */\nexport interface NotificationProviderOptions {\n /**\n * How to find the ACTIVE locale when an error toast needs its catalogue.\n * Defaults to the locale persisted by `<LanguageSwitch>` under\n * {@link DEFAULT_LANGUAGE_STORAGE_KEY}.\n *\n * The escape hatch exists because the default is only right for an app that\n * left `storageKey` alone: `<LanguageSwitch storageKey=\"acme:lang\">` writes\n * somewhere this factory does not look, and the toast would silently take the\n * fallback catalogue forever. Such an app passes\n * `{ resolveLocale: () => loadLocale('acme:lang') }` — or reads its own i18n\n * facade directly, which is strictly better still.\n *\n * ⚠️ It is a FUNCTION, not a value, and that is load-bearing: both examples\n * build this sink once (`React.useMemo(…, [])`) and it has no React context\n * to subscribe to, so a locale captured at construction would freeze at\n * whatever was active on the first render. Called per toast instead.\n */\n readonly resolveLocale?: () => string | undefined;\n}\n\nexport function createNotificationProvider(\n options: NotificationProviderOptions = {},\n): NotificationSink {\n const resolveLocale = options.resolveLocale ?? (() => loadLocale());\n return {\n open: ({ type, message, description }) => {\n let text = message;\n let detail = description;\n if (type === 'error') {\n // `loadLocale()`, not the legacy `loadLanguage()` this used to call:\n // that one recognises only `'en'`/`'ru'` and answers `'ru'` for\n // everything else, including an empty key — so an app registering\n // `en`/`es`/`fr` got a Russian toast in every locale and on every first\n // visit. This factory is not a component and never sees the i18n\n // context, so storage is the only locale available to it; a host that\n // wants better passes `resolveLocale`.\n const friendly = toFriendlyError(message, description, resolveLocale());\n text = friendly.title;\n detail = friendly.detail;\n }\n // `info` is a plain notice that dismisses itself — never `toast.loading`,\n // whose spinner stays on screen until someone closes it.\n const fn = type === 'error' ? toast.error : type === 'info' ? toast.info : toast.success;\n fn(text, { description: detail });\n },\n close: (key: string) => {\n toast.dismiss(key);\n },\n };\n}\n","'use client';\nimport { useOptionalLocale, useOptionalT, useRegisterNotificationSink } from '@burojs/react';\nimport { useMemo, useRef } from 'react';\nimport { Toaster as SonnerToaster, type ToasterProps as SonnerProps, toast } from 'sonner';\nimport { loadLocale } from '../layout/language-storage.js';\nimport { useTheme } from '../layout/use-theme.js';\nimport { createNotificationProvider } from './notification-provider.js';\n\nexport interface ToasterProps extends SonnerProps {}\n\n/**\n * Shadcn-canonical Sonner setup, and — inside a `<BuroProvider>` — the app's\n * notification sink: the dispatcher's default `notify` (every handler's\n * `notify`, and a thrown handler's error) is delivered here. Outside a\n * provider it registers nothing and still renders anything sent with `toast()`.\n *\n * Bound to design tokens via `toastOptions.classNames`, so toasts inherit the\n * app's light/dark theme through the same CSS-variable cascade as the rest of\n * the UI; `theme` is reactive via `useTheme()`. The error catalogue follows the\n * ACTIVE i18n locale, read per toast so a language switch is honoured; with no\n * i18n provider it falls back to the locale `<LanguageSwitch>` persisted.\n */\nexport function Toaster(props: ToasterProps): React.ReactElement {\n // `useOptionalT`: the toaster may sit outside a BuroProvider, so it must\n // degrade rather than throw.\n const t = useOptionalT();\n const { resolved: theme } = useTheme();\n const locale = useOptionalLocale();\n const localeRef = useRef(locale);\n localeRef.current = locale;\n const sink = useMemo(\n () => createNotificationProvider({ resolveLocale: () => localeRef.current ?? loadLocale() }),\n [],\n );\n useRegisterNotificationSink(sink);\n\n return (\n <SonnerToaster\n /*\n ⚠️ Sonner's default accessible name is \"Notifications alt+T\" and reaches\n the accessibility tree on every page; it is replaced by the bundle's\n `notifications.region`. The literal fallback is English, like every\n framework default.\n */\n containerAriaLabel={t('notifications.region', { defaultValue: 'Notifications' })}\n theme={theme}\n position=\"top-right\"\n closeButton\n className=\"toaster group\"\n toastOptions={{\n classNames: {\n toast:\n 'group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg',\n description: 'group-[.toast]:text-muted-foreground',\n actionButton: 'group-[.toast]:bg-primary group-[.toast]:text-primary-foreground',\n cancelButton: 'group-[.toast]:bg-muted group-[.toast]:text-muted-foreground',\n closeButton:\n 'group-[.toast]:bg-background group-[.toast]:text-muted-foreground group-[.toast]:border-border group-[.toast]:hover:bg-muted group-[.toast]:hover:text-foreground',\n },\n }}\n {...props}\n />\n );\n}\n\nexport { toast };\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"toaster-CfCRLgR-.js","names":["Toaster","SonnerToaster"],"sources":["../src/primitives/popover.tsx","../src/layout/link-component.tsx","../src/layout/language-storage.ts","../src/lib/friendly-error.ts","../src/notification/notification-provider.ts","../src/notification/toaster.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport * as PopoverPrimitive from '@radix-ui/react-popover';\nimport { cn } from '../lib/cn.js';\n\n/**\n * Thin wrapper around Radix Popover, mirroring the structure of the\n * Dialog / Select primitives in this package so the Tailwind tokens\n * stay aligned. Re-exports `Root` / `Trigger` / `Anchor` / `Close`\n * directly (no styling needed) and styles `Content` to match the\n * shadcn Popover defaults.\n */\n\nconst Popover = PopoverPrimitive.Root;\nconst PopoverTrigger = PopoverPrimitive.Trigger;\nconst PopoverAnchor = PopoverPrimitive.Anchor;\nconst PopoverClose = PopoverPrimitive.Close;\n\nexport type PopoverContentProps = React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>;\n\nconst PopoverContent = React.forwardRef<\n React.ElementRef<typeof PopoverPrimitive.Content>,\n PopoverContentProps\n>(({ className, align = 'start', sideOffset = 4, ...props }, ref) => (\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n ref={ref}\n align={align}\n sideOffset={sideOffset}\n className={cn(\n 'z-50 w-72 rounded-md border bg-popover p-3 text-popover-foreground shadow-md outline-hidden',\n 'duration-[var(--duration-overlay)] ease-[var(--ease-overlay)]',\n 'data-[state=open]:animate-in data-[state=closed]:animate-out',\n 'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',\n 'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',\n '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',\n className,\n )}\n {...props}\n />\n </PopoverPrimitive.Portal>\n));\nPopoverContent.displayName = PopoverPrimitive.Content.displayName;\n\nexport { Popover, PopoverTrigger, PopoverAnchor, PopoverClose, PopoverContent };\n","'use client';\nimport {\n type AnchorHTMLAttributes,\n type ComponentType,\n type ReactElement,\n type ReactNode,\n createContext,\n forwardRef,\n useContext,\n} from 'react';\n\n/**\n * Props every `LinkComponent` must accept. We intentionally mirror the\n * native `<a>` API surface so adopters writing a small wrapper around\n * their router's link primitive (next/link, react-router, TanStack\n * Router, etc.) can pass them straight through.\n *\n * `next/link` already accepts these names verbatim. `react-router`'s\n * `<Link>` uses `to` instead of `href` — adopters wrap once:\n *\n * const RouterLink: LinkComponent = ({ href, ...rest }) =>\n * <Link to={href} {...rest} />;\n */\nexport type LinkComponentProps = Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> & {\n href: string;\n children?: ReactNode;\n};\n\nexport type LinkComponent = ComponentType<LinkComponentProps>;\n\n/**\n * Default fallback — a plain `<a href>` anchor. Triggers a full\n * document load. Adopters that ship a SPA router (Next.js App Router,\n * react-router) install their router's `<Link>` via\n * `<LinkComponentProvider>` so internal navigation stays client-side.\n */\nconst DefaultLinkComponent: LinkComponent = forwardRef<HTMLAnchorElement, LinkComponentProps>(\n function DefaultLinkComponent({ children, ...rest }, ref) {\n return (\n <a ref={ref} {...rest}>\n {children}\n </a>\n );\n },\n);\n\nconst LinkComponentContext = createContext<LinkComponent>(DefaultLinkComponent);\n\nexport interface LinkComponentProviderProps {\n /**\n * The router-aware Link component to use throughout `@burojs/ui-shadcn` for\n * internal navigation. Pass `Link` from `next/link` for Next.js App Router;\n * wrap your router's link primitive once for react-router / TanStack Router.\n */\n linkComponent: LinkComponent;\n children: ReactNode;\n}\n\n/**\n * Install a router-aware `LinkComponent` for every framework component that\n * renders an internal navigation link (sidebar entries, action links, relation\n * cells, the list-empty Create CTA, …). Without it the framework falls back to\n * a raw `<a>` — correct, but a full document reload on every click.\n *\n * This is a link component and nothing else: the location and imperative\n * navigation are the `RouterAdapter`'s (`RouterAdapterProvider` and\n * `useRouteNavigate` from `@burojs/react`), the one router seam.\n *\n * import Link from 'next/link';\n * <LinkComponentProvider linkComponent={Link}>\n * <App />\n * </LinkComponentProvider>\n */\nexport function LinkComponentProvider({\n linkComponent,\n children,\n}: LinkComponentProviderProps): ReactElement {\n return (\n <LinkComponentContext.Provider value={linkComponent}>{children}</LinkComponentContext.Provider>\n );\n}\n\n/**\n * Read the current `LinkComponent`. Call this from any framework\n * component that needs to render an internal-navigation link, then\n * use the returned component in JSX:\n *\n * const RouterLink = useLinkComponent();\n * return <RouterLink href={href}>{label}</RouterLink>;\n *\n * Always returns a usable component — the default fallback emits a\n * raw `<a href>` so the component never has to null-check.\n */\nexport function useLinkComponent(): LinkComponent {\n return useContext(LinkComponentContext);\n}\n","import { DEFAULT_LANGUAGE_STORAGE_KEY } from '@burojs/react';\n\n/**\n * Default localStorage key (`'buro:language'`, owned by `@burojs/react`).\n * Framework-neutral so multiple adopters on the same domain don't collide.\n * Override per-app with `<BuroProvider languageStorageKey>` and pass the same\n * key to `loadLocale(key)` when restoring the choice at boot.\n */\nexport { DEFAULT_LANGUAGE_STORAGE_KEY };\n\n/**\n * Legacy RU/EN-only pair. `<LanguageSwitch>` itself no longer uses these —\n * see its own docblock. New code that needs an arbitrary (not just 'en'/'ru')\n * locale code should use `loadLocale`/`saveLocale` instead.\n *\n * ⚠️ **THE ARGUMENT THAT FROZE THIS PAIR EXPIRED WHEN SP9 DELETED THE TWO\n * APPLICATIONS, and the replacement argument is weaker.** Until then this\n * block said that `apps/playground` and `apps/l2-web-ui` hand-rolled their own\n * two-language dropdown submenu against `loadLanguage`/`saveLanguage`/\n * `LanguageCode`/`DEFAULT_LANGUAGE` directly, so narrowing or reshaping them\n * would break real, working code outside this package. Both applications are\n * gone (`docs/departing-apps.md`). Measured again after SP9 task 10, over the\n * whole repository:\n *\n * - `loadLanguage` has exactly ONE consumer left — `fields/format.ts`, the\n * no-provider locale fallback for the `Intl` renderers, which keeps it\n * deliberately (`ru-RU` and `en-US` are both real answers for a formatter\n * and neither is neutral). Task 10 removed the other two:\n * `notification/notification-provider.ts` reads `loadLocale()` and\n * `resource/list-error-state.tsx` reads the live `useLocale()`, because an\n * app registering `en`/`es`/`fr` was served the RUSSIAN error catalogue\n * through this pair's `'ru'` default — in every locale and on every first\n * visit;\n * - `saveLanguage`, `LanguageCode` and `DEFAULT_LANGUAGE` have **no consumer\n * in any application or example**, only this package's own tests.\n *\n * They are still exported, so reshaping them is still a published-API break\n * needing a `minor` changeset that says \"breaking\" — but it is no longer\n * blocked by an in-repository consumer, which is what the old sentence\n * claimed.\n */\nexport type LanguageCode = 'en' | 'ru';\n\n/**\n * Default locale applied when the user has NOT explicitly chosen a\n * language yet (fresh visit / no stored preference / SSR). The default\n * targets a Russian-first app, so a first visit renders in\n * `'ru'`; picking `EN` in the legacy two-language submenu persists the\n * choice and it takes precedence on every subsequent load.\n */\nexport const DEFAULT_LANGUAGE: LanguageCode = 'ru';\n\n/**\n * Read the stored language preference. Returns {@link DEFAULT_LANGUAGE}\n * (`'ru'`) when nothing is stored (or when localStorage is unavailable,\n * e.g. SSR / disabled) so a fresh visit is Russian-first.\n *\n * Legacy, RU/EN-only — see {@link LanguageCode}'s docblock. Exported so\n * consumers can read the same value during provider boot (before the React\n * tree mounts) — typical use is to feed the result into\n * `createI18nextAdapter({ defaultLocale })` so the initial render is already\n * in the correct language.\n */\nexport function loadLanguage(storageKey: string = DEFAULT_LANGUAGE_STORAGE_KEY): LanguageCode {\n if (typeof window === 'undefined') return DEFAULT_LANGUAGE;\n try {\n const saved = window.localStorage.getItem(storageKey);\n if (saved === 'ru' || saved === 'en') return saved;\n } catch {\n // localStorage may be disabled — fall through to default\n }\n return DEFAULT_LANGUAGE;\n}\n\n/**\n * Persist the language preference. Legacy, RU/EN-only — see\n * {@link LanguageCode}'s docblock, which also records that its last two\n * in-repository callers (the departing applications' two-language dropdown\n * submenus) left with SP9. Exported so consumer apps can call it from custom\n * UI without importing a component; nothing in this repository calls it\n * outside this package's own tests.\n */\nexport function saveLanguage(\n code: LanguageCode,\n storageKey: string = DEFAULT_LANGUAGE_STORAGE_KEY,\n): void {\n if (typeof window === 'undefined') return;\n try {\n window.localStorage.setItem(storageKey, code);\n } catch {\n // localStorage may be disabled — silently no-op\n }\n}\n\n/**\n * Read an arbitrary locale code (not restricted to 'en'/'ru') under a\n * localStorage key. Returns `undefined` when nothing is stored, unavailable,\n * or empty — unlike {@link loadLanguage} there is no fixed two-code default\n * to fall back to, so the caller (which knows its own registry) decides what\n * \"nothing chosen yet\" means.\n */\nexport function loadLocale(storageKey: string = DEFAULT_LANGUAGE_STORAGE_KEY): string | undefined {\n if (typeof window === 'undefined') return undefined;\n try {\n return window.localStorage.getItem(storageKey) ?? undefined;\n } catch {\n return undefined;\n }\n}\n\n/** Persist an arbitrary locale code. Generic counterpart to {@link saveLanguage}. */\nexport function saveLocale(code: string, storageKey: string = DEFAULT_LANGUAGE_STORAGE_KEY): void {\n if (typeof window === 'undefined') return;\n try {\n window.localStorage.setItem(storageKey, code);\n } catch {\n // localStorage may be disabled — silently no-op\n }\n}\n","/**\n * Turn a developer-facing error string into something a user can act on.\n *\n * Two surfaces need this and they are reached by different code paths — the\n * notification provider (a legacy query adapter's default query-error\n * toast) and the inline\n * error panel a list renders in place of its rows. Fixing only the first left\n * `/document_document` still printing a raw English «Failed to fetch» under a\n * Russian heading, which is how this ended up in a second acceptance round.\n * One helper, both call sites.\n *\n * Anything we do not recognise is passed through unchanged: a message written\n * by the adopter's own `onError` is almost certainly better than a generic\n * substitute.\n */\n\n/** A legacy query adapter's own untranslated wording plus the raw fetch/network failures. */\nconst DEV_FACING =\n /^Error \\(status code:|^Failed to fetch$|^NetworkError|^Load failed$|^TypeError: (Failed to fetch|NetworkError)/i;\nconst NETWORK = /Failed to fetch|NetworkError|Load failed|ERR_INTERNET_DISCONNECTED/i;\n/**\n * A machine transport trace, e.g.\n * «Temporal GET /namespaces/default/schedules?maximumPageSize=10 -> 502»\n *\n * A data provider that reports which call failed is doing the right thing —\n * that string belongs in a bug report. It does not belong in front of an\n * operator as the entire explanation of why their page is empty, which is\n * exactly what `/schedules` did when the Temporal cluster went down.\n *\n * Recognised by an HTTP verb followed by an arrow and a status code; nothing\n * an adopter would hand-write looks like this, so the pass-through contract\n * for adopter-authored messages is preserved.\n */\nconst HTTP_TRACE = /\\b(?:GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\\b[^\\n]*->\\s*(\\d{3})\\b/;\n\nconst STRINGS = {\n ru: {\n title: 'Не удалось выполнить запрос',\n offline: 'Нет связи с сервером. Проверьте подключение и повторите.',\n unavailable: 'Сервис временно недоступен. Повторите попытку через минуту.',\n generic: 'Попробуйте повторить действие.',\n },\n en: {\n title: 'Request failed',\n offline: 'Cannot reach the server. Check your connection and try again.',\n unavailable: 'The service is temporarily unavailable. Try again in a minute.',\n generic: 'Please try again.',\n },\n} as const;\n\nexport interface FriendlyError {\n /** Short headline. Empty when the original message should be kept. */\n title: string;\n /** Explanation the user can act on. */\n detail: string;\n /** True when the input was recognised as developer-facing and replaced. */\n replaced: boolean;\n}\n\n/**\n * @param locale the ACTIVE locale code, whatever the host's registry calls it —\n * `'es'`, `'fr'`, `'pt-BR'` — or `undefined` where none is known. Narrowing\n * it to this module's two-entry catalogue happens HERE, once.\n *\n * ⚠️ It used to happen at each call site, as `locale === 'ru' ? 'ru' : 'en'`\n * written out four times, and two of those four wrote it against\n * `loadLanguage()` instead of the live locale — whose vocabulary is `'en' |\n * 'ru'` and whose default is `'ru'`, so an application registering\n * `en`/`es`/`fr` got the RUSSIAN catalogue for every error panel and every\n * error toast, including on a first visit. Widening this parameter is what\n * lets a call site hand over the locale it actually has instead of\n * pre-narrowing it, so the same mistake has nowhere left to live. Ship a new\n * catalogue by adding a key to {@link STRINGS}; call sites do not change.\n */\nexport function toFriendlyError(\n message: unknown,\n description: unknown,\n locale: string | undefined,\n): FriendlyError {\n const s =\n (locale !== undefined ? STRINGS[locale as keyof typeof STRINGS] : undefined) ?? STRINGS.en;\n const raw = `${String(message ?? '')} ${String(description ?? '')}`;\n const isDevFacing = DEV_FACING.test(String(message ?? '').trim());\n const isNetwork = NETWORK.test(raw);\n const trace = HTTP_TRACE.exec(String(message ?? '').trim());\n\n if (trace) {\n // 5xx is the server's problem and waiting is the right advice; anything\n // else is at least not something the operator can read a URL out of.\n const status = Number(trace[1]);\n return {\n title: s.title,\n detail: status >= 500 ? s.unavailable : s.generic,\n replaced: true,\n };\n }\n\n if (!isDevFacing && !isNetwork) {\n return {\n title: String(message ?? ''),\n detail: String(description ?? ''),\n replaced: false,\n };\n }\n return {\n title: s.title,\n detail: isNetwork ? s.offline : String(description ?? '') || s.generic,\n replaced: true,\n };\n}\n","import type { NotificationSinkMessage } from '@burojs/react';\nimport { toast } from 'sonner';\nimport { DEFAULT_LANGUAGE_STORAGE_KEY, loadLocale } from '../layout/language-storage.js';\nimport { toFriendlyError } from '../lib/friendly-error.js';\n\n/** `<Toaster>`'s sink: `@burojs/react`'s `NotificationSink`, plus `close`. */\nexport interface NotificationSink {\n open(args: NotificationSinkMessage): void;\n close(key: string): void;\n}\n\n/**\n * A legacy query adapter can build its default query-error notification outside\n * our i18n bundle: in a Russian-primary app the user\n * saw «Error (status code: undefined)» / «Failed to fetch», plus it duplicated\n * the inline error state a list already renders. We can't localize a string we\n * don't own, so `toFriendlyError` recognises it and substitutes plain language.\n * The SAME helper backs the list's inline panel — see friendly-error.ts for why\n * that matters.\n */\nexport interface NotificationProviderOptions {\n /**\n * How to find the ACTIVE locale when an error toast needs its catalogue.\n * Defaults to the locale persisted by `<LanguageSwitch>` under\n * {@link DEFAULT_LANGUAGE_STORAGE_KEY}.\n *\n * The escape hatch exists because the default is only right for an app that\n * left `storageKey` alone: `<LanguageSwitch storageKey=\"acme:lang\">` writes\n * somewhere this factory does not look, and the toast would silently take the\n * fallback catalogue forever. Such an app passes\n * `{ resolveLocale: () => loadLocale('acme:lang') }` — or reads its own i18n\n * facade directly, which is strictly better still.\n *\n * ⚠️ It is a FUNCTION, not a value, and that is load-bearing: both examples\n * build this sink once (`React.useMemo(…, [])`) and it has no React context\n * to subscribe to, so a locale captured at construction would freeze at\n * whatever was active on the first render. Called per toast instead.\n */\n readonly resolveLocale?: () => string | undefined;\n}\n\nexport function createNotificationProvider(\n options: NotificationProviderOptions = {},\n): NotificationSink {\n const resolveLocale = options.resolveLocale ?? (() => loadLocale());\n return {\n open: ({ type, message, description }) => {\n let text = message;\n let detail = description;\n if (type === 'error') {\n // `loadLocale()`, not the legacy `loadLanguage()` this used to call:\n // that one recognises only `'en'`/`'ru'` and answers `'ru'` for\n // everything else, including an empty key — so an app registering\n // `en`/`es`/`fr` got a Russian toast in every locale and on every first\n // visit. This factory is not a component and never sees the i18n\n // context, so storage is the only locale available to it; a host that\n // wants better passes `resolveLocale`.\n const friendly = toFriendlyError(message, description, resolveLocale());\n text = friendly.title;\n detail = friendly.detail;\n }\n // `info` is a plain notice that dismisses itself — never `toast.loading`,\n // whose spinner stays on screen until someone closes it.\n const fn = type === 'error' ? toast.error : type === 'info' ? toast.info : toast.success;\n fn(text, { description: detail });\n },\n close: (key: string) => {\n toast.dismiss(key);\n },\n };\n}\n","'use client';\nimport { useOptionalLocale, useOptionalT, useRegisterNotificationSink } from '@burojs/react';\nimport { useMemo, useRef } from 'react';\nimport { Toaster as SonnerToaster, type ToasterProps as SonnerProps, toast } from 'sonner';\nimport { loadLocale } from '../layout/language-storage.js';\nimport { useTheme } from '../layout/use-theme.js';\nimport { createNotificationProvider } from './notification-provider.js';\n\nexport interface ToasterProps extends SonnerProps {}\n\n/**\n * Shadcn-canonical Sonner setup, and — inside a `<BuroProvider>` — the app's\n * notification sink: the dispatcher's default `notify` (every handler's\n * `notify`, and a thrown handler's error) is delivered here. Outside a\n * provider it registers nothing and still renders anything sent with `toast()`.\n *\n * Bound to design tokens via `toastOptions.classNames`, so toasts inherit the\n * app's light/dark theme through the same CSS-variable cascade as the rest of\n * the UI; `theme` is reactive via `useTheme()`. The error catalogue follows the\n * ACTIVE i18n locale, read per toast so a language switch is honoured; with no\n * i18n provider it falls back to the locale `<LanguageSwitch>` persisted.\n */\nexport function Toaster(props: ToasterProps): React.ReactElement {\n // `useOptionalT`: the toaster may sit outside a BuroProvider, so it must\n // degrade rather than throw.\n const t = useOptionalT();\n const { resolved: theme } = useTheme();\n const locale = useOptionalLocale();\n const localeRef = useRef(locale);\n localeRef.current = locale;\n const sink = useMemo(\n () => createNotificationProvider({ resolveLocale: () => localeRef.current ?? loadLocale() }),\n [],\n );\n useRegisterNotificationSink(sink);\n\n return (\n <SonnerToaster\n /*\n ⚠️ Sonner's default accessible name is \"Notifications alt+T\" and reaches\n the accessibility tree on every page; it is replaced by the bundle's\n `notifications.region`. The literal fallback is English, like every\n framework default.\n */\n containerAriaLabel={t('notifications.region', { defaultValue: 'Notifications' })}\n theme={theme}\n position=\"top-right\"\n closeButton\n className=\"toaster group\"\n toastOptions={{\n classNames: {\n toast:\n 'group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg',\n description: 'group-[.toast]:text-muted-foreground',\n actionButton: 'group-[.toast]:bg-primary group-[.toast]:text-primary-foreground',\n cancelButton: 'group-[.toast]:bg-muted group-[.toast]:text-muted-foreground',\n closeButton:\n 'group-[.toast]:bg-background group-[.toast]:text-muted-foreground group-[.toast]:border-border group-[.toast]:hover:bg-muted group-[.toast]:hover:text-foreground',\n },\n }}\n {...props}\n />\n );\n}\n\nexport { toast };\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"use-dialog-filter-state-BBCC0OEK.cjs","names":["useApp","useFilterFields","useState","EMPTY_FILTER_GROUP","useCallback","useListAccess","useMemo","narrowSearchDecl","composeListFilter","namesHiddenField"],"sources":["../src/fields/use-dialog-filter-state.ts"],"sourcesContent":["import {\n EMPTY_FILTER_GROUP,\n composeListFilter,\n type ErasedResourceHandle,\n type FilterExpression,\n type FilterGroup,\n type FixedFilterInput,\n type ResolvedFixedFilter,\n type SearchDecl,\n} from '@burojs/core';\nimport { useApp, useFilterFields, useListAccess, type FilterFieldSpec } from '@burojs/react';\nimport { namesHiddenField, narrowSearchDecl } from './search-access.js';\nimport { useCallback, useMemo, useState } from 'react';\n\n/** The portable erased AST — the only shape this module deals in. */\ntype ErasedExpression = FilterExpression<ErasedResourceHandle>;\n\n/** Options for {@link useDialogFilterState}. */\nexport interface UseDialogFilterStateOptions {\n /** Call-site narrowing (e.g. scope the target list to a product group). */\n readonly fixedFilters?: readonly FixedFilterInput[];\n /**\n * Fallback search field, used ONLY when the target resource declares no\n * `views.list.search`. Wrapped into a single-field `SearchFieldsDecl`\n * (`{ fields: [searchField] }`, implicit `contains` — same degenerate form\n * `searchToFilter` already gives a bare field-name string) so the override\n * goes through the exact same `composeListFilter` → `searchToFilter` path\n * as a real declaration, rather than a second hand-built predicate at the\n * call site. The target's own declaration always wins when present — this\n * is a fallback, not an override of a declared search.\n */\n readonly searchField?: string;\n /**\n * Gates the field-derivation walk (`useFilterFields`'s `categorizeField`\n * pass over every field of the resource). Defaults to `true`. A caller\n * whose UI isn't visible yet (e.g. `RelationPickerDialog` before it's\n * opened) should pass `false` to skip that work on every mount /\n * `fixedFilters`-identity change; the derivation recomputes in full the\n * next render where this flips back to `true`.\n */\n readonly enabled?: boolean;\n}\n\n/** Return shape of {@link useDialogFilterState}. */\nexport interface DialogFilterState {\n readonly group: FilterGroup;\n readonly setGroup: (next: FilterGroup) => void;\n readonly search: string;\n readonly setSearch: (next: string) => void;\n readonly page: number;\n readonly setPage: (page: number) => void;\n readonly available: readonly FilterFieldSpec[];\n readonly fixed: readonly ResolvedFixedFilter[];\n /** The single expression to hand the data provider. */\n readonly filter: ErasedExpression | undefined;\n /** Whether the target has a search for this user (no field left means no search box). */\n readonly searchEnabled: boolean;\n /** The read must not be sent: undecided access, or a filter naming a field the user may not view. */\n readonly blocked: boolean;\n readonly reset: () => void;\n}\n\n/**\n * Local (non-URL) filter state for the relation-picker's advanced-search\n * dialog.\n *\n * `useResourceList` cannot serve this: it unconditionally calls\n * `useResourceUrlState`, which throws without a `RouterAdapterProvider` and,\n * when one IS present, writes to `?<resource>.*`. A picker dialog mounted\n * inside a form for resource A, searching TARGET resource B, would then\n * write B's list state into the URL — clobbering a real B list page open on\n * another tab of the same app, and reading back whatever that page last\n * wrote on open. So this hook keeps `group`/`search`/`page` in plain\n * `useState` and reuses the SAME composition core's list controller uses\n * (`composeListFilter`) so the two never drift on what a filter means.\n *\n * No `pinned` slot: pinned controls are a list-PAGE affordance (permanent\n * screen real estate for a couple of always-visible facets); a modal has no\n * spare real estate to spend on them.\n */\nexport function useDialogFilterState(\n resource: string,\n options: UseDialogFilterStateOptions,\n): DialogFilterState {\n const app = useApp();\n const def = app.registry.get(resource);\n const { available, fixed } = useFilterFields(resource, {\n fixedFilters: options.fixedFilters,\n enabled: options.enabled,\n });\n\n const [group, setGroupState] = useState<FilterGroup>(EMPTY_FILTER_GROUP);\n const [search, setSearchState] = useState('');\n const [page, setPage] = useState(1);\n\n // Any change to WHAT is filtered invalidates the current page — the same\n // rule `useResourceList`'s URL-state controller applies to its own\n // group/search setters.\n const setGroup = useCallback((next: FilterGroup) => {\n setGroupState(next);\n setPage(1);\n }, []);\n\n const setSearch = useCallback((next: string) => {\n setSearchState(next);\n setPage(1);\n }, []);\n\n const reset = useCallback(() => {\n setGroupState(EMPTY_FILTER_GROUP);\n setSearchState('');\n setPage(1);\n }, []);\n\n // The target's own declaration always wins; `options.searchField` only\n // fills in when the target declares no search at all. Memoized so an\n // omitted declaration doesn't hand `composeListFilter`'s `filter` memo a\n // fresh `{ fields: [...] }` literal (and therefore a spurious recompute)\n // on every render — see `UseDialogFilterStateOptions.searchField`'s doc.\n const { searchField } = options;\n const access = useListAccess(resource);\n const accessReady = access.status === 'ready';\n const searchDecl = useMemo<SearchDecl | undefined>(() => {\n const declared = def?.views?.list?.search;\n const base =\n declared !== undefined\n ? declared\n : searchField === undefined\n ? undefined\n : { fields: [searchField] };\n return narrowSearchDecl(base, (field) => access.fieldVisible(field));\n }, [def, searchField, access]);\n const searchContext = useMemo(() => ({ resource, def }), [resource, def]);\n\n const filter = useMemo<ErasedExpression | undefined>(\n () => composeListFilter({ fixed, group, search, searchDecl, searchContext }),\n [fixed, group, search, searchDecl, searchContext],\n );\n\n // A read whose composed filter names a field the user may not view is forbidden (an author\n // predicate, or a function search's output); an undecided access sends nothing yet.\n const blocked = !accessReady || namesHiddenField(filter, (field) => access.fieldVisible(field));\n\n return useMemo<DialogFilterState>(\n () => ({\n searchEnabled: searchDecl !== undefined,\n blocked,\n group,\n setGroup,\n search,\n setSearch,\n page,\n setPage,\n available,\n fixed,\n filter,\n reset,\n }),\n [\n group,\n setGroup,\n search,\n setSearch,\n page,\n available,\n fixed,\n filter,\n reset,\n searchDecl,\n blocked,\n ],\n );\n}\n"],"mappings":";;;;;AAgFA,SAAgB,qBACd,UACA,SACmB;CAEnB,MAAM,OAAA,GADMA,cAAAA,OAAAA,CACE,CAAC,CAAC,SAAS,IAAI,QAAQ;CACrC,MAAM,EAAE,WAAW,WAAA,GAAUC,cAAAA,gBAAAA,CAAgB,UAAU;EACrD,cAAc,QAAQ;EACtB,SAAS,QAAQ;CACnB,CAAC;CAED,MAAM,CAAC,OAAO,kBAAA,GAAiBC,MAAAA,SAAAA,CAAsBC,aAAAA,kBAAkB;CACvE,MAAM,CAAC,QAAQ,mBAAA,GAAkBD,MAAAA,SAAAA,CAAS,EAAE;CAC5C,MAAM,CAAC,MAAM,YAAA,GAAWA,MAAAA,SAAAA,CAAS,CAAC;CAKlC,MAAM,YAAA,GAAWE,MAAAA,YAAAA,EAAa,SAAsB;EAClD,cAAc,IAAI;EAClB,QAAQ,CAAC;CACX,GAAG,CAAC,CAAC;CAEL,MAAM,aAAA,GAAYA,MAAAA,YAAAA,EAAa,SAAiB;EAC9C,eAAe,IAAI;EACnB,QAAQ,CAAC;CACX,GAAG,CAAC,CAAC;CAEL,MAAM,SAAA,GAAQA,MAAAA,YAAAA,OAAkB;EAC9B,cAAcD,aAAAA,kBAAkB;EAChC,eAAe,EAAE;EACjB,QAAQ,CAAC;CACX,GAAG,CAAC,CAAC;CAOL,MAAM,EAAE,gBAAgB;CACxB,MAAM,UAAA,GAASE,cAAAA,cAAAA,CAAc,QAAQ;CACrC,MAAM,cAAc,OAAO,WAAW;CACtC,MAAM,cAAA,GAAaC,MAAAA,QAAAA,OAAsC;EACvD,MAAM,WAAW,KAAK,OAAO,MAAM;EAOnC,OAAOC,sBAAAA,iBALL,aAAa,KAAA,IACT,WACA,gBAAgB,KAAA,IACd,KAAA,IACA,EAAE,QAAQ,CAAC,WAAW,EAAE,IACD,UAAU,OAAO,aAAa,KAAK,CAAC;CACrE,GAAG;EAAC;EAAK;EAAa;CAAM,CAAC;CAC7B,MAAM,iBAAA,GAAgBD,MAAAA,QAAAA,QAAe;EAAE;EAAU;CAAI,IAAI,CAAC,UAAU,GAAG,CAAC;CAExE,MAAM,UAAA,GAASA,MAAAA,QAAAA,QAAAA,GACPE,aAAAA,kBAAAA,CAAkB;EAAE;EAAO;EAAO;EAAQ;EAAY;CAAc,CAAC,GAC3E;EAAC;EAAO;EAAO;EAAQ;EAAY;CAAa,CAClD;CAIA,MAAM,UAAU,CAAC,eAAeC,sBAAAA,iBAAiB,SAAS,UAAU,OAAO,aAAa,KAAK,CAAC;CAE9F,QAAA,GAAOH,MAAAA,QAAAA,QACE;EACL,eAAe,eAAe,KAAA;EAC9B;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,IACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CACF;AACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"use-dialog-filter-state-BDcgS5Oz.js","names":[],"sources":["../src/fields/use-dialog-filter-state.ts"],"sourcesContent":["import {\n EMPTY_FILTER_GROUP,\n composeListFilter,\n type ErasedResourceHandle,\n type FilterExpression,\n type FilterGroup,\n type FixedFilterInput,\n type ResolvedFixedFilter,\n type SearchDecl,\n} from '@burojs/core';\nimport { useApp, useFilterFields, useListAccess, type FilterFieldSpec } from '@burojs/react';\nimport { namesHiddenField, narrowSearchDecl } from './search-access.js';\nimport { useCallback, useMemo, useState } from 'react';\n\n/** The portable erased AST — the only shape this module deals in. */\ntype ErasedExpression = FilterExpression<ErasedResourceHandle>;\n\n/** Options for {@link useDialogFilterState}. */\nexport interface UseDialogFilterStateOptions {\n /** Call-site narrowing (e.g. scope the target list to a product group). */\n readonly fixedFilters?: readonly FixedFilterInput[];\n /**\n * Fallback search field, used ONLY when the target resource declares no\n * `views.list.search`. Wrapped into a single-field `SearchFieldsDecl`\n * (`{ fields: [searchField] }`, implicit `contains` — same degenerate form\n * `searchToFilter` already gives a bare field-name string) so the override\n * goes through the exact same `composeListFilter` → `searchToFilter` path\n * as a real declaration, rather than a second hand-built predicate at the\n * call site. The target's own declaration always wins when present — this\n * is a fallback, not an override of a declared search.\n */\n readonly searchField?: string;\n /**\n * Gates the field-derivation walk (`useFilterFields`'s `categorizeField`\n * pass over every field of the resource). Defaults to `true`. A caller\n * whose UI isn't visible yet (e.g. `RelationPickerDialog` before it's\n * opened) should pass `false` to skip that work on every mount /\n * `fixedFilters`-identity change; the derivation recomputes in full the\n * next render where this flips back to `true`.\n */\n readonly enabled?: boolean;\n}\n\n/** Return shape of {@link useDialogFilterState}. */\nexport interface DialogFilterState {\n readonly group: FilterGroup;\n readonly setGroup: (next: FilterGroup) => void;\n readonly search: string;\n readonly setSearch: (next: string) => void;\n readonly page: number;\n readonly setPage: (page: number) => void;\n readonly available: readonly FilterFieldSpec[];\n readonly fixed: readonly ResolvedFixedFilter[];\n /** The single expression to hand the data provider. */\n readonly filter: ErasedExpression | undefined;\n /** Whether the target has a search for this user (no field left means no search box). */\n readonly searchEnabled: boolean;\n /** The read must not be sent: undecided access, or a filter naming a field the user may not view. */\n readonly blocked: boolean;\n readonly reset: () => void;\n}\n\n/**\n * Local (non-URL) filter state for the relation-picker's advanced-search\n * dialog.\n *\n * `useResourceList` cannot serve this: it unconditionally calls\n * `useResourceUrlState`, which throws without a `RouterAdapterProvider` and,\n * when one IS present, writes to `?<resource>.*`. A picker dialog mounted\n * inside a form for resource A, searching TARGET resource B, would then\n * write B's list state into the URL — clobbering a real B list page open on\n * another tab of the same app, and reading back whatever that page last\n * wrote on open. So this hook keeps `group`/`search`/`page` in plain\n * `useState` and reuses the SAME composition core's list controller uses\n * (`composeListFilter`) so the two never drift on what a filter means.\n *\n * No `pinned` slot: pinned controls are a list-PAGE affordance (permanent\n * screen real estate for a couple of always-visible facets); a modal has no\n * spare real estate to spend on them.\n */\nexport function useDialogFilterState(\n resource: string,\n options: UseDialogFilterStateOptions,\n): DialogFilterState {\n const app = useApp();\n const def = app.registry.get(resource);\n const { available, fixed } = useFilterFields(resource, {\n fixedFilters: options.fixedFilters,\n enabled: options.enabled,\n });\n\n const [group, setGroupState] = useState<FilterGroup>(EMPTY_FILTER_GROUP);\n const [search, setSearchState] = useState('');\n const [page, setPage] = useState(1);\n\n // Any change to WHAT is filtered invalidates the current page — the same\n // rule `useResourceList`'s URL-state controller applies to its own\n // group/search setters.\n const setGroup = useCallback((next: FilterGroup) => {\n setGroupState(next);\n setPage(1);\n }, []);\n\n const setSearch = useCallback((next: string) => {\n setSearchState(next);\n setPage(1);\n }, []);\n\n const reset = useCallback(() => {\n setGroupState(EMPTY_FILTER_GROUP);\n setSearchState('');\n setPage(1);\n }, []);\n\n // The target's own declaration always wins; `options.searchField` only\n // fills in when the target declares no search at all. Memoized so an\n // omitted declaration doesn't hand `composeListFilter`'s `filter` memo a\n // fresh `{ fields: [...] }` literal (and therefore a spurious recompute)\n // on every render — see `UseDialogFilterStateOptions.searchField`'s doc.\n const { searchField } = options;\n const access = useListAccess(resource);\n const accessReady = access.status === 'ready';\n const searchDecl = useMemo<SearchDecl | undefined>(() => {\n const declared = def?.views?.list?.search;\n const base =\n declared !== undefined\n ? declared\n : searchField === undefined\n ? undefined\n : { fields: [searchField] };\n return narrowSearchDecl(base, (field) => access.fieldVisible(field));\n }, [def, searchField, access]);\n const searchContext = useMemo(() => ({ resource, def }), [resource, def]);\n\n const filter = useMemo<ErasedExpression | undefined>(\n () => composeListFilter({ fixed, group, search, searchDecl, searchContext }),\n [fixed, group, search, searchDecl, searchContext],\n );\n\n // A read whose composed filter names a field the user may not view is forbidden (an author\n // predicate, or a function search's output); an undecided access sends nothing yet.\n const blocked = !accessReady || namesHiddenField(filter, (field) => access.fieldVisible(field));\n\n return useMemo<DialogFilterState>(\n () => ({\n searchEnabled: searchDecl !== undefined,\n blocked,\n group,\n setGroup,\n search,\n setSearch,\n page,\n setPage,\n available,\n fixed,\n filter,\n reset,\n }),\n [\n group,\n setGroup,\n search,\n setSearch,\n page,\n available,\n fixed,\n filter,\n reset,\n searchDecl,\n blocked,\n ],\n );\n}\n"],"mappings":";;;;;AAgFA,SAAgB,qBACd,UACA,SACmB;CAEnB,MAAM,MADM,OACE,CAAC,CAAC,SAAS,IAAI,QAAQ;CACrC,MAAM,EAAE,WAAW,UAAU,gBAAgB,UAAU;EACrD,cAAc,QAAQ;EACtB,SAAS,QAAQ;CACnB,CAAC;CAED,MAAM,CAAC,OAAO,iBAAiB,SAAsB,kBAAkB;CACvE,MAAM,CAAC,QAAQ,kBAAkB,SAAS,EAAE;CAC5C,MAAM,CAAC,MAAM,WAAW,SAAS,CAAC;CAKlC,MAAM,WAAW,aAAa,SAAsB;EAClD,cAAc,IAAI;EAClB,QAAQ,CAAC;CACX,GAAG,CAAC,CAAC;CAEL,MAAM,YAAY,aAAa,SAAiB;EAC9C,eAAe,IAAI;EACnB,QAAQ,CAAC;CACX,GAAG,CAAC,CAAC;CAEL,MAAM,QAAQ,kBAAkB;EAC9B,cAAc,kBAAkB;EAChC,eAAe,EAAE;EACjB,QAAQ,CAAC;CACX,GAAG,CAAC,CAAC;CAOL,MAAM,EAAE,gBAAgB;CACxB,MAAM,SAAS,cAAc,QAAQ;CACrC,MAAM,cAAc,OAAO,WAAW;CACtC,MAAM,aAAa,cAAsC;EACvD,MAAM,WAAW,KAAK,OAAO,MAAM;EAOnC,OAAO,iBALL,aAAa,KAAA,IACT,WACA,gBAAgB,KAAA,IACd,KAAA,IACA,EAAE,QAAQ,CAAC,WAAW,EAAE,IACD,UAAU,OAAO,aAAa,KAAK,CAAC;CACrE,GAAG;EAAC;EAAK;EAAa;CAAM,CAAC;CAC7B,MAAM,gBAAgB,eAAe;EAAE;EAAU;CAAI,IAAI,CAAC,UAAU,GAAG,CAAC;CAExE,MAAM,SAAS,cACP,kBAAkB;EAAE;EAAO;EAAO;EAAQ;EAAY;CAAc,CAAC,GAC3E;EAAC;EAAO;EAAO;EAAQ;EAAY;CAAa,CAClD;CAIA,MAAM,UAAU,CAAC,eAAe,iBAAiB,SAAS,UAAU,OAAO,aAAa,KAAK,CAAC;CAE9F,OAAO,eACE;EACL,eAAe,eAAe,KAAA;EAC9B;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,IACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CACF;AACF"}