@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,6 +1,6 @@
1
- const require_check_confirm_dialog = require("./check-confirm-dialog-BRByTFpg.cjs");
1
+ const require_check_confirm_dialog = require("./check-confirm-dialog-C-NHgMST.cjs");
2
2
  const require_button = require("./button-BxnnE28H.cjs");
3
- const require_flow_screen = require("./flow-screen-CX05b3G9.cjs");
3
+ const require_flow_screen = require("./flow-screen-Bcz9NF2V.cjs");
4
4
  let _burojs_react = require("@burojs/react");
5
5
  let _tabler_icons_react = require("@tabler/icons-react");
6
6
  let react = require("react");
@@ -82,12 +82,12 @@ function InlineFlowHost({ resource = "", name = "", target: givenTarget, label,
82
82
  role: "status",
83
83
  "data-buro-flow-state": "stale",
84
84
  className: "flex flex-wrap items-center gap-2 text-sm text-muted-foreground",
85
- children: [(0, react_jsx_runtime.jsx)("span", { children: require_check_confirm_dialog.text(t, "flow.noLongerApplies", "This action no longer applies") }), (0, react_jsx_runtime.jsx)(require_button.Button, {
85
+ children: [(0, react_jsx_runtime.jsx)("span", { children: t("flow.noLongerApplies", { defaultValue: "This action no longer applies" }) }), (0, react_jsx_runtime.jsx)(require_button.Button, {
86
86
  type: "button",
87
87
  size: "sm",
88
88
  variant: "outline",
89
89
  onClick: onDiscard,
90
- children: require_check_confirm_dialog.text(t, "flow.discard", "Discard")
90
+ children: t("flow.discard", { defaultValue: "Discard" })
91
91
  })]
92
92
  }) : null, opened ? (0, react_jsx_runtime.jsx)("fieldset", {
93
93
  disabled: stale,
@@ -109,4 +109,4 @@ function InlineFlowHost({ resource = "", name = "", target: givenTarget, label,
109
109
  //#endregion
110
110
  exports.InlineFlowHost = InlineFlowHost;
111
111
 
112
- //# sourceMappingURL=inline-flow-host-B7U1OJUe.cjs.map
112
+ //# sourceMappingURL=inline-flow-host-3vw7LzzD.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inline-flow-host-3vw7LzzD.cjs","names":["useTestIds","useFlowChrome","useMemo","useFlowRun","useScreenState","useOptionalT","Button","HostedFlowScreen","IconLoader2"],"sources":["../src/flows/inline-flow-host.tsx"],"sourcesContent":["'use client';\n/**\n * The inline host (P6 3.12): an item flow drawn in place in a show tree. The run lives in the\n * placement's lease, held by the screen, so a tab switch away and back finds the typed input and\n * a write in flight, and the flow's attempt slot stays the one P4 keys on (user, flow, record).\n */\nimport type { FlowTarget, Row } from '@burojs/core';\nimport type { InlineLease } from '@burojs/react';\nimport { useOptionalT, useScreenState, useTestIds } from '@burojs/react';\nimport { useFlowRun } from '@burojs/react/flows';\nimport { IconLoader2 } from '@tabler/icons-react';\nimport { type ReactElement, useEffect, useMemo } from 'react';\nimport { Button } from '../primitives/button.js';\nimport { useFlowChrome } from './chrome.js';\nimport { type FlowHostBinding, HostedFlowScreen } from './flow-screen.js';\n\nexport interface InlineFlowHostProps {\n /** The resource of an item flow on a record screen; a page names `target` instead. */\n readonly resource?: string;\n readonly name?: string;\n /** The flow, when it is not an item flow of the screen's resource (a page's, P7 3.15). */\n readonly target?: FlowTarget;\n /** The label of a flow with no resource to ask (an app flow's). */\n readonly label?: string;\n /** The record an item flow runs on; none on a page. */\n readonly record?: Row;\n readonly lease?: InlineLease;\n readonly placementKey: string;\n /**\n * The flow no longer applies to the record (its `when` turned false) while the input is dirty\n * or the attempt unresolved: the node stays, read-only, with \"no longer applies\" and Discard.\n */\n readonly stale?: boolean;\n readonly onDiscard?: () => void;\n}\n\nexport function InlineFlowHost({\n resource = '',\n name = '',\n target: givenTarget,\n label,\n record,\n lease,\n placementKey,\n stale = false,\n onDiscard,\n}: InlineFlowHostProps): ReactElement {\n const tid = useTestIds();\n const own = useFlowChrome(resource, name);\n const chrome = label === undefined ? own : { ...own, label, labelText: label };\n const target = useMemo<FlowTarget>(\n () => givenTarget ?? { resource, action: name },\n [givenTarget, resource, name],\n );\n const flow = useFlowRun(target, {\n ...(record === undefined ? {} : { record }),\n surface: 'inline',\n ...(lease === undefined ? {} : { lease }),\n });\n // `then` is this host's to run, once the form it succeeded in has started over.\n flow.holdThen(true);\n const { run, snapshot, compiled } = flow;\n const binding = useMemo<FlowHostBinding>(\n () => ({\n kind: 'inline',\n close: () => flow.reset(),\n finish: () => {\n flow.runThen();\n flow.reset();\n },\n }),\n // biome-ignore lint/correctness/useExhaustiveDependencies: reset and runThen are stable callbacks\n [flow.reset, flow.runThen],\n );\n const holder = useScreenState()?.inline;\n const t = useOptionalT();\n // The lease's guard state, from the run: unsaved input or an unresolved attempt (dirty), a\n // write in flight (locked), and whether a node shows it. The screen's blockers read these\n // when the node is not on screen (tab switched, placement hidden).\n useEffect(() => {\n if (lease === undefined || holder === undefined) return;\n lease.mounted += 1;\n lease.label = chrome.labelText;\n holder.touch();\n return () => {\n lease.mounted -= 1;\n holder.touch();\n };\n }, [lease, holder, chrome.labelText]);\n useEffect(() => {\n if (lease === undefined || holder === undefined || run === null) return;\n const sync = () => {\n const now = run.getSnapshot();\n if (lease.initial === undefined && now.history.includes('open'))\n lease.initial = JSON.stringify(now.values);\n const dirty =\n now.outcome?.outcome !== 'success' &&\n (now.outcome?.outcome === 'unknown' ||\n (lease.initial !== undefined && JSON.stringify(now.values) !== lease.initial));\n const locked = now.control === 'running';\n if (dirty === lease.dirty && locked === lease.locked) return;\n lease.dirty = dirty;\n lease.locked = locked;\n holder.touch();\n };\n sync();\n return run.subscribe(sync);\n }, [lease, holder, run]);\n const opened =\n run !== null &&\n compiled !== null &&\n (snapshot.history.includes('open') || snapshot.step === 'outcome');\n return (\n <div\n data-testid={tid.inlineFlow(compiled?.flowId ?? `${resource}/actions/${name}`, placementKey)}\n data-buro-host=\"inline\"\n className=\"flex min-h-0 flex-col gap-4\"\n >\n {stale ? (\n <div\n role=\"status\"\n data-buro-flow-state=\"stale\"\n className=\"flex flex-wrap items-center gap-2 text-sm text-muted-foreground\"\n >\n <span>\n {t('flow.noLongerApplies', { defaultValue: 'This action no longer applies' })}\n </span>\n <Button type=\"button\" size=\"sm\" variant=\"outline\" onClick={onDiscard}>\n {t('flow.discard', { defaultValue: 'Discard' })}\n </Button>\n </div>\n ) : null}\n {opened ? (\n <fieldset disabled={stale} className=\"m-0 min-w-0 border-0 p-0\">\n <HostedFlowScreen\n binding={binding}\n host=\"inline\"\n run={run}\n compiled={compiled}\n label={chrome.labelText}\n record={record}\n />\n </fieldset>\n ) : (\n <IconLoader2 className=\"h-5 w-5 animate-spin self-center\" aria-hidden=\"true\" />\n )}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- import { h as useFlowChrome, m as text } from "./check-confirm-dialog-CkaVTPT9.js";
1
+ import { m as useFlowChrome } from "./check-confirm-dialog-2j0gOd7x.js";
2
2
  import { t as Button } from "./button-MWVeZaqj.js";
3
- import { HostedFlowScreen } from "./flow-screen-CmbARSqg.js";
3
+ import { HostedFlowScreen } from "./flow-screen-DCdli6Ha.js";
4
4
  import { useOptionalT, useScreenState, useTestIds } from "@burojs/react";
5
5
  import { IconLoader2 } from "@tabler/icons-react";
6
6
  import { useEffect, useMemo } from "react";
@@ -82,12 +82,12 @@ function InlineFlowHost({ resource = "", name = "", target: givenTarget, label,
82
82
  role: "status",
83
83
  "data-buro-flow-state": "stale",
84
84
  className: "flex flex-wrap items-center gap-2 text-sm text-muted-foreground",
85
- children: [jsx("span", { children: text(t, "flow.noLongerApplies", "This action no longer applies") }), jsx(Button, {
85
+ children: [jsx("span", { children: t("flow.noLongerApplies", { defaultValue: "This action no longer applies" }) }), jsx(Button, {
86
86
  type: "button",
87
87
  size: "sm",
88
88
  variant: "outline",
89
89
  onClick: onDiscard,
90
- children: text(t, "flow.discard", "Discard")
90
+ children: t("flow.discard", { defaultValue: "Discard" })
91
91
  })]
92
92
  }) : null, opened ? jsx("fieldset", {
93
93
  disabled: stale,
@@ -109,4 +109,4 @@ function InlineFlowHost({ resource = "", name = "", target: givenTarget, label,
109
109
  //#endregion
110
110
  export { InlineFlowHost };
111
111
 
112
- //# sourceMappingURL=inline-flow-host-C3H2UpSA.js.map
112
+ //# sourceMappingURL=inline-flow-host-C0rI9B7f.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inline-flow-host-C0rI9B7f.js","names":[],"sources":["../src/flows/inline-flow-host.tsx"],"sourcesContent":["'use client';\n/**\n * The inline host (P6 3.12): an item flow drawn in place in a show tree. The run lives in the\n * placement's lease, held by the screen, so a tab switch away and back finds the typed input and\n * a write in flight, and the flow's attempt slot stays the one P4 keys on (user, flow, record).\n */\nimport type { FlowTarget, Row } from '@burojs/core';\nimport type { InlineLease } from '@burojs/react';\nimport { useOptionalT, useScreenState, useTestIds } from '@burojs/react';\nimport { useFlowRun } from '@burojs/react/flows';\nimport { IconLoader2 } from '@tabler/icons-react';\nimport { type ReactElement, useEffect, useMemo } from 'react';\nimport { Button } from '../primitives/button.js';\nimport { useFlowChrome } from './chrome.js';\nimport { type FlowHostBinding, HostedFlowScreen } from './flow-screen.js';\n\nexport interface InlineFlowHostProps {\n /** The resource of an item flow on a record screen; a page names `target` instead. */\n readonly resource?: string;\n readonly name?: string;\n /** The flow, when it is not an item flow of the screen's resource (a page's, P7 3.15). */\n readonly target?: FlowTarget;\n /** The label of a flow with no resource to ask (an app flow's). */\n readonly label?: string;\n /** The record an item flow runs on; none on a page. */\n readonly record?: Row;\n readonly lease?: InlineLease;\n readonly placementKey: string;\n /**\n * The flow no longer applies to the record (its `when` turned false) while the input is dirty\n * or the attempt unresolved: the node stays, read-only, with \"no longer applies\" and Discard.\n */\n readonly stale?: boolean;\n readonly onDiscard?: () => void;\n}\n\nexport function InlineFlowHost({\n resource = '',\n name = '',\n target: givenTarget,\n label,\n record,\n lease,\n placementKey,\n stale = false,\n onDiscard,\n}: InlineFlowHostProps): ReactElement {\n const tid = useTestIds();\n const own = useFlowChrome(resource, name);\n const chrome = label === undefined ? own : { ...own, label, labelText: label };\n const target = useMemo<FlowTarget>(\n () => givenTarget ?? { resource, action: name },\n [givenTarget, resource, name],\n );\n const flow = useFlowRun(target, {\n ...(record === undefined ? {} : { record }),\n surface: 'inline',\n ...(lease === undefined ? {} : { lease }),\n });\n // `then` is this host's to run, once the form it succeeded in has started over.\n flow.holdThen(true);\n const { run, snapshot, compiled } = flow;\n const binding = useMemo<FlowHostBinding>(\n () => ({\n kind: 'inline',\n close: () => flow.reset(),\n finish: () => {\n flow.runThen();\n flow.reset();\n },\n }),\n // biome-ignore lint/correctness/useExhaustiveDependencies: reset and runThen are stable callbacks\n [flow.reset, flow.runThen],\n );\n const holder = useScreenState()?.inline;\n const t = useOptionalT();\n // The lease's guard state, from the run: unsaved input or an unresolved attempt (dirty), a\n // write in flight (locked), and whether a node shows it. The screen's blockers read these\n // when the node is not on screen (tab switched, placement hidden).\n useEffect(() => {\n if (lease === undefined || holder === undefined) return;\n lease.mounted += 1;\n lease.label = chrome.labelText;\n holder.touch();\n return () => {\n lease.mounted -= 1;\n holder.touch();\n };\n }, [lease, holder, chrome.labelText]);\n useEffect(() => {\n if (lease === undefined || holder === undefined || run === null) return;\n const sync = () => {\n const now = run.getSnapshot();\n if (lease.initial === undefined && now.history.includes('open'))\n lease.initial = JSON.stringify(now.values);\n const dirty =\n now.outcome?.outcome !== 'success' &&\n (now.outcome?.outcome === 'unknown' ||\n (lease.initial !== undefined && JSON.stringify(now.values) !== lease.initial));\n const locked = now.control === 'running';\n if (dirty === lease.dirty && locked === lease.locked) return;\n lease.dirty = dirty;\n lease.locked = locked;\n holder.touch();\n };\n sync();\n return run.subscribe(sync);\n }, [lease, holder, run]);\n const opened =\n run !== null &&\n compiled !== null &&\n (snapshot.history.includes('open') || snapshot.step === 'outcome');\n return (\n <div\n data-testid={tid.inlineFlow(compiled?.flowId ?? `${resource}/actions/${name}`, placementKey)}\n data-buro-host=\"inline\"\n className=\"flex min-h-0 flex-col gap-4\"\n >\n {stale ? (\n <div\n role=\"status\"\n data-buro-flow-state=\"stale\"\n className=\"flex flex-wrap items-center gap-2 text-sm text-muted-foreground\"\n >\n <span>\n {t('flow.noLongerApplies', { defaultValue: 'This action no longer applies' })}\n </span>\n <Button type=\"button\" size=\"sm\" variant=\"outline\" onClick={onDiscard}>\n {t('flow.discard', { defaultValue: 'Discard' })}\n </Button>\n </div>\n ) : null}\n {opened ? (\n <fieldset disabled={stale} className=\"m-0 min-w-0 border-0 p-0\">\n <HostedFlowScreen\n binding={binding}\n host=\"inline\"\n run={run}\n compiled={compiled}\n label={chrome.labelText}\n record={record}\n />\n </fieldset>\n ) : (\n <IconLoader2 className=\"h-5 w-5 animate-spin self-center\" aria-hidden=\"true\" />\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;AAoCA,SAAgB,eAAe,EAC7B,WAAW,IACX,OAAO,IACP,QAAQ,aACR,OACA,QACA,OACA,cACA,QAAQ,OACR,aACoC;CACpC,MAAM,MAAM,WAAW;CACvB,MAAM,MAAM,cAAc,UAAU,IAAI;CACxC,MAAM,SAAS,UAAU,KAAA,IAAY,MAAM;EAAE,GAAG;EAAK;EAAO,WAAW;CAAM;CAC7E,MAAM,SAAS,cACP,eAAe;EAAE;EAAU,QAAQ;CAAK,GAC9C;EAAC;EAAa;EAAU;CAAI,CAC9B;CACA,MAAM,OAAO,WAAW,QAAQ;EAC9B,GAAI,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO;EACzC,SAAS;EACT,GAAI,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM;CACzC,CAAC;CAED,KAAK,SAAS,IAAI;CAClB,MAAM,EAAE,KAAK,UAAU,aAAa;CACpC,MAAM,UAAU,eACP;EACL,MAAM;EACN,aAAa,KAAK,MAAM;EACxB,cAAc;GACZ,KAAK,QAAQ;GACb,KAAK,MAAM;EACb;CACF,IAEA,CAAC,KAAK,OAAO,KAAK,OAAO,CAC3B;CACA,MAAM,SAAS,eAAe,CAAC,EAAE;CACjC,MAAM,IAAI,aAAa;CAIvB,gBAAgB;EACd,IAAI,UAAU,KAAA,KAAa,WAAW,KAAA,GAAW;EACjD,MAAM,WAAW;EACjB,MAAM,QAAQ,OAAO;EACrB,OAAO,MAAM;EACb,aAAa;GACX,MAAM,WAAW;GACjB,OAAO,MAAM;EACf;CACF,GAAG;EAAC;EAAO;EAAQ,OAAO;CAAS,CAAC;CACpC,gBAAgB;EACd,IAAI,UAAU,KAAA,KAAa,WAAW,KAAA,KAAa,QAAQ,MAAM;EACjE,MAAM,aAAa;GACjB,MAAM,MAAM,IAAI,YAAY;GAC5B,IAAI,MAAM,YAAY,KAAA,KAAa,IAAI,QAAQ,SAAS,MAAM,GAC5D,MAAM,UAAU,KAAK,UAAU,IAAI,MAAM;GAC3C,MAAM,QACJ,IAAI,SAAS,YAAY,cACxB,IAAI,SAAS,YAAY,aACvB,MAAM,YAAY,KAAA,KAAa,KAAK,UAAU,IAAI,MAAM,MAAM,MAAM;GACzE,MAAM,SAAS,IAAI,YAAY;GAC/B,IAAI,UAAU,MAAM,SAAS,WAAW,MAAM,QAAQ;GACtD,MAAM,QAAQ;GACd,MAAM,SAAS;GACf,OAAO,MAAM;EACf;EACA,KAAK;EACL,OAAO,IAAI,UAAU,IAAI;CAC3B,GAAG;EAAC;EAAO;EAAQ;CAAG,CAAC;CACvB,MAAM,SACJ,QAAQ,QACR,aAAa,SACZ,SAAS,QAAQ,SAAS,MAAM,KAAK,SAAS,SAAS;CAC1D,OACE,KAAC,OAAD;EACE,eAAa,IAAI,WAAW,UAAU,UAAU,GAAG,SAAS,WAAW,QAAQ,YAAY;EAC3F,kBAAe;EACf,WAAU;EAHZ,UAAA,CAKG,QACC,KAAC,OAAD;GACE,MAAK;GACL,wBAAqB;GACrB,WAAU;GAHZ,UAAA,CAKE,IAAC,QAAD,EAAA,UACG,EAAE,wBAAwB,EAAE,cAAc,gCAAgC,CAAC,EACxE,CAAA,GACN,IAAC,QAAD;IAAQ,MAAK;IAAS,MAAK;IAAK,SAAQ;IAAU,SAAS;IACxD,UAAA,EAAE,gBAAgB,EAAE,cAAc,UAAU,CAAC;GACxC,CAAA,CACL;EACH,CAAA,IAAA,MACH,SACC,IAAC,YAAD;GAAU,UAAU;GAAO,WAAU;GACnC,UAAA,IAAC,kBAAD;IACW;IACT,MAAK;IACA;IACK;IACV,OAAO,OAAO;IACN;GACT,CAAA;EACO,CAAA,IAEV,IAAC,aAAD;GAAa,WAAU;GAAmC,eAAY;EAAQ,CAAA,CAE7E;;AAET"}
@@ -1 +1 @@
1
- {"version":3,"file":"label-66W1qbke.js","names":[],"sources":["../src/primitives/label.tsx"],"sourcesContent":["'use client';\nimport { useOptionalT } from '@burojs/react';\n\nimport * as React from 'react';\nimport * as LabelPrimitive from '@radix-ui/react-label';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../lib/cn.js';\n\nconst labelVariants = cva(\n 'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',\n);\n\nexport type LabelProps = React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &\n VariantProps<typeof labelVariants> & {\n /**\n * When true, append a destructive-colored asterisk after the label text\n * plus a screen-reader-only \"(required)\" hint. This is the single-source\n * required-indicator style — every form should render its required-field\n * label as `<Label required>...</Label>` rather than hand-rolling the\n * asterisk markup. The visual asterisk is `aria-hidden`; AT users get\n * the spoken hint via the sr-only span. (Inputs are still expected to\n * carry their own `aria-required` / `required` HTML attributes for the\n * native semantics.)\n */\n required?: boolean;\n };\n\nconst Label = React.forwardRef<React.ElementRef<typeof LabelPrimitive.Root>, LabelProps>(\n ({ className, required, children, ...props }, ref) => {\n // Localized because this renders inside a Russian-primary product; a\n // screen-reader user should not hear an English \"(required)\".\n const t = useOptionalT();\n return (\n <LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props}>\n {children}\n {required && (\n <>\n <span className=\"ml-0.5 text-destructive\" aria-hidden=\"true\">\n *\n </span>\n <span className=\"sr-only\">\n {' '}\n {t('validation.requiredHint', { defaultValue: '(required)' })}\n </span>\n </>\n )}\n </LabelPrimitive.Root>\n );\n },\n);\nLabel.displayName = LabelPrimitive.Root.displayName;\n\nexport { Label };\n"],"mappings":";;;;;;;AAQA,MAAM,gBAAgB,IACpB,4FACF;AAiBA,MAAM,QAAQ,MAAM,YACjB,EAAE,WAAW,UAAU,UAAU,GAAG,SAAS,QAAQ;CAGpD,MAAM,IAAI,aAAa;CACvB,OACE,KAAC,eAAe,MAAhB;EAA0B;EAAK,WAAW,GAAG,cAAc,GAAG,SAAS;EAAG,GAAI;EAA9E,UAAA,CACG,UACA,YACC,KAAA,YAAA,EAAA,UAAA,CACE,IAAC,QAAD;GAAM,WAAU;GAA0B,eAAY;GAAO,UAAA;EAEvD,CAAA,GACN,KAAC,QAAD;GAAM,WAAU;GAAhB,UAAA,CACG,KACA,EAAE,2BAA2B,EAAE,cAAc,aAAa,CAAC,CACxD;EACN,CAAA,CAAA,EAAA,CAAA,CAEe;;AAEzB,CACF;AACA,MAAM,cAAc,eAAe,KAAK"}
1
+ {"version":3,"file":"label-66W1qbke.js","names":[],"sources":["../src/primitives/label.tsx"],"sourcesContent":["'use client';\nimport { useOptionalT } from '@burojs/react';\n\nimport * as React from 'react';\nimport * as LabelPrimitive from '@radix-ui/react-label';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../lib/cn.js';\n\nconst labelVariants = cva(\n 'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',\n);\n\nexport type LabelProps = React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &\n VariantProps<typeof labelVariants> & {\n /**\n * When true, append a destructive-colored asterisk after the label text\n * plus a screen-reader-only \"(required)\" hint. This is the single-source\n * required-indicator style — every form should render its required-field\n * label as `<Label required>...</Label>` rather than hand-rolling the\n * asterisk markup. The visual asterisk is `aria-hidden`; AT users get\n * the spoken hint via the sr-only span. (Inputs are still expected to\n * carry their own `aria-required` / `required` HTML attributes for the\n * native semantics.)\n */\n required?: boolean;\n };\n\nconst Label = React.forwardRef<React.ElementRef<typeof LabelPrimitive.Root>, LabelProps>(\n ({ className, required, children, ...props }, ref) => {\n // Localized so that a screen-reader user in a non-English app does not\n // hear an English \"(required)\".\n const t = useOptionalT();\n return (\n <LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props}>\n {children}\n {required && (\n <>\n <span className=\"ml-0.5 text-destructive\" aria-hidden=\"true\">\n *\n </span>\n <span className=\"sr-only\">\n {' '}\n {t('validation.requiredHint', { defaultValue: '(required)' })}\n </span>\n </>\n )}\n </LabelPrimitive.Root>\n );\n },\n);\nLabel.displayName = LabelPrimitive.Root.displayName;\n\nexport { Label };\n"],"mappings":";;;;;;;AAQA,MAAM,gBAAgB,IACpB,4FACF;AAiBA,MAAM,QAAQ,MAAM,YACjB,EAAE,WAAW,UAAU,UAAU,GAAG,SAAS,QAAQ;CAGpD,MAAM,IAAI,aAAa;CACvB,OACE,KAAC,eAAe,MAAhB;EAA0B;EAAK,WAAW,GAAG,cAAc,GAAG,SAAS;EAAG,GAAI;EAA9E,UAAA,CACG,UACA,YACC,KAAA,YAAA,EAAA,UAAA,CACE,IAAC,QAAD;GAAM,WAAU;GAA0B,eAAY;GAAO,UAAA;EAEvD,CAAA,GACN,KAAC,QAAD;GAAM,WAAU;GAAhB,UAAA,CACG,KACA,EAAE,2BAA2B,EAAE,cAAc,aAAa,CAAC,CACxD;EACN,CAAA,CAAA,EAAA,CAAA,CAEe;;AAEzB,CACF;AACA,MAAM,cAAc,eAAe,KAAK"}
@@ -1 +1 @@
1
- {"version":3,"file":"label-w6JYf2cF.cjs","names":["cva","React","useOptionalT","LabelPrimitive","cn"],"sources":["../src/primitives/label.tsx"],"sourcesContent":["'use client';\nimport { useOptionalT } from '@burojs/react';\n\nimport * as React from 'react';\nimport * as LabelPrimitive from '@radix-ui/react-label';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../lib/cn.js';\n\nconst labelVariants = cva(\n 'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',\n);\n\nexport type LabelProps = React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &\n VariantProps<typeof labelVariants> & {\n /**\n * When true, append a destructive-colored asterisk after the label text\n * plus a screen-reader-only \"(required)\" hint. This is the single-source\n * required-indicator style — every form should render its required-field\n * label as `<Label required>...</Label>` rather than hand-rolling the\n * asterisk markup. The visual asterisk is `aria-hidden`; AT users get\n * the spoken hint via the sr-only span. (Inputs are still expected to\n * carry their own `aria-required` / `required` HTML attributes for the\n * native semantics.)\n */\n required?: boolean;\n };\n\nconst Label = React.forwardRef<React.ElementRef<typeof LabelPrimitive.Root>, LabelProps>(\n ({ className, required, children, ...props }, ref) => {\n // Localized because this renders inside a Russian-primary product; a\n // screen-reader user should not hear an English \"(required)\".\n const t = useOptionalT();\n return (\n <LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props}>\n {children}\n {required && (\n <>\n <span className=\"ml-0.5 text-destructive\" aria-hidden=\"true\">\n *\n </span>\n <span className=\"sr-only\">\n {' '}\n {t('validation.requiredHint', { defaultValue: '(required)' })}\n </span>\n </>\n )}\n </LabelPrimitive.Root>\n );\n },\n);\nLabel.displayName = LabelPrimitive.Root.displayName;\n\nexport { Label };\n"],"mappings":";;;;;;;;;AAQA,MAAM,iBAAA,GAAgBA,yBAAAA,IAAAA,CACpB,4FACF;AAiBA,MAAM,QAAQC,MAAM,YACjB,EAAE,WAAW,UAAU,UAAU,GAAG,SAAS,QAAQ;CAGpD,MAAM,KAAA,GAAIC,cAAAA,aAAAA,CAAa;CACvB,QACE,GAAA,kBAAA,KAAA,CAACC,sBAAe,MAAhB;EAA0B;EAAK,WAAWC,kBAAAA,GAAG,cAAc,GAAG,SAAS;EAAG,GAAI;EAA9E,UAAA,CACG,UACA,aACC,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA,EACE,GAAA,kBAAA,IAAA,CAAC,QAAD;GAAM,WAAU;GAA0B,eAAY;GAAO,UAAA;EAEvD,CAAA,IACN,GAAA,kBAAA,KAAA,CAAC,QAAD;GAAM,WAAU;GAAhB,UAAA,CACG,KACA,EAAE,2BAA2B,EAAE,cAAc,aAAa,CAAC,CACxD;EACN,CAAA,CAAA,EAAA,CAAA,CAEe;;AAEzB,CACF;AACA,MAAM,cAAcD,sBAAe,KAAK"}
1
+ {"version":3,"file":"label-w6JYf2cF.cjs","names":["cva","React","useOptionalT","LabelPrimitive","cn"],"sources":["../src/primitives/label.tsx"],"sourcesContent":["'use client';\nimport { useOptionalT } from '@burojs/react';\n\nimport * as React from 'react';\nimport * as LabelPrimitive from '@radix-ui/react-label';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../lib/cn.js';\n\nconst labelVariants = cva(\n 'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',\n);\n\nexport type LabelProps = React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &\n VariantProps<typeof labelVariants> & {\n /**\n * When true, append a destructive-colored asterisk after the label text\n * plus a screen-reader-only \"(required)\" hint. This is the single-source\n * required-indicator style — every form should render its required-field\n * label as `<Label required>...</Label>` rather than hand-rolling the\n * asterisk markup. The visual asterisk is `aria-hidden`; AT users get\n * the spoken hint via the sr-only span. (Inputs are still expected to\n * carry their own `aria-required` / `required` HTML attributes for the\n * native semantics.)\n */\n required?: boolean;\n };\n\nconst Label = React.forwardRef<React.ElementRef<typeof LabelPrimitive.Root>, LabelProps>(\n ({ className, required, children, ...props }, ref) => {\n // Localized so that a screen-reader user in a non-English app does not\n // hear an English \"(required)\".\n const t = useOptionalT();\n return (\n <LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props}>\n {children}\n {required && (\n <>\n <span className=\"ml-0.5 text-destructive\" aria-hidden=\"true\">\n *\n </span>\n <span className=\"sr-only\">\n {' '}\n {t('validation.requiredHint', { defaultValue: '(required)' })}\n </span>\n </>\n )}\n </LabelPrimitive.Root>\n );\n },\n);\nLabel.displayName = LabelPrimitive.Root.displayName;\n\nexport { Label };\n"],"mappings":";;;;;;;;;AAQA,MAAM,iBAAA,GAAgBA,yBAAAA,IAAAA,CACpB,4FACF;AAiBA,MAAM,QAAQC,MAAM,YACjB,EAAE,WAAW,UAAU,UAAU,GAAG,SAAS,QAAQ;CAGpD,MAAM,KAAA,GAAIC,cAAAA,aAAAA,CAAa;CACvB,QACE,GAAA,kBAAA,KAAA,CAACC,sBAAe,MAAhB;EAA0B;EAAK,WAAWC,kBAAAA,GAAG,cAAc,GAAG,SAAS;EAAG,GAAI;EAA9E,UAAA,CACG,UACA,aACC,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA,EACE,GAAA,kBAAA,IAAA,CAAC,QAAD;GAAM,WAAU;GAA0B,eAAY;GAAO,UAAA;EAEvD,CAAA,IACN,GAAA,kBAAA,KAAA,CAAC,QAAD;GAAM,WAAU;GAAhB,UAAA,CACG,KACA,EAAE,2BAA2B,EAAE,cAAc,aAAa,CAAC,CACxD;EACN,CAAA,CAAA,EAAA,CAAA,CAEe;;AAEzB,CACF;AACA,MAAM,cAAcD,sBAAe,KAAK"}
@@ -0,0 +1,153 @@
1
+ const require_use_theme = require("./use-theme-DFlpXils.cjs");
2
+ let _burojs_core = require("@burojs/core");
3
+ let _burojs_react = require("@burojs/react");
4
+ let react = require("react");
5
+ react = require_use_theme.__toESM(react, 1);
6
+ let react_jsx_runtime = require("react/jsx-runtime");
7
+ //#region src/fields/candidates-match.ts
8
+ function rowMatches(row, filters) {
9
+ let unknown = false;
10
+ for (const filter of filters) {
11
+ const group = filter;
12
+ if (Array.isArray(group.and) || Array.isArray(group.or)) {
13
+ const answers = (Array.isArray(group.and) ? group.and : group.or).map((part) => rowMatches(row, [part]));
14
+ const all = Array.isArray(group.and);
15
+ const decided = answers.filter((answer) => answer !== void 0);
16
+ if (all ? decided.includes(false) : decided.length > 0 && !decided.includes(true)) return false;
17
+ if (decided.length < answers.length && !(all ? false : decided.includes(true))) unknown = true;
18
+ continue;
19
+ }
20
+ const { field, op, value } = filter;
21
+ if (typeof field !== "string" || typeof op !== "string") continue;
22
+ if (!Object.hasOwn(row, field)) {
23
+ unknown = true;
24
+ continue;
25
+ }
26
+ const held = holds(row[field], op, value);
27
+ if (held === false) return false;
28
+ if (held === void 0) unknown = true;
29
+ }
30
+ return unknown ? void 0 : true;
31
+ }
32
+ function holds(actual, op, expected) {
33
+ const list = Array.isArray(expected) ? expected : void 0;
34
+ const text = (value) => String(value ?? "").toLowerCase();
35
+ switch (op) {
36
+ case "eq": return Object.is(actual, expected) || String(actual) === String(expected);
37
+ case "neq": return !(Object.is(actual, expected) || String(actual) === String(expected));
38
+ case "in": return list === void 0 ? void 0 : list.some((entry) => String(entry) === String(actual));
39
+ case "notIn": return list === void 0 ? void 0 : !list.some((entry) => String(entry) === String(actual));
40
+ case "gt": return compare(actual, expected, (a, b) => a > b);
41
+ case "gte": return compare(actual, expected, (a, b) => a >= b);
42
+ case "lt": return compare(actual, expected, (a, b) => a < b);
43
+ case "lte": return compare(actual, expected, (a, b) => a <= b);
44
+ case "contains": return text(actual).includes(text(expected));
45
+ case "startsWith": return text(actual).startsWith(text(expected));
46
+ case "endsWith": return text(actual).endsWith(text(expected));
47
+ case "isNull": return actual === null || actual === void 0;
48
+ case "isNotNull": return actual !== null && actual !== void 0;
49
+ default: return;
50
+ }
51
+ }
52
+ function compare(actual, expected, test) {
53
+ return typeof actual === "number" && typeof expected === "number" || typeof actual === "string" && typeof expected === "string" ? test(actual, expected) : void 0;
54
+ }
55
+ //#endregion
56
+ //#region src/fields/candidates-gate.ts
57
+ const NO_SOURCES = Object.freeze({});
58
+ const NO_FILTERS = Object.freeze([]);
59
+ function useCandidatesGate(input) {
60
+ const { to, candidates, sources, resource, fieldName } = input;
61
+ const t = (0, _burojs_react.useOptionalT)();
62
+ const app = (0, _burojs_react.useApp)();
63
+ const tid = (0, _burojs_react.useTestIds)();
64
+ const ownerCaps = (0, _burojs_react.useI18nCaps)(resource);
65
+ const targetCaps = (0, _burojs_react.useI18nCaps)(to ?? resource);
66
+ const access = (0, _burojs_react.useCandidatesAccess)(to ?? "", candidates);
67
+ const resolution = react.useMemo(() => (0, _burojs_core.resolveCandidates)(candidates, sources ?? NO_SOURCES), [candidates, sources]);
68
+ if (candidates === void 0 || candidates.length === 0) return { filters: NO_FILTERS };
69
+ const testId = tid.relationCandidatesHint(resource, fieldName);
70
+ if (access.status === "pending") return {
71
+ filters: NO_FILTERS,
72
+ gate: { kind: "pending" }
73
+ };
74
+ if (access.status === "forbidden") {
75
+ const declared = (0, _burojs_core.declaredText)("field", (app.registry.get(to ?? "")?.fields)?.[access.field], "label");
76
+ const label = (0, _burojs_core.resolveFieldLabel)(targetCaps, access.field, declared);
77
+ return {
78
+ filters: NO_FILTERS,
79
+ gate: {
80
+ kind: "forbidden",
81
+ testId,
82
+ message: t("relationPicker.cannotSearchBy", {
83
+ params: { label },
84
+ defaultValue: `You cannot search by ${label}`
85
+ })
86
+ }
87
+ };
88
+ }
89
+ if (resolution.status === "pending") return {
90
+ filters: NO_FILTERS,
91
+ gate: { kind: "pending" }
92
+ };
93
+ if (resolution.status === "empty") {
94
+ const { source, path } = resolution.hint;
95
+ const head = path[0];
96
+ const declared = (source === "values" || source === "record") && head !== void 0 ? (0, _burojs_core.declaredText)("field", (app.registry.get(resource)?.fields)?.[head], "label") : void 0;
97
+ const label = (0, _burojs_core.resolveFieldLabel)(ownerCaps, head ?? source, declared);
98
+ return {
99
+ filters: NO_FILTERS,
100
+ gate: {
101
+ kind: "empty",
102
+ testId,
103
+ message: t("relationPicker.chooseFirst", {
104
+ params: { label },
105
+ defaultValue: `Choose ${label} first`
106
+ })
107
+ }
108
+ };
109
+ }
110
+ return { filters: resolution.filters };
111
+ }
112
+ function useCandidateSelection(input) {
113
+ const { fixedFilters } = input;
114
+ const gate = useCandidatesGate(input);
115
+ const filters = gate.filters;
116
+ const combined = react.useMemo(() => filters.length === 0 ? fixedFilters : [...filters, ...fixedFilters ?? []], [filters, fixedFilters]);
117
+ const rowFits = react.useMemo(() => filters.length === 0 ? void 0 : (row) => rowMatches(row, filters), [filters]);
118
+ return {
119
+ fixedFilters: combined,
120
+ ...gate.gate === void 0 ? {} : { gate: gate.gate },
121
+ ...rowFits === void 0 ? {} : { rowFits }
122
+ };
123
+ }
124
+ //#endregion
125
+ //#region src/fields/lazy-relation-picker-dialog.tsx
126
+ const Dialog = (0, react.lazy)(() => Promise.resolve().then(() => require("./relation-picker-dialog-9Vg5vvR1.cjs")).then((module) => ({ default: module.RelationPickerDialog })));
127
+ function LazyRelationPickerDialog(props) {
128
+ return (0, react_jsx_runtime.jsx)(react.Suspense, {
129
+ fallback: null,
130
+ children: (0, react_jsx_runtime.jsx)(Dialog, { ...props })
131
+ });
132
+ }
133
+ //#endregion
134
+ Object.defineProperty(exports, "LazyRelationPickerDialog", {
135
+ enumerable: true,
136
+ get: function() {
137
+ return LazyRelationPickerDialog;
138
+ }
139
+ });
140
+ Object.defineProperty(exports, "useCandidateSelection", {
141
+ enumerable: true,
142
+ get: function() {
143
+ return useCandidateSelection;
144
+ }
145
+ });
146
+ Object.defineProperty(exports, "useCandidatesGate", {
147
+ enumerable: true,
148
+ get: function() {
149
+ return useCandidatesGate;
150
+ }
151
+ });
152
+
153
+ //# sourceMappingURL=lazy-relation-picker-dialog-Bt8lrEIu.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lazy-relation-picker-dialog-Bt8lrEIu.cjs","names":["useOptionalT","useApp","useTestIds","useI18nCaps","useCandidatesAccess","React","resolveCandidates","declaredText","resolveFieldLabel","lazy","Suspense"],"sources":["../src/fields/candidates-match.ts","../src/fields/candidates-gate.ts","../src/fields/lazy-relation-picker-dialog.tsx"],"sourcesContent":["import type { FixedFilterInput } from '@burojs/core';\n\ntype Entry = { readonly field?: unknown; readonly op?: unknown; readonly value?: unknown };\n\n/**\n * Whether `row` meets every candidate filter (P7 3.4): `true`, `false`, or `undefined` when the\n * row does not carry a field a filter names (a narrower projection), so nothing can be said.\n * Only the flat `{ field, op, value }` entries candidates resolve to are evaluated; this is what\n * \"does not match the current filter\" is decided on, never what is sent.\n */\nexport function rowMatches(\n row: Readonly<Record<string, unknown>>,\n filters: readonly FixedFilterInput[],\n): boolean | undefined {\n let unknown = false;\n for (const filter of filters) {\n const group = filter as { readonly and?: unknown; readonly or?: unknown };\n if (Array.isArray(group.and) || Array.isArray(group.or)) {\n const parts = (\n Array.isArray(group.and) ? group.and : group.or\n ) as readonly FixedFilterInput[];\n const answers = parts.map((part) => rowMatches(row, [part]));\n const all = Array.isArray(group.and);\n const decided = answers.filter((answer) => answer !== undefined);\n if (all ? decided.includes(false) : decided.length > 0 && !decided.includes(true))\n return false;\n if (decided.length < answers.length && !(all ? false : decided.includes(true)))\n unknown = true;\n continue;\n }\n const { field, op, value } = filter as Entry;\n if (typeof field !== 'string' || typeof op !== 'string') continue;\n if (!Object.hasOwn(row, field)) {\n unknown = true;\n continue;\n }\n const held = holds(row[field], op, value);\n if (held === false) return false;\n if (held === undefined) unknown = true;\n }\n return unknown ? undefined : true;\n}\n\nfunction holds(actual: unknown, op: string, expected: unknown): boolean | undefined {\n const list = Array.isArray(expected) ? (expected as readonly unknown[]) : undefined;\n const text = (value: unknown) => String(value ?? '').toLowerCase();\n switch (op) {\n case 'eq':\n return Object.is(actual, expected) || String(actual) === String(expected);\n case 'neq':\n return !(Object.is(actual, expected) || String(actual) === String(expected));\n case 'in':\n return list === undefined\n ? undefined\n : list.some((entry) => String(entry) === String(actual));\n case 'notIn':\n return list === undefined\n ? undefined\n : !list.some((entry) => String(entry) === String(actual));\n case 'gt':\n return compare(actual, expected, (a, b) => a > b);\n case 'gte':\n return compare(actual, expected, (a, b) => a >= b);\n case 'lt':\n return compare(actual, expected, (a, b) => a < b);\n case 'lte':\n return compare(actual, expected, (a, b) => a <= b);\n case 'contains':\n return text(actual).includes(text(expected));\n case 'startsWith':\n return text(actual).startsWith(text(expected));\n case 'endsWith':\n return text(actual).endsWith(text(expected));\n case 'isNull':\n return actual === null || actual === undefined;\n case 'isNotNull':\n return actual !== null && actual !== undefined;\n default:\n return undefined;\n }\n}\n\nfunction compare(\n actual: unknown,\n expected: unknown,\n test: (a: number | string, b: number | string) => boolean,\n): boolean | undefined {\n const both =\n (typeof actual === 'number' && typeof expected === 'number') ||\n (typeof actual === 'string' && typeof expected === 'string');\n return both ? test(actual as number | string, expected as number | string) : undefined;\n}\n","import {\n type FixedFilterInput,\n type RelationCandidate,\n type ScreenSources,\n resolveCandidates,\n resolveFieldLabel,\n declaredText,\n} from '@burojs/core';\nimport { useApp, useCandidatesAccess, useI18nCaps, useOptionalT, useTestIds } from '@burojs/react';\nimport * as React from 'react';\nimport { rowMatches } from './candidates-match.js';\n\n/** A select that must not read its target now (P7 3.4): why, and what it tells the user. */\nexport type CandidatesGate =\n | { readonly kind: 'pending' }\n | { readonly kind: 'empty'; readonly message: string; readonly testId: string }\n | { readonly kind: 'forbidden'; readonly message: string; readonly testId: string };\n\nconst NO_SOURCES: ScreenSources = Object.freeze({});\nconst NO_FILTERS: readonly FixedFilterInput[] = Object.freeze([]);\n\n/**\n * A relation field's `candidates` as the select applies them (P7 3.4): the filters to send and,\n * when they say the target must not be read yet, the gate that tells the user why. The refs are\n * read from the owner's projected sources, so a field P5 hides reads `null` (the select asks for\n * it first, and sends nothing); a candidate on a target field the user may not view forbids the\n * read; an undecided source or permission map keeps the select disabled.\n */\nexport function useCandidatesGate(input: {\n readonly to: string | undefined;\n readonly candidates: readonly RelationCandidate[] | undefined;\n readonly sources: ScreenSources | undefined;\n readonly resource: string;\n readonly fieldName: string;\n}): { readonly filters: readonly FixedFilterInput[]; readonly gate?: CandidatesGate } {\n const { to, candidates, sources, resource, fieldName } = input;\n const t = useOptionalT();\n const app = useApp();\n const tid = useTestIds();\n const ownerCaps = useI18nCaps(resource);\n const targetCaps = useI18nCaps(to ?? resource);\n const access = useCandidatesAccess(to ?? '', candidates);\n const resolution = React.useMemo(\n () => resolveCandidates(candidates, sources ?? NO_SOURCES),\n [candidates, sources],\n );\n if (candidates === undefined || candidates.length === 0) return { filters: NO_FILTERS };\n const testId = tid.relationCandidatesHint(resource, fieldName);\n if (access.status === 'pending') return { filters: NO_FILTERS, gate: { kind: 'pending' } };\n if (access.status === 'forbidden') {\n const declared = declaredText(\n 'field',\n (app.registry.get(to ?? '')?.fields as Record<string, unknown> | undefined)?.[access.field],\n 'label',\n );\n const label = resolveFieldLabel(targetCaps, access.field, declared);\n return {\n filters: NO_FILTERS,\n gate: {\n kind: 'forbidden',\n testId,\n message: t('relationPicker.cannotSearchBy', {\n params: { label },\n defaultValue: `You cannot search by ${label}`,\n }),\n },\n };\n }\n if (resolution.status === 'pending') return { filters: NO_FILTERS, gate: { kind: 'pending' } };\n if (resolution.status === 'empty') {\n const { source, path } = resolution.hint;\n const head = path[0];\n // The field a `values` / `record` ref reads is labelled as the owner labels it; any other\n // source (`scope`, `user`) names the key it reads, humanised.\n const own = source === 'values' || source === 'record';\n const declared =\n own && head !== undefined\n ? declaredText(\n 'field',\n (app.registry.get(resource)?.fields as Record<string, unknown> | undefined)?.[head],\n 'label',\n )\n : undefined;\n const label = resolveFieldLabel(ownerCaps, head ?? source, declared);\n return {\n filters: NO_FILTERS,\n gate: {\n kind: 'empty',\n testId,\n message: t('relationPicker.chooseFirst', {\n params: { label },\n defaultValue: `Choose ${label} first`,\n }),\n },\n };\n }\n return { filters: resolution.filters };\n}\n\n/**\n * A select's declared candidates as the shared select wiring applies them (`CandidatesRelationPicker`\n * and `useRelationPicker`): the gate, the resolved candidate filters prepended to the caller's\n * `fixedFilters`, and whether a loaded row fits them (`undefined` when no candidate filter applies).\n */\nexport function useCandidateSelection(input: {\n readonly to: string | undefined;\n readonly candidates: readonly RelationCandidate[] | undefined;\n readonly sources: ScreenSources | undefined;\n readonly resource: string;\n readonly fieldName: string;\n readonly fixedFilters: readonly FixedFilterInput[] | undefined;\n}): {\n readonly fixedFilters: readonly FixedFilterInput[] | undefined;\n readonly gate?: CandidatesGate;\n readonly rowFits?: (row: Record<string, unknown>) => boolean | undefined;\n} {\n const { fixedFilters } = input;\n const gate = useCandidatesGate(input);\n const filters = gate.filters;\n const combined = React.useMemo(\n () => (filters.length === 0 ? fixedFilters : [...filters, ...(fixedFilters ?? [])]),\n [filters, fixedFilters],\n );\n const rowFits = React.useMemo(\n () =>\n filters.length === 0 ? undefined : (row: Record<string, unknown>) => rowMatches(row, filters),\n [filters],\n );\n return {\n fixedFilters: combined,\n ...(gate.gate === undefined ? {} : { gate: gate.gate }),\n ...(rowFits === undefined ? {} : { rowFits }),\n };\n}\n","import { type ReactElement, Suspense, lazy } from 'react';\nimport type { RelationPickerDialogProps } from './relation-picker-dialog.js';\n\nconst Dialog = lazy(() =>\n import('./relation-picker-dialog.js').then((module) => ({\n default: module.RelationPickerDialog,\n })),\n);\n\n/** The \"Advanced search\" dialog, loaded on the first open: nothing is drawn until it arrives. */\nexport function LazyRelationPickerDialog<const N extends string = string>(\n props: RelationPickerDialogProps<N>,\n): ReactElement {\n return (\n <Suspense fallback={null}>\n <Dialog {...props} />\n </Suspense>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,135 @@
1
+ import { declaredText, resolveCandidates, resolveFieldLabel } from "@burojs/core";
2
+ import { useApp, useCandidatesAccess, useI18nCaps, useOptionalT, useTestIds } from "@burojs/react";
3
+ import * as React from "react";
4
+ import { Suspense, lazy } from "react";
5
+ import { jsx } from "react/jsx-runtime";
6
+ //#region src/fields/candidates-match.ts
7
+ function rowMatches(row, filters) {
8
+ let unknown = false;
9
+ for (const filter of filters) {
10
+ const group = filter;
11
+ if (Array.isArray(group.and) || Array.isArray(group.or)) {
12
+ const answers = (Array.isArray(group.and) ? group.and : group.or).map((part) => rowMatches(row, [part]));
13
+ const all = Array.isArray(group.and);
14
+ const decided = answers.filter((answer) => answer !== void 0);
15
+ if (all ? decided.includes(false) : decided.length > 0 && !decided.includes(true)) return false;
16
+ if (decided.length < answers.length && !(all ? false : decided.includes(true))) unknown = true;
17
+ continue;
18
+ }
19
+ const { field, op, value } = filter;
20
+ if (typeof field !== "string" || typeof op !== "string") continue;
21
+ if (!Object.hasOwn(row, field)) {
22
+ unknown = true;
23
+ continue;
24
+ }
25
+ const held = holds(row[field], op, value);
26
+ if (held === false) return false;
27
+ if (held === void 0) unknown = true;
28
+ }
29
+ return unknown ? void 0 : true;
30
+ }
31
+ function holds(actual, op, expected) {
32
+ const list = Array.isArray(expected) ? expected : void 0;
33
+ const text = (value) => String(value ?? "").toLowerCase();
34
+ switch (op) {
35
+ case "eq": return Object.is(actual, expected) || String(actual) === String(expected);
36
+ case "neq": return !(Object.is(actual, expected) || String(actual) === String(expected));
37
+ case "in": return list === void 0 ? void 0 : list.some((entry) => String(entry) === String(actual));
38
+ case "notIn": return list === void 0 ? void 0 : !list.some((entry) => String(entry) === String(actual));
39
+ case "gt": return compare(actual, expected, (a, b) => a > b);
40
+ case "gte": return compare(actual, expected, (a, b) => a >= b);
41
+ case "lt": return compare(actual, expected, (a, b) => a < b);
42
+ case "lte": return compare(actual, expected, (a, b) => a <= b);
43
+ case "contains": return text(actual).includes(text(expected));
44
+ case "startsWith": return text(actual).startsWith(text(expected));
45
+ case "endsWith": return text(actual).endsWith(text(expected));
46
+ case "isNull": return actual === null || actual === void 0;
47
+ case "isNotNull": return actual !== null && actual !== void 0;
48
+ default: return;
49
+ }
50
+ }
51
+ function compare(actual, expected, test) {
52
+ return typeof actual === "number" && typeof expected === "number" || typeof actual === "string" && typeof expected === "string" ? test(actual, expected) : void 0;
53
+ }
54
+ //#endregion
55
+ //#region src/fields/candidates-gate.ts
56
+ const NO_SOURCES = Object.freeze({});
57
+ const NO_FILTERS = Object.freeze([]);
58
+ function useCandidatesGate(input) {
59
+ const { to, candidates, sources, resource, fieldName } = input;
60
+ const t = useOptionalT();
61
+ const app = useApp();
62
+ const tid = useTestIds();
63
+ const ownerCaps = useI18nCaps(resource);
64
+ const targetCaps = useI18nCaps(to ?? resource);
65
+ const access = useCandidatesAccess(to ?? "", candidates);
66
+ const resolution = React.useMemo(() => resolveCandidates(candidates, sources ?? NO_SOURCES), [candidates, sources]);
67
+ if (candidates === void 0 || candidates.length === 0) return { filters: NO_FILTERS };
68
+ const testId = tid.relationCandidatesHint(resource, fieldName);
69
+ if (access.status === "pending") return {
70
+ filters: NO_FILTERS,
71
+ gate: { kind: "pending" }
72
+ };
73
+ if (access.status === "forbidden") {
74
+ const declared = declaredText("field", (app.registry.get(to ?? "")?.fields)?.[access.field], "label");
75
+ const label = resolveFieldLabel(targetCaps, access.field, declared);
76
+ return {
77
+ filters: NO_FILTERS,
78
+ gate: {
79
+ kind: "forbidden",
80
+ testId,
81
+ message: t("relationPicker.cannotSearchBy", {
82
+ params: { label },
83
+ defaultValue: `You cannot search by ${label}`
84
+ })
85
+ }
86
+ };
87
+ }
88
+ if (resolution.status === "pending") return {
89
+ filters: NO_FILTERS,
90
+ gate: { kind: "pending" }
91
+ };
92
+ if (resolution.status === "empty") {
93
+ const { source, path } = resolution.hint;
94
+ const head = path[0];
95
+ const declared = (source === "values" || source === "record") && head !== void 0 ? declaredText("field", (app.registry.get(resource)?.fields)?.[head], "label") : void 0;
96
+ const label = resolveFieldLabel(ownerCaps, head ?? source, declared);
97
+ return {
98
+ filters: NO_FILTERS,
99
+ gate: {
100
+ kind: "empty",
101
+ testId,
102
+ message: t("relationPicker.chooseFirst", {
103
+ params: { label },
104
+ defaultValue: `Choose ${label} first`
105
+ })
106
+ }
107
+ };
108
+ }
109
+ return { filters: resolution.filters };
110
+ }
111
+ function useCandidateSelection(input) {
112
+ const { fixedFilters } = input;
113
+ const gate = useCandidatesGate(input);
114
+ const filters = gate.filters;
115
+ const combined = React.useMemo(() => filters.length === 0 ? fixedFilters : [...filters, ...fixedFilters ?? []], [filters, fixedFilters]);
116
+ const rowFits = React.useMemo(() => filters.length === 0 ? void 0 : (row) => rowMatches(row, filters), [filters]);
117
+ return {
118
+ fixedFilters: combined,
119
+ ...gate.gate === void 0 ? {} : { gate: gate.gate },
120
+ ...rowFits === void 0 ? {} : { rowFits }
121
+ };
122
+ }
123
+ //#endregion
124
+ //#region src/fields/lazy-relation-picker-dialog.tsx
125
+ const Dialog = lazy(() => import("./relation-picker-dialog-DoEY8EkH.js").then((module) => ({ default: module.RelationPickerDialog })));
126
+ function LazyRelationPickerDialog(props) {
127
+ return jsx(Suspense, {
128
+ fallback: null,
129
+ children: jsx(Dialog, { ...props })
130
+ });
131
+ }
132
+ //#endregion
133
+ export { useCandidateSelection as n, useCandidatesGate as r, LazyRelationPickerDialog as t };
134
+
135
+ //# sourceMappingURL=lazy-relation-picker-dialog-CAScLPb2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lazy-relation-picker-dialog-CAScLPb2.js","names":[],"sources":["../src/fields/candidates-match.ts","../src/fields/candidates-gate.ts","../src/fields/lazy-relation-picker-dialog.tsx"],"sourcesContent":["import type { FixedFilterInput } from '@burojs/core';\n\ntype Entry = { readonly field?: unknown; readonly op?: unknown; readonly value?: unknown };\n\n/**\n * Whether `row` meets every candidate filter (P7 3.4): `true`, `false`, or `undefined` when the\n * row does not carry a field a filter names (a narrower projection), so nothing can be said.\n * Only the flat `{ field, op, value }` entries candidates resolve to are evaluated; this is what\n * \"does not match the current filter\" is decided on, never what is sent.\n */\nexport function rowMatches(\n row: Readonly<Record<string, unknown>>,\n filters: readonly FixedFilterInput[],\n): boolean | undefined {\n let unknown = false;\n for (const filter of filters) {\n const group = filter as { readonly and?: unknown; readonly or?: unknown };\n if (Array.isArray(group.and) || Array.isArray(group.or)) {\n const parts = (\n Array.isArray(group.and) ? group.and : group.or\n ) as readonly FixedFilterInput[];\n const answers = parts.map((part) => rowMatches(row, [part]));\n const all = Array.isArray(group.and);\n const decided = answers.filter((answer) => answer !== undefined);\n if (all ? decided.includes(false) : decided.length > 0 && !decided.includes(true))\n return false;\n if (decided.length < answers.length && !(all ? false : decided.includes(true)))\n unknown = true;\n continue;\n }\n const { field, op, value } = filter as Entry;\n if (typeof field !== 'string' || typeof op !== 'string') continue;\n if (!Object.hasOwn(row, field)) {\n unknown = true;\n continue;\n }\n const held = holds(row[field], op, value);\n if (held === false) return false;\n if (held === undefined) unknown = true;\n }\n return unknown ? undefined : true;\n}\n\nfunction holds(actual: unknown, op: string, expected: unknown): boolean | undefined {\n const list = Array.isArray(expected) ? (expected as readonly unknown[]) : undefined;\n const text = (value: unknown) => String(value ?? '').toLowerCase();\n switch (op) {\n case 'eq':\n return Object.is(actual, expected) || String(actual) === String(expected);\n case 'neq':\n return !(Object.is(actual, expected) || String(actual) === String(expected));\n case 'in':\n return list === undefined\n ? undefined\n : list.some((entry) => String(entry) === String(actual));\n case 'notIn':\n return list === undefined\n ? undefined\n : !list.some((entry) => String(entry) === String(actual));\n case 'gt':\n return compare(actual, expected, (a, b) => a > b);\n case 'gte':\n return compare(actual, expected, (a, b) => a >= b);\n case 'lt':\n return compare(actual, expected, (a, b) => a < b);\n case 'lte':\n return compare(actual, expected, (a, b) => a <= b);\n case 'contains':\n return text(actual).includes(text(expected));\n case 'startsWith':\n return text(actual).startsWith(text(expected));\n case 'endsWith':\n return text(actual).endsWith(text(expected));\n case 'isNull':\n return actual === null || actual === undefined;\n case 'isNotNull':\n return actual !== null && actual !== undefined;\n default:\n return undefined;\n }\n}\n\nfunction compare(\n actual: unknown,\n expected: unknown,\n test: (a: number | string, b: number | string) => boolean,\n): boolean | undefined {\n const both =\n (typeof actual === 'number' && typeof expected === 'number') ||\n (typeof actual === 'string' && typeof expected === 'string');\n return both ? test(actual as number | string, expected as number | string) : undefined;\n}\n","import {\n type FixedFilterInput,\n type RelationCandidate,\n type ScreenSources,\n resolveCandidates,\n resolveFieldLabel,\n declaredText,\n} from '@burojs/core';\nimport { useApp, useCandidatesAccess, useI18nCaps, useOptionalT, useTestIds } from '@burojs/react';\nimport * as React from 'react';\nimport { rowMatches } from './candidates-match.js';\n\n/** A select that must not read its target now (P7 3.4): why, and what it tells the user. */\nexport type CandidatesGate =\n | { readonly kind: 'pending' }\n | { readonly kind: 'empty'; readonly message: string; readonly testId: string }\n | { readonly kind: 'forbidden'; readonly message: string; readonly testId: string };\n\nconst NO_SOURCES: ScreenSources = Object.freeze({});\nconst NO_FILTERS: readonly FixedFilterInput[] = Object.freeze([]);\n\n/**\n * A relation field's `candidates` as the select applies them (P7 3.4): the filters to send and,\n * when they say the target must not be read yet, the gate that tells the user why. The refs are\n * read from the owner's projected sources, so a field P5 hides reads `null` (the select asks for\n * it first, and sends nothing); a candidate on a target field the user may not view forbids the\n * read; an undecided source or permission map keeps the select disabled.\n */\nexport function useCandidatesGate(input: {\n readonly to: string | undefined;\n readonly candidates: readonly RelationCandidate[] | undefined;\n readonly sources: ScreenSources | undefined;\n readonly resource: string;\n readonly fieldName: string;\n}): { readonly filters: readonly FixedFilterInput[]; readonly gate?: CandidatesGate } {\n const { to, candidates, sources, resource, fieldName } = input;\n const t = useOptionalT();\n const app = useApp();\n const tid = useTestIds();\n const ownerCaps = useI18nCaps(resource);\n const targetCaps = useI18nCaps(to ?? resource);\n const access = useCandidatesAccess(to ?? '', candidates);\n const resolution = React.useMemo(\n () => resolveCandidates(candidates, sources ?? NO_SOURCES),\n [candidates, sources],\n );\n if (candidates === undefined || candidates.length === 0) return { filters: NO_FILTERS };\n const testId = tid.relationCandidatesHint(resource, fieldName);\n if (access.status === 'pending') return { filters: NO_FILTERS, gate: { kind: 'pending' } };\n if (access.status === 'forbidden') {\n const declared = declaredText(\n 'field',\n (app.registry.get(to ?? '')?.fields as Record<string, unknown> | undefined)?.[access.field],\n 'label',\n );\n const label = resolveFieldLabel(targetCaps, access.field, declared);\n return {\n filters: NO_FILTERS,\n gate: {\n kind: 'forbidden',\n testId,\n message: t('relationPicker.cannotSearchBy', {\n params: { label },\n defaultValue: `You cannot search by ${label}`,\n }),\n },\n };\n }\n if (resolution.status === 'pending') return { filters: NO_FILTERS, gate: { kind: 'pending' } };\n if (resolution.status === 'empty') {\n const { source, path } = resolution.hint;\n const head = path[0];\n // The field a `values` / `record` ref reads is labelled as the owner labels it; any other\n // source (`scope`, `user`) names the key it reads, humanised.\n const own = source === 'values' || source === 'record';\n const declared =\n own && head !== undefined\n ? declaredText(\n 'field',\n (app.registry.get(resource)?.fields as Record<string, unknown> | undefined)?.[head],\n 'label',\n )\n : undefined;\n const label = resolveFieldLabel(ownerCaps, head ?? source, declared);\n return {\n filters: NO_FILTERS,\n gate: {\n kind: 'empty',\n testId,\n message: t('relationPicker.chooseFirst', {\n params: { label },\n defaultValue: `Choose ${label} first`,\n }),\n },\n };\n }\n return { filters: resolution.filters };\n}\n\n/**\n * A select's declared candidates as the shared select wiring applies them (`CandidatesRelationPicker`\n * and `useRelationPicker`): the gate, the resolved candidate filters prepended to the caller's\n * `fixedFilters`, and whether a loaded row fits them (`undefined` when no candidate filter applies).\n */\nexport function useCandidateSelection(input: {\n readonly to: string | undefined;\n readonly candidates: readonly RelationCandidate[] | undefined;\n readonly sources: ScreenSources | undefined;\n readonly resource: string;\n readonly fieldName: string;\n readonly fixedFilters: readonly FixedFilterInput[] | undefined;\n}): {\n readonly fixedFilters: readonly FixedFilterInput[] | undefined;\n readonly gate?: CandidatesGate;\n readonly rowFits?: (row: Record<string, unknown>) => boolean | undefined;\n} {\n const { fixedFilters } = input;\n const gate = useCandidatesGate(input);\n const filters = gate.filters;\n const combined = React.useMemo(\n () => (filters.length === 0 ? fixedFilters : [...filters, ...(fixedFilters ?? [])]),\n [filters, fixedFilters],\n );\n const rowFits = React.useMemo(\n () =>\n filters.length === 0 ? undefined : (row: Record<string, unknown>) => rowMatches(row, filters),\n [filters],\n );\n return {\n fixedFilters: combined,\n ...(gate.gate === undefined ? {} : { gate: gate.gate }),\n ...(rowFits === undefined ? {} : { rowFits }),\n };\n}\n","import { type ReactElement, Suspense, lazy } from 'react';\nimport type { RelationPickerDialogProps } from './relation-picker-dialog.js';\n\nconst Dialog = lazy(() =>\n import('./relation-picker-dialog.js').then((module) => ({\n default: module.RelationPickerDialog,\n })),\n);\n\n/** The \"Advanced search\" dialog, loaded on the first open: nothing is drawn until it arrives. */\nexport function LazyRelationPickerDialog<const N extends string = string>(\n props: RelationPickerDialogProps<N>,\n): ReactElement {\n return (\n <Suspense fallback={null}>\n <Dialog {...props} />\n </Suspense>\n );\n}\n"],"mappings":"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"}
@@ -1182,9 +1182,8 @@ declare function docSlug(text: string): string;
1182
1182
  * The current fragment, DECODED, without its `#`.
1183
1183
  *
1184
1184
  * `window.location.hash` hands back a percent-encoded string —
1185
- * `#%D0%BF%D0%BE%D1%87%D0%B5%D0%BC%D1%83…` for `#почему…` — so every
1186
- * comparison against a slug fails, silently, for exactly the alphabet this
1187
- * project writes its documentation in. It works perfectly in English, which is
1185
+ * `#%D0%BF%D0%BE%D1%87%D0%B5%D0%BC%D1%83…` for a non-ASCII slug — so every
1186
+ * comparison against a slug fails, silently, for every non-ASCII alphabet. It works perfectly in ASCII-only slugs, which is
1188
1187
  * the worst possible way for it to be wrong.
1189
1188
  */
1190
1189
  declare function readDocHash(): string;
@@ -1182,9 +1182,8 @@ declare function docSlug(text: string): string;
1182
1182
  * The current fragment, DECODED, without its `#`.
1183
1183
  *
1184
1184
  * `window.location.hash` hands back a percent-encoded string —
1185
- * `#%D0%BF%D0%BE%D1%87%D0%B5%D0%BC%D1%83…` for `#почему…` — so every
1186
- * comparison against a slug fails, silently, for exactly the alphabet this
1187
- * project writes its documentation in. It works perfectly in English, which is
1185
+ * `#%D0%BF%D0%BE%D1%87%D0%B5%D0%BC%D1%83…` for a non-ASCII slug — so every
1186
+ * comparison against a slug fails, silently, for every non-ASCII alphabet. It works perfectly in ASCII-only slugs, which is
1188
1187
  * the worst possible way for it to be wrong.
1189
1188
  */
1190
1189
  declare function readDocHash(): string;