@burojs/ui-shadcn 0.9.0 → 0.10.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 (108) hide show
  1. package/dist/{bulk-summary-2HLgz7Il.cjs → bulk-summary-Chc61Pyw.cjs} +9 -7
  2. package/dist/bulk-summary-Chc61Pyw.cjs.map +1 -0
  3. package/dist/{bulk-summary-D6A0ua21.js → bulk-summary-DpSQD2Fq.js} +9 -7
  4. package/dist/bulk-summary-DpSQD2Fq.js.map +1 -0
  5. package/dist/{candidates-relation-picker-QvoY2bOQ.js → candidates-relation-picker-DRsHKe6N.js} +3 -3
  6. package/dist/{candidates-relation-picker-QvoY2bOQ.js.map → candidates-relation-picker-DRsHKe6N.js.map} +1 -1
  7. package/dist/{candidates-relation-picker-pEAWKQEY.cjs → candidates-relation-picker-GIxsp7D_.cjs} +3 -3
  8. package/dist/{candidates-relation-picker-pEAWKQEY.cjs.map → candidates-relation-picker-GIxsp7D_.cjs.map} +1 -1
  9. package/dist/{check-confirm-dialog-W-8WOmGh.cjs → check-confirm-dialog-BMSb7wFv.cjs} +17 -9
  10. package/dist/check-confirm-dialog-BMSb7wFv.cjs.map +1 -0
  11. package/dist/{check-confirm-dialog-B-CbJTln.js → check-confirm-dialog-B_u3YVHS.js} +18 -10
  12. package/dist/{check-confirm-dialog-B-CbJTln.js.map → check-confirm-dialog-B_u3YVHS.js.map} +1 -1
  13. package/dist/{filter-builder-04nas3eq.js → filter-builder-DX-xC3Yd.js} +2 -2
  14. package/dist/{filter-builder-04nas3eq.js.map → filter-builder-DX-xC3Yd.js.map} +1 -1
  15. package/dist/{filter-builder-DQX-TMFh.cjs → filter-builder-Dt5E8PSX.cjs} +2 -2
  16. package/dist/{filter-builder-DQX-TMFh.cjs.map → filter-builder-Dt5E8PSX.cjs.map} +1 -1
  17. package/dist/{flow-runtime-DyNIYfUP.cjs → flow-runtime-CQ4wf8co.cjs} +2 -2
  18. package/dist/{flow-runtime-DyNIYfUP.cjs.map → flow-runtime-CQ4wf8co.cjs.map} +1 -1
  19. package/dist/{flow-runtime-BEIyym7d.js → flow-runtime-Q2vD7R3c.js} +2 -2
  20. package/dist/{flow-runtime-BEIyym7d.js.map → flow-runtime-Q2vD7R3c.js.map} +1 -1
  21. package/dist/{flow-screen-DY1Z9PbG.js → flow-screen-B1y2yizP.js} +18 -18
  22. package/dist/flow-screen-B1y2yizP.js.map +1 -0
  23. package/dist/{flow-screen-FE5Xhb3t.cjs → flow-screen-sw2cP70t.cjs} +18 -18
  24. package/dist/flow-screen-sw2cP70t.cjs.map +1 -0
  25. package/dist/index.cjs +2183 -109
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.cts +76 -8
  28. package/dist/index.d.ts +76 -8
  29. package/dist/index.js +2095 -24
  30. package/dist/index.js.map +1 -1
  31. package/dist/{inline-flow-host-yVLo6-sM.cjs → inline-flow-host-CkhoA69R.cjs} +3 -3
  32. package/dist/{inline-flow-host-yVLo6-sM.cjs.map → inline-flow-host-CkhoA69R.cjs.map} +1 -1
  33. package/dist/{inline-flow-host-D6u-RlsV.js → inline-flow-host-DqbXqcPS.js} +3 -3
  34. package/dist/{inline-flow-host-D6u-RlsV.js.map → inline-flow-host-DqbXqcPS.js.map} +1 -1
  35. package/dist/{lazy-relation-picker-dialog-BaORufxQ.js → lazy-relation-picker-dialog-BaIEWLbF.js} +3 -52
  36. package/dist/lazy-relation-picker-dialog-BaIEWLbF.js.map +1 -0
  37. package/dist/{lazy-relation-picker-dialog-C_VlGlDz.cjs → lazy-relation-picker-dialog-CeRzOAi0.cjs} +3 -52
  38. package/dist/lazy-relation-picker-dialog-CeRzOAi0.cjs.map +1 -0
  39. package/dist/{page-flow-route-CyMzUidK.js → page-flow-route-CP7cS7FY.js} +5 -5
  40. package/dist/page-flow-route-CP7cS7FY.js.map +1 -0
  41. package/dist/{page-flow-route-OFx7h7Ja.cjs → page-flow-route-UDx8qvdM.cjs} +9 -9
  42. package/dist/page-flow-route-UDx8qvdM.cjs.map +1 -0
  43. package/dist/{place-node-BZF5Af6x.cjs → place-node-C5ZmuHaN.cjs} +149 -40
  44. package/dist/place-node-C5ZmuHaN.cjs.map +1 -0
  45. package/dist/{place-node-DRjmJGQ_.js → place-node-DwWAigv0.js} +146 -43
  46. package/dist/place-node-DwWAigv0.js.map +1 -0
  47. package/dist/record-trail-store-Cjo9vtod.cjs +126 -0
  48. package/dist/record-trail-store-Cjo9vtod.cjs.map +1 -0
  49. package/dist/record-trail-store-Dn6bVry4.js +91 -0
  50. package/dist/record-trail-store-Dn6bVry4.js.map +1 -0
  51. package/dist/{related-list-cards-xVvgSlu-.cjs → related-list-cards-BypKfm9t.cjs} +3 -3
  52. package/dist/{related-list-cards-xVvgSlu-.cjs.map → related-list-cards-BypKfm9t.cjs.map} +1 -1
  53. package/dist/{related-list-cards-2hLitVkg.js → related-list-cards-Dcmruy09.js} +3 -3
  54. package/dist/{related-list-cards-2hLitVkg.js.map → related-list-cards-Dcmruy09.js.map} +1 -1
  55. package/dist/{related-list-timeline-Dsf5WewG.cjs → related-list-timeline-D-KClgKb.cjs} +4 -4
  56. package/dist/{related-list-timeline-Dsf5WewG.cjs.map → related-list-timeline-D-KClgKb.cjs.map} +1 -1
  57. package/dist/{related-list-timeline-CxJqe6eK.js → related-list-timeline-DZON_qSc.js} +4 -4
  58. package/dist/{related-list-timeline-CxJqe6eK.js.map → related-list-timeline-DZON_qSc.js.map} +1 -1
  59. package/dist/{related-rows-DDhp9axl.cjs → related-rows-DgF05ssi.cjs} +4 -4
  60. package/dist/{related-rows-DDhp9axl.cjs.map → related-rows-DgF05ssi.cjs.map} +1 -1
  61. package/dist/{related-rows-DL6CWsrj.js → related-rows-ETZl5CB9.js} +4 -4
  62. package/dist/{related-rows-DL6CWsrj.js.map → related-rows-ETZl5CB9.js.map} +1 -1
  63. package/dist/{relation-create-_SFuPQGM.cjs → relation-create-B8zngAcA.cjs} +46 -11
  64. package/dist/relation-create-B8zngAcA.cjs.map +1 -0
  65. package/dist/{relation-create-6WicROWA.js → relation-create-CeCWyxIb.js} +47 -12
  66. package/dist/relation-create-CeCWyxIb.js.map +1 -0
  67. package/dist/{relation-many-picker-mGEQDWo2.js → relation-many-picker-CT7nKfE2.js} +4 -4
  68. package/dist/{relation-many-picker-mGEQDWo2.js.map → relation-many-picker-CT7nKfE2.js.map} +1 -1
  69. package/dist/{relation-many-picker-BBNsmkaX.cjs → relation-many-picker-Cq0EHY5I.cjs} +4 -4
  70. package/dist/{relation-many-picker-BBNsmkaX.cjs.map → relation-many-picker-Cq0EHY5I.cjs.map} +1 -1
  71. package/dist/{relation-picker-BbO41cFV.js → relation-picker-CCyuMeGq.js} +6 -6
  72. package/dist/{relation-picker-BbO41cFV.js.map → relation-picker-CCyuMeGq.js.map} +1 -1
  73. package/dist/{relation-picker-jk9D_uwn.cjs → relation-picker-DmwTzgsd.cjs} +6 -6
  74. package/dist/{relation-picker-jk9D_uwn.cjs.map → relation-picker-DmwTzgsd.cjs.map} +1 -1
  75. package/dist/{relation-picker-dialog-BgSG_8bU.js → relation-picker-dialog-CoWKjNv8.js} +4 -4
  76. package/dist/{relation-picker-dialog-BgSG_8bU.js.map → relation-picker-dialog-CoWKjNv8.js.map} +1 -1
  77. package/dist/{relation-picker-dialog-Duqy2r0n.cjs → relation-picker-dialog-mbwyNK43.cjs} +4 -4
  78. package/dist/{relation-picker-dialog-Duqy2r0n.cjs.map → relation-picker-dialog-mbwyNK43.cjs.map} +1 -1
  79. package/dist/{relation-select-C3aV18kT.cjs → relation-select-CguIo2M5.cjs} +2 -2
  80. package/dist/{relation-select-C3aV18kT.cjs.map → relation-select-CguIo2M5.cjs.map} +1 -1
  81. package/dist/{relation-select-CjQT9LpS.js → relation-select-nAYxhopN.js} +2 -2
  82. package/dist/{relation-select-CjQT9LpS.js.map → relation-select-nAYxhopN.js.map} +1 -1
  83. package/dist/{use-dialog-filter-state-lsTJxrB4.cjs → use-dialog-filter-state-CpWblz3C.cjs} +2 -2
  84. package/dist/{use-dialog-filter-state-lsTJxrB4.cjs.map → use-dialog-filter-state-CpWblz3C.cjs.map} +1 -1
  85. package/dist/{use-dialog-filter-state-CJoeY-1j.js → use-dialog-filter-state-ZYxOp5WO.js} +2 -2
  86. package/dist/{use-dialog-filter-state-CJoeY-1j.js.map → use-dialog-filter-state-ZYxOp5WO.js.map} +1 -1
  87. package/dist/{use-record-subtitle-BJ9rnj6F.cjs → use-record-subtitle-B4lTR7pf.cjs} +2 -2
  88. package/dist/{use-record-subtitle-BJ9rnj6F.cjs.map → use-record-subtitle-B4lTR7pf.cjs.map} +1 -1
  89. package/dist/{use-record-subtitle-w3ZhXNlf.js → use-record-subtitle-pWMBqQx9.js} +2 -2
  90. package/dist/{use-record-subtitle-w3ZhXNlf.js.map → use-record-subtitle-pWMBqQx9.js.map} +1 -1
  91. package/package.json +9 -9
  92. package/dist/bulk-summary-2HLgz7Il.cjs.map +0 -1
  93. package/dist/bulk-summary-D6A0ua21.js.map +0 -1
  94. package/dist/check-confirm-dialog-W-8WOmGh.cjs.map +0 -1
  95. package/dist/flow-screen-DY1Z9PbG.js.map +0 -1
  96. package/dist/flow-screen-FE5Xhb3t.cjs.map +0 -1
  97. package/dist/lazy-relation-picker-dialog-BaORufxQ.js.map +0 -1
  98. package/dist/lazy-relation-picker-dialog-C_VlGlDz.cjs.map +0 -1
  99. package/dist/page-flow-route-CyMzUidK.js.map +0 -1
  100. package/dist/page-flow-route-OFx7h7Ja.cjs.map +0 -1
  101. package/dist/place-node-BZF5Af6x.cjs.map +0 -1
  102. package/dist/place-node-DRjmJGQ_.js.map +0 -1
  103. package/dist/relation-create-6WicROWA.js.map +0 -1
  104. package/dist/relation-create-_SFuPQGM.cjs.map +0 -1
  105. package/dist/resource-page-router-CzaNATSp.js +0 -2010
  106. package/dist/resource-page-router-CzaNATSp.js.map +0 -1
  107. package/dist/resource-page-router-dmVIeu5s.cjs +0 -2231
  108. package/dist/resource-page-router-dmVIeu5s.cjs.map +0 -1
@@ -1,6 +1,6 @@
1
- const require_check_confirm_dialog = require("./check-confirm-dialog-W-8WOmGh.cjs");
1
+ const require_check_confirm_dialog = require("./check-confirm-dialog-BMSb7wFv.cjs");
2
2
  const require_button = require("./button-BxnnE28H.cjs");
3
- const require_flow_screen = require("./flow-screen-FE5Xhb3t.cjs");
3
+ const require_flow_screen = require("./flow-screen-sw2cP70t.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");
@@ -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-yVLo6-sM.cjs.map
112
+ //# sourceMappingURL=inline-flow-host-CkhoA69R.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"inline-flow-host-yVLo6-sM.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
+ {"version":3,"file":"inline-flow-host-CkhoA69R.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 } from "./check-confirm-dialog-B-CbJTln.js";
1
+ import { h as useFlowChrome } from "./check-confirm-dialog-B_u3YVHS.js";
2
2
  import { t as Button } from "./button-MWVeZaqj.js";
3
- import { HostedFlowScreen } from "./flow-screen-DY1Z9PbG.js";
3
+ import { HostedFlowScreen } from "./flow-screen-B1y2yizP.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";
@@ -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-D6u-RlsV.js.map
112
+ //# sourceMappingURL=inline-flow-host-DqbXqcPS.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"inline-flow-host-D6u-RlsV.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
+ {"version":3,"file":"inline-flow-host-DqbXqcPS.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,57 +1,8 @@
1
- import { declaredText, resolveCandidates, resolveFieldLabel } from "@burojs/core";
1
+ import { declaredText, resolveCandidates, resolveFieldLabel, rowMatches } from "@burojs/core";
2
2
  import { useApp, useCandidatesAccess, useI18nCaps, useOptionalT, useTestIds } from "@burojs/react";
3
3
  import * as React from "react";
4
4
  import { Suspense, lazy } from "react";
5
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
6
  //#region src/fields/candidates-gate.ts
56
7
  const NO_SOURCES = Object.freeze({});
57
8
  const NO_FILTERS = Object.freeze([]);
@@ -122,7 +73,7 @@ function useCandidateSelection(input) {
122
73
  }
123
74
  //#endregion
124
75
  //#region src/fields/lazy-relation-picker-dialog.tsx
125
- const Dialog = lazy(() => import("./relation-picker-dialog-BgSG_8bU.js").then((module) => ({ default: module.RelationPickerDialog })));
76
+ const Dialog = lazy(() => import("./relation-picker-dialog-CoWKjNv8.js").then((module) => ({ default: module.RelationPickerDialog })));
126
77
  function LazyRelationPickerDialog(props) {
127
78
  return jsx(Suspense, {
128
79
  fallback: null,
@@ -132,4 +83,4 @@ function LazyRelationPickerDialog(props) {
132
83
  //#endregion
133
84
  export { useCandidateSelection as n, useCandidatesGate as r, LazyRelationPickerDialog as t };
134
85
 
135
- //# sourceMappingURL=lazy-relation-picker-dialog-BaORufxQ.js.map
86
+ //# sourceMappingURL=lazy-relation-picker-dialog-BaIEWLbF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lazy-relation-picker-dialog-BaIEWLbF.js","names":[],"sources":["../src/fields/candidates-gate.ts","../src/fields/lazy-relation-picker-dialog.tsx"],"sourcesContent":["import {\n type FixedFilterInput,\n type RelationCandidate,\n type ScreenSources,\n resolveCandidates,\n resolveFieldLabel,\n declaredText,\n rowMatches,\n} from '@burojs/core';\nimport { useApp, useCandidatesAccess, useI18nCaps, useOptionalT, useTestIds } from '@burojs/react';\nimport * as React from 'react';\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":";;;;;;AAkBA,MAAM,aAA4B,OAAO,OAAO,CAAC,CAAC;AAClD,MAAM,aAA0C,OAAO,OAAO,CAAC,CAAC;AAShE,SAAgB,kBAAkB,OAMoD;CACpF,MAAM,EAAE,IAAI,YAAY,SAAS,UAAU,cAAc;CACzD,MAAM,IAAI,aAAa;CACvB,MAAM,MAAM,OAAO;CACnB,MAAM,MAAM,WAAW;CACvB,MAAM,YAAY,YAAY,QAAQ;CACtC,MAAM,aAAa,YAAY,MAAM,QAAQ;CAC7C,MAAM,SAAS,oBAAoB,MAAM,IAAI,UAAU;CACvD,MAAM,aAAa,MAAM,cACjB,kBAAkB,YAAY,WAAW,UAAU,GACzD,CAAC,YAAY,OAAO,CACtB;CACA,IAAI,eAAe,KAAA,KAAa,WAAW,WAAW,GAAG,OAAO,EAAE,SAAS,WAAW;CACtF,MAAM,SAAS,IAAI,uBAAuB,UAAU,SAAS;CAC7D,IAAI,OAAO,WAAW,WAAW,OAAO;EAAE,SAAS;EAAY,MAAM,EAAE,MAAM,UAAU;CAAE;CACzF,IAAI,OAAO,WAAW,aAAa;EACjC,MAAM,WAAW,aACf,UACC,IAAI,SAAS,IAAI,MAAM,EAAE,CAAC,EAAE,OAAA,GAAiD,OAAO,QACrF,OACF;EACA,MAAM,QAAQ,kBAAkB,YAAY,OAAO,OAAO,QAAQ;EAClE,OAAO;GACL,SAAS;GACT,MAAM;IACJ,MAAM;IACN;IACA,SAAS,EAAE,iCAAiC;KAC1C,QAAQ,EAAE,MAAM;KAChB,cAAc,wBAAwB;IACxC,CAAC;GACH;EACF;CACF;CACA,IAAI,WAAW,WAAW,WAAW,OAAO;EAAE,SAAS;EAAY,MAAM,EAAE,MAAM,UAAU;CAAE;CAC7F,IAAI,WAAW,WAAW,SAAS;EACjC,MAAM,EAAE,QAAQ,SAAS,WAAW;EACpC,MAAM,OAAO,KAAK;EAIlB,MAAM,YADM,WAAW,YAAY,WAAW,aAErC,SAAS,KAAA,IACZ,aACE,UACC,IAAI,SAAS,IAAI,QAAQ,CAAC,EAAE,OAAA,GAAiD,OAC9E,OACF,IACA,KAAA;EACN,MAAM,QAAQ,kBAAkB,WAAW,QAAQ,QAAQ,QAAQ;EACnE,OAAO;GACL,SAAS;GACT,MAAM;IACJ,MAAM;IACN;IACA,SAAS,EAAE,8BAA8B;KACvC,QAAQ,EAAE,MAAM;KAChB,cAAc,UAAU,MAAM;IAChC,CAAC;GACH;EACF;CACF;CACA,OAAO,EAAE,SAAS,WAAW,QAAQ;AACvC;AAOA,SAAgB,sBAAsB,OAWpC;CACA,MAAM,EAAE,iBAAiB;CACzB,MAAM,OAAO,kBAAkB,KAAK;CACpC,MAAM,UAAU,KAAK;CACrB,MAAM,WAAW,MAAM,cACd,QAAQ,WAAW,IAAI,eAAe,CAAC,GAAG,SAAS,GAAI,gBAAgB,CAAC,CAAE,GACjF,CAAC,SAAS,YAAY,CACxB;CACA,MAAM,UAAU,MAAM,cAElB,QAAQ,WAAW,IAAI,KAAA,KAAa,QAAiC,WAAW,KAAK,OAAO,GAC9F,CAAC,OAAO,CACV;CACA,OAAO;EACL,cAAc;EACd,GAAI,KAAK,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM,KAAK,KAAK;EACrD,GAAI,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ;CAC7C;AACF;;;AClIA,MAAM,SAAS,WACb,OAAO,uCAA8B,CAAC,MAAM,YAAY,EACtD,SAAS,OAAO,qBAClB,EAAE,CACJ;AAGA,SAAgB,yBACd,OACc;CACd,OACE,IAAC,UAAD;EAAU,UAAU;EAClB,UAAA,IAAC,QAAD,EAAQ,GAAI,MAAQ,CAAA;CACZ,CAAA;AAEd"}
@@ -4,55 +4,6 @@ let _burojs_react = require("@burojs/react");
4
4
  let react = require("react");
5
5
  react = require_use_theme.__toESM(react, 1);
6
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
7
  //#region src/fields/candidates-gate.ts
57
8
  const NO_SOURCES = Object.freeze({});
58
9
  const NO_FILTERS = Object.freeze([]);
@@ -114,7 +65,7 @@ function useCandidateSelection(input) {
114
65
  const gate = useCandidatesGate(input);
115
66
  const filters = gate.filters;
116
67
  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]);
68
+ const rowFits = react.useMemo(() => filters.length === 0 ? void 0 : (row) => (0, _burojs_core.rowMatches)(row, filters), [filters]);
118
69
  return {
119
70
  fixedFilters: combined,
120
71
  ...gate.gate === void 0 ? {} : { gate: gate.gate },
@@ -123,7 +74,7 @@ function useCandidateSelection(input) {
123
74
  }
124
75
  //#endregion
125
76
  //#region src/fields/lazy-relation-picker-dialog.tsx
126
- const Dialog = (0, react.lazy)(() => Promise.resolve().then(() => require("./relation-picker-dialog-Duqy2r0n.cjs")).then((module) => ({ default: module.RelationPickerDialog })));
77
+ const Dialog = (0, react.lazy)(() => Promise.resolve().then(() => require("./relation-picker-dialog-mbwyNK43.cjs")).then((module) => ({ default: module.RelationPickerDialog })));
127
78
  function LazyRelationPickerDialog(props) {
128
79
  return (0, react_jsx_runtime.jsx)(react.Suspense, {
129
80
  fallback: null,
@@ -150,4 +101,4 @@ Object.defineProperty(exports, "useCandidatesGate", {
150
101
  }
151
102
  });
152
103
 
153
- //# sourceMappingURL=lazy-relation-picker-dialog-C_VlGlDz.cjs.map
104
+ //# sourceMappingURL=lazy-relation-picker-dialog-CeRzOAi0.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lazy-relation-picker-dialog-CeRzOAi0.cjs","names":["useOptionalT","useApp","useTestIds","useI18nCaps","useCandidatesAccess","React","resolveCandidates","declaredText","resolveFieldLabel","rowMatches","lazy","Suspense"],"sources":["../src/fields/candidates-gate.ts","../src/fields/lazy-relation-picker-dialog.tsx"],"sourcesContent":["import {\n type FixedFilterInput,\n type RelationCandidate,\n type ScreenSources,\n resolveCandidates,\n resolveFieldLabel,\n declaredText,\n rowMatches,\n} from '@burojs/core';\nimport { useApp, useCandidatesAccess, useI18nCaps, useOptionalT, useTestIds } from '@burojs/react';\nimport * as React from 'react';\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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"}
@@ -1,9 +1,9 @@
1
1
  import { l as useLinkComponent } from "./toaster-Ct_YHGs6.js";
2
- import { h as useFlowChrome, v as reasonText } from "./check-confirm-dialog-B-CbJTln.js";
2
+ import { h as useFlowChrome, v as reasonText } from "./check-confirm-dialog-B_u3YVHS.js";
3
3
  import { t as Button } from "./button-MWVeZaqj.js";
4
- import { b as LoadError, x as RecordState, y as InvalidRouteId } from "./relation-create-6WicROWA.js";
5
- import { I as canonicalNavKey, h as usePublishRecordTrail, m as recordTrailKey, t as NavAreaNotFound } from "./resource-page-router-CzaNATSp.js";
6
- import { FlowHostBindingContext, FlowScreen } from "./flow-screen-DY1Z9PbG.js";
4
+ import { b as LoadError, x as RecordState, y as InvalidRouteId } from "./relation-create-CeCWyxIb.js";
5
+ import { a as canonicalNavKey, i as NavAreaNotFound, n as usePublishRecordTrail, t as recordTrailKey } from "./record-trail-store-Dn6bVry4.js";
6
+ import { FlowHostBindingContext, FlowScreen } from "./flow-screen-B1y2yizP.js";
7
7
  import { compileFlow, dtoFields, effectiveFlow, hrefFor, permissionsUndecided } from "@burojs/core";
8
8
  import { recordRouteAvailable, retryRecordRead, useApp, useApplicationSnapshot, useDispatcherEffects, useFlowRowResolver, useI18nCaps, useOne, useOptionalT, usePermissions, useProjectedTitle, useRouteNavigate, useRouteRecordId, useTestIds } from "@burojs/react";
9
9
  import { IconLoader2 } from "@tabler/icons-react";
@@ -286,4 +286,4 @@ function PageFlowRun(props) {
286
286
  //#endregion
287
287
  export { PageFlowRoute };
288
288
 
289
- //# sourceMappingURL=page-flow-route-CyMzUidK.js.map
289
+ //# sourceMappingURL=page-flow-route-CP7cS7FY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-flow-route-CP7cS7FY.js","names":[],"sources":["../src/flows/page-flow-route.tsx"],"sourcesContent":["'use client';\n/**\n * A page-hosted flow's route (P6 3.11): `<record route>/<flow name>`. It owns the whole gate in\n * order, so a user who may not run the flow never sees a trace of it:\n *\n * 1. the permission map is decided, else the record route's loading state and nothing is read;\n * 2. static: the resource has a record page, the flow is an item flow and, in the published\n * snapshot, its `host` is `page`; else the record route's not-found;\n * 3. the record is read by id with the record DTO;\n * 4. the flow's gate over that row (`requires`, the mutation's `requires`, `action/run` rules):\n * hidden, absent, or a missing or forbidden row is the same not-found as `/articles/missing`;\n * a false `when` or a blocking pre-click check is \"not available\" and the way back;\n * 5. only then the run (`useFlowRun`) and its sources.\n */\nimport {\n type RecordId,\n type RouteMatch,\n compileFlow,\n dtoFields,\n effectiveFlow,\n hrefFor,\n permissionsUndecided,\n} from '@burojs/core';\nimport {\n recordRouteAvailable,\n retryRecordRead,\n useApp,\n useApplicationSnapshot,\n useDispatcherEffects,\n useFlowRowResolver,\n useI18nCaps,\n useOne,\n useOptionalT,\n usePermissions,\n useProjectedTitle,\n useRouteNavigate,\n useRouteRecordId,\n useTestIds,\n} from '@burojs/react';\nimport { useFlowRun } from '@burojs/react/flows';\nimport { IconLoader2 } from '@tabler/icons-react';\nimport { type ReactElement, useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useLinkComponent } from '../layout/link-component.js';\nimport { reasonText } from '../lib/reason-text.js';\nimport { InvalidRouteId, LoadError } from '../load-error/load-error-view.js';\nimport { recordTrailKey, usePublishRecordTrail } from '../layout/record-trail-store.js';\nimport { RecordState } from '../record/record-state.js';\nimport { NavAreaNotFound } from '../layout/nav-area-not-found.js';\nimport { canonicalNavKey } from '../resource-key.js';\nimport { Button } from '../primitives/button.js';\nimport { useFlowChrome } from './chrome.js';\nimport { type FlowHostBinding, FlowHostBindingContext, FlowScreen } from './flow-screen.js';\n\ntype Row = { id: string } & Record<string, unknown>;\n\ninterface PageFlowProps {\n readonly resource: string;\n readonly id: string;\n readonly name: string;\n}\n\nexport interface PageFlowRouteProps {\n readonly match: RouteMatch;\n}\n\n/** The route: the static gate, then the record, then the flow's own gate. */\nexport function PageFlowRoute({ match }: PageFlowRouteProps): ReactElement {\n const app = useApp();\n const snapshot = useApplicationSnapshot();\n const permissions = usePermissions();\n const resource = canonicalNavKey(match as never);\n const id = match.id ?? '';\n const name = match.flow ?? '';\n // (1) Decided before anything is read.\n if (permissionsUndecided(permissions)) return <RecordState state=\"loading\" />;\n // (2) Static: a record page to hang the route on, and an item flow whose effective host is page.\n const flow = effectiveFlow(snapshot, match.ref, name);\n const hasRecordPage =\n recordRouteAvailable(app.registry, resource, 'show') ||\n recordRouteAvailable(app.registry, resource, 'edit');\n // A name no item flow answers to is no route at all (`/orders/x/segments`): the framework 404,\n // as for any unmatched URL. A flow that exists but is not page-hosted, or a record page that is\n // missing, keeps the record route's not-found, so a denied flow reads like a missing record.\n if (flow === undefined) return <NavAreaNotFound />;\n if (!hasRecordPage || flow.host !== 'page' || id === '') return <RecordState state=\"not-found\" />;\n return <PageFlowRecord key={`${resource}:${id}:${name}`} {...{ resource, id, name }} />;\n}\n\n/** (3) The record by id, with the record DTO: the same read the record route makes. */\nfunction PageFlowRecord(props: PageFlowProps): ReactElement {\n const { resource, id } = props;\n // The URL's id as the id field types it (spec 4.19); an invalid one names no record.\n const recordId = useRouteRecordId(resource, id);\n if (recordId === undefined) return <InvalidRouteId resource={resource} />;\n return <PageFlowRead {...props} recordId={recordId} />;\n}\n\n/** The record by its typed id. */\nfunction PageFlowRead(props: PageFlowProps & { readonly recordId: RecordId }): ReactElement {\n const { resource, recordId } = props;\n const app = useApp();\n const def = app.registry.get(resource);\n const projection = useMemo(\n () => (def === undefined ? undefined : dtoFields(def, 'record')),\n [def],\n );\n const query = useOne(resource, {\n id: recordId,\n retry: retryRecordRead,\n ...(projection === undefined ? {} : { projection }),\n });\n const result = query.data as { readonly data?: unknown } | undefined;\n if (result !== undefined) {\n const record = result.data;\n if (record === null || typeof record !== 'object') return <RecordState state=\"not-found\" />;\n return (\n <PageFlowGate resource={resource} id={props.id} name={props.name} record={record as Row} />\n );\n }\n if (query.error != null) {\n return (\n <LoadError\n surface=\"record\"\n resource={resource}\n error={query.error}\n retry={() => void query.refetch()}\n />\n );\n }\n return <RecordState state=\"loading\" />;\n}\n\n/** (4) The flow's gate over the row, as its button decides it: no second rule here. */\nfunction PageFlowGate(props: PageFlowProps & { readonly record: Row }): ReactElement {\n const { resource, name, record } = props;\n const resolve = useFlowRowResolver(resource);\n const control = resolve(name, record);\n // Someone else's change can take the flow away under a form that holds input: the page keeps\n // the form, read-only, with the \"no longer applies\" notice and Discard (3.12), instead of\n // unmounting it silently. `useRef` here, `PageFlowRun` mounted from the first available render.\n const dirty = useRef(false);\n const running = useRef(false);\n const goneNow =\n (control.state === 'absent' && control.cause === 'when') || control.state === 'disabled';\n const keep = goneNow && running.current && dirty.current;\n const track = (value: boolean) => {\n dirty.current = value;\n };\n if (keep)\n return (\n <PageFlowRun {...props} stale onDirty={track} onMounted={(on) => (running.current = on)} />\n );\n switch (control.state) {\n case 'undecided':\n case 'pending':\n return <RecordState state=\"loading\" />;\n case 'absent':\n return control.cause === 'when' ? (\n <PageFlowUnavailable {...props} />\n ) : (\n <RecordState state=\"not-found\" />\n );\n case 'disabled':\n return (\n <PageFlowUnavailable\n {...props}\n {...(control.reason === undefined ? {} : { reason: control.reason })}\n />\n );\n default:\n return (\n <PageFlowRun\n {...props}\n record={(control.record ?? record) as Row}\n onDirty={track}\n onMounted={(on) => (running.current = on)}\n />\n );\n }\n}\n\n/**\n * The flow's name, the record's title and the record's way back, shared by every state of the\n * page that shows the record. It also tells the header's trail (`<HeaderBreadcrumbs>`) the\n * record's title and the flow's label, which the trail ends with: only these states do, so a\n * loading or not-found flow route never names its flow.\n */\nfunction usePageFlowFrame(props: PageFlowProps & { readonly record: Row }) {\n const { resource, id, name, record } = props;\n const app = useApp();\n const chrome = useFlowChrome(resource, name);\n const title = useProjectedTitle(resource, id, record);\n const showable = recordRouteAvailable(app.registry, resource, 'show');\n const recordHref = hrefFor(app.registry, resource, {\n action: showable ? 'show' : 'edit',\n id,\n });\n usePublishRecordTrail({\n key: recordTrailKey(resource, id, `flow:${name}`),\n title,\n flowLabel: chrome.labelText,\n });\n return { chrome, title, recordHref };\n}\n\n/** `when` false, or a blocking check: the reason and the way back, no form. */\nfunction PageFlowUnavailable(\n props: PageFlowProps & { readonly record: Row; readonly reason?: string },\n): ReactElement {\n const t = useOptionalT();\n const caps = useI18nCaps(props.resource);\n const tid = useTestIds();\n const { recordHref } = usePageFlowFrame(props);\n const Link = useLinkComponent();\n const flowId = usePageFlowId(props.resource, props.name);\n return (\n <div>\n <div\n role=\"status\"\n data-testid={`${tid.pageFlow(flowId)}:unavailable`}\n className=\"flex flex-col gap-2 px-1 py-6 text-sm\"\n >\n <p className=\"font-medium\">\n {t('flow.notAvailable', { defaultValue: 'This action is not available' })}\n </p>\n {props.reason === undefined ? null : (\n <p className=\"text-muted-foreground\">{reasonText(caps, props.reason, props.resource)}</p>\n )}\n <Link href={recordHref} className=\"underline\">\n {t('flow.back', { defaultValue: 'Back' })}\n </Link>\n </div>\n </div>\n );\n}\n\n/** The flow's identity (`default:articles/actions/rename`), for test ids; stable when compiled. */\nfunction usePageFlowId(resource: string, name: string): string {\n const app = useApp();\n const def = app.registry.get(resource);\n return useMemo(() => {\n try {\n return def === undefined\n ? `${resource}/actions/${name}`\n : compileFlow(def as never, name).flowId;\n } catch {\n return `${resource}/actions/${name}`;\n }\n }, [def, resource, name]);\n}\n\n/** (5) The run and its host. */\nfunction PageFlowRun(\n props: PageFlowProps & {\n readonly record: Row;\n /** The flow no longer applies: the form stays, read-only, with a notice and Discard. */\n readonly stale?: boolean;\n readonly onDirty?: (dirty: boolean) => void;\n readonly onMounted?: (mounted: boolean) => void;\n },\n): ReactElement {\n const { resource, name, stale = false, onDirty, onMounted } = props;\n // The run belongs to the record as it was opened: the refetch after the write must not build\n // a new run (and lose the outcome `then` is about to run on). Display reads the fresh one.\n const [record] = useState(props.record);\n const t = useOptionalT();\n const caps = useI18nCaps(resource);\n const tid = useTestIds();\n const navigate = useRouteNavigate();\n const Link = useLinkComponent();\n const scopeEffects = useDispatcherEffects();\n const { chrome, title, recordHref } = usePageFlowFrame(props);\n const navigateRef = useRef(navigate);\n navigateRef.current = navigate;\n // `redirect` replaces the page: Back cannot reach a form that has been submitted.\n const thenEffects = useCallback(\n () => ({\n ...scopeEffects(),\n redirect: (to: Parameters<typeof navigate>[0]) => navigateRef.current(to, { replace: true }),\n }),\n [scopeEffects],\n );\n const target = useMemo(() => ({ resource, action: name }), [resource, name]);\n const flow = useFlowRun(target, { record, surface: 'page', thenEffects });\n // `then` is the page's to run, once it left the form (4.13).\n flow.holdThen(true);\n const { run, snapshot, compiled } = flow;\n const flowRef = useRef(flow);\n flowRef.current = flow;\n\n // The page leaves the form behind: after the form below it reset (a clean form asks the guard\n // nothing), replace the page by the destination, then run `then` over it.\n const [finished, setFinished] = useState(false);\n useEffect(() => {\n if (!finished) return;\n const current = flowRef.current;\n if (current.compiled?.flow.then?.redirect === undefined)\n navigateRef.current(recordHref, { replace: true });\n // After the route committed: an overlay opened by `then` belongs to the destination, and a\n // route change in flight would close it again.\n setTimeout(() => current.runThen(), 0);\n }, [finished, recordHref]);\n const binding = useMemo<FlowHostBinding>(\n () => ({\n kind: 'page',\n close: () => navigateRef.current(recordHref),\n finish: () => setFinished(true),\n }),\n [recordHref],\n );\n\n useEffect(() => {\n onMounted?.(true);\n return () => onMounted?.(false);\n }, [onMounted]);\n // Unsaved input or an unresolved attempt: what the gate must not unmount silently.\n useEffect(() => {\n if (run === null) return;\n let initial: string | undefined;\n const sync = () => {\n const now = run.getSnapshot();\n if (initial === undefined && now.history.includes('open'))\n initial = JSON.stringify(now.values);\n onDirty?.(\n now.outcome?.outcome !== 'success' &&\n (now.outcome?.outcome === 'unknown' ||\n (initial !== undefined && JSON.stringify(now.values) !== initial)),\n );\n };\n sync();\n return run.subscribe(sync);\n }, [run, onDirty]);\n // Discard: the input is dropped first, so the guard has nothing to ask, then the page leaves.\n const [discarded, setDiscarded] = useState(false);\n useEffect(() => {\n if (discarded) navigateRef.current(recordHref, { replace: true });\n }, [discarded, recordHref]);\n\n const documentTitle = `${chrome.labelText}${title === '' ? '' : ` · ${title}`}`;\n useEffect(() => {\n const previous = document.title;\n document.title = documentTitle;\n return () => {\n document.title = previous;\n };\n }, [documentTitle]);\n\n const opened =\n run !== null &&\n compiled !== null &&\n (snapshot.history.includes('open') || snapshot.step === 'outcome');\n const refused = snapshot.control === 'disabled' || snapshot.control === 'absent';\n return (\n <div\n data-testid={compiled === null ? undefined : tid.pageFlow(compiled.flowId)}\n className=\"flex min-h-0 flex-col gap-4\"\n >\n <div className=\"flex flex-wrap items-center gap-2\">\n <Link\n href={recordHref}\n className=\"ml-auto text-sm underline\"\n data-testid={`${tid.pageFlow(compiled?.flowId ?? name)}:back`}\n >\n {t('flow.back', { defaultValue: 'Back' })}\n </Link>\n </div>\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\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n onClick={() => {\n flow.reset();\n setDiscarded(true);\n }}\n >\n {t('flow.discard', { defaultValue: 'Discard' })}\n </Button>\n </div>\n ) : null}\n {opened ? (\n <FlowHostBindingContext.Provider value={binding}>\n <fieldset disabled={stale} className=\"m-0 min-w-0 border-0 p-0\">\n <FlowScreen\n host=\"page\"\n run={run}\n compiled={compiled}\n label={chrome.labelText}\n {...(title === '' ? {} : { title })}\n record={record}\n />\n </fieldset>\n </FlowHostBindingContext.Provider>\n ) : refused ? (\n <p role=\"alert\" className=\"text-sm\">\n {snapshot.reason === undefined\n ? t('flow.unavailable', { defaultValue: 'Not allowed.' })\n : reasonText(caps, snapshot.reason, resource)}\n </p>\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,9 +1,9 @@
1
1
  const require_toaster = require("./toaster-BbByOytP.cjs");
2
- const require_check_confirm_dialog = require("./check-confirm-dialog-W-8WOmGh.cjs");
2
+ const require_check_confirm_dialog = require("./check-confirm-dialog-BMSb7wFv.cjs");
3
3
  const require_button = require("./button-BxnnE28H.cjs");
4
- const require_relation_create = require("./relation-create-_SFuPQGM.cjs");
5
- const require_resource_page_router = require("./resource-page-router-dmVIeu5s.cjs");
6
- const require_flow_screen = require("./flow-screen-FE5Xhb3t.cjs");
4
+ const require_relation_create = require("./relation-create-B8zngAcA.cjs");
5
+ const require_record_trail_store = require("./record-trail-store-Cjo9vtod.cjs");
6
+ const require_flow_screen = require("./flow-screen-sw2cP70t.cjs");
7
7
  let _burojs_core = require("@burojs/core");
8
8
  let _burojs_react = require("@burojs/react");
9
9
  let _tabler_icons_react = require("@tabler/icons-react");
@@ -15,13 +15,13 @@ function PageFlowRoute({ match }) {
15
15
  const app = (0, _burojs_react.useApp)();
16
16
  const snapshot = (0, _burojs_react.useApplicationSnapshot)();
17
17
  const permissions = (0, _burojs_react.usePermissions)();
18
- const resource = require_resource_page_router.canonicalNavKey(match);
18
+ const resource = require_record_trail_store.canonicalNavKey(match);
19
19
  const id = match.id ?? "";
20
20
  const name = match.flow ?? "";
21
21
  if ((0, _burojs_core.permissionsUndecided)(permissions)) return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "loading" });
22
22
  const flow = (0, _burojs_core.effectiveFlow)(snapshot, match.ref, name);
23
23
  const hasRecordPage = (0, _burojs_react.recordRouteAvailable)(app.registry, resource, "show") || (0, _burojs_react.recordRouteAvailable)(app.registry, resource, "edit");
24
- if (flow === void 0) return (0, react_jsx_runtime.jsx)(require_resource_page_router.NavAreaNotFound, {});
24
+ if (flow === void 0) return (0, react_jsx_runtime.jsx)(require_record_trail_store.NavAreaNotFound, {});
25
25
  if (!hasRecordPage || flow.host !== "page" || id === "") return (0, react_jsx_runtime.jsx)(require_relation_create.RecordState, { state: "not-found" });
26
26
  return (0, react_jsx_runtime.jsx)(PageFlowRecord, {
27
27
  resource,
@@ -107,8 +107,8 @@ function usePageFlowFrame(props) {
107
107
  action: showable ? "show" : "edit",
108
108
  id
109
109
  });
110
- require_resource_page_router.usePublishRecordTrail({
111
- key: require_resource_page_router.recordTrailKey(resource, id, `flow:${name}`),
110
+ require_record_trail_store.usePublishRecordTrail({
111
+ key: require_record_trail_store.recordTrailKey(resource, id, `flow:${name}`),
112
112
  title,
113
113
  flowLabel: chrome.labelText
114
114
  });
@@ -286,4 +286,4 @@ function PageFlowRun(props) {
286
286
  //#endregion
287
287
  exports.PageFlowRoute = PageFlowRoute;
288
288
 
289
- //# sourceMappingURL=page-flow-route-OFx7h7Ja.cjs.map
289
+ //# sourceMappingURL=page-flow-route-UDx8qvdM.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-flow-route-UDx8qvdM.cjs","names":["useApp","useApplicationSnapshot","usePermissions","canonicalNavKey","permissionsUndecided","RecordState","effectiveFlow","recordRouteAvailable","NavAreaNotFound","useRouteRecordId","InvalidRouteId","useMemo","dtoFields","useOne","retryRecordRead","LoadError","useFlowRowResolver","useRef","useFlowChrome","useProjectedTitle","hrefFor","recordTrailKey","useOptionalT","useI18nCaps","useTestIds","useLinkComponent","reasonText","compileFlow","useState","useRouteNavigate","useDispatcherEffects","useCallback","useFlowRun","Button","FlowHostBindingContext","FlowScreen","IconLoader2"],"sources":["../src/flows/page-flow-route.tsx"],"sourcesContent":["'use client';\n/**\n * A page-hosted flow's route (P6 3.11): `<record route>/<flow name>`. It owns the whole gate in\n * order, so a user who may not run the flow never sees a trace of it:\n *\n * 1. the permission map is decided, else the record route's loading state and nothing is read;\n * 2. static: the resource has a record page, the flow is an item flow and, in the published\n * snapshot, its `host` is `page`; else the record route's not-found;\n * 3. the record is read by id with the record DTO;\n * 4. the flow's gate over that row (`requires`, the mutation's `requires`, `action/run` rules):\n * hidden, absent, or a missing or forbidden row is the same not-found as `/articles/missing`;\n * a false `when` or a blocking pre-click check is \"not available\" and the way back;\n * 5. only then the run (`useFlowRun`) and its sources.\n */\nimport {\n type RecordId,\n type RouteMatch,\n compileFlow,\n dtoFields,\n effectiveFlow,\n hrefFor,\n permissionsUndecided,\n} from '@burojs/core';\nimport {\n recordRouteAvailable,\n retryRecordRead,\n useApp,\n useApplicationSnapshot,\n useDispatcherEffects,\n useFlowRowResolver,\n useI18nCaps,\n useOne,\n useOptionalT,\n usePermissions,\n useProjectedTitle,\n useRouteNavigate,\n useRouteRecordId,\n useTestIds,\n} from '@burojs/react';\nimport { useFlowRun } from '@burojs/react/flows';\nimport { IconLoader2 } from '@tabler/icons-react';\nimport { type ReactElement, useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useLinkComponent } from '../layout/link-component.js';\nimport { reasonText } from '../lib/reason-text.js';\nimport { InvalidRouteId, LoadError } from '../load-error/load-error-view.js';\nimport { recordTrailKey, usePublishRecordTrail } from '../layout/record-trail-store.js';\nimport { RecordState } from '../record/record-state.js';\nimport { NavAreaNotFound } from '../layout/nav-area-not-found.js';\nimport { canonicalNavKey } from '../resource-key.js';\nimport { Button } from '../primitives/button.js';\nimport { useFlowChrome } from './chrome.js';\nimport { type FlowHostBinding, FlowHostBindingContext, FlowScreen } from './flow-screen.js';\n\ntype Row = { id: string } & Record<string, unknown>;\n\ninterface PageFlowProps {\n readonly resource: string;\n readonly id: string;\n readonly name: string;\n}\n\nexport interface PageFlowRouteProps {\n readonly match: RouteMatch;\n}\n\n/** The route: the static gate, then the record, then the flow's own gate. */\nexport function PageFlowRoute({ match }: PageFlowRouteProps): ReactElement {\n const app = useApp();\n const snapshot = useApplicationSnapshot();\n const permissions = usePermissions();\n const resource = canonicalNavKey(match as never);\n const id = match.id ?? '';\n const name = match.flow ?? '';\n // (1) Decided before anything is read.\n if (permissionsUndecided(permissions)) return <RecordState state=\"loading\" />;\n // (2) Static: a record page to hang the route on, and an item flow whose effective host is page.\n const flow = effectiveFlow(snapshot, match.ref, name);\n const hasRecordPage =\n recordRouteAvailable(app.registry, resource, 'show') ||\n recordRouteAvailable(app.registry, resource, 'edit');\n // A name no item flow answers to is no route at all (`/orders/x/segments`): the framework 404,\n // as for any unmatched URL. A flow that exists but is not page-hosted, or a record page that is\n // missing, keeps the record route's not-found, so a denied flow reads like a missing record.\n if (flow === undefined) return <NavAreaNotFound />;\n if (!hasRecordPage || flow.host !== 'page' || id === '') return <RecordState state=\"not-found\" />;\n return <PageFlowRecord key={`${resource}:${id}:${name}`} {...{ resource, id, name }} />;\n}\n\n/** (3) The record by id, with the record DTO: the same read the record route makes. */\nfunction PageFlowRecord(props: PageFlowProps): ReactElement {\n const { resource, id } = props;\n // The URL's id as the id field types it (spec 4.19); an invalid one names no record.\n const recordId = useRouteRecordId(resource, id);\n if (recordId === undefined) return <InvalidRouteId resource={resource} />;\n return <PageFlowRead {...props} recordId={recordId} />;\n}\n\n/** The record by its typed id. */\nfunction PageFlowRead(props: PageFlowProps & { readonly recordId: RecordId }): ReactElement {\n const { resource, recordId } = props;\n const app = useApp();\n const def = app.registry.get(resource);\n const projection = useMemo(\n () => (def === undefined ? undefined : dtoFields(def, 'record')),\n [def],\n );\n const query = useOne(resource, {\n id: recordId,\n retry: retryRecordRead,\n ...(projection === undefined ? {} : { projection }),\n });\n const result = query.data as { readonly data?: unknown } | undefined;\n if (result !== undefined) {\n const record = result.data;\n if (record === null || typeof record !== 'object') return <RecordState state=\"not-found\" />;\n return (\n <PageFlowGate resource={resource} id={props.id} name={props.name} record={record as Row} />\n );\n }\n if (query.error != null) {\n return (\n <LoadError\n surface=\"record\"\n resource={resource}\n error={query.error}\n retry={() => void query.refetch()}\n />\n );\n }\n return <RecordState state=\"loading\" />;\n}\n\n/** (4) The flow's gate over the row, as its button decides it: no second rule here. */\nfunction PageFlowGate(props: PageFlowProps & { readonly record: Row }): ReactElement {\n const { resource, name, record } = props;\n const resolve = useFlowRowResolver(resource);\n const control = resolve(name, record);\n // Someone else's change can take the flow away under a form that holds input: the page keeps\n // the form, read-only, with the \"no longer applies\" notice and Discard (3.12), instead of\n // unmounting it silently. `useRef` here, `PageFlowRun` mounted from the first available render.\n const dirty = useRef(false);\n const running = useRef(false);\n const goneNow =\n (control.state === 'absent' && control.cause === 'when') || control.state === 'disabled';\n const keep = goneNow && running.current && dirty.current;\n const track = (value: boolean) => {\n dirty.current = value;\n };\n if (keep)\n return (\n <PageFlowRun {...props} stale onDirty={track} onMounted={(on) => (running.current = on)} />\n );\n switch (control.state) {\n case 'undecided':\n case 'pending':\n return <RecordState state=\"loading\" />;\n case 'absent':\n return control.cause === 'when' ? (\n <PageFlowUnavailable {...props} />\n ) : (\n <RecordState state=\"not-found\" />\n );\n case 'disabled':\n return (\n <PageFlowUnavailable\n {...props}\n {...(control.reason === undefined ? {} : { reason: control.reason })}\n />\n );\n default:\n return (\n <PageFlowRun\n {...props}\n record={(control.record ?? record) as Row}\n onDirty={track}\n onMounted={(on) => (running.current = on)}\n />\n );\n }\n}\n\n/**\n * The flow's name, the record's title and the record's way back, shared by every state of the\n * page that shows the record. It also tells the header's trail (`<HeaderBreadcrumbs>`) the\n * record's title and the flow's label, which the trail ends with: only these states do, so a\n * loading or not-found flow route never names its flow.\n */\nfunction usePageFlowFrame(props: PageFlowProps & { readonly record: Row }) {\n const { resource, id, name, record } = props;\n const app = useApp();\n const chrome = useFlowChrome(resource, name);\n const title = useProjectedTitle(resource, id, record);\n const showable = recordRouteAvailable(app.registry, resource, 'show');\n const recordHref = hrefFor(app.registry, resource, {\n action: showable ? 'show' : 'edit',\n id,\n });\n usePublishRecordTrail({\n key: recordTrailKey(resource, id, `flow:${name}`),\n title,\n flowLabel: chrome.labelText,\n });\n return { chrome, title, recordHref };\n}\n\n/** `when` false, or a blocking check: the reason and the way back, no form. */\nfunction PageFlowUnavailable(\n props: PageFlowProps & { readonly record: Row; readonly reason?: string },\n): ReactElement {\n const t = useOptionalT();\n const caps = useI18nCaps(props.resource);\n const tid = useTestIds();\n const { recordHref } = usePageFlowFrame(props);\n const Link = useLinkComponent();\n const flowId = usePageFlowId(props.resource, props.name);\n return (\n <div>\n <div\n role=\"status\"\n data-testid={`${tid.pageFlow(flowId)}:unavailable`}\n className=\"flex flex-col gap-2 px-1 py-6 text-sm\"\n >\n <p className=\"font-medium\">\n {t('flow.notAvailable', { defaultValue: 'This action is not available' })}\n </p>\n {props.reason === undefined ? null : (\n <p className=\"text-muted-foreground\">{reasonText(caps, props.reason, props.resource)}</p>\n )}\n <Link href={recordHref} className=\"underline\">\n {t('flow.back', { defaultValue: 'Back' })}\n </Link>\n </div>\n </div>\n );\n}\n\n/** The flow's identity (`default:articles/actions/rename`), for test ids; stable when compiled. */\nfunction usePageFlowId(resource: string, name: string): string {\n const app = useApp();\n const def = app.registry.get(resource);\n return useMemo(() => {\n try {\n return def === undefined\n ? `${resource}/actions/${name}`\n : compileFlow(def as never, name).flowId;\n } catch {\n return `${resource}/actions/${name}`;\n }\n }, [def, resource, name]);\n}\n\n/** (5) The run and its host. */\nfunction PageFlowRun(\n props: PageFlowProps & {\n readonly record: Row;\n /** The flow no longer applies: the form stays, read-only, with a notice and Discard. */\n readonly stale?: boolean;\n readonly onDirty?: (dirty: boolean) => void;\n readonly onMounted?: (mounted: boolean) => void;\n },\n): ReactElement {\n const { resource, name, stale = false, onDirty, onMounted } = props;\n // The run belongs to the record as it was opened: the refetch after the write must not build\n // a new run (and lose the outcome `then` is about to run on). Display reads the fresh one.\n const [record] = useState(props.record);\n const t = useOptionalT();\n const caps = useI18nCaps(resource);\n const tid = useTestIds();\n const navigate = useRouteNavigate();\n const Link = useLinkComponent();\n const scopeEffects = useDispatcherEffects();\n const { chrome, title, recordHref } = usePageFlowFrame(props);\n const navigateRef = useRef(navigate);\n navigateRef.current = navigate;\n // `redirect` replaces the page: Back cannot reach a form that has been submitted.\n const thenEffects = useCallback(\n () => ({\n ...scopeEffects(),\n redirect: (to: Parameters<typeof navigate>[0]) => navigateRef.current(to, { replace: true }),\n }),\n [scopeEffects],\n );\n const target = useMemo(() => ({ resource, action: name }), [resource, name]);\n const flow = useFlowRun(target, { record, surface: 'page', thenEffects });\n // `then` is the page's to run, once it left the form (4.13).\n flow.holdThen(true);\n const { run, snapshot, compiled } = flow;\n const flowRef = useRef(flow);\n flowRef.current = flow;\n\n // The page leaves the form behind: after the form below it reset (a clean form asks the guard\n // nothing), replace the page by the destination, then run `then` over it.\n const [finished, setFinished] = useState(false);\n useEffect(() => {\n if (!finished) return;\n const current = flowRef.current;\n if (current.compiled?.flow.then?.redirect === undefined)\n navigateRef.current(recordHref, { replace: true });\n // After the route committed: an overlay opened by `then` belongs to the destination, and a\n // route change in flight would close it again.\n setTimeout(() => current.runThen(), 0);\n }, [finished, recordHref]);\n const binding = useMemo<FlowHostBinding>(\n () => ({\n kind: 'page',\n close: () => navigateRef.current(recordHref),\n finish: () => setFinished(true),\n }),\n [recordHref],\n );\n\n useEffect(() => {\n onMounted?.(true);\n return () => onMounted?.(false);\n }, [onMounted]);\n // Unsaved input or an unresolved attempt: what the gate must not unmount silently.\n useEffect(() => {\n if (run === null) return;\n let initial: string | undefined;\n const sync = () => {\n const now = run.getSnapshot();\n if (initial === undefined && now.history.includes('open'))\n initial = JSON.stringify(now.values);\n onDirty?.(\n now.outcome?.outcome !== 'success' &&\n (now.outcome?.outcome === 'unknown' ||\n (initial !== undefined && JSON.stringify(now.values) !== initial)),\n );\n };\n sync();\n return run.subscribe(sync);\n }, [run, onDirty]);\n // Discard: the input is dropped first, so the guard has nothing to ask, then the page leaves.\n const [discarded, setDiscarded] = useState(false);\n useEffect(() => {\n if (discarded) navigateRef.current(recordHref, { replace: true });\n }, [discarded, recordHref]);\n\n const documentTitle = `${chrome.labelText}${title === '' ? '' : ` · ${title}`}`;\n useEffect(() => {\n const previous = document.title;\n document.title = documentTitle;\n return () => {\n document.title = previous;\n };\n }, [documentTitle]);\n\n const opened =\n run !== null &&\n compiled !== null &&\n (snapshot.history.includes('open') || snapshot.step === 'outcome');\n const refused = snapshot.control === 'disabled' || snapshot.control === 'absent';\n return (\n <div\n data-testid={compiled === null ? undefined : tid.pageFlow(compiled.flowId)}\n className=\"flex min-h-0 flex-col gap-4\"\n >\n <div className=\"flex flex-wrap items-center gap-2\">\n <Link\n href={recordHref}\n className=\"ml-auto text-sm underline\"\n data-testid={`${tid.pageFlow(compiled?.flowId ?? name)}:back`}\n >\n {t('flow.back', { defaultValue: 'Back' })}\n </Link>\n </div>\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\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n onClick={() => {\n flow.reset();\n setDiscarded(true);\n }}\n >\n {t('flow.discard', { defaultValue: 'Discard' })}\n </Button>\n </div>\n ) : null}\n {opened ? (\n <FlowHostBindingContext.Provider value={binding}>\n <fieldset disabled={stale} className=\"m-0 min-w-0 border-0 p-0\">\n <FlowScreen\n host=\"page\"\n run={run}\n compiled={compiled}\n label={chrome.labelText}\n {...(title === '' ? {} : { title })}\n record={record}\n />\n </fieldset>\n </FlowHostBindingContext.Provider>\n ) : refused ? (\n <p role=\"alert\" className=\"text-sm\">\n {snapshot.reason === undefined\n ? t('flow.unavailable', { defaultValue: 'Not allowed.' })\n : reasonText(caps, snapshot.reason, resource)}\n </p>\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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"}