@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.
- package/dist/{bulk-summary-2HLgz7Il.cjs → bulk-summary-Chc61Pyw.cjs} +9 -7
- package/dist/bulk-summary-Chc61Pyw.cjs.map +1 -0
- package/dist/{bulk-summary-D6A0ua21.js → bulk-summary-DpSQD2Fq.js} +9 -7
- package/dist/bulk-summary-DpSQD2Fq.js.map +1 -0
- package/dist/{candidates-relation-picker-QvoY2bOQ.js → candidates-relation-picker-DRsHKe6N.js} +3 -3
- package/dist/{candidates-relation-picker-QvoY2bOQ.js.map → candidates-relation-picker-DRsHKe6N.js.map} +1 -1
- package/dist/{candidates-relation-picker-pEAWKQEY.cjs → candidates-relation-picker-GIxsp7D_.cjs} +3 -3
- package/dist/{candidates-relation-picker-pEAWKQEY.cjs.map → candidates-relation-picker-GIxsp7D_.cjs.map} +1 -1
- package/dist/{check-confirm-dialog-W-8WOmGh.cjs → check-confirm-dialog-BMSb7wFv.cjs} +17 -9
- package/dist/check-confirm-dialog-BMSb7wFv.cjs.map +1 -0
- package/dist/{check-confirm-dialog-B-CbJTln.js → check-confirm-dialog-B_u3YVHS.js} +18 -10
- package/dist/{check-confirm-dialog-B-CbJTln.js.map → check-confirm-dialog-B_u3YVHS.js.map} +1 -1
- package/dist/{filter-builder-04nas3eq.js → filter-builder-DX-xC3Yd.js} +2 -2
- package/dist/{filter-builder-04nas3eq.js.map → filter-builder-DX-xC3Yd.js.map} +1 -1
- package/dist/{filter-builder-DQX-TMFh.cjs → filter-builder-Dt5E8PSX.cjs} +2 -2
- package/dist/{filter-builder-DQX-TMFh.cjs.map → filter-builder-Dt5E8PSX.cjs.map} +1 -1
- package/dist/{flow-runtime-DyNIYfUP.cjs → flow-runtime-CQ4wf8co.cjs} +2 -2
- package/dist/{flow-runtime-DyNIYfUP.cjs.map → flow-runtime-CQ4wf8co.cjs.map} +1 -1
- package/dist/{flow-runtime-BEIyym7d.js → flow-runtime-Q2vD7R3c.js} +2 -2
- package/dist/{flow-runtime-BEIyym7d.js.map → flow-runtime-Q2vD7R3c.js.map} +1 -1
- package/dist/{flow-screen-DY1Z9PbG.js → flow-screen-B1y2yizP.js} +18 -18
- package/dist/flow-screen-B1y2yizP.js.map +1 -0
- package/dist/{flow-screen-FE5Xhb3t.cjs → flow-screen-sw2cP70t.cjs} +18 -18
- package/dist/flow-screen-sw2cP70t.cjs.map +1 -0
- package/dist/index.cjs +2183 -109
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +76 -8
- package/dist/index.d.ts +76 -8
- package/dist/index.js +2095 -24
- package/dist/index.js.map +1 -1
- package/dist/{inline-flow-host-yVLo6-sM.cjs → inline-flow-host-CkhoA69R.cjs} +3 -3
- package/dist/{inline-flow-host-yVLo6-sM.cjs.map → inline-flow-host-CkhoA69R.cjs.map} +1 -1
- package/dist/{inline-flow-host-D6u-RlsV.js → inline-flow-host-DqbXqcPS.js} +3 -3
- package/dist/{inline-flow-host-D6u-RlsV.js.map → inline-flow-host-DqbXqcPS.js.map} +1 -1
- package/dist/{lazy-relation-picker-dialog-BaORufxQ.js → lazy-relation-picker-dialog-BaIEWLbF.js} +3 -52
- package/dist/lazy-relation-picker-dialog-BaIEWLbF.js.map +1 -0
- package/dist/{lazy-relation-picker-dialog-C_VlGlDz.cjs → lazy-relation-picker-dialog-CeRzOAi0.cjs} +3 -52
- package/dist/lazy-relation-picker-dialog-CeRzOAi0.cjs.map +1 -0
- package/dist/{page-flow-route-CyMzUidK.js → page-flow-route-CP7cS7FY.js} +5 -5
- package/dist/page-flow-route-CP7cS7FY.js.map +1 -0
- package/dist/{page-flow-route-OFx7h7Ja.cjs → page-flow-route-UDx8qvdM.cjs} +9 -9
- package/dist/page-flow-route-UDx8qvdM.cjs.map +1 -0
- package/dist/{place-node-BZF5Af6x.cjs → place-node-C5ZmuHaN.cjs} +149 -40
- package/dist/place-node-C5ZmuHaN.cjs.map +1 -0
- package/dist/{place-node-DRjmJGQ_.js → place-node-DwWAigv0.js} +146 -43
- package/dist/place-node-DwWAigv0.js.map +1 -0
- package/dist/record-trail-store-Cjo9vtod.cjs +126 -0
- package/dist/record-trail-store-Cjo9vtod.cjs.map +1 -0
- package/dist/record-trail-store-Dn6bVry4.js +91 -0
- package/dist/record-trail-store-Dn6bVry4.js.map +1 -0
- package/dist/{related-list-cards-xVvgSlu-.cjs → related-list-cards-BypKfm9t.cjs} +3 -3
- package/dist/{related-list-cards-xVvgSlu-.cjs.map → related-list-cards-BypKfm9t.cjs.map} +1 -1
- package/dist/{related-list-cards-2hLitVkg.js → related-list-cards-Dcmruy09.js} +3 -3
- package/dist/{related-list-cards-2hLitVkg.js.map → related-list-cards-Dcmruy09.js.map} +1 -1
- package/dist/{related-list-timeline-Dsf5WewG.cjs → related-list-timeline-D-KClgKb.cjs} +4 -4
- package/dist/{related-list-timeline-Dsf5WewG.cjs.map → related-list-timeline-D-KClgKb.cjs.map} +1 -1
- package/dist/{related-list-timeline-CxJqe6eK.js → related-list-timeline-DZON_qSc.js} +4 -4
- package/dist/{related-list-timeline-CxJqe6eK.js.map → related-list-timeline-DZON_qSc.js.map} +1 -1
- package/dist/{related-rows-DDhp9axl.cjs → related-rows-DgF05ssi.cjs} +4 -4
- package/dist/{related-rows-DDhp9axl.cjs.map → related-rows-DgF05ssi.cjs.map} +1 -1
- package/dist/{related-rows-DL6CWsrj.js → related-rows-ETZl5CB9.js} +4 -4
- package/dist/{related-rows-DL6CWsrj.js.map → related-rows-ETZl5CB9.js.map} +1 -1
- package/dist/{relation-create-_SFuPQGM.cjs → relation-create-B8zngAcA.cjs} +46 -11
- package/dist/relation-create-B8zngAcA.cjs.map +1 -0
- package/dist/{relation-create-6WicROWA.js → relation-create-CeCWyxIb.js} +47 -12
- package/dist/relation-create-CeCWyxIb.js.map +1 -0
- package/dist/{relation-many-picker-mGEQDWo2.js → relation-many-picker-CT7nKfE2.js} +4 -4
- package/dist/{relation-many-picker-mGEQDWo2.js.map → relation-many-picker-CT7nKfE2.js.map} +1 -1
- package/dist/{relation-many-picker-BBNsmkaX.cjs → relation-many-picker-Cq0EHY5I.cjs} +4 -4
- package/dist/{relation-many-picker-BBNsmkaX.cjs.map → relation-many-picker-Cq0EHY5I.cjs.map} +1 -1
- package/dist/{relation-picker-BbO41cFV.js → relation-picker-CCyuMeGq.js} +6 -6
- package/dist/{relation-picker-BbO41cFV.js.map → relation-picker-CCyuMeGq.js.map} +1 -1
- package/dist/{relation-picker-jk9D_uwn.cjs → relation-picker-DmwTzgsd.cjs} +6 -6
- package/dist/{relation-picker-jk9D_uwn.cjs.map → relation-picker-DmwTzgsd.cjs.map} +1 -1
- package/dist/{relation-picker-dialog-BgSG_8bU.js → relation-picker-dialog-CoWKjNv8.js} +4 -4
- package/dist/{relation-picker-dialog-BgSG_8bU.js.map → relation-picker-dialog-CoWKjNv8.js.map} +1 -1
- package/dist/{relation-picker-dialog-Duqy2r0n.cjs → relation-picker-dialog-mbwyNK43.cjs} +4 -4
- package/dist/{relation-picker-dialog-Duqy2r0n.cjs.map → relation-picker-dialog-mbwyNK43.cjs.map} +1 -1
- package/dist/{relation-select-C3aV18kT.cjs → relation-select-CguIo2M5.cjs} +2 -2
- package/dist/{relation-select-C3aV18kT.cjs.map → relation-select-CguIo2M5.cjs.map} +1 -1
- package/dist/{relation-select-CjQT9LpS.js → relation-select-nAYxhopN.js} +2 -2
- package/dist/{relation-select-CjQT9LpS.js.map → relation-select-nAYxhopN.js.map} +1 -1
- package/dist/{use-dialog-filter-state-lsTJxrB4.cjs → use-dialog-filter-state-CpWblz3C.cjs} +2 -2
- package/dist/{use-dialog-filter-state-lsTJxrB4.cjs.map → use-dialog-filter-state-CpWblz3C.cjs.map} +1 -1
- package/dist/{use-dialog-filter-state-CJoeY-1j.js → use-dialog-filter-state-ZYxOp5WO.js} +2 -2
- package/dist/{use-dialog-filter-state-CJoeY-1j.js.map → use-dialog-filter-state-ZYxOp5WO.js.map} +1 -1
- package/dist/{use-record-subtitle-BJ9rnj6F.cjs → use-record-subtitle-B4lTR7pf.cjs} +2 -2
- package/dist/{use-record-subtitle-BJ9rnj6F.cjs.map → use-record-subtitle-B4lTR7pf.cjs.map} +1 -1
- package/dist/{use-record-subtitle-w3ZhXNlf.js → use-record-subtitle-pWMBqQx9.js} +2 -2
- package/dist/{use-record-subtitle-w3ZhXNlf.js.map → use-record-subtitle-pWMBqQx9.js.map} +1 -1
- package/package.json +9 -9
- package/dist/bulk-summary-2HLgz7Il.cjs.map +0 -1
- package/dist/bulk-summary-D6A0ua21.js.map +0 -1
- package/dist/check-confirm-dialog-W-8WOmGh.cjs.map +0 -1
- package/dist/flow-screen-DY1Z9PbG.js.map +0 -1
- package/dist/flow-screen-FE5Xhb3t.cjs.map +0 -1
- package/dist/lazy-relation-picker-dialog-BaORufxQ.js.map +0 -1
- package/dist/lazy-relation-picker-dialog-C_VlGlDz.cjs.map +0 -1
- package/dist/page-flow-route-CyMzUidK.js.map +0 -1
- package/dist/page-flow-route-OFx7h7Ja.cjs.map +0 -1
- package/dist/place-node-BZF5Af6x.cjs.map +0 -1
- package/dist/place-node-DRjmJGQ_.js.map +0 -1
- package/dist/relation-create-6WicROWA.js.map +0 -1
- package/dist/relation-create-_SFuPQGM.cjs.map +0 -1
- package/dist/resource-page-router-CzaNATSp.js +0 -2010
- package/dist/resource-page-router-CzaNATSp.js.map +0 -1
- package/dist/resource-page-router-dmVIeu5s.cjs +0 -2231
- package/dist/resource-page-router-dmVIeu5s.cjs.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
require("./toaster-BbByOytP.cjs");
|
|
2
|
-
const require_check_confirm_dialog = require("./check-confirm-dialog-
|
|
2
|
+
const require_check_confirm_dialog = require("./check-confirm-dialog-BMSb7wFv.cjs");
|
|
3
3
|
const require_success_notices = require("./success-notices-Cl4b6MLQ.cjs");
|
|
4
4
|
let _burojs_core = require("@burojs/core");
|
|
5
5
|
let _burojs_react = require("@burojs/react");
|
|
@@ -287,4 +287,4 @@ exports.AppFlowRunner = AppFlowRunner;
|
|
|
287
287
|
exports.BulkFlowRunner = BulkFlowRunner;
|
|
288
288
|
exports.FlowRunner = FlowRunner;
|
|
289
289
|
|
|
290
|
-
//# sourceMappingURL=flow-runtime-
|
|
290
|
+
//# sourceMappingURL=flow-runtime-CQ4wf8co.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flow-runtime-DyNIYfUP.cjs","names":["useOptionalT","APP_ACTION_RESOURCE","useI18nCaps","useNoticeSink","useState","useRef","useCallback","reasonText","toMessageRef","CheckConfirmDialog","useMemo","useFlowRun","useFlowChrome","recordKeyOf","useApp","useProjectedTitle","useFlowHost","useTestIds","makeTestId","useFlowDialogTexts"],"sources":["../src/flows/flow-runtime.tsx"],"sourcesContent":["'use client';\n/**\n * The flow runtime's side of the UI kit (P4, the coordinator's ruling on the bundle): every\n * component that holds a run. It loads on the first sign that a user means to run a flow (a\n * hover, a focus, a menu opening, at the latest the click) through `./load-runtime.js`, and with\n * it `@burojs/react/flows` and `@burojs/core/flows` — the flow machine stays out of an\n * application's first screen.\n */\nimport { toMessageRef } from '@burojs/core/internal';\nimport {\n APP_ACTION_RESOURCE,\n type BulkProgress,\n type FlowControlState,\n type FlowResult,\n type Row,\n type ValidationIssue,\n} from '@burojs/core';\nimport {\n type CheckGateState,\n recordKeyOf,\n useApp,\n useI18nCaps,\n useOptionalT,\n useProjectedTitle,\n useTestIds,\n} from '@burojs/react';\nimport {\n type FlowHostControl,\n type UseFlowRunResult,\n useFlowHost,\n useFlowRun,\n} from '@burojs/react/flows';\nimport { type ReactElement, useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { makeTestId } from '../actions/action-button.js';\nimport { CheckConfirmDialog } from '../checks/check-confirm-dialog.js';\nimport { useNoticeSink } from '../forms/success-notices.js';\nimport { reasonText } from '../lib/reason-text.js';\nimport { toast } from '../notification/toaster.js';\nimport { type FlowChrome, useFlowChrome, useFlowDialogTexts } from './chrome.js';\n\nconst NO_ISSUES: readonly ValidationIssue[] = Object.freeze([]);\n\n/**\n * Runs a flow from its control (4.15): a flow with a host presents it and the interaction ends\n * when it closes; a `{ label, submit }` flow sends, asks through the confirm dialog when\n * `confirm` or a fired warning asks, and shows `rejected`, `failed` and `unknown` in the flow's\n * screen in a dialog (`success` notifies through the flow's `then` and shows the write's notices; a lock another tab holds\n * says so; an `unavailable` send toasts the run's reason). `launch()` settles when the interaction is over.\n */\nfunction useFlowLauncher(\n flow: UseFlowRunResult,\n host: FlowHostControl,\n chrome: FlowChrome,\n resource: string,\n testid: string,\n): { readonly launch: () => Promise<void>; readonly dialog: ReactElement | null } {\n const t = useOptionalT();\n // An app flow's reason resolves app-wide: it has no resource bundle of its own.\n const own = resource === APP_ACTION_RESOURCE ? undefined : resource;\n const caps = useI18nCaps(own);\n // The write's own notices (spec 4.7): a host-less flow mounts no flow screen to show them, so\n // the launcher shows them through the same sink the flow screen uses.\n const showNotices = useNoticeSink(own);\n const [confirming, setConfirming] = useState(false);\n const decide = useRef<((proceed: boolean) => void) | null>(null);\n const latest = useRef(flow);\n latest.current = flow;\n useEffect(\n () => () => {\n decide.current?.(false);\n decide.current = null;\n },\n [],\n );\n\n const launch = useCallback(async (): Promise<void> => {\n const { run, compiled } = latest.current;\n if (run === null || compiled === null) return;\n if (compiled.hasHost) {\n await (host.open() ?? Promise.resolve());\n return;\n }\n let result: FlowResult = await run.submit();\n while (result.outcome === 'halted' && (result.step === 'accept' || result.step === 'review')) {\n setConfirming(true);\n const proceed = await new Promise<boolean>((resolve) => {\n decide.current = resolve;\n });\n decide.current = null;\n setConfirming(false);\n if (!proceed) {\n run.startOver();\n return;\n }\n result = await run.accept();\n }\n if (result.outcome === 'success') {\n const { notices } = run.getSnapshot();\n if (notices.length > 0) showNotices(notices);\n return;\n }\n // Another tab holds the attempt's lock: nothing was sent (4.10).\n if (result.outcome === 'failed' && 'reason' in result && result.reason === 'busy') {\n toast(t('flow.busyElsewhere', { defaultValue: 'This action is running in another tab.' }));\n return;\n }\n // The send found the flow unavailable (a check that runs at submit, access revoked since the\n // click): the run's reason, as a refusal before the click shows it.\n if (result.outcome === 'unavailable') {\n const reason = run.getSnapshot().reason;\n toast(\n reason === undefined\n ? t('availability.denied', { defaultValue: \"This action isn't available\" })\n : reasonText(caps, reason, own),\n );\n return;\n }\n if (\n result.outcome === 'rejected' ||\n result.outcome === 'failed' ||\n result.outcome === 'unknown' ||\n (result.outcome === 'halted' && result.step === 'outcome')\n )\n await (host.open('dialog') ?? Promise.resolve());\n }, [host, t, caps, own, showNotices]);\n\n const { snapshot, compiled } = flow;\n const gate: CheckGateState = {\n resource,\n open: confirming,\n busy: false,\n header: null,\n blockers: NO_ISSUES,\n confirmable: confirming\n ? snapshot.warnings.map(\n (warning): ValidationIssue => ({\n code: 'check.warning',\n // The machine's text (bundle and params resolved); the key is the check's.\n message: {\n ...toMessageRef(warning.message, `checks.${warning.id}`),\n // The run's text is final (bundle and params resolved): the dialog shows it as is.\n params: { resolved: true },\n },\n path: [],\n check: { id: warning.id },\n source: 'check',\n severity: 'warning',\n }),\n )\n : NO_ISSUES,\n proceed: () => decide.current?.(true),\n cancel: () => decide.current?.(false),\n };\n const dialog =\n compiled === null || compiled.hasHost ? null : (\n <CheckConfirmDialog\n state={gate}\n testid={`${testid}:confirm`}\n title={chrome.confirmTitle}\n proceedLabel={chrome.confirmProceed}\n {...(chrome.dismiss === undefined ? {} : { cancelLabel: chrome.dismiss })}\n tone={chrome.destructive ? 'destructive' : 'default'}\n />\n );\n return { launch, dialog };\n}\n\nexport interface FlowRunnerProps {\n readonly resource: string;\n readonly actionName: string;\n readonly record?: Row;\n readonly scope: string;\n /** The interaction is over (the host closed, the write answered, the confirm was declined). */\n readonly onClose: () => void;\n}\n\n/**\n * @internal A flow started from a control that holds no run — a row's button, a menu item\n * (4.15: a menu item \"presents its host through the runtime from `onSelect`, so the menu closes\n * normally\"). It renders no control: it starts the run (its `with` sources load now) and, once\n * the run has decided, presents the host or sends; `onClose` reports the end of the\n * interaction. A run that decides against the click (a check over a `with` source fired) says\n * why.\n */\nexport function FlowRunner({\n resource,\n actionName,\n record,\n scope,\n onClose,\n}: FlowRunnerProps): ReactElement | null {\n const target = useMemo(() => ({ resource, action: actionName }), [resource, actionName]);\n const flow = useFlowRun(target, {\n ...(record === undefined ? {} : { record }),\n surface: scope === 'row' ? 'row' : 'menu',\n });\n const chrome = useFlowChrome(resource, actionName);\n const recordKey = recordKeyOf(useApp().registry.get(resource), record);\n const title = useProjectedTitle(resource, recordKey, record);\n const host = useFlowHost(flow, {\n label: chrome.labelText,\n ...(record === undefined || title === '' ? {} : { title }),\n ...(record === undefined ? {} : { record }),\n });\n const tid = useTestIds();\n const t = useOptionalT();\n const caps = useI18nCaps(resource);\n const testid = makeTestId(scope, resource, actionName, String(recordKey ?? ''), tid);\n const { launch, dialog } = useFlowLauncher(flow, host, chrome, resource, testid);\n const started = useRef(false);\n const onCloseRef = useRef(onClose);\n onCloseRef.current = onClose;\n const { snapshot, compiled } = flow;\n const decided =\n compiled !== null &&\n (snapshot.control === 'disabled' ||\n snapshot.control === 'absent' ||\n (snapshot.control === 'ready' &&\n (!compiled.hasHost || snapshot.history.includes('open') || snapshot.step === 'outcome')));\n useEffect(() => {\n if (!decided || started.current) return;\n started.current = true;\n if (snapshot.control !== 'ready') {\n toast(\n snapshot.reason === undefined\n ? t('availability.denied', { defaultValue: \"This action isn't available\" })\n : reasonText(caps, snapshot.reason, resource),\n );\n onCloseRef.current();\n return;\n }\n void launch().finally(() => onCloseRef.current());\n }, [decided, snapshot.control, snapshot.reason, launch, t, caps]);\n return dialog;\n}\n\nexport interface AppFlowRunnerProps {\n /** The app action's name (`defineAppAction({ name, kind: 'flow' })`). */\n readonly name: string;\n /** Its label, as the opener resolved it (`appActions.<name>` over the declared default). */\n readonly label: string;\n /** The opener's test id: the confirm dialog's ids suffix it (`<testid>:confirm:…`). */\n readonly testid: string;\n readonly onClose: () => void;\n}\n\n/**\n * @internal An app flow started from its control (`AppFlowButton`, P4-D): the same launcher as a\n * resource flow's — the host when the flow has a form or a review, else the send with the\n * confirm dialog — over the target `{ appAction: name }`, with no record.\n */\nexport function AppFlowRunner({\n name,\n label,\n testid,\n onClose,\n}: AppFlowRunnerProps): ReactElement | null {\n const target = useMemo(() => ({ appAction: name }), [name]);\n const flow = useFlowRun(target, { surface: 'app' });\n const dialogTexts = useFlowDialogTexts('', name, label);\n const chrome: FlowChrome = {\n label,\n labelText: label,\n icon: undefined,\n destructive: false,\n ...dialogTexts,\n };\n const host = useFlowHost(flow, { label });\n const t = useOptionalT();\n const caps = useI18nCaps();\n const { launch, dialog } = useFlowLauncher(flow, host, chrome, APP_ACTION_RESOURCE, testid);\n const started = useRef(false);\n const onCloseRef = useRef(onClose);\n onCloseRef.current = onClose;\n const { snapshot, compiled } = flow;\n const decided =\n compiled !== null &&\n (snapshot.control === 'disabled' ||\n snapshot.control === 'absent' ||\n (snapshot.control === 'ready' &&\n (!compiled.hasHost || snapshot.history.includes('open') || snapshot.step === 'outcome')));\n useEffect(() => {\n if (!decided || started.current) return;\n started.current = true;\n if (snapshot.control !== 'ready') {\n toast(\n snapshot.reason === undefined\n ? t('availability.denied', { defaultValue: \"This action isn't available\" })\n : reasonText(caps, snapshot.reason),\n );\n onCloseRef.current();\n return;\n }\n void launch().finally(() => onCloseRef.current());\n }, [decided, snapshot.control, snapshot.reason, launch, t, caps]);\n return dialog;\n}\n\nexport interface BulkFlowRunnerProps {\n readonly resource: string;\n readonly actionName: string;\n readonly ids: readonly string[];\n /** The run is over: its result and its per-id report (absent when nothing was sent). */\n readonly onFinish: (result: FlowResult, progress: BulkProgress | undefined) => void;\n}\n\n/**\n * @internal A bulk flow's run over the selection (4.16), started by the bar's click: the confirm\n * (`confirm` and the fired warnings) asks through the confirm dialog, then the run (re-reading the\n * rows first where the flow declares `submit.reread`) writes each under its own key; `onFinish` reports the result and the per-id report.\n */\nexport function BulkFlowRunner({\n resource,\n actionName,\n ids,\n onFinish,\n}: BulkFlowRunnerProps): ReactElement | null {\n const tid = useTestIds();\n const t = useOptionalT();\n const caps = useI18nCaps(resource);\n const idsKey = ids.join('\\u0000');\n // biome-ignore lint/correctness/useExhaustiveDependencies: keyed by the ids' values\n const selection = useMemo(() => ({ ids: [...ids], count: ids.length }), [idsKey]);\n const target = useMemo(() => ({ resource, action: actionName }), [resource, actionName]);\n const flow = useFlowRun(target, { selection, surface: 'bulk' });\n const chrome = useFlowChrome(resource, actionName);\n const testid = tid.bulkAction(resource, actionName);\n const [confirming, setConfirming] = useState(false);\n const decide = useRef<((proceed: boolean) => void) | null>(null);\n const started = useRef(false);\n const onFinishRef = useRef(onFinish);\n onFinishRef.current = onFinish;\n const { run, snapshot } = flow;\n useEffect(\n () => () => {\n decide.current?.(false);\n decide.current = null;\n },\n [],\n );\n const decided =\n run !== null && snapshot.control !== 'undecided' && snapshot.control !== 'pending';\n useEffect(() => {\n if (!decided || started.current || run === null) return;\n started.current = true;\n void (async () => {\n if (run.getSnapshot().control !== 'ready') {\n const refusal = run.getSnapshot().reason;\n toast(\n refusal === undefined\n ? t('availability.denied', { defaultValue: \"This action isn't available\" })\n : reasonText(caps, refusal, resource),\n );\n onFinishRef.current(\n Object.freeze({ outcome: 'unavailable', state: 'disabled' }),\n undefined,\n );\n return;\n }\n let result = await run.submit();\n while (\n result.outcome === 'halted' &&\n (result.step === 'accept' || result.step === 'review')\n ) {\n setConfirming(true);\n const proceed = await new Promise<boolean>((resolve) => {\n decide.current = resolve;\n });\n decide.current = null;\n setConfirming(false);\n if (!proceed) {\n run.startOver();\n onFinishRef.current(result, undefined);\n return;\n }\n result = await run.accept();\n }\n if (result.outcome === 'failed' && 'reason' in result && result.reason === 'busy')\n toast(t('flow.busyElsewhere', { defaultValue: 'This action is running in another tab.' }));\n onFinishRef.current(result, run.getSnapshot().bulk);\n })();\n }, [decided, run, t, caps, resource]);\n const gate: CheckGateState = {\n resource,\n open: confirming,\n busy: false,\n header: null,\n blockers: NO_ISSUES,\n confirmable: confirming\n ? snapshot.warnings.map(\n (warning): ValidationIssue => ({\n code: 'check.warning',\n // The machine's text (bundle and params resolved); the key is the check's.\n message: {\n ...toMessageRef(\n warning.rows === undefined\n ? warning.message\n : `${warning.message} — ${t('flow.bulkWarningRows', {\n defaultValue: warning.rows === 1 ? '1 row' : `${warning.rows} rows`,\n count: warning.rows,\n })}`,\n `checks.${warning.id}`,\n ),\n // The run's text is final (bundle and params resolved): the dialog shows it as is.\n params: { resolved: true },\n },\n path: [],\n check: { id: warning.id },\n source: 'check',\n severity: 'warning',\n }),\n )\n : NO_ISSUES,\n proceed: () => decide.current?.(true),\n cancel: () => decide.current?.(false),\n };\n return (\n <CheckConfirmDialog\n state={gate}\n testid={`${testid}:confirm`}\n title={chrome.confirmTitle}\n proceedLabel={chrome.confirmProceed}\n {...(chrome.dismiss === undefined ? {} : { cancelLabel: chrome.dismiss })}\n tone={chrome.destructive ? 'destructive' : 'default'}\n />\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"flow-runtime-CQ4wf8co.cjs","names":["useOptionalT","APP_ACTION_RESOURCE","useI18nCaps","useNoticeSink","useState","useRef","useCallback","reasonText","toMessageRef","CheckConfirmDialog","useMemo","useFlowRun","useFlowChrome","recordKeyOf","useApp","useProjectedTitle","useFlowHost","useTestIds","makeTestId","useFlowDialogTexts"],"sources":["../src/flows/flow-runtime.tsx"],"sourcesContent":["'use client';\n/**\n * The flow runtime's side of the UI kit (P4, the coordinator's ruling on the bundle): every\n * component that holds a run. It loads on the first sign that a user means to run a flow (a\n * hover, a focus, a menu opening, at the latest the click) through `./load-runtime.js`, and with\n * it `@burojs/react/flows` and `@burojs/core/flows` — the flow machine stays out of an\n * application's first screen.\n */\nimport { toMessageRef } from '@burojs/core/internal';\nimport {\n APP_ACTION_RESOURCE,\n type BulkProgress,\n type FlowControlState,\n type FlowResult,\n type Row,\n type ValidationIssue,\n} from '@burojs/core';\nimport {\n type CheckGateState,\n recordKeyOf,\n useApp,\n useI18nCaps,\n useOptionalT,\n useProjectedTitle,\n useTestIds,\n} from '@burojs/react';\nimport {\n type FlowHostControl,\n type UseFlowRunResult,\n useFlowHost,\n useFlowRun,\n} from '@burojs/react/flows';\nimport { type ReactElement, useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { makeTestId } from '../actions/action-button.js';\nimport { CheckConfirmDialog } from '../checks/check-confirm-dialog.js';\nimport { useNoticeSink } from '../forms/success-notices.js';\nimport { reasonText } from '../lib/reason-text.js';\nimport { toast } from '../notification/toaster.js';\nimport { type FlowChrome, useFlowChrome, useFlowDialogTexts } from './chrome.js';\n\nconst NO_ISSUES: readonly ValidationIssue[] = Object.freeze([]);\n\n/**\n * Runs a flow from its control (4.15): a flow with a host presents it and the interaction ends\n * when it closes; a `{ label, submit }` flow sends, asks through the confirm dialog when\n * `confirm` or a fired warning asks, and shows `rejected`, `failed` and `unknown` in the flow's\n * screen in a dialog (`success` notifies through the flow's `then` and shows the write's notices; a lock another tab holds\n * says so; an `unavailable` send toasts the run's reason). `launch()` settles when the interaction is over.\n */\nfunction useFlowLauncher(\n flow: UseFlowRunResult,\n host: FlowHostControl,\n chrome: FlowChrome,\n resource: string,\n testid: string,\n): { readonly launch: () => Promise<void>; readonly dialog: ReactElement | null } {\n const t = useOptionalT();\n // An app flow's reason resolves app-wide: it has no resource bundle of its own.\n const own = resource === APP_ACTION_RESOURCE ? undefined : resource;\n const caps = useI18nCaps(own);\n // The write's own notices (spec 4.7): a host-less flow mounts no flow screen to show them, so\n // the launcher shows them through the same sink the flow screen uses.\n const showNotices = useNoticeSink(own);\n const [confirming, setConfirming] = useState(false);\n const decide = useRef<((proceed: boolean) => void) | null>(null);\n const latest = useRef(flow);\n latest.current = flow;\n useEffect(\n () => () => {\n decide.current?.(false);\n decide.current = null;\n },\n [],\n );\n\n const launch = useCallback(async (): Promise<void> => {\n const { run, compiled } = latest.current;\n if (run === null || compiled === null) return;\n if (compiled.hasHost) {\n await (host.open() ?? Promise.resolve());\n return;\n }\n let result: FlowResult = await run.submit();\n while (result.outcome === 'halted' && (result.step === 'accept' || result.step === 'review')) {\n setConfirming(true);\n const proceed = await new Promise<boolean>((resolve) => {\n decide.current = resolve;\n });\n decide.current = null;\n setConfirming(false);\n if (!proceed) {\n run.startOver();\n return;\n }\n result = await run.accept();\n }\n if (result.outcome === 'success') {\n const { notices } = run.getSnapshot();\n if (notices.length > 0) showNotices(notices);\n return;\n }\n // Another tab holds the attempt's lock: nothing was sent (4.10).\n if (result.outcome === 'failed' && 'reason' in result && result.reason === 'busy') {\n toast(t('flow.busyElsewhere', { defaultValue: 'This action is running in another tab.' }));\n return;\n }\n // The send found the flow unavailable (a check that runs at submit, access revoked since the\n // click): the run's reason, as a refusal before the click shows it.\n if (result.outcome === 'unavailable') {\n const reason = run.getSnapshot().reason;\n toast(\n reason === undefined\n ? t('availability.denied', { defaultValue: \"This action isn't available\" })\n : reasonText(caps, reason, own),\n );\n return;\n }\n if (\n result.outcome === 'rejected' ||\n result.outcome === 'failed' ||\n result.outcome === 'unknown' ||\n (result.outcome === 'halted' && result.step === 'outcome')\n )\n await (host.open('dialog') ?? Promise.resolve());\n }, [host, t, caps, own, showNotices]);\n\n const { snapshot, compiled } = flow;\n const gate: CheckGateState = {\n resource,\n open: confirming,\n busy: false,\n header: null,\n blockers: NO_ISSUES,\n confirmable: confirming\n ? snapshot.warnings.map(\n (warning): ValidationIssue => ({\n code: 'check.warning',\n // The machine's text (bundle and params resolved); the key is the check's.\n message: {\n ...toMessageRef(warning.message, `checks.${warning.id}`),\n // The run's text is final (bundle and params resolved): the dialog shows it as is.\n params: { resolved: true },\n },\n path: [],\n check: { id: warning.id },\n source: 'check',\n severity: 'warning',\n }),\n )\n : NO_ISSUES,\n proceed: () => decide.current?.(true),\n cancel: () => decide.current?.(false),\n };\n const dialog =\n compiled === null || compiled.hasHost ? null : (\n <CheckConfirmDialog\n state={gate}\n testid={`${testid}:confirm`}\n title={chrome.confirmTitle}\n proceedLabel={chrome.confirmProceed}\n {...(chrome.dismiss === undefined ? {} : { cancelLabel: chrome.dismiss })}\n tone={chrome.destructive ? 'destructive' : 'default'}\n />\n );\n return { launch, dialog };\n}\n\nexport interface FlowRunnerProps {\n readonly resource: string;\n readonly actionName: string;\n readonly record?: Row;\n readonly scope: string;\n /** The interaction is over (the host closed, the write answered, the confirm was declined). */\n readonly onClose: () => void;\n}\n\n/**\n * @internal A flow started from a control that holds no run — a row's button, a menu item\n * (4.15: a menu item \"presents its host through the runtime from `onSelect`, so the menu closes\n * normally\"). It renders no control: it starts the run (its `with` sources load now) and, once\n * the run has decided, presents the host or sends; `onClose` reports the end of the\n * interaction. A run that decides against the click (a check over a `with` source fired) says\n * why.\n */\nexport function FlowRunner({\n resource,\n actionName,\n record,\n scope,\n onClose,\n}: FlowRunnerProps): ReactElement | null {\n const target = useMemo(() => ({ resource, action: actionName }), [resource, actionName]);\n const flow = useFlowRun(target, {\n ...(record === undefined ? {} : { record }),\n surface: scope === 'row' ? 'row' : 'menu',\n });\n const chrome = useFlowChrome(resource, actionName);\n const recordKey = recordKeyOf(useApp().registry.get(resource), record);\n const title = useProjectedTitle(resource, recordKey, record);\n const host = useFlowHost(flow, {\n label: chrome.labelText,\n ...(record === undefined || title === '' ? {} : { title }),\n ...(record === undefined ? {} : { record }),\n });\n const tid = useTestIds();\n const t = useOptionalT();\n const caps = useI18nCaps(resource);\n const testid = makeTestId(scope, resource, actionName, String(recordKey ?? ''), tid);\n const { launch, dialog } = useFlowLauncher(flow, host, chrome, resource, testid);\n const started = useRef(false);\n const onCloseRef = useRef(onClose);\n onCloseRef.current = onClose;\n const { snapshot, compiled } = flow;\n const decided =\n compiled !== null &&\n (snapshot.control === 'disabled' ||\n snapshot.control === 'absent' ||\n (snapshot.control === 'ready' &&\n (!compiled.hasHost || snapshot.history.includes('open') || snapshot.step === 'outcome')));\n useEffect(() => {\n if (!decided || started.current) return;\n started.current = true;\n if (snapshot.control !== 'ready') {\n toast(\n snapshot.reason === undefined\n ? t('availability.denied', { defaultValue: \"This action isn't available\" })\n : reasonText(caps, snapshot.reason, resource),\n );\n onCloseRef.current();\n return;\n }\n void launch().finally(() => onCloseRef.current());\n }, [decided, snapshot.control, snapshot.reason, launch, t, caps]);\n return dialog;\n}\n\nexport interface AppFlowRunnerProps {\n /** The app action's name (`defineAppAction({ name, kind: 'flow' })`). */\n readonly name: string;\n /** Its label, as the opener resolved it (`appActions.<name>` over the declared default). */\n readonly label: string;\n /** The opener's test id: the confirm dialog's ids suffix it (`<testid>:confirm:…`). */\n readonly testid: string;\n readonly onClose: () => void;\n}\n\n/**\n * @internal An app flow started from its control (`AppFlowButton`, P4-D): the same launcher as a\n * resource flow's — the host when the flow has a form or a review, else the send with the\n * confirm dialog — over the target `{ appAction: name }`, with no record.\n */\nexport function AppFlowRunner({\n name,\n label,\n testid,\n onClose,\n}: AppFlowRunnerProps): ReactElement | null {\n const target = useMemo(() => ({ appAction: name }), [name]);\n const flow = useFlowRun(target, { surface: 'app' });\n const dialogTexts = useFlowDialogTexts('', name, label);\n const chrome: FlowChrome = {\n label,\n labelText: label,\n icon: undefined,\n destructive: false,\n ...dialogTexts,\n };\n const host = useFlowHost(flow, { label });\n const t = useOptionalT();\n const caps = useI18nCaps();\n const { launch, dialog } = useFlowLauncher(flow, host, chrome, APP_ACTION_RESOURCE, testid);\n const started = useRef(false);\n const onCloseRef = useRef(onClose);\n onCloseRef.current = onClose;\n const { snapshot, compiled } = flow;\n const decided =\n compiled !== null &&\n (snapshot.control === 'disabled' ||\n snapshot.control === 'absent' ||\n (snapshot.control === 'ready' &&\n (!compiled.hasHost || snapshot.history.includes('open') || snapshot.step === 'outcome')));\n useEffect(() => {\n if (!decided || started.current) return;\n started.current = true;\n if (snapshot.control !== 'ready') {\n toast(\n snapshot.reason === undefined\n ? t('availability.denied', { defaultValue: \"This action isn't available\" })\n : reasonText(caps, snapshot.reason),\n );\n onCloseRef.current();\n return;\n }\n void launch().finally(() => onCloseRef.current());\n }, [decided, snapshot.control, snapshot.reason, launch, t, caps]);\n return dialog;\n}\n\nexport interface BulkFlowRunnerProps {\n readonly resource: string;\n readonly actionName: string;\n readonly ids: readonly string[];\n /** The run is over: its result and its per-id report (absent when nothing was sent). */\n readonly onFinish: (result: FlowResult, progress: BulkProgress | undefined) => void;\n}\n\n/**\n * @internal A bulk flow's run over the selection (4.16), started by the bar's click: the confirm\n * (`confirm` and the fired warnings) asks through the confirm dialog, then the run (re-reading the\n * rows first where the flow declares `submit.reread`) writes each under its own key; `onFinish` reports the result and the per-id report.\n */\nexport function BulkFlowRunner({\n resource,\n actionName,\n ids,\n onFinish,\n}: BulkFlowRunnerProps): ReactElement | null {\n const tid = useTestIds();\n const t = useOptionalT();\n const caps = useI18nCaps(resource);\n const idsKey = ids.join('\\u0000');\n // biome-ignore lint/correctness/useExhaustiveDependencies: keyed by the ids' values\n const selection = useMemo(() => ({ ids: [...ids], count: ids.length }), [idsKey]);\n const target = useMemo(() => ({ resource, action: actionName }), [resource, actionName]);\n const flow = useFlowRun(target, { selection, surface: 'bulk' });\n const chrome = useFlowChrome(resource, actionName);\n const testid = tid.bulkAction(resource, actionName);\n const [confirming, setConfirming] = useState(false);\n const decide = useRef<((proceed: boolean) => void) | null>(null);\n const started = useRef(false);\n const onFinishRef = useRef(onFinish);\n onFinishRef.current = onFinish;\n const { run, snapshot } = flow;\n useEffect(\n () => () => {\n decide.current?.(false);\n decide.current = null;\n },\n [],\n );\n const decided =\n run !== null && snapshot.control !== 'undecided' && snapshot.control !== 'pending';\n useEffect(() => {\n if (!decided || started.current || run === null) return;\n started.current = true;\n void (async () => {\n if (run.getSnapshot().control !== 'ready') {\n const refusal = run.getSnapshot().reason;\n toast(\n refusal === undefined\n ? t('availability.denied', { defaultValue: \"This action isn't available\" })\n : reasonText(caps, refusal, resource),\n );\n onFinishRef.current(\n Object.freeze({ outcome: 'unavailable', state: 'disabled' }),\n undefined,\n );\n return;\n }\n let result = await run.submit();\n while (\n result.outcome === 'halted' &&\n (result.step === 'accept' || result.step === 'review')\n ) {\n setConfirming(true);\n const proceed = await new Promise<boolean>((resolve) => {\n decide.current = resolve;\n });\n decide.current = null;\n setConfirming(false);\n if (!proceed) {\n run.startOver();\n onFinishRef.current(result, undefined);\n return;\n }\n result = await run.accept();\n }\n if (result.outcome === 'failed' && 'reason' in result && result.reason === 'busy')\n toast(t('flow.busyElsewhere', { defaultValue: 'This action is running in another tab.' }));\n onFinishRef.current(result, run.getSnapshot().bulk);\n })();\n }, [decided, run, t, caps, resource]);\n const gate: CheckGateState = {\n resource,\n open: confirming,\n busy: false,\n header: null,\n blockers: NO_ISSUES,\n confirmable: confirming\n ? snapshot.warnings.map(\n (warning): ValidationIssue => ({\n code: 'check.warning',\n // The machine's text (bundle and params resolved); the key is the check's.\n message: {\n ...toMessageRef(\n warning.rows === undefined\n ? warning.message\n : `${warning.message} — ${t('flow.bulkWarningRows', {\n defaultValue: warning.rows === 1 ? '1 row' : `${warning.rows} rows`,\n count: warning.rows,\n })}`,\n `checks.${warning.id}`,\n ),\n // The run's text is final (bundle and params resolved): the dialog shows it as is.\n params: { resolved: true },\n },\n path: [],\n check: { id: warning.id },\n source: 'check',\n severity: 'warning',\n }),\n )\n : NO_ISSUES,\n proceed: () => decide.current?.(true),\n cancel: () => decide.current?.(false),\n };\n return (\n <CheckConfirmDialog\n state={gate}\n testid={`${testid}:confirm`}\n title={chrome.confirmTitle}\n proceedLabel={chrome.confirmProceed}\n {...(chrome.dismiss === undefined ? {} : { cancelLabel: chrome.dismiss })}\n tone={chrome.destructive ? 'destructive' : 'default'}\n />\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as toast } from "./toaster-Ct_YHGs6.js";
|
|
2
|
-
import { a as makeTestId, g as useFlowDialogTexts, h as useFlowChrome, t as CheckConfirmDialog, v as reasonText } from "./check-confirm-dialog-
|
|
2
|
+
import { a as makeTestId, g as useFlowDialogTexts, h as useFlowChrome, t as CheckConfirmDialog, v as reasonText } from "./check-confirm-dialog-B_u3YVHS.js";
|
|
3
3
|
import { t as useNoticeSink } from "./success-notices-CrcWOGSo.js";
|
|
4
4
|
import { APP_ACTION_RESOURCE } from "@burojs/core";
|
|
5
5
|
import { recordKeyOf, useApp, useI18nCaps, useOptionalT, useProjectedTitle, useTestIds } from "@burojs/react";
|
|
@@ -284,4 +284,4 @@ function BulkFlowRunner({ resource, actionName, ids, onFinish }) {
|
|
|
284
284
|
//#endregion
|
|
285
285
|
export { AppFlowRunner, BulkFlowRunner, FlowRunner };
|
|
286
286
|
|
|
287
|
-
//# sourceMappingURL=flow-runtime-
|
|
287
|
+
//# sourceMappingURL=flow-runtime-Q2vD7R3c.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flow-runtime-BEIyym7d.js","names":[],"sources":["../src/flows/flow-runtime.tsx"],"sourcesContent":["'use client';\n/**\n * The flow runtime's side of the UI kit (P4, the coordinator's ruling on the bundle): every\n * component that holds a run. It loads on the first sign that a user means to run a flow (a\n * hover, a focus, a menu opening, at the latest the click) through `./load-runtime.js`, and with\n * it `@burojs/react/flows` and `@burojs/core/flows` — the flow machine stays out of an\n * application's first screen.\n */\nimport { toMessageRef } from '@burojs/core/internal';\nimport {\n APP_ACTION_RESOURCE,\n type BulkProgress,\n type FlowControlState,\n type FlowResult,\n type Row,\n type ValidationIssue,\n} from '@burojs/core';\nimport {\n type CheckGateState,\n recordKeyOf,\n useApp,\n useI18nCaps,\n useOptionalT,\n useProjectedTitle,\n useTestIds,\n} from '@burojs/react';\nimport {\n type FlowHostControl,\n type UseFlowRunResult,\n useFlowHost,\n useFlowRun,\n} from '@burojs/react/flows';\nimport { type ReactElement, useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { makeTestId } from '../actions/action-button.js';\nimport { CheckConfirmDialog } from '../checks/check-confirm-dialog.js';\nimport { useNoticeSink } from '../forms/success-notices.js';\nimport { reasonText } from '../lib/reason-text.js';\nimport { toast } from '../notification/toaster.js';\nimport { type FlowChrome, useFlowChrome, useFlowDialogTexts } from './chrome.js';\n\nconst NO_ISSUES: readonly ValidationIssue[] = Object.freeze([]);\n\n/**\n * Runs a flow from its control (4.15): a flow with a host presents it and the interaction ends\n * when it closes; a `{ label, submit }` flow sends, asks through the confirm dialog when\n * `confirm` or a fired warning asks, and shows `rejected`, `failed` and `unknown` in the flow's\n * screen in a dialog (`success` notifies through the flow's `then` and shows the write's notices; a lock another tab holds\n * says so; an `unavailable` send toasts the run's reason). `launch()` settles when the interaction is over.\n */\nfunction useFlowLauncher(\n flow: UseFlowRunResult,\n host: FlowHostControl,\n chrome: FlowChrome,\n resource: string,\n testid: string,\n): { readonly launch: () => Promise<void>; readonly dialog: ReactElement | null } {\n const t = useOptionalT();\n // An app flow's reason resolves app-wide: it has no resource bundle of its own.\n const own = resource === APP_ACTION_RESOURCE ? undefined : resource;\n const caps = useI18nCaps(own);\n // The write's own notices (spec 4.7): a host-less flow mounts no flow screen to show them, so\n // the launcher shows them through the same sink the flow screen uses.\n const showNotices = useNoticeSink(own);\n const [confirming, setConfirming] = useState(false);\n const decide = useRef<((proceed: boolean) => void) | null>(null);\n const latest = useRef(flow);\n latest.current = flow;\n useEffect(\n () => () => {\n decide.current?.(false);\n decide.current = null;\n },\n [],\n );\n\n const launch = useCallback(async (): Promise<void> => {\n const { run, compiled } = latest.current;\n if (run === null || compiled === null) return;\n if (compiled.hasHost) {\n await (host.open() ?? Promise.resolve());\n return;\n }\n let result: FlowResult = await run.submit();\n while (result.outcome === 'halted' && (result.step === 'accept' || result.step === 'review')) {\n setConfirming(true);\n const proceed = await new Promise<boolean>((resolve) => {\n decide.current = resolve;\n });\n decide.current = null;\n setConfirming(false);\n if (!proceed) {\n run.startOver();\n return;\n }\n result = await run.accept();\n }\n if (result.outcome === 'success') {\n const { notices } = run.getSnapshot();\n if (notices.length > 0) showNotices(notices);\n return;\n }\n // Another tab holds the attempt's lock: nothing was sent (4.10).\n if (result.outcome === 'failed' && 'reason' in result && result.reason === 'busy') {\n toast(t('flow.busyElsewhere', { defaultValue: 'This action is running in another tab.' }));\n return;\n }\n // The send found the flow unavailable (a check that runs at submit, access revoked since the\n // click): the run's reason, as a refusal before the click shows it.\n if (result.outcome === 'unavailable') {\n const reason = run.getSnapshot().reason;\n toast(\n reason === undefined\n ? t('availability.denied', { defaultValue: \"This action isn't available\" })\n : reasonText(caps, reason, own),\n );\n return;\n }\n if (\n result.outcome === 'rejected' ||\n result.outcome === 'failed' ||\n result.outcome === 'unknown' ||\n (result.outcome === 'halted' && result.step === 'outcome')\n )\n await (host.open('dialog') ?? Promise.resolve());\n }, [host, t, caps, own, showNotices]);\n\n const { snapshot, compiled } = flow;\n const gate: CheckGateState = {\n resource,\n open: confirming,\n busy: false,\n header: null,\n blockers: NO_ISSUES,\n confirmable: confirming\n ? snapshot.warnings.map(\n (warning): ValidationIssue => ({\n code: 'check.warning',\n // The machine's text (bundle and params resolved); the key is the check's.\n message: {\n ...toMessageRef(warning.message, `checks.${warning.id}`),\n // The run's text is final (bundle and params resolved): the dialog shows it as is.\n params: { resolved: true },\n },\n path: [],\n check: { id: warning.id },\n source: 'check',\n severity: 'warning',\n }),\n )\n : NO_ISSUES,\n proceed: () => decide.current?.(true),\n cancel: () => decide.current?.(false),\n };\n const dialog =\n compiled === null || compiled.hasHost ? null : (\n <CheckConfirmDialog\n state={gate}\n testid={`${testid}:confirm`}\n title={chrome.confirmTitle}\n proceedLabel={chrome.confirmProceed}\n {...(chrome.dismiss === undefined ? {} : { cancelLabel: chrome.dismiss })}\n tone={chrome.destructive ? 'destructive' : 'default'}\n />\n );\n return { launch, dialog };\n}\n\nexport interface FlowRunnerProps {\n readonly resource: string;\n readonly actionName: string;\n readonly record?: Row;\n readonly scope: string;\n /** The interaction is over (the host closed, the write answered, the confirm was declined). */\n readonly onClose: () => void;\n}\n\n/**\n * @internal A flow started from a control that holds no run — a row's button, a menu item\n * (4.15: a menu item \"presents its host through the runtime from `onSelect`, so the menu closes\n * normally\"). It renders no control: it starts the run (its `with` sources load now) and, once\n * the run has decided, presents the host or sends; `onClose` reports the end of the\n * interaction. A run that decides against the click (a check over a `with` source fired) says\n * why.\n */\nexport function FlowRunner({\n resource,\n actionName,\n record,\n scope,\n onClose,\n}: FlowRunnerProps): ReactElement | null {\n const target = useMemo(() => ({ resource, action: actionName }), [resource, actionName]);\n const flow = useFlowRun(target, {\n ...(record === undefined ? {} : { record }),\n surface: scope === 'row' ? 'row' : 'menu',\n });\n const chrome = useFlowChrome(resource, actionName);\n const recordKey = recordKeyOf(useApp().registry.get(resource), record);\n const title = useProjectedTitle(resource, recordKey, record);\n const host = useFlowHost(flow, {\n label: chrome.labelText,\n ...(record === undefined || title === '' ? {} : { title }),\n ...(record === undefined ? {} : { record }),\n });\n const tid = useTestIds();\n const t = useOptionalT();\n const caps = useI18nCaps(resource);\n const testid = makeTestId(scope, resource, actionName, String(recordKey ?? ''), tid);\n const { launch, dialog } = useFlowLauncher(flow, host, chrome, resource, testid);\n const started = useRef(false);\n const onCloseRef = useRef(onClose);\n onCloseRef.current = onClose;\n const { snapshot, compiled } = flow;\n const decided =\n compiled !== null &&\n (snapshot.control === 'disabled' ||\n snapshot.control === 'absent' ||\n (snapshot.control === 'ready' &&\n (!compiled.hasHost || snapshot.history.includes('open') || snapshot.step === 'outcome')));\n useEffect(() => {\n if (!decided || started.current) return;\n started.current = true;\n if (snapshot.control !== 'ready') {\n toast(\n snapshot.reason === undefined\n ? t('availability.denied', { defaultValue: \"This action isn't available\" })\n : reasonText(caps, snapshot.reason, resource),\n );\n onCloseRef.current();\n return;\n }\n void launch().finally(() => onCloseRef.current());\n }, [decided, snapshot.control, snapshot.reason, launch, t, caps]);\n return dialog;\n}\n\nexport interface AppFlowRunnerProps {\n /** The app action's name (`defineAppAction({ name, kind: 'flow' })`). */\n readonly name: string;\n /** Its label, as the opener resolved it (`appActions.<name>` over the declared default). */\n readonly label: string;\n /** The opener's test id: the confirm dialog's ids suffix it (`<testid>:confirm:…`). */\n readonly testid: string;\n readonly onClose: () => void;\n}\n\n/**\n * @internal An app flow started from its control (`AppFlowButton`, P4-D): the same launcher as a\n * resource flow's — the host when the flow has a form or a review, else the send with the\n * confirm dialog — over the target `{ appAction: name }`, with no record.\n */\nexport function AppFlowRunner({\n name,\n label,\n testid,\n onClose,\n}: AppFlowRunnerProps): ReactElement | null {\n const target = useMemo(() => ({ appAction: name }), [name]);\n const flow = useFlowRun(target, { surface: 'app' });\n const dialogTexts = useFlowDialogTexts('', name, label);\n const chrome: FlowChrome = {\n label,\n labelText: label,\n icon: undefined,\n destructive: false,\n ...dialogTexts,\n };\n const host = useFlowHost(flow, { label });\n const t = useOptionalT();\n const caps = useI18nCaps();\n const { launch, dialog } = useFlowLauncher(flow, host, chrome, APP_ACTION_RESOURCE, testid);\n const started = useRef(false);\n const onCloseRef = useRef(onClose);\n onCloseRef.current = onClose;\n const { snapshot, compiled } = flow;\n const decided =\n compiled !== null &&\n (snapshot.control === 'disabled' ||\n snapshot.control === 'absent' ||\n (snapshot.control === 'ready' &&\n (!compiled.hasHost || snapshot.history.includes('open') || snapshot.step === 'outcome')));\n useEffect(() => {\n if (!decided || started.current) return;\n started.current = true;\n if (snapshot.control !== 'ready') {\n toast(\n snapshot.reason === undefined\n ? t('availability.denied', { defaultValue: \"This action isn't available\" })\n : reasonText(caps, snapshot.reason),\n );\n onCloseRef.current();\n return;\n }\n void launch().finally(() => onCloseRef.current());\n }, [decided, snapshot.control, snapshot.reason, launch, t, caps]);\n return dialog;\n}\n\nexport interface BulkFlowRunnerProps {\n readonly resource: string;\n readonly actionName: string;\n readonly ids: readonly string[];\n /** The run is over: its result and its per-id report (absent when nothing was sent). */\n readonly onFinish: (result: FlowResult, progress: BulkProgress | undefined) => void;\n}\n\n/**\n * @internal A bulk flow's run over the selection (4.16), started by the bar's click: the confirm\n * (`confirm` and the fired warnings) asks through the confirm dialog, then the run (re-reading the\n * rows first where the flow declares `submit.reread`) writes each under its own key; `onFinish` reports the result and the per-id report.\n */\nexport function BulkFlowRunner({\n resource,\n actionName,\n ids,\n onFinish,\n}: BulkFlowRunnerProps): ReactElement | null {\n const tid = useTestIds();\n const t = useOptionalT();\n const caps = useI18nCaps(resource);\n const idsKey = ids.join('\\u0000');\n // biome-ignore lint/correctness/useExhaustiveDependencies: keyed by the ids' values\n const selection = useMemo(() => ({ ids: [...ids], count: ids.length }), [idsKey]);\n const target = useMemo(() => ({ resource, action: actionName }), [resource, actionName]);\n const flow = useFlowRun(target, { selection, surface: 'bulk' });\n const chrome = useFlowChrome(resource, actionName);\n const testid = tid.bulkAction(resource, actionName);\n const [confirming, setConfirming] = useState(false);\n const decide = useRef<((proceed: boolean) => void) | null>(null);\n const started = useRef(false);\n const onFinishRef = useRef(onFinish);\n onFinishRef.current = onFinish;\n const { run, snapshot } = flow;\n useEffect(\n () => () => {\n decide.current?.(false);\n decide.current = null;\n },\n [],\n );\n const decided =\n run !== null && snapshot.control !== 'undecided' && snapshot.control !== 'pending';\n useEffect(() => {\n if (!decided || started.current || run === null) return;\n started.current = true;\n void (async () => {\n if (run.getSnapshot().control !== 'ready') {\n const refusal = run.getSnapshot().reason;\n toast(\n refusal === undefined\n ? t('availability.denied', { defaultValue: \"This action isn't available\" })\n : reasonText(caps, refusal, resource),\n );\n onFinishRef.current(\n Object.freeze({ outcome: 'unavailable', state: 'disabled' }),\n undefined,\n );\n return;\n }\n let result = await run.submit();\n while (\n result.outcome === 'halted' &&\n (result.step === 'accept' || result.step === 'review')\n ) {\n setConfirming(true);\n const proceed = await new Promise<boolean>((resolve) => {\n decide.current = resolve;\n });\n decide.current = null;\n setConfirming(false);\n if (!proceed) {\n run.startOver();\n onFinishRef.current(result, undefined);\n return;\n }\n result = await run.accept();\n }\n if (result.outcome === 'failed' && 'reason' in result && result.reason === 'busy')\n toast(t('flow.busyElsewhere', { defaultValue: 'This action is running in another tab.' }));\n onFinishRef.current(result, run.getSnapshot().bulk);\n })();\n }, [decided, run, t, caps, resource]);\n const gate: CheckGateState = {\n resource,\n open: confirming,\n busy: false,\n header: null,\n blockers: NO_ISSUES,\n confirmable: confirming\n ? snapshot.warnings.map(\n (warning): ValidationIssue => ({\n code: 'check.warning',\n // The machine's text (bundle and params resolved); the key is the check's.\n message: {\n ...toMessageRef(\n warning.rows === undefined\n ? warning.message\n : `${warning.message} — ${t('flow.bulkWarningRows', {\n defaultValue: warning.rows === 1 ? '1 row' : `${warning.rows} rows`,\n count: warning.rows,\n })}`,\n `checks.${warning.id}`,\n ),\n // The run's text is final (bundle and params resolved): the dialog shows it as is.\n params: { resolved: true },\n },\n path: [],\n check: { id: warning.id },\n source: 'check',\n severity: 'warning',\n }),\n )\n : NO_ISSUES,\n proceed: () => decide.current?.(true),\n cancel: () => decide.current?.(false),\n };\n return (\n <CheckConfirmDialog\n state={gate}\n testid={`${testid}:confirm`}\n title={chrome.confirmTitle}\n proceedLabel={chrome.confirmProceed}\n {...(chrome.dismiss === undefined ? {} : { cancelLabel: chrome.dismiss })}\n tone={chrome.destructive ? 'destructive' : 'default'}\n />\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"flow-runtime-Q2vD7R3c.js","names":[],"sources":["../src/flows/flow-runtime.tsx"],"sourcesContent":["'use client';\n/**\n * The flow runtime's side of the UI kit (P4, the coordinator's ruling on the bundle): every\n * component that holds a run. It loads on the first sign that a user means to run a flow (a\n * hover, a focus, a menu opening, at the latest the click) through `./load-runtime.js`, and with\n * it `@burojs/react/flows` and `@burojs/core/flows` — the flow machine stays out of an\n * application's first screen.\n */\nimport { toMessageRef } from '@burojs/core/internal';\nimport {\n APP_ACTION_RESOURCE,\n type BulkProgress,\n type FlowControlState,\n type FlowResult,\n type Row,\n type ValidationIssue,\n} from '@burojs/core';\nimport {\n type CheckGateState,\n recordKeyOf,\n useApp,\n useI18nCaps,\n useOptionalT,\n useProjectedTitle,\n useTestIds,\n} from '@burojs/react';\nimport {\n type FlowHostControl,\n type UseFlowRunResult,\n useFlowHost,\n useFlowRun,\n} from '@burojs/react/flows';\nimport { type ReactElement, useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { makeTestId } from '../actions/action-button.js';\nimport { CheckConfirmDialog } from '../checks/check-confirm-dialog.js';\nimport { useNoticeSink } from '../forms/success-notices.js';\nimport { reasonText } from '../lib/reason-text.js';\nimport { toast } from '../notification/toaster.js';\nimport { type FlowChrome, useFlowChrome, useFlowDialogTexts } from './chrome.js';\n\nconst NO_ISSUES: readonly ValidationIssue[] = Object.freeze([]);\n\n/**\n * Runs a flow from its control (4.15): a flow with a host presents it and the interaction ends\n * when it closes; a `{ label, submit }` flow sends, asks through the confirm dialog when\n * `confirm` or a fired warning asks, and shows `rejected`, `failed` and `unknown` in the flow's\n * screen in a dialog (`success` notifies through the flow's `then` and shows the write's notices; a lock another tab holds\n * says so; an `unavailable` send toasts the run's reason). `launch()` settles when the interaction is over.\n */\nfunction useFlowLauncher(\n flow: UseFlowRunResult,\n host: FlowHostControl,\n chrome: FlowChrome,\n resource: string,\n testid: string,\n): { readonly launch: () => Promise<void>; readonly dialog: ReactElement | null } {\n const t = useOptionalT();\n // An app flow's reason resolves app-wide: it has no resource bundle of its own.\n const own = resource === APP_ACTION_RESOURCE ? undefined : resource;\n const caps = useI18nCaps(own);\n // The write's own notices (spec 4.7): a host-less flow mounts no flow screen to show them, so\n // the launcher shows them through the same sink the flow screen uses.\n const showNotices = useNoticeSink(own);\n const [confirming, setConfirming] = useState(false);\n const decide = useRef<((proceed: boolean) => void) | null>(null);\n const latest = useRef(flow);\n latest.current = flow;\n useEffect(\n () => () => {\n decide.current?.(false);\n decide.current = null;\n },\n [],\n );\n\n const launch = useCallback(async (): Promise<void> => {\n const { run, compiled } = latest.current;\n if (run === null || compiled === null) return;\n if (compiled.hasHost) {\n await (host.open() ?? Promise.resolve());\n return;\n }\n let result: FlowResult = await run.submit();\n while (result.outcome === 'halted' && (result.step === 'accept' || result.step === 'review')) {\n setConfirming(true);\n const proceed = await new Promise<boolean>((resolve) => {\n decide.current = resolve;\n });\n decide.current = null;\n setConfirming(false);\n if (!proceed) {\n run.startOver();\n return;\n }\n result = await run.accept();\n }\n if (result.outcome === 'success') {\n const { notices } = run.getSnapshot();\n if (notices.length > 0) showNotices(notices);\n return;\n }\n // Another tab holds the attempt's lock: nothing was sent (4.10).\n if (result.outcome === 'failed' && 'reason' in result && result.reason === 'busy') {\n toast(t('flow.busyElsewhere', { defaultValue: 'This action is running in another tab.' }));\n return;\n }\n // The send found the flow unavailable (a check that runs at submit, access revoked since the\n // click): the run's reason, as a refusal before the click shows it.\n if (result.outcome === 'unavailable') {\n const reason = run.getSnapshot().reason;\n toast(\n reason === undefined\n ? t('availability.denied', { defaultValue: \"This action isn't available\" })\n : reasonText(caps, reason, own),\n );\n return;\n }\n if (\n result.outcome === 'rejected' ||\n result.outcome === 'failed' ||\n result.outcome === 'unknown' ||\n (result.outcome === 'halted' && result.step === 'outcome')\n )\n await (host.open('dialog') ?? Promise.resolve());\n }, [host, t, caps, own, showNotices]);\n\n const { snapshot, compiled } = flow;\n const gate: CheckGateState = {\n resource,\n open: confirming,\n busy: false,\n header: null,\n blockers: NO_ISSUES,\n confirmable: confirming\n ? snapshot.warnings.map(\n (warning): ValidationIssue => ({\n code: 'check.warning',\n // The machine's text (bundle and params resolved); the key is the check's.\n message: {\n ...toMessageRef(warning.message, `checks.${warning.id}`),\n // The run's text is final (bundle and params resolved): the dialog shows it as is.\n params: { resolved: true },\n },\n path: [],\n check: { id: warning.id },\n source: 'check',\n severity: 'warning',\n }),\n )\n : NO_ISSUES,\n proceed: () => decide.current?.(true),\n cancel: () => decide.current?.(false),\n };\n const dialog =\n compiled === null || compiled.hasHost ? null : (\n <CheckConfirmDialog\n state={gate}\n testid={`${testid}:confirm`}\n title={chrome.confirmTitle}\n proceedLabel={chrome.confirmProceed}\n {...(chrome.dismiss === undefined ? {} : { cancelLabel: chrome.dismiss })}\n tone={chrome.destructive ? 'destructive' : 'default'}\n />\n );\n return { launch, dialog };\n}\n\nexport interface FlowRunnerProps {\n readonly resource: string;\n readonly actionName: string;\n readonly record?: Row;\n readonly scope: string;\n /** The interaction is over (the host closed, the write answered, the confirm was declined). */\n readonly onClose: () => void;\n}\n\n/**\n * @internal A flow started from a control that holds no run — a row's button, a menu item\n * (4.15: a menu item \"presents its host through the runtime from `onSelect`, so the menu closes\n * normally\"). It renders no control: it starts the run (its `with` sources load now) and, once\n * the run has decided, presents the host or sends; `onClose` reports the end of the\n * interaction. A run that decides against the click (a check over a `with` source fired) says\n * why.\n */\nexport function FlowRunner({\n resource,\n actionName,\n record,\n scope,\n onClose,\n}: FlowRunnerProps): ReactElement | null {\n const target = useMemo(() => ({ resource, action: actionName }), [resource, actionName]);\n const flow = useFlowRun(target, {\n ...(record === undefined ? {} : { record }),\n surface: scope === 'row' ? 'row' : 'menu',\n });\n const chrome = useFlowChrome(resource, actionName);\n const recordKey = recordKeyOf(useApp().registry.get(resource), record);\n const title = useProjectedTitle(resource, recordKey, record);\n const host = useFlowHost(flow, {\n label: chrome.labelText,\n ...(record === undefined || title === '' ? {} : { title }),\n ...(record === undefined ? {} : { record }),\n });\n const tid = useTestIds();\n const t = useOptionalT();\n const caps = useI18nCaps(resource);\n const testid = makeTestId(scope, resource, actionName, String(recordKey ?? ''), tid);\n const { launch, dialog } = useFlowLauncher(flow, host, chrome, resource, testid);\n const started = useRef(false);\n const onCloseRef = useRef(onClose);\n onCloseRef.current = onClose;\n const { snapshot, compiled } = flow;\n const decided =\n compiled !== null &&\n (snapshot.control === 'disabled' ||\n snapshot.control === 'absent' ||\n (snapshot.control === 'ready' &&\n (!compiled.hasHost || snapshot.history.includes('open') || snapshot.step === 'outcome')));\n useEffect(() => {\n if (!decided || started.current) return;\n started.current = true;\n if (snapshot.control !== 'ready') {\n toast(\n snapshot.reason === undefined\n ? t('availability.denied', { defaultValue: \"This action isn't available\" })\n : reasonText(caps, snapshot.reason, resource),\n );\n onCloseRef.current();\n return;\n }\n void launch().finally(() => onCloseRef.current());\n }, [decided, snapshot.control, snapshot.reason, launch, t, caps]);\n return dialog;\n}\n\nexport interface AppFlowRunnerProps {\n /** The app action's name (`defineAppAction({ name, kind: 'flow' })`). */\n readonly name: string;\n /** Its label, as the opener resolved it (`appActions.<name>` over the declared default). */\n readonly label: string;\n /** The opener's test id: the confirm dialog's ids suffix it (`<testid>:confirm:…`). */\n readonly testid: string;\n readonly onClose: () => void;\n}\n\n/**\n * @internal An app flow started from its control (`AppFlowButton`, P4-D): the same launcher as a\n * resource flow's — the host when the flow has a form or a review, else the send with the\n * confirm dialog — over the target `{ appAction: name }`, with no record.\n */\nexport function AppFlowRunner({\n name,\n label,\n testid,\n onClose,\n}: AppFlowRunnerProps): ReactElement | null {\n const target = useMemo(() => ({ appAction: name }), [name]);\n const flow = useFlowRun(target, { surface: 'app' });\n const dialogTexts = useFlowDialogTexts('', name, label);\n const chrome: FlowChrome = {\n label,\n labelText: label,\n icon: undefined,\n destructive: false,\n ...dialogTexts,\n };\n const host = useFlowHost(flow, { label });\n const t = useOptionalT();\n const caps = useI18nCaps();\n const { launch, dialog } = useFlowLauncher(flow, host, chrome, APP_ACTION_RESOURCE, testid);\n const started = useRef(false);\n const onCloseRef = useRef(onClose);\n onCloseRef.current = onClose;\n const { snapshot, compiled } = flow;\n const decided =\n compiled !== null &&\n (snapshot.control === 'disabled' ||\n snapshot.control === 'absent' ||\n (snapshot.control === 'ready' &&\n (!compiled.hasHost || snapshot.history.includes('open') || snapshot.step === 'outcome')));\n useEffect(() => {\n if (!decided || started.current) return;\n started.current = true;\n if (snapshot.control !== 'ready') {\n toast(\n snapshot.reason === undefined\n ? t('availability.denied', { defaultValue: \"This action isn't available\" })\n : reasonText(caps, snapshot.reason),\n );\n onCloseRef.current();\n return;\n }\n void launch().finally(() => onCloseRef.current());\n }, [decided, snapshot.control, snapshot.reason, launch, t, caps]);\n return dialog;\n}\n\nexport interface BulkFlowRunnerProps {\n readonly resource: string;\n readonly actionName: string;\n readonly ids: readonly string[];\n /** The run is over: its result and its per-id report (absent when nothing was sent). */\n readonly onFinish: (result: FlowResult, progress: BulkProgress | undefined) => void;\n}\n\n/**\n * @internal A bulk flow's run over the selection (4.16), started by the bar's click: the confirm\n * (`confirm` and the fired warnings) asks through the confirm dialog, then the run (re-reading the\n * rows first where the flow declares `submit.reread`) writes each under its own key; `onFinish` reports the result and the per-id report.\n */\nexport function BulkFlowRunner({\n resource,\n actionName,\n ids,\n onFinish,\n}: BulkFlowRunnerProps): ReactElement | null {\n const tid = useTestIds();\n const t = useOptionalT();\n const caps = useI18nCaps(resource);\n const idsKey = ids.join('\\u0000');\n // biome-ignore lint/correctness/useExhaustiveDependencies: keyed by the ids' values\n const selection = useMemo(() => ({ ids: [...ids], count: ids.length }), [idsKey]);\n const target = useMemo(() => ({ resource, action: actionName }), [resource, actionName]);\n const flow = useFlowRun(target, { selection, surface: 'bulk' });\n const chrome = useFlowChrome(resource, actionName);\n const testid = tid.bulkAction(resource, actionName);\n const [confirming, setConfirming] = useState(false);\n const decide = useRef<((proceed: boolean) => void) | null>(null);\n const started = useRef(false);\n const onFinishRef = useRef(onFinish);\n onFinishRef.current = onFinish;\n const { run, snapshot } = flow;\n useEffect(\n () => () => {\n decide.current?.(false);\n decide.current = null;\n },\n [],\n );\n const decided =\n run !== null && snapshot.control !== 'undecided' && snapshot.control !== 'pending';\n useEffect(() => {\n if (!decided || started.current || run === null) return;\n started.current = true;\n void (async () => {\n if (run.getSnapshot().control !== 'ready') {\n const refusal = run.getSnapshot().reason;\n toast(\n refusal === undefined\n ? t('availability.denied', { defaultValue: \"This action isn't available\" })\n : reasonText(caps, refusal, resource),\n );\n onFinishRef.current(\n Object.freeze({ outcome: 'unavailable', state: 'disabled' }),\n undefined,\n );\n return;\n }\n let result = await run.submit();\n while (\n result.outcome === 'halted' &&\n (result.step === 'accept' || result.step === 'review')\n ) {\n setConfirming(true);\n const proceed = await new Promise<boolean>((resolve) => {\n decide.current = resolve;\n });\n decide.current = null;\n setConfirming(false);\n if (!proceed) {\n run.startOver();\n onFinishRef.current(result, undefined);\n return;\n }\n result = await run.accept();\n }\n if (result.outcome === 'failed' && 'reason' in result && result.reason === 'busy')\n toast(t('flow.busyElsewhere', { defaultValue: 'This action is running in another tab.' }));\n onFinishRef.current(result, run.getSnapshot().bulk);\n })();\n }, [decided, run, t, caps, resource]);\n const gate: CheckGateState = {\n resource,\n open: confirming,\n busy: false,\n header: null,\n blockers: NO_ISSUES,\n confirmable: confirming\n ? snapshot.warnings.map(\n (warning): ValidationIssue => ({\n code: 'check.warning',\n // The machine's text (bundle and params resolved); the key is the check's.\n message: {\n ...toMessageRef(\n warning.rows === undefined\n ? warning.message\n : `${warning.message} — ${t('flow.bulkWarningRows', {\n defaultValue: warning.rows === 1 ? '1 row' : `${warning.rows} rows`,\n count: warning.rows,\n })}`,\n `checks.${warning.id}`,\n ),\n // The run's text is final (bundle and params resolved): the dialog shows it as is.\n params: { resolved: true },\n },\n path: [],\n check: { id: warning.id },\n source: 'check',\n severity: 'warning',\n }),\n )\n : NO_ISSUES,\n proceed: () => decide.current?.(true),\n cancel: () => decide.current?.(false),\n };\n return (\n <CheckConfirmDialog\n state={gate}\n testid={`${testid}:confirm`}\n title={chrome.confirmTitle}\n proceedLabel={chrome.confirmProceed}\n {...(chrome.dismiss === undefined ? {} : { cancelLabel: chrome.dismiss })}\n tone={chrome.destructive ? 'destructive' : 'default'}\n />\n );\n}\n"],"mappings":";;;;;;;;;;AAwCA,MAAM,YAAwC,OAAO,OAAO,CAAC,CAAC;AAS9D,SAAS,gBACP,MACA,MACA,QACA,UACA,QACgF;CAChF,MAAM,IAAI,aAAa;CAEvB,MAAM,MAAM,aAAa,sBAAsB,KAAA,IAAY;CAC3D,MAAM,OAAO,YAAY,GAAG;CAG5B,MAAM,cAAc,cAAc,GAAG;CACrC,MAAM,CAAC,YAAY,iBAAiB,SAAS,KAAK;CAClD,MAAM,SAAS,OAA4C,IAAI;CAC/D,MAAM,SAAS,OAAO,IAAI;CAC1B,OAAO,UAAU;CACjB,sBACc;EACV,OAAO,UAAU,KAAK;EACtB,OAAO,UAAU;CACnB,GACA,CAAC,CACH;CAEA,MAAM,SAAS,YAAY,YAA2B;EACpD,MAAM,EAAE,KAAK,aAAa,OAAO;EACjC,IAAI,QAAQ,QAAQ,aAAa,MAAM;EACvC,IAAI,SAAS,SAAS;GACpB,OAAO,KAAK,KAAK,KAAK,QAAQ,QAAQ;GACtC;EACF;EACA,IAAI,SAAqB,MAAM,IAAI,OAAO;EAC1C,OAAO,OAAO,YAAY,aAAa,OAAO,SAAS,YAAY,OAAO,SAAS,WAAW;GAC5F,cAAc,IAAI;GAClB,MAAM,UAAU,MAAM,IAAI,SAAkB,YAAY;IACtD,OAAO,UAAU;GACnB,CAAC;GACD,OAAO,UAAU;GACjB,cAAc,KAAK;GACnB,IAAI,CAAC,SAAS;IACZ,IAAI,UAAU;IACd;GACF;GACA,SAAS,MAAM,IAAI,OAAO;EAC5B;EACA,IAAI,OAAO,YAAY,WAAW;GAChC,MAAM,EAAE,YAAY,IAAI,YAAY;GACpC,IAAI,QAAQ,SAAS,GAAG,YAAY,OAAO;GAC3C;EACF;EAEA,IAAI,OAAO,YAAY,YAAY,YAAY,UAAU,OAAO,WAAW,QAAQ;GACjF,MAAM,EAAE,sBAAsB,EAAE,cAAc,yCAAyC,CAAC,CAAC;GACzF;EACF;EAGA,IAAI,OAAO,YAAY,eAAe;GACpC,MAAM,SAAS,IAAI,YAAY,CAAC,CAAC;GACjC,MACE,WAAW,KAAA,IACP,EAAE,uBAAuB,EAAE,cAAc,8BAA8B,CAAC,IACxE,WAAW,MAAM,QAAQ,GAAG,CAClC;GACA;EACF;EACA,IACE,OAAO,YAAY,cACnB,OAAO,YAAY,YACnB,OAAO,YAAY,aAClB,OAAO,YAAY,YAAY,OAAO,SAAS,WAEhD,OAAO,KAAK,KAAK,QAAQ,KAAK,QAAQ,QAAQ;CAClD,GAAG;EAAC;EAAM;EAAG;EAAM;EAAK;CAAW,CAAC;CAEpC,MAAM,EAAE,UAAU,aAAa;CAC/B,MAAM,OAAuB;EAC3B;EACA,MAAM;EACN,MAAM;EACN,QAAQ;EACR,UAAU;EACV,aAAa,aACT,SAAS,SAAS,KACf,aAA8B;GAC7B,MAAM;GAEN,SAAS;IACP,GAAG,aAAa,QAAQ,SAAS,UAAU,QAAQ,IAAI;IAEvD,QAAQ,EAAE,UAAU,KAAK;GAC3B;GACA,MAAM,CAAC;GACP,OAAO,EAAE,IAAI,QAAQ,GAAG;GACxB,QAAQ;GACR,UAAU;EACZ,EACF,IACA;EACJ,eAAe,OAAO,UAAU,IAAI;EACpC,cAAc,OAAO,UAAU,KAAK;CACtC;CAYA,OAAO;EAAE;EAAQ,QAVf,aAAa,QAAQ,SAAS,UAAU,OACtC,IAAC,oBAAD;GACE,OAAO;GACP,QAAQ,GAAG,OAAO;GAClB,OAAO,OAAO;GACd,cAAc,OAAO;GACrB,GAAK,OAAO,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,aAAa,OAAO,QAAQ;GACvE,MAAM,OAAO,cAAc,gBAAgB;EAC5C,CAAA;CAEmB;AAC1B;AAmBA,SAAgB,WAAW,EACzB,UACA,YACA,QACA,OACA,WACuC;CACvC,MAAM,SAAS,eAAe;EAAE;EAAU,QAAQ;CAAW,IAAI,CAAC,UAAU,UAAU,CAAC;CACvF,MAAM,OAAO,WAAW,QAAQ;EAC9B,GAAI,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO;EACzC,SAAS,UAAU,QAAQ,QAAQ;CACrC,CAAC;CACD,MAAM,SAAS,cAAc,UAAU,UAAU;CACjD,MAAM,YAAY,YAAY,OAAO,CAAC,CAAC,SAAS,IAAI,QAAQ,GAAG,MAAM;CACrE,MAAM,QAAQ,kBAAkB,UAAU,WAAW,MAAM;CAC3D,MAAM,OAAO,YAAY,MAAM;EAC7B,OAAO,OAAO;EACd,GAAI,WAAW,KAAA,KAAa,UAAU,KAAK,CAAC,IAAI,EAAE,MAAM;EACxD,GAAI,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO;CAC3C,CAAC;CACD,MAAM,MAAM,WAAW;CACvB,MAAM,IAAI,aAAa;CACvB,MAAM,OAAO,YAAY,QAAQ;CAEjC,MAAM,EAAE,QAAQ,WAAW,gBAAgB,MAAM,MAAM,QAAQ,UADhD,WAAW,OAAO,UAAU,YAAY,OAAO,aAAa,EAAE,GAAG,GACF,CAAC;CAC/E,MAAM,UAAU,OAAO,KAAK;CAC5B,MAAM,aAAa,OAAO,OAAO;CACjC,WAAW,UAAU;CACrB,MAAM,EAAE,UAAU,aAAa;CAC/B,MAAM,UACJ,aAAa,SACZ,SAAS,YAAY,cACpB,SAAS,YAAY,YACpB,SAAS,YAAY,YACnB,CAAC,SAAS,WAAW,SAAS,QAAQ,SAAS,MAAM,KAAK,SAAS,SAAS;CACnF,gBAAgB;EACd,IAAI,CAAC,WAAW,QAAQ,SAAS;EACjC,QAAQ,UAAU;EAClB,IAAI,SAAS,YAAY,SAAS;GAChC,MACE,SAAS,WAAW,KAAA,IAChB,EAAE,uBAAuB,EAAE,cAAc,8BAA8B,CAAC,IACxE,WAAW,MAAM,SAAS,QAAQ,QAAQ,CAChD;GACA,WAAW,QAAQ;GACnB;EACF;EACA,OAAY,CAAC,CAAC,cAAc,WAAW,QAAQ,CAAC;CAClD,GAAG;EAAC;EAAS,SAAS;EAAS,SAAS;EAAQ;EAAQ;EAAG;CAAI,CAAC;CAChE,OAAO;AACT;AAiBA,SAAgB,cAAc,EAC5B,MACA,OACA,QACA,WAC0C;CAC1C,MAAM,SAAS,eAAe,EAAE,WAAW,KAAK,IAAI,CAAC,IAAI,CAAC;CAC1D,MAAM,OAAO,WAAW,QAAQ,EAAE,SAAS,MAAM,CAAC;CAElD,MAAM,SAAqB;EACzB;EACA,WAAW;EACX,MAAM,KAAA;EACN,aAAa;EACb,GANkB,mBAAmB,IAAI,MAAM,KAMlC;CACf;CACA,MAAM,OAAO,YAAY,MAAM,EAAE,MAAM,CAAC;CACxC,MAAM,IAAI,aAAa;CACvB,MAAM,OAAO,YAAY;CACzB,MAAM,EAAE,QAAQ,WAAW,gBAAgB,MAAM,MAAM,QAAQ,qBAAqB,MAAM;CAC1F,MAAM,UAAU,OAAO,KAAK;CAC5B,MAAM,aAAa,OAAO,OAAO;CACjC,WAAW,UAAU;CACrB,MAAM,EAAE,UAAU,aAAa;CAC/B,MAAM,UACJ,aAAa,SACZ,SAAS,YAAY,cACpB,SAAS,YAAY,YACpB,SAAS,YAAY,YACnB,CAAC,SAAS,WAAW,SAAS,QAAQ,SAAS,MAAM,KAAK,SAAS,SAAS;CACnF,gBAAgB;EACd,IAAI,CAAC,WAAW,QAAQ,SAAS;EACjC,QAAQ,UAAU;EAClB,IAAI,SAAS,YAAY,SAAS;GAChC,MACE,SAAS,WAAW,KAAA,IAChB,EAAE,uBAAuB,EAAE,cAAc,8BAA8B,CAAC,IACxE,WAAW,MAAM,SAAS,MAAM,CACtC;GACA,WAAW,QAAQ;GACnB;EACF;EACA,OAAY,CAAC,CAAC,cAAc,WAAW,QAAQ,CAAC;CAClD,GAAG;EAAC;EAAS,SAAS;EAAS,SAAS;EAAQ;EAAQ;EAAG;CAAI,CAAC;CAChE,OAAO;AACT;AAeA,SAAgB,eAAe,EAC7B,UACA,YACA,KACA,YAC2C;CAC3C,MAAM,MAAM,WAAW;CACvB,MAAM,IAAI,aAAa;CACvB,MAAM,OAAO,YAAY,QAAQ;CACjC,MAAM,SAAS,IAAI,KAAK,IAAQ;CAEhC,MAAM,YAAY,eAAe;EAAE,KAAK,CAAC,GAAG,GAAG;EAAG,OAAO,IAAI;CAAO,IAAI,CAAC,MAAM,CAAC;CAChF,MAAM,SAAS,eAAe;EAAE;EAAU,QAAQ;CAAW,IAAI,CAAC,UAAU,UAAU,CAAC;CACvF,MAAM,OAAO,WAAW,QAAQ;EAAE;EAAW,SAAS;CAAO,CAAC;CAC9D,MAAM,SAAS,cAAc,UAAU,UAAU;CACjD,MAAM,SAAS,IAAI,WAAW,UAAU,UAAU;CAClD,MAAM,CAAC,YAAY,iBAAiB,SAAS,KAAK;CAClD,MAAM,SAAS,OAA4C,IAAI;CAC/D,MAAM,UAAU,OAAO,KAAK;CAC5B,MAAM,cAAc,OAAO,QAAQ;CACnC,YAAY,UAAU;CACtB,MAAM,EAAE,KAAK,aAAa;CAC1B,sBACc;EACV,OAAO,UAAU,KAAK;EACtB,OAAO,UAAU;CACnB,GACA,CAAC,CACH;CACA,MAAM,UACJ,QAAQ,QAAQ,SAAS,YAAY,eAAe,SAAS,YAAY;CAC3E,gBAAgB;EACd,IAAI,CAAC,WAAW,QAAQ,WAAW,QAAQ,MAAM;EACjD,QAAQ,UAAU;EAClB,CAAM,YAAY;GAChB,IAAI,IAAI,YAAY,CAAC,CAAC,YAAY,SAAS;IACzC,MAAM,UAAU,IAAI,YAAY,CAAC,CAAC;IAClC,MACE,YAAY,KAAA,IACR,EAAE,uBAAuB,EAAE,cAAc,8BAA8B,CAAC,IACxE,WAAW,MAAM,SAAS,QAAQ,CACxC;IACA,YAAY,QACV,OAAO,OAAO;KAAE,SAAS;KAAe,OAAO;IAAW,CAAC,GAC3D,KAAA,CACF;IACA;GACF;GACA,IAAI,SAAS,MAAM,IAAI,OAAO;GAC9B,OACE,OAAO,YAAY,aAClB,OAAO,SAAS,YAAY,OAAO,SAAS,WAC7C;IACA,cAAc,IAAI;IAClB,MAAM,UAAU,MAAM,IAAI,SAAkB,YAAY;KACtD,OAAO,UAAU;IACnB,CAAC;IACD,OAAO,UAAU;IACjB,cAAc,KAAK;IACnB,IAAI,CAAC,SAAS;KACZ,IAAI,UAAU;KACd,YAAY,QAAQ,QAAQ,KAAA,CAAS;KACrC;IACF;IACA,SAAS,MAAM,IAAI,OAAO;GAC5B;GACA,IAAI,OAAO,YAAY,YAAY,YAAY,UAAU,OAAO,WAAW,QACzE,MAAM,EAAE,sBAAsB,EAAE,cAAc,yCAAyC,CAAC,CAAC;GAC3F,YAAY,QAAQ,QAAQ,IAAI,YAAY,CAAC,CAAC,IAAI;EACpD,EAAA,CAAG;CACL,GAAG;EAAC;EAAS;EAAK;EAAG;EAAM;CAAQ,CAAC;CACpC,MAAM,OAAuB;EAC3B;EACA,MAAM;EACN,MAAM;EACN,QAAQ;EACR,UAAU;EACV,aAAa,aACT,SAAS,SAAS,KACf,aAA8B;GAC7B,MAAM;GAEN,SAAS;IACP,GAAG,aACD,QAAQ,SAAS,KAAA,IACb,QAAQ,UACR,GAAG,QAAQ,QAAQ,KAAK,EAAE,wBAAwB;KAChD,cAAc,QAAQ,SAAS,IAAI,UAAU,GAAG,QAAQ,KAAK;KAC7D,OAAO,QAAQ;IACjB,CAAC,KACL,UAAU,QAAQ,IACpB;IAEA,QAAQ,EAAE,UAAU,KAAK;GAC3B;GACA,MAAM,CAAC;GACP,OAAO,EAAE,IAAI,QAAQ,GAAG;GACxB,QAAQ;GACR,UAAU;EACZ,EACF,IACA;EACJ,eAAe,OAAO,UAAU,IAAI;EACpC,cAAc,OAAO,UAAU,KAAK;CACtC;CACA,OACE,IAAC,oBAAD;EACE,OAAO;EACP,QAAQ,GAAG,OAAO;EAClB,OAAO,OAAO;EACd,cAAc,OAAO;EACrB,GAAK,OAAO,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,aAAa,OAAO,QAAQ;EACvE,MAAM,OAAO,cAAc,gBAAgB;CAC5C,CAAA;AAEL"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { M as useFocusOnMount, P as OwnTitleContext, ft as DocInfo, j as OwnTitleHeading, v as reasonText } from "./check-confirm-dialog-
|
|
1
|
+
import { M as useFocusOnMount, P as OwnTitleContext, ft as DocInfo, j as OwnTitleHeading, v as reasonText } from "./check-confirm-dialog-B_u3YVHS.js";
|
|
2
2
|
import { t as Button } from "./button-MWVeZaqj.js";
|
|
3
|
-
import {
|
|
3
|
+
import { Nt as FieldDisplay, U as ScreenTree, Y as FormControlProvider, Z as useFormControlOf, n as viewOf, t as selectImplementation } from "./place-node-DwWAigv0.js";
|
|
4
4
|
import { t as useNoticeSink } from "./success-notices-CrcWOGSo.js";
|
|
5
5
|
import { declaredText, fieldSensitivity, flowRecordOf, humanizeKey, textsValueAt, validatePlacementProps } from "@burojs/core";
|
|
6
6
|
import { BulkSelectionScope, REJECTED_KEYS, ScreenStateProvider, resolveValidationMessage, specificErrorText, useChromeT, useCurrentUserId, useDismissHold, useDismissPending, useFlowFormCatalog, useFlowOpenImplementation, useFormController, useI18nCaps, useNavigationBlocker, useOptionalRouterAdapter, useOptionalT, useProjectedTitle, useTestIds, useUIInstance, useUIPresentationRuntime } from "@burojs/react";
|
|
@@ -114,7 +114,12 @@ function OverlayBinding({ children }) {
|
|
|
114
114
|
function WithBinding({ children }) {
|
|
115
115
|
return useContext(FlowHostBindingContext) !== null ? jsx(Fragment$1, { children }) : jsx(OverlayBinding, { children });
|
|
116
116
|
}
|
|
117
|
-
function outcomeMessage(snapshot, busy, t, caps,
|
|
117
|
+
function outcomeMessage(snapshot, busy, t, caps, textPrefixes, flow, reasonOf) {
|
|
118
|
+
const place = { action: {
|
|
119
|
+
prefix: textPrefixes[0] ?? "",
|
|
120
|
+
prefixes: textPrefixes,
|
|
121
|
+
texts: flow?.texts
|
|
122
|
+
} };
|
|
118
123
|
if (busy) return t("flow.busyElsewhere", { defaultValue: "This action is running in another tab." });
|
|
119
124
|
const outcome = snapshot.outcome;
|
|
120
125
|
if (outcome === void 0 || outcome.outcome === "success") {
|
|
@@ -130,14 +135,11 @@ function outcomeMessage(snapshot, busy, t, caps, textPrefix, flow, reasonOf) {
|
|
|
130
135
|
const specific = specificErrorText({
|
|
131
136
|
code,
|
|
132
137
|
..."message" in outcome && outcome.message !== void 0 ? { message: outcome.message } : {}
|
|
133
|
-
}, caps,
|
|
134
|
-
prefix: textPrefix,
|
|
135
|
-
texts: flow?.texts
|
|
136
|
-
} });
|
|
138
|
+
}, caps, place);
|
|
137
139
|
if (specific !== void 0) return specific;
|
|
138
140
|
}
|
|
139
141
|
const key = kind === void 0 ? void 0 : REJECTED_KEYS[kind];
|
|
140
|
-
if (key !== void 0) return t(`${
|
|
142
|
+
if (key !== void 0) return textPrefixes.reduceRight((rest, prefix) => t(`${prefix}.rejected.${key}`, { defaultValue: rest }), textsValueAt(flow?.texts, ["rejected", key]) ?? t(`flow.rejected.${key}`, { defaultValue: "Nothing was saved." }));
|
|
141
143
|
return t("flow.rejected.precondition", { defaultValue: "The record changed. Nothing was sent." });
|
|
142
144
|
}
|
|
143
145
|
if (outcome.outcome === "failed") {
|
|
@@ -146,10 +148,7 @@ function outcomeMessage(snapshot, busy, t, caps, textPrefix, flow, reasonOf) {
|
|
|
146
148
|
return (code === void 0 ? void 0 : specificErrorText({
|
|
147
149
|
code,
|
|
148
150
|
..."message" in outcome && outcome.message !== void 0 ? { message: outcome.message } : {}
|
|
149
|
-
}, caps, {
|
|
150
|
-
prefix: textPrefix,
|
|
151
|
-
texts: flow?.texts
|
|
152
|
-
} })) ?? t("flow.failed", { defaultValue: "The request could not be sent. Nothing was saved." });
|
|
151
|
+
}, caps, place)) ?? t("flow.failed", { defaultValue: "The request could not be sent. Nothing was saved." });
|
|
153
152
|
}
|
|
154
153
|
return null;
|
|
155
154
|
}
|
|
@@ -355,9 +354,10 @@ function FlowScreenBody({ run, host, label, title: givenTitle, compiled, record:
|
|
|
355
354
|
}
|
|
356
355
|
settle(await run.submit());
|
|
357
356
|
};
|
|
358
|
-
const
|
|
359
|
-
const
|
|
360
|
-
const
|
|
357
|
+
const ownKey = (slot) => compiled.textKeys.prefixes.map((prefix) => `${prefix}.${slot}`).find((key) => caps.has(key));
|
|
358
|
+
const pendingKey = ownKey("pending");
|
|
359
|
+
const pendingLabel = pendingKey !== void 0 ? caps.t(pendingKey) : `${label}…`;
|
|
360
|
+
const message = outcomeMessage(snapshot, busy, t, caps, compiled.textKeys.prefixes, compiled.flow, (reason) => reasonText(caps, reason, resource));
|
|
361
361
|
const formErrorTexts = formErrors.map((issue) => resolveValidationMessage({
|
|
362
362
|
code: issue.code ?? "",
|
|
363
363
|
message: issue.message,
|
|
@@ -366,8 +366,8 @@ function FlowScreenBody({ run, host, label, title: givenTitle, compiled, record:
|
|
|
366
366
|
has: caps.has,
|
|
367
367
|
t: caps.t
|
|
368
368
|
})).filter((text) => text !== message);
|
|
369
|
-
const dismissKey =
|
|
370
|
-
const cancelWord = (
|
|
369
|
+
const dismissKey = ownKey("dismiss");
|
|
370
|
+
const cancelWord = (dismissKey !== void 0 ? caps.t(dismissKey) : void 0) ?? declaredText("flow", compiled.flow, "dismiss") ?? chromeT("actions.cancel", { defaultValue: "Cancel" });
|
|
371
371
|
const couldNotCheck = snapshot.control === "disabled" && snapshot.unverified === true;
|
|
372
372
|
const steps = form.steps;
|
|
373
373
|
const lastStep = steps === null || steps.ids.length === 0 || steps.current === steps.ids[steps.ids.length - 1];
|
|
@@ -783,4 +783,4 @@ function FlowOpenBlock({ open, testid }) {
|
|
|
783
783
|
//#endregion
|
|
784
784
|
export { FlowHostBindingContext, FlowScreen, HostedFlowScreen };
|
|
785
785
|
|
|
786
|
-
//# sourceMappingURL=flow-screen-
|
|
786
|
+
//# sourceMappingURL=flow-screen-B1y2yizP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow-screen-B1y2yizP.js","names":[],"sources":["../src/flows/review-diff.tsx","../src/flows/flow-screen.tsx"],"sourcesContent":["'use client';\nimport { fieldSensitivity, humanizeKey, type Row } from '@burojs/core';\nimport { type FormController, useOptionalT } from '@burojs/react';\nimport type { ReactElement } from 'react';\nimport { FieldDisplay } from '../forms/field.js';\n\n/** The built-in review block of a flow (`review: true`, P4 spec 4.4). */\nexport const REVIEW_DIFF_BLOCK = 'buro:review-diff';\n\nexport interface ReviewDiffProps {\n /** The flow's form: its active fields, their definitions and labels. */\n readonly form: FormController;\n /** The values the form opened on (`form.initial`): the baseline of the diff. */\n readonly initial: Row;\n /** The values as they will be submitted. */\n readonly values: Row;\n /** Text and doc keys of the form (`<resource>.actions.<name>`). */\n readonly i18nPrefix: string;\n /** The test id base (the flow's host). */\n readonly testid: string;\n}\n\n/** Whether a field is `sensitive` (a mark or a mask). */\nfunction sensitive(definition: unknown): boolean {\n if (fieldSensitivity(definition) !== undefined) return true;\n if (definition === null || typeof definition !== 'object') return false;\n const opts = (definition as { readonly opts?: unknown }).opts;\n const marked =\n opts !== null && typeof opts === 'object'\n ? (opts as { readonly sensitive?: unknown }).sensitive\n : undefined;\n return marked !== undefined && marked !== false && marked !== null;\n}\n\nconst same = (a: unknown, b: unknown): boolean => {\n if (Object.is(a, b)) return true;\n const empty = (value: unknown) => value === undefined || value === null || value === '';\n if (empty(a) && empty(b)) return true;\n try {\n return JSON.stringify(a) === JSON.stringify(b);\n } catch {\n return false;\n }\n};\n\n/**\n * The review of a flow (`review: true`, 4.4): one row per active form field whose value differs\n * from the one the form opened on — its label, the old display value and the new one. A\n * `sensitive` field says \"changed\" and shows no value, old or new.\n */\nexport function ReviewDiff({\n form,\n initial,\n values,\n i18nPrefix,\n testid,\n}: ReviewDiffProps): ReactElement {\n const t = useOptionalT();\n const changedText = t('review.changed', { defaultValue: 'changed' });\n const rows = form.fields.filter((binding) => !same(initial[binding.name], values[binding.name]));\n return (\n <dl data-testid={`${testid}:review`} data-buro-block={REVIEW_DIFF_BLOCK} className=\"grid gap-2\">\n {rows.map((binding) => {\n const definition = binding.field as unknown as { readonly label?: unknown };\n const label =\n typeof definition.label === 'string' ? definition.label : humanizeKey(binding.name);\n const hidden = sensitive(binding.field);\n return (\n <div\n key={binding.name}\n data-testid={`${testid}:review:${binding.name}`}\n className=\"grid grid-cols-[minmax(0,1fr)_minmax(0,2fr)] gap-2 text-sm\"\n >\n <dt className=\"font-medium\">{label}</dt>\n <dd className=\"flex flex-wrap items-center gap-2\">\n {hidden ? (\n <span className=\"text-muted-foreground\">{changedText}</span>\n ) : (\n <>\n <span data-buro-review=\"old\" className=\"text-muted-foreground line-through\">\n <FieldDisplay\n i18nPrefix={i18nPrefix}\n name={binding.name}\n field={binding.field as never}\n value={initial[binding.name]}\n fallback={<span>{display(initial[binding.name])}</span>}\n />\n </span>\n <span aria-hidden=\"true\">→</span>\n <span data-buro-review=\"new\">\n <FieldDisplay\n i18nPrefix={i18nPrefix}\n name={binding.name}\n field={binding.field as never}\n value={values[binding.name]}\n fallback={<span>{display(values[binding.name])}</span>}\n />\n </span>\n </>\n )}\n </dd>\n </div>\n );\n })}\n </dl>\n );\n}\n\nconst display = (value: unknown): string =>\n value === undefined || value === null || value === '' ? '—' : String(value);\n","'use client';\nimport {\n type CompiledFlow,\n type FlowResult,\n type FlowRun,\n declaredText,\n flowRecordOf,\n type FlowSnapshot,\n type PropValidation,\n textsValueAt,\n validatePlacementProps,\n} from '@burojs/core';\nimport {\n BulkSelectionScope,\n type ErrorTextCaps,\n type ErrorTextPlace,\n REJECTED_KEYS,\n specificErrorText,\n type FlowScreenProps,\n type FlowStart,\n ScreenStateProvider,\n resolveValidationMessage,\n useFlowOpenImplementation,\n useCurrentUserId,\n useDismissHold,\n useDismissPending,\n useFlowFormCatalog,\n useNavigationBlocker,\n useOptionalRouterAdapter,\n useFormController,\n useI18nCaps,\n useChromeT,\n useOptionalT,\n useProjectedTitle,\n useTestIds,\n useUIInstance,\n useUIPresentationRuntime,\n} from '@burojs/react';\nimport { fieldEntriesToMap } from '@burojs/core/internal';\nimport {\n FlowTextsScope,\n useFlowFieldConditions,\n useFlowForm,\n useFlowMetaSources,\n useFlowRun,\n} from '@burojs/react/flows';\nimport * as DialogPrimitive from '@radix-ui/react-dialog';\nimport { IconLoader2, IconX } from '@tabler/icons-react';\nimport {\n type ReactElement,\n type ReactNode,\n Suspense,\n createContext,\n useContext,\n useMemo,\n useEffect,\n useRef,\n useState,\n useSyncExternalStore,\n} from 'react';\nimport { DocInfo } from '../doc/doc-info.js';\nimport { useNoticeSink } from '../forms/success-notices.js';\nimport { reasonText } from '../lib/reason-text.js';\nimport { Button } from '../primitives/button.js';\nimport { FormControlProvider, useFormControlOf } from '../resource/form-context.js';\nimport { ScreenTree } from '../screen/screen-tree.js';\nimport { selectImplementation, viewOf } from '../blocks/place-node.js';\nimport { ReviewDiff } from './review-diff.js';\nimport { OwnTitleContext } from '../ui-presentations/shell.js';\nimport { OwnTitleHeading, useFocusOnMount } from './overlay-heading.js';\n\n/**\n * Thrown from the form controller's write: the controller validated (and revealed the first\n * failing field), and the run — not the controller — sends. A write that throws leaves the form\n * dirty and its draft in place (the controller re-baselines only on a write that resolves), and\n * an abort-shaped value is no reportable failure.\n */\nconst HELD = Object.freeze({ name: 'AbortError', message: 'The flow run sends the values.' });\n\n/**\n * How the flow screen leaves its host (P6): an overlay dismisses its presentation instance, a\n * page navigates to the record through the guard, an inline placement shows the next form. The\n * screen asks `close()` for Cancel, ✕ and Back, and `finish()` once a success needs nothing more\n * shown (no `then.open: { block }`).\n * @internal\n */\nexport interface FlowHostBinding {\n readonly kind: 'overlay' | 'page' | 'inline';\n close(): void;\n finish(): void;\n}\n\n/** @internal Provided by the page and inline hosts; an overlay builds its own. */\n/** @internal */\nexport function HostedFlowScreen(\n props: FlowScreenProps & { readonly binding: FlowHostBinding },\n): ReactElement | null {\n const { binding, ...rest } = props;\n return (\n <FlowHostBindingContext.Provider value={binding}>\n <FlowScreen {...rest} />\n </FlowHostBindingContext.Provider>\n );\n}\n\nexport const FlowHostBindingContext = createContext<FlowHostBinding | null>(null);\n\n/** Gives the screen below it the overlay's binding: its presentation instance. */\nfunction OverlayBinding({ children }: { readonly children: ReactNode }): ReactElement {\n const instance = useUIInstance();\n const runtime = useUIPresentationRuntime();\n const binding = useMemo<FlowHostBinding>(\n () => ({\n kind: 'overlay',\n close: () => instance.dismiss(),\n finish: () => runtime.dismiss(instance.id),\n }),\n [instance, runtime],\n );\n return (\n <FlowHostBindingContext.Provider value={binding}>{children}</FlowHostBindingContext.Provider>\n );\n}\n\n/** The screen's binding when a page or inline host provided one, else the overlay's. */\nfunction WithBinding({ children }: { readonly children: ReactNode }): ReactElement {\n const provided = useContext(FlowHostBindingContext);\n return provided !== null ? <>{children}</> : <OverlayBinding>{children}</OverlayBinding>;\n}\n\ntype Translate = ReturnType<typeof useOptionalT>;\n\n/**\n * What the outcome area says, or `null` when the screen has nothing to report. A rejection reads\n * the specific text of its code first (spec 4.15 steps 1 to 4: the flow's `<prefix>.validation.<code>`\n * and declared `texts.validation`, the provider's reference, the shared code texts). Only when none\n * resolves does a mapped kind read the flow's own `<prefix>.rejected.<kind>`, then its declared\n * `texts.rejected.<kind>` (`flow`), before the framework's neutral `flow.rejected.<kind>`;\n * `textPrefixes` is the compiled flow's `textKeys.prefixes`: each level is read before the next.\n */\nfunction outcomeMessage(\n snapshot: FlowSnapshot,\n busy: boolean,\n t: Translate,\n caps: ErrorTextCaps,\n textPrefixes: readonly string[],\n flow: { readonly texts?: unknown } | undefined,\n reasonOf: (reason: string) => string,\n): string | null {\n // A base member's flow reads its own key, then its base's (REF-131 §9.5).\n const place: ErrorTextPlace = {\n action: { prefix: textPrefixes[0] ?? '', prefixes: textPrefixes, texts: flow?.texts },\n };\n if (busy)\n return t('flow.busyElsewhere', { defaultValue: 'This action is running in another tab.' });\n const outcome = snapshot.outcome;\n if (outcome === undefined || outcome.outcome === 'success') {\n // A check that could not decide blocks the flow (4.3): its reason, with Retry.\n if (snapshot.control === 'disabled' && snapshot.reason !== undefined)\n return reasonOf(snapshot.reason);\n return null;\n }\n if (outcome.outcome === 'unknown')\n return [\n outcome.applied === 'partial'\n ? t('flow.unknownPartial', {\n defaultValue: 'Part of this may have been applied. Nothing was resent.',\n })\n : t('flow.unknown', {\n defaultValue: 'It may have been applied. Nothing was resent.',\n }),\n ...(snapshot.reason === undefined ? [] : [reasonOf(snapshot.reason)]),\n ].join(' ');\n if (outcome.outcome === 'rejected') {\n if (snapshot.reason !== undefined) return reasonOf(snapshot.reason);\n const kind = 'kind' in outcome ? outcome.kind : undefined;\n const code = 'code' in outcome ? outcome.code : undefined;\n if (code !== undefined) {\n const specific = specificErrorText(\n {\n code,\n ...('message' in outcome && outcome.message !== undefined\n ? { message: outcome.message }\n : {}),\n },\n caps,\n place,\n );\n if (specific !== undefined) return specific;\n }\n const key = kind === undefined ? undefined : REJECTED_KEYS[kind];\n if (key !== undefined)\n return textPrefixes.reduceRight(\n (rest, prefix) => t(`${prefix}.rejected.${key}`, { defaultValue: rest }),\n textsValueAt(flow?.texts, ['rejected', key]) ??\n t(`flow.rejected.${key}`, { defaultValue: 'Nothing was saved.' }),\n );\n return t('flow.rejected.precondition', {\n defaultValue: 'The record changed. Nothing was sent.',\n });\n }\n if (outcome.outcome === 'failed') {\n if (snapshot.reason !== undefined) return reasonOf(snapshot.reason);\n // The code's own text first (spec 4.15), as the bulk summary and the record frame read it.\n const code = 'code' in outcome ? outcome.code : undefined;\n const specific =\n code === undefined\n ? undefined\n : specificErrorText(\n {\n code,\n ...('message' in outcome && outcome.message !== undefined\n ? { message: outcome.message }\n : {}),\n },\n caps,\n place,\n );\n return (\n specific ??\n t('flow.failed', { defaultValue: 'The request could not be sent. Nothing was saved.' })\n );\n }\n return null;\n}\n\n/**\n * The UI kit's flow host screen (`presentationHosts.screens.flow`, presented under `buro:flow`;\n * P4 spec 4.15, 4.19): the action's label and the record's title with its «i» and ✕; the form\n * (a `steps` body is a wizard), the final screen's warnings and `confirm`, and the outcome\n * screens; a footer of Back, Cancel and the submit button, labelled with the action's label and\n * its pending text while the write runs.\n *\n * The presentation is a dismiss scope (P3-30): Escape, an outside click, ✕ and Cancel close\n * through it, so a dirty form asks first; Back between steps stays in the host and asks nothing.\n * From the send to the outcome the screen holds the scope's pending lock — nothing closes it,\n * and the run holds every route change. `success` closes the host without asking; `rejected`\n * and `failed` return to the dirty form; `unknown` closes without asking and keeps the attempt.\n */\nexport function FlowScreen(props: FlowScreenProps): ReactElement | null {\n if (props.run !== undefined && props.compiled !== undefined)\n return <HeldFlowScreen {...props} run={props.run} compiled={props.compiled} />;\n if (props.start !== undefined) return <OwnedFlowScreen {...props} start={props.start} />;\n return null;\n}\n\ntype HeldProps = FlowScreenProps & { readonly run: FlowRun; readonly compiled: CompiledFlow };\n\n/**\n * A bulk run's record frame (read-scope spec 4, rule 1): the form's `'context'` reads take the\n * value every selected row agrees on, else the session's. A run without a selection adds nothing.\n */\nfunction SelectionScope(props: {\n readonly selection: FlowScreenProps['selection'];\n readonly resource: string | null;\n readonly children: ReactNode;\n}): ReactElement {\n if (props.selection === undefined || props.resource === null) return <>{props.children}</>;\n return (\n <BulkSelectionScope resource={props.resource} ids={props.selection.ids}>\n {props.children}\n </BulkSelectionScope>\n );\n}\n\n/** The screen over a run it is given. */\nfunction HeldFlowScreen(props: HeldProps): ReactElement {\n // \"I've checked — start over\" (4.8) opens a fresh form: the body mounts again, so the form\n // takes the run's fresh values as its baseline and offers the stored draft.\n const [generation, setGeneration] = useState(0);\n // An app flow's form reads its texts in its `common.appActions.<name>` entry.\n return (\n <FlowTextsScope compiled={props.compiled}>\n <WithBinding>\n <ScreenStateProvider key={generation}>\n <SelectionScope selection={props.selection} resource={props.compiled.resource}>\n <FlowScreenBody {...props} onFreshForm={() => setGeneration((value) => value + 1)} />\n </SelectionScope>\n </ScreenStateProvider>\n </WithBinding>\n </FlowTextsScope>\n );\n}\n\n/**\n * The host owning its run (P4-C review I1): the run lives as long as the host, not as long as\n * the control that opened it — a row that left the page, a menu item that closed — so a dirty\n * form still asks before it closes and a pending write still holds its lock. `then` waits until\n * the host has gone (its form and its blocker with it), then runs through the opener's\n * dispatcher scope; each outcome is reported to the opener.\n */\nfunction OwnedFlowScreen(props: FlowScreenProps & { readonly start: FlowStart }): ReactElement {\n const { start, effects, onSettle } = props;\n const flow = useFlowRun(start.target, {\n ...(start.record === undefined ? {} : { record: start.record }),\n ...(start.args === undefined ? {} : { args: start.args }),\n ...(start.selection === undefined ? {} : { selection: start.selection }),\n surface: 'host',\n ...(effects === undefined ? {} : { thenEffects: effects }),\n });\n // `then` is the host's to run, after it closed.\n flow.holdThen(true);\n const latest = useRef(flow);\n latest.current = flow;\n useEffect(\n () => () => {\n // After the commit that removed the host: its form's blocker is gone.\n setTimeout(() => {\n latest.current.holdThen(false);\n latest.current.runThen();\n }, 0);\n },\n [],\n );\n const { run, snapshot, compiled } = flow;\n const outcome = snapshot.outcome;\n useEffect(() => {\n if (outcome !== undefined) onSettle?.(outcome);\n }, [outcome, onSettle]);\n const instance = useUIInstance();\n const t = useOptionalT();\n const caps = useI18nCaps(compiled?.resource ?? undefined);\n const tid = useTestIds();\n const opened =\n run !== null &&\n compiled !== null &&\n (snapshot.history.includes('open') || snapshot.step === 'outcome');\n if (opened) return <HeldFlowScreen {...props} run={run} compiled={compiled} />;\n // Not opened yet: its gate, its sources and a stored attempt decide first. A run that\n // decided against opening says why.\n const refused = snapshot.control === 'disabled' || snapshot.control === 'absent';\n return (\n <div\n data-testid={compiled === null ? undefined : `${tid.flowHost(compiled.flowId)}:opening`}\n data-buro-host={props.host}\n data-buro-flow-step={refused ? 'refused' : 'opening'}\n aria-busy={refused ? undefined : 'true'}\n className=\"flex min-h-0 flex-1 flex-col gap-4\"\n >\n <OwnTitleHeading label={props.label} />\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, compiled?.resource ?? undefined)}\n </p>\n ) : (\n <IconLoader2 className=\"h-5 w-5 animate-spin self-center\" aria-hidden=\"true\" />\n )}\n <div className=\"flex justify-end\">\n <Button type=\"button\" variant=\"ghost\" onClick={() => instance.dismiss()}>\n {t('flow.close', { defaultValue: 'Close' })}\n </Button>\n </div>\n </div>\n );\n}\n\nfunction FlowScreenBody({\n run,\n host,\n label,\n title: givenTitle,\n compiled,\n record: givenRecord,\n args,\n selection,\n onFreshForm,\n}: HeldProps & { readonly onFreshForm: () => void }): ReactElement {\n // A collection-level flow has no record, whoever passed one (spec 5.1): its title, its form and\n // its review read none.\n const record = flowRecordOf(compiled, givenRecord);\n const snapshot = useSyncSnapshot(run);\n const binding = useContext(FlowHostBindingContext) as FlowHostBinding;\n const tid = useTestIds();\n const t = useOptionalT();\n const chromeT = useChromeT();\n const resource = compiled.resource ?? undefined;\n const caps = useI18nCaps(resource);\n const ownTitle = useContext(OwnTitleContext);\n const flowId = compiled.flowId;\n const recordId = record?.[compiled.idField] ?? record?.id;\n const recordTitle = useProjectedTitle(resource, recordId, record);\n const title =\n givenTitle ?? (record === undefined || recordTitle === '' ? undefined : recordTitle);\n const form = useFlowForm(run, compiled, snapshot, {\n ...(record === undefined ? {} : { record }),\n ...(args === undefined ? {} : { args }),\n ...(selection === undefined ? {} : { selection: selection.ids }),\n });\n const formControl = useFormControlOf(form);\n const hasForm = compiled.flow.form !== undefined;\n const [busy, setBusy] = useState(false);\n // The values the form opened on: the review's baseline (4.4). The host opens on an opened run,\n // before anything was typed.\n const [initial] = useState(() => run.getSnapshot().values);\n // Form-level messages: a server's validation refusal on a key no field holds (M14), a\n // resource-level validator's.\n const formErrors = form.errors.filter((issue) => issue.field === '_form');\n\n // The pending lock (4.19): from the re-read to the persisted outcome nothing closes the host.\n const locked = snapshot.control === 'running';\n\n const outcome = snapshot.outcome?.outcome;\n const unknown = outcome === 'unknown';\n const succeeded = outcome === 'success';\n const finalStep = snapshot.step === 'review' || snapshot.step === 'accept';\n\n // `success` closes the host, unasked: nothing unsaved remains (4.19). The run settled the\n // mutation's effects before it answered (4.13).\n // `then.open: { block, props }` keeps the host and draws the block instead (4.13): its close is\n // the block's own button and ✕, and `result` goes with the host.\n const openBlock = succeeded ? blockOpen(snapshot.effects?.open) : null;\n useDismissPending(locked);\n // `dismiss: 'explicit'` (L3 9.14): while the block shows, the overlay drops its own Escape,\n // outside click and every guarded dismiss aimed at it (the block's own included); the header ✕\n // is not drawn and the host's Done button closes it. Everything from outside the window asks\n // through the navigation guard, as a dirty form does: a route change, Back, a reload, and\n // closing an enclosing overlay (an inline host's sheet, a quick sheet the flow was opened\n // from). A change of the signed-in user releases the guard: sign-out is never held.\n const held = openBlock?.dismiss === 'explicit';\n const userId = useCurrentUserId();\n // The user the held window was shown to: captured when it is first held (not at mount, when the\n // id may still be loading), forgotten when it is released. An idempotent write per render.\n const heldBy = useRef<{ readonly id: string | null } | null>(null);\n if (!held) heldBy.current = null;\n else if (heldBy.current === null) heldBy.current = { id: userId };\n const guarding = held && userId === heldBy.current?.id;\n const leaveGuard = useNavigationBlocker(guarding);\n const hold = useDismissHold(guarding && binding.kind === 'overlay');\n // A confirmed route change leaves the page the window was opened over: close it with it, even\n // when its opener stays mounted (an app-level button).\n const pathname = useOptionalRouterAdapter()?.pathname;\n const heldAt = useRef<string | undefined>(undefined);\n useEffect(() => {\n if (!held || binding.kind !== 'overlay') {\n heldAt.current = undefined;\n return;\n }\n if (heldAt.current === undefined) heldAt.current = pathname;\n else if (heldAt.current !== pathname) {\n hold.close();\n binding.finish();\n }\n }, [held, pathname, binding, hold]);\n // The write's own notices (spec 4.7), once per success, before the host closes.\n const showNotices = useNoticeSink(resource);\n const shownNotices = useRef<unknown>(null);\n useEffect(() => {\n if (!succeeded || snapshot.notices.length === 0 || shownNotices.current === snapshot.notices)\n return;\n shownNotices.current = snapshot.notices;\n showNotices(snapshot.notices);\n }, [succeeded, snapshot.notices, showNotices]);\n useEffect(() => {\n if (succeeded && !locked && openBlock === null) binding.finish();\n }, [succeeded, locked, openBlock, binding]);\n\n const prefix =\n compiled.resource === null\n ? `appActions.${compiled.name}`\n : `${compiled.resource}.actions.${compiled.name}`;\n\n const settle = (result: FlowResult) => {\n setBusy(result.outcome === 'failed' && 'reason' in result && result.reason === 'busy');\n };\n const submit = async () => {\n if (locked) return;\n setBusy(false);\n if (finalStep) {\n settle(await run.accept());\n return;\n }\n if (unknown && editingNew) {\n // Send as new: the form as filled now, validated, then the confirmation (P4-C review C2).\n let valid = false;\n await form.handleSubmit(() => {\n valid = true;\n throw HELD;\n })();\n if (valid) setConfirmingNew(true);\n return;\n }\n if (unknown) return;\n if (hasForm) {\n // The controller validates the active fields and reveals the first failing one (its step\n // included); the run sends.\n let validated = false;\n await form.handleSubmit(() => {\n validated = true;\n throw HELD;\n })();\n if (!validated) return;\n }\n settle(await run.submit());\n };\n\n // The flow's own texts, level by level: a base member's key, then its base's (REF-131 §9.5).\n const ownKey = (slot: string) =>\n compiled.textKeys.prefixes.map((prefix) => `${prefix}.${slot}`).find((key) => caps.has(key));\n const pendingKey = ownKey('pending');\n const pendingLabel = pendingKey !== undefined ? caps.t(pendingKey) : `${label}…`;\n const message = outcomeMessage(\n snapshot,\n busy,\n t,\n caps,\n compiled.textKeys.prefixes,\n compiled.flow,\n (reason) => reasonText(caps, reason, resource),\n );\n // The form-level issues, resolved here so a language switch re-renders them; one that says\n // what the outcome heading already says is not shown twice.\n const formErrorTexts = formErrors\n .map((issue) =>\n resolveValidationMessage(\n {\n code: issue.code ?? '',\n message: issue.message,\n ...(issue.check === undefined ? {} : { check: issue.check }),\n },\n { has: caps.has, t: caps.t },\n ),\n )\n .filter((text) => text !== message);\n // The flow's own word for its cancel buttons (`<prefix>.dismiss`, then its declared\n // `texts.dismiss`), else the kit's.\n const dismissKey = ownKey('dismiss');\n const cancelWord =\n (dismissKey !== undefined ? caps.t(dismissKey) : undefined) ??\n declaredText('flow', compiled.flow, 'dismiss') ??\n chromeT('actions.cancel', { defaultValue: 'Cancel' });\n // The run flags a check that could not decide; its reason is a translation, never compared.\n const couldNotCheck = snapshot.control === 'disabled' && snapshot.unverified === true;\n const steps = form.steps;\n const lastStep =\n steps === null || steps.ids.length === 0 || steps.current === steps.ids[steps.ids.length - 1];\n const showSubmit = !unknown && !succeeded && (!hasForm || finalStep || lastStep);\n // The unknown screen's exits (4.8).\n const [confirmingNew, setConfirmingNew] = useState(false);\n // Send as new sends the form as it is now (4.8): the user fills it again and it is validated\n // first — after a reload it holds only its initial values (P4-C review C2).\n const [editingNew, setEditingNew] = useState(false);\n const checkable = compiled.flow.submit.onUnknown !== undefined;\n const unhandled = unknown && !checkable && !snapshot.canResend;\n const exit = (action: () => Promise<FlowResult>) => () => {\n if (!locked) void action().then(settle);\n };\n // An overlay's Cancel keeps the draft so it survives the close (4.19); an inline Reset means\n // \"start over\", so the next form must not offer the input it just threw away (REF-51). An\n // unknown outcome's Close keeps it, like every unresolved attempt (4.11).\n const close = () => {\n if (binding.kind === 'inline' && hasForm && !unknown) form.draft.discard();\n binding.close();\n };\n\n const headingRef = useRef<HTMLHeadingElement>(null);\n useFocusOnMount(headingRef);\n // When a `then.open` block replaces the form, focus goes to its Done button (the heading where\n // no Done is drawn): the hidden form took the focused submit button with it.\n const doneRef = useRef<HTMLButtonElement>(null);\n const blockShown = openBlock !== null;\n useEffect(() => {\n if (blockShown) (doneRef.current ?? headingRef.current)?.focus();\n }, [blockShown]);\n const heading = (\n <h2\n ref={headingRef}\n tabIndex={-1}\n data-buro-overlay-heading=\"\"\n className=\"min-w-0 flex-1 break-words text-lg font-semibold tracking-tight focus-visible:outline-hidden\"\n >\n {label}\n {title === undefined ? null : (\n <span className=\"font-normal text-muted-foreground\">\n {/* Text, not margin: the dialog's accessible name is its text, which would glue the two. */}\n {' — '}\n {title}\n </span>\n )}\n </h2>\n );\n\n return (\n <div\n data-testid={tid.flowHost(flowId)}\n data-buro-host={host}\n data-buro-flow-step={snapshot.step}\n aria-busy={locked ? 'true' : undefined}\n className=\"flex min-h-0 flex-1 flex-col gap-4\"\n >\n {binding.kind === 'inline' ? null : (\n <div data-buro-region=\"flow-header\" className=\"flex items-center gap-2 pr-1\">\n {ownTitle ? <DialogPrimitive.Title asChild>{heading}</DialogPrimitive.Title> : heading}\n {compiled.resource === null ? null : (\n <DocInfo\n address={`${compiled.resource}/actions/${compiled.name}`}\n name={label}\n testId={`${tid.flowHost(flowId)}:info`}\n />\n )}\n {binding.kind === 'overlay' && !held ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8 shrink-0\"\n data-testid={tid.flowClose(flowId)}\n aria-label={t('flow.close', { defaultValue: 'Close' })}\n onClick={close}\n >\n <IconX className=\"h-4 w-4\" aria-hidden=\"true\" />\n </Button>\n ) : null}\n </div>\n )}\n {openBlock !== null ? (\n <FlowOpenBlock open={openBlock} prefix={prefix} testid={tid.flowHost(flowId)} />\n ) : null}\n {openBlock !== null && (binding.kind !== 'overlay' || held) ? (\n <div className=\"flex justify-end\">\n <Button\n type=\"button\"\n variant=\"outline\"\n ref={doneRef}\n data-testid={tid.flowClose(flowId)}\n onClick={() => {\n // Done is the window's own way out: its guard lets it go first (a page host's\n // close is a guarded navigation to the record).\n leaveGuard.release();\n if (held && binding.kind === 'overlay') {\n // Unconditionally, with every overlay the block opened above it (M4).\n hold.close();\n binding.finish();\n } else close();\n }}\n >\n {t('flow.done', { defaultValue: 'Done' })}\n </Button>\n </div>\n ) : null}\n <form\n hidden={openBlock !== null}\n noValidate\n className={openBlock === null ? 'flex min-h-0 flex-1 flex-col gap-4' : 'hidden'}\n onSubmit={(event) => {\n event.preventDefault();\n void submit();\n }}\n >\n <div className=\"-mx-1 flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto px-1\">\n {message === null ? null : (\n <div\n role={unknown || outcome === 'rejected' || outcome === 'failed' ? 'alert' : 'status'}\n data-testid={tid.flowOutcome(flowId)}\n data-buro-flow-outcome={busy ? 'busy' : (outcome ?? snapshot.control)}\n className=\"flex flex-wrap items-center gap-2 rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive\"\n >\n <span>{message}</span>\n {couldNotCheck ? (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n className=\"ml-auto\"\n onClick={() => run.retryChecks()}\n >\n {chromeT('actions.retry', { defaultValue: 'Retry' })}\n </Button>\n ) : null}\n </div>\n )}\n {hasForm && form.draft.pending !== null && (!unknown || editingNew) ? (\n <div\n data-testid={tid.flowDraft(flowId)}\n role=\"status\"\n aria-live=\"polite\"\n className=\"flex flex-wrap items-center gap-2 rounded-md border border-warning/50 bg-warning/10 px-3 py-2 text-sm\"\n >\n <span className=\"font-medium\">\n {t('draft.restorePrompt', { defaultValue: 'Restore draft?' })}\n </span>\n <div className=\"ml-auto flex gap-2\">\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n data-testid={`${tid.flowDraft(flowId)}:restore`}\n onClick={form.draft.restore}\n >\n {t('draft.restore', { defaultValue: 'Restore' })}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n data-testid={`${tid.flowDraft(flowId)}:discard`}\n onClick={form.draft.discard}\n >\n {t('draft.discard', { defaultValue: 'Discard' })}\n </Button>\n </div>\n </div>\n ) : null}\n {formErrorTexts.length > 0 ? (\n <div\n role=\"alert\"\n data-testid={`${tid.flowHost(flowId)}:form-errors`}\n className=\"flex flex-col gap-1 rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive\"\n >\n {formErrorTexts.map((text, index) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: one failed write's fixed list\n <p key={index}>{text}</p>\n ))}\n </div>\n ) : null}\n {finalStep && compiled.flow.review === true ? (\n <ReviewDiff\n form={form}\n initial={initial}\n values={snapshot.values}\n i18nPrefix={prefix}\n testid={tid.flowHost(flowId)}\n />\n ) : finalStep && Array.isArray(compiled.flow.review) ? (\n <ReviewTree\n compiled={compiled}\n tree={compiled.flow.review}\n values={snapshot.values}\n prefix={prefix}\n run={run}\n {...(record === undefined ? {} : { record })}\n {...(args === undefined ? {} : { args })}\n />\n ) : hasForm ? (\n <FormControlProvider value={formControl}>\n <ScreenTree\n region=\"form-body\"\n resource={prefix}\n mode=\"create\"\n compiled={form.screen}\n controller={form}\n // The record scheme: the leaves carry `form-field-input:<prefix>:create:<name>`\n // test ids, and their texts key as `resources.<prefix>.fields.<name>.…` (4.4).\n leafIds=\"record\"\n disabled={locked || (unknown && !editingNew) || finalStep || succeeded}\n />\n </FormControlProvider>\n ) : null}\n {finalStep && snapshot.warnings.length > 0 ? (\n <ul\n role=\"status\"\n data-buro-region=\"flow-warnings\"\n className=\"flex flex-col gap-1 rounded-md border border-warning/50 bg-warning/10 px-3 py-2 text-sm text-warning-emphasis\"\n >\n {snapshot.warnings.map((warning) => (\n <li key={warning.id} data-testid={`${tid.flowHost(flowId)}:warning:${warning.id}`}>\n {warning.message}\n </li>\n ))}\n </ul>\n ) : null}\n </div>\n {unhandled ? (\n <p data-testid={`${tid.flowOutcome(flowId)}:unhandled`} className=\"text-sm\">\n {t('flow.unknownUnhandled', { defaultValue: 'Check the record before trying again.' })}\n </p>\n ) : null}\n {unknown && confirmingNew ? (\n <div\n role=\"alertdialog\"\n aria-label={t('flow.sendAsNew', { defaultValue: 'Send as new' })}\n data-testid={`${tid.flowSendAsNew(flowId)}:confirm`}\n className=\"flex flex-wrap items-center gap-2 rounded-md border border-warning/50 bg-warning/10 px-3 py-2 text-sm\"\n >\n <span>\n {t('flow.sendAsNewConfirm', {\n defaultValue: 'This may apply the change twice. Send it as a new request?',\n })}\n </span>\n <div className=\"ml-auto flex gap-2\">\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n data-testid={`${tid.flowSendAsNew(flowId)}:cancel`}\n onClick={() => setConfirmingNew(false)}\n >\n {cancelWord}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"destructive\"\n data-testid={`${tid.flowSendAsNew(flowId)}:ok`}\n onClick={() => {\n setConfirmingNew(false);\n exit(() => run.sendAsNew({ confirmed: true }))();\n }}\n >\n {t('flow.sendAsNew', { defaultValue: 'Send as new' })}\n </Button>\n </div>\n </div>\n ) : null}\n {unknown ? (\n <div data-buro-region=\"flow-unknown-exits\" className=\"flex flex-wrap gap-2\">\n {checkable ? (\n <Button\n type=\"button\"\n variant=\"default\"\n data-testid={tid.flowCheckAgain(flowId)}\n disabled={locked}\n onClick={exit(() => run.checkAgain())}\n >\n {t('flow.checkAgain', { defaultValue: 'Check again' })}\n </Button>\n ) : null}\n {snapshot.canResend ? (\n <Button\n type=\"button\"\n variant=\"outline\"\n data-testid={tid.flowResend(flowId)}\n disabled={locked}\n onClick={exit(() => run.resend())}\n >\n {t('flow.resend', { defaultValue: 'Resend' })}\n </Button>\n ) : null}\n <Button\n type=\"button\"\n variant=\"outline\"\n data-testid={tid.flowSendAsNew(flowId)}\n disabled={locked || confirmingNew || editingNew}\n onClick={() => {\n if (hasForm) setEditingNew(true);\n else setConfirmingNew(true);\n }}\n >\n {t('flow.sendAsNew', { defaultValue: 'Send as new' })}\n </Button>\n <Button\n type=\"button\"\n variant=\"outline\"\n data-testid={tid.flowStartOver(flowId)}\n disabled={locked}\n onClick={() => {\n run.startOver();\n onFreshForm();\n }}\n >\n {t('flow.startOver', { defaultValue: \"I've checked — start over\" })}\n </Button>\n </div>\n ) : null}\n <div data-buro-region=\"flow-footer\" className=\"flex flex-wrap items-center gap-2\">\n {finalStep && hasForm && !locked ? (\n <Button\n type=\"button\"\n variant=\"outline\"\n data-testid={tid.flowBack(flowId)}\n onClick={() => run.back()}\n >\n {t('flow.back', { defaultValue: 'Back' })}\n </Button>\n ) : null}\n <div className=\"ml-auto flex gap-2\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n data-testid={tid.flowCancel(flowId)}\n disabled={locked}\n onClick={close}\n >\n {unknown\n ? t('flow.close', { defaultValue: 'Close' })\n : binding.kind === 'inline'\n ? t('flow.reset', { defaultValue: 'Reset' })\n : cancelWord}\n </Button>\n {unknown && editingNew ? (\n <Button\n type=\"submit\"\n variant=\"destructive\"\n data-testid={`${tid.flowSendAsNew(flowId)}:submit`}\n disabled={locked || confirmingNew}\n onMouseDown={(event) => event.preventDefault()}\n >\n {t('flow.sendAsNew', { defaultValue: 'Send as new' })}\n </Button>\n ) : null}\n {showSubmit ? (\n <Button\n type=\"submit\"\n variant={compiled.flow.variant === 'destructive' ? 'destructive' : 'default'}\n data-testid={tid.flowSubmit(flowId)}\n disabled={locked || couldNotCheck}\n aria-busy={locked ? 'true' : undefined}\n // Without this, focusing out of a field a blur error just inserted moves the\n // button, and the click that lands on its old position is swallowed.\n onMouseDown={(event) => event.preventDefault()}\n >\n {locked ? (\n <IconLoader2 className=\"h-4 w-4 animate-spin\" aria-hidden=\"true\" />\n ) : null}\n {locked ? pendingLabel : label}\n </Button>\n ) : null}\n </div>\n </div>\n </form>\n </div>\n );\n}\n\n/** The run's snapshot, re-rendering on each change. */\nfunction useSyncSnapshot(run: FlowRun): FlowSnapshot {\n return useSyncExternalStore(run.subscribe, run.getSnapshot, run.getSnapshot);\n}\n\nconst NO_FIELDS = Object.freeze({});\n\n/**\n * `review: (l) => [...]` (4.4): a show tree over the flow's values — displays and placements\n * only, no inputs — drawn by a show-mode form over the flow's fields.\n */\nfunction ReviewTree({\n compiled,\n tree,\n values,\n prefix,\n run,\n record,\n args,\n}: {\n readonly compiled: CompiledFlow;\n readonly tree: readonly unknown[];\n readonly values: Readonly<Record<string, unknown>>;\n readonly prefix: string;\n readonly run: FlowRun;\n readonly record?: Row;\n readonly args?: Row;\n}): ReactElement {\n const fields = compiled.flow.form?.fields;\n // A review places what it shows: a field the tree does not place leaves the show mode (its\n // `in`), so a review of blocks alone (spec 3.6) is not refused for the fields it leaves out.\n const map = useState(() => {\n if (fields === undefined) return NO_FIELDS;\n const placed = placedLeaves(tree);\n return fieldEntriesToMap(\n (fields as readonly Readonly<Record<string, unknown>>[]).map((field) =>\n placed.has(String(field.name)) ? field : { ...field, in: ['create'] },\n ) as never,\n );\n })[0];\n const body = useState(() => () => tree as never)[0];\n // The app's blocks: a review tree places them (P4-D, spec 3.6's `l.place(offeringReview)`).\n const blocks = useFlowFormCatalog();\n // The run's record and args, like the form step reads them (G35): the controller honours meta\n // sources only under the run's claim, so the review carries the run and its form id. Compiled\n // as a review, the tree's `values` stay the form's values while `record` is the run's.\n const metaSources = useFlowMetaSources(record, args, compiled.resource);\n // The form's `fieldConditions` (REF-132 §4.8): the review plans its fields as the form did, so a\n // field a callback removed from the form is not shown here either.\n const fieldConditions = useFlowFieldConditions(compiled);\n const review = useFormController({\n blocks,\n flowRun: run,\n formId: compiled.formId,\n metaSources,\n ...(fieldConditions === undefined ? {} : { flowFieldConditions: fieldConditions }),\n review: true,\n fields: map as never,\n body,\n mode: 'show',\n i18nPrefix: prefix,\n value: values as never,\n });\n return (\n <ScreenTree\n region=\"form-body\"\n resource={prefix}\n mode=\"show\"\n compiled={review.screen}\n controller={review}\n leafIds=\"record\"\n />\n );\n}\n\n/** The field names a tree places as leaves (a string child of any node). */\nfunction placedLeaves(tree: readonly unknown[]): ReadonlySet<string> {\n const out = new Set<string>();\n const walk = (node: unknown): void => {\n if (typeof node === 'string') {\n out.add(node);\n return;\n }\n if (node === null || typeof node !== 'object') return;\n const children = (node as { readonly children?: unknown }).children;\n if (Array.isArray(children)) for (const child of children) walk(child);\n };\n for (const node of tree) walk(node);\n return out;\n}\n\n/**\n * A `then.open` block target, once resolved (`{ block, props, dismiss? }`); `null` for anything\n * else.\n */\nfunction blockOpen(open: unknown): BlockOpen | null {\n if (open === null || typeof open !== 'object' || !Object.hasOwn(open, 'block')) return null;\n const { block, props, dismiss } = open as {\n readonly block?: unknown;\n readonly props?: unknown;\n readonly dismiss?: unknown;\n };\n const ref =\n block !== null && typeof block === 'object' && 'ref' in block\n ? (block as { readonly ref: unknown }).ref\n : block;\n if (\n ref === null ||\n typeof ref !== 'object' ||\n typeof (ref as EntityRefLike).namespace !== 'string' ||\n typeof (ref as EntityRefLike).id !== 'string'\n )\n return null;\n return {\n block: ref as EntityRefLike,\n props: props !== null && typeof props === 'object' ? (props as Row) : {},\n ...(dismiss === 'explicit' ? { dismiss } : {}),\n };\n}\n\ninterface BlockOpen {\n readonly block: EntityRefLike;\n readonly props: Row;\n /** `'explicit'`: only the host's Done button closes the window (L3 9.14). */\n readonly dismiss?: 'explicit';\n}\n\ninterface EntityRefLike {\n readonly namespace: string;\n readonly id: string;\n}\ntype Row = Readonly<Record<string, unknown>>;\n\n/**\n * The block `then.open` names, drawn in the host after success (4.13): its implementation from\n * the mounted catalog (an app's over the kit's), its props validated against the block's schemas\n * at mount (P1b+P1c decision 35); a failed validation, or a block nothing implements, says so.\n */\nfunction FlowOpenBlock({\n open,\n testid,\n}: {\n readonly open: { readonly block: EntityRefLike; readonly props: Row };\n readonly prefix: string;\n readonly testid: string;\n}): ReactElement {\n const t = useOptionalT();\n const id = `${open.block.namespace}:${open.block.id}`;\n const implementation = selectImplementation(id, useFlowOpenImplementation(id) as never);\n const [validation, setValidation] = useState<PropValidation | null>(() =>\n implementation === undefined\n ? null\n : validatePlacementProps(implementation.definition as never, open.props),\n );\n useEffect(() => {\n if (validation?.status !== 'pending') return;\n let live = true;\n void validation.settled.then((settled) => {\n if (live) setValidation(settled);\n });\n return () => {\n live = false;\n };\n }, [validation]);\n const failed = implementation === undefined || validation?.status === 'failed';\n const View = implementation === undefined ? null : viewOf(implementation);\n return (\n <div\n data-testid={`${testid}:open`}\n data-buro-block={id}\n className=\"min-h-0 flex-1 overflow-y-auto\"\n >\n {failed ? (\n <p role=\"alert\" className=\"text-sm text-muted-foreground\">\n {t('block.notImplemented', { defaultValue: 'This section is not available.' })}\n </p>\n ) : View === null || validation?.status !== 'ready' ? null : (\n <Suspense fallback={null}>\n <View\n props={validation.props as never}\n data={NO_FIELDS as never}\n t={(key, options) =>\n t(`blocks.${id}.${key}`, {\n ...(options?.params === undefined ? {} : { params: options.params }),\n ...(options?.count === undefined ? {} : { count: options.count }),\n })\n }\n />\n </Suspense>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const require_use_theme = require("./use-theme-DFlpXils.cjs");
|
|
2
|
-
const require_check_confirm_dialog = require("./check-confirm-dialog-
|
|
2
|
+
const require_check_confirm_dialog = require("./check-confirm-dialog-BMSb7wFv.cjs");
|
|
3
3
|
const require_button = require("./button-BxnnE28H.cjs");
|
|
4
|
-
const require_place_node = require("./place-node-
|
|
4
|
+
const require_place_node = require("./place-node-C5ZmuHaN.cjs");
|
|
5
5
|
const require_success_notices = require("./success-notices-Cl4b6MLQ.cjs");
|
|
6
6
|
let _burojs_core = require("@burojs/core");
|
|
7
7
|
let _burojs_react = require("@burojs/react");
|
|
@@ -116,7 +116,12 @@ function OverlayBinding({ children }) {
|
|
|
116
116
|
function WithBinding({ children }) {
|
|
117
117
|
return (0, react.useContext)(FlowHostBindingContext) !== null ? (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children }) : (0, react_jsx_runtime.jsx)(OverlayBinding, { children });
|
|
118
118
|
}
|
|
119
|
-
function outcomeMessage(snapshot, busy, t, caps,
|
|
119
|
+
function outcomeMessage(snapshot, busy, t, caps, textPrefixes, flow, reasonOf) {
|
|
120
|
+
const place = { action: {
|
|
121
|
+
prefix: textPrefixes[0] ?? "",
|
|
122
|
+
prefixes: textPrefixes,
|
|
123
|
+
texts: flow?.texts
|
|
124
|
+
} };
|
|
120
125
|
if (busy) return t("flow.busyElsewhere", { defaultValue: "This action is running in another tab." });
|
|
121
126
|
const outcome = snapshot.outcome;
|
|
122
127
|
if (outcome === void 0 || outcome.outcome === "success") {
|
|
@@ -132,14 +137,11 @@ function outcomeMessage(snapshot, busy, t, caps, textPrefix, flow, reasonOf) {
|
|
|
132
137
|
const specific = (0, _burojs_react.specificErrorText)({
|
|
133
138
|
code,
|
|
134
139
|
..."message" in outcome && outcome.message !== void 0 ? { message: outcome.message } : {}
|
|
135
|
-
}, caps,
|
|
136
|
-
prefix: textPrefix,
|
|
137
|
-
texts: flow?.texts
|
|
138
|
-
} });
|
|
140
|
+
}, caps, place);
|
|
139
141
|
if (specific !== void 0) return specific;
|
|
140
142
|
}
|
|
141
143
|
const key = kind === void 0 ? void 0 : _burojs_react.REJECTED_KEYS[kind];
|
|
142
|
-
if (key !== void 0) return t(`${
|
|
144
|
+
if (key !== void 0) return textPrefixes.reduceRight((rest, prefix) => t(`${prefix}.rejected.${key}`, { defaultValue: rest }), (0, _burojs_core.textsValueAt)(flow?.texts, ["rejected", key]) ?? t(`flow.rejected.${key}`, { defaultValue: "Nothing was saved." }));
|
|
143
145
|
return t("flow.rejected.precondition", { defaultValue: "The record changed. Nothing was sent." });
|
|
144
146
|
}
|
|
145
147
|
if (outcome.outcome === "failed") {
|
|
@@ -148,10 +150,7 @@ function outcomeMessage(snapshot, busy, t, caps, textPrefix, flow, reasonOf) {
|
|
|
148
150
|
return (code === void 0 ? void 0 : (0, _burojs_react.specificErrorText)({
|
|
149
151
|
code,
|
|
150
152
|
..."message" in outcome && outcome.message !== void 0 ? { message: outcome.message } : {}
|
|
151
|
-
}, caps, {
|
|
152
|
-
prefix: textPrefix,
|
|
153
|
-
texts: flow?.texts
|
|
154
|
-
} })) ?? t("flow.failed", { defaultValue: "The request could not be sent. Nothing was saved." });
|
|
153
|
+
}, caps, place)) ?? t("flow.failed", { defaultValue: "The request could not be sent. Nothing was saved." });
|
|
155
154
|
}
|
|
156
155
|
return null;
|
|
157
156
|
}
|
|
@@ -357,9 +356,10 @@ function FlowScreenBody({ run, host, label, title: givenTitle, compiled, record:
|
|
|
357
356
|
}
|
|
358
357
|
settle(await run.submit());
|
|
359
358
|
};
|
|
360
|
-
const
|
|
361
|
-
const
|
|
362
|
-
const
|
|
359
|
+
const ownKey = (slot) => compiled.textKeys.prefixes.map((prefix) => `${prefix}.${slot}`).find((key) => caps.has(key));
|
|
360
|
+
const pendingKey = ownKey("pending");
|
|
361
|
+
const pendingLabel = pendingKey !== void 0 ? caps.t(pendingKey) : `${label}…`;
|
|
362
|
+
const message = outcomeMessage(snapshot, busy, t, caps, compiled.textKeys.prefixes, compiled.flow, (reason) => require_check_confirm_dialog.reasonText(caps, reason, resource));
|
|
363
363
|
const formErrorTexts = formErrors.map((issue) => (0, _burojs_react.resolveValidationMessage)({
|
|
364
364
|
code: issue.code ?? "",
|
|
365
365
|
message: issue.message,
|
|
@@ -368,8 +368,8 @@ function FlowScreenBody({ run, host, label, title: givenTitle, compiled, record:
|
|
|
368
368
|
has: caps.has,
|
|
369
369
|
t: caps.t
|
|
370
370
|
})).filter((text) => text !== message);
|
|
371
|
-
const dismissKey =
|
|
372
|
-
const cancelWord = (
|
|
371
|
+
const dismissKey = ownKey("dismiss");
|
|
372
|
+
const cancelWord = (dismissKey !== void 0 ? caps.t(dismissKey) : void 0) ?? (0, _burojs_core.declaredText)("flow", compiled.flow, "dismiss") ?? chromeT("actions.cancel", { defaultValue: "Cancel" });
|
|
373
373
|
const couldNotCheck = snapshot.control === "disabled" && snapshot.unverified === true;
|
|
374
374
|
const steps = form.steps;
|
|
375
375
|
const lastStep = steps === null || steps.ids.length === 0 || steps.current === steps.ids[steps.ids.length - 1];
|
|
@@ -787,4 +787,4 @@ exports.FlowHostBindingContext = FlowHostBindingContext;
|
|
|
787
787
|
exports.FlowScreen = FlowScreen;
|
|
788
788
|
exports.HostedFlowScreen = HostedFlowScreen;
|
|
789
789
|
|
|
790
|
-
//# sourceMappingURL=flow-screen-
|
|
790
|
+
//# sourceMappingURL=flow-screen-sw2cP70t.cjs.map
|