@mgamadeus/ddd-agents 0.1.0-alpha.25 → 0.1.0-alpha.27
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/chat.js +6 -6
- package/dist/chunks/{ConversationMessageInputComposerWidgets-BxyaFBA6.js → ConversationMessageInputComposerWidgets-CzQnpW0h.js} +4 -4
- package/dist/chunks/{ConversationMessageInputComposerWidgets-BxyaFBA6.js.map → ConversationMessageInputComposerWidgets-CzQnpW0h.js.map} +1 -1
- package/dist/chunks/{WebSearchResultsConversationWidget-as3p5bHw.js → WebSearchResultsConversationWidget-tDhawe9f.js} +55 -50
- package/dist/chunks/{WebSearchResultsConversationWidget-as3p5bHw.js.map → WebSearchResultsConversationWidget-tDhawe9f.js.map} +1 -1
- package/dist/chunks/{canvas-reducers-Bfp_i7lc.js → canvas-reducers-BdIPZW_6.js} +2 -2
- package/dist/chunks/{canvas-reducers-Bfp_i7lc.js.map → canvas-reducers-BdIPZW_6.js.map} +1 -1
- package/dist/chunks/{canvasBodies-Cvu3l38p.js → canvasBodies-BiUt8MUG.js} +3 -3
- package/dist/chunks/{canvasBodies-Cvu3l38p.js.map → canvasBodies-BiUt8MUG.js.map} +1 -1
- package/dist/chunks/index-7Qc_3GbG.js.map +1 -1
- package/dist/chunks/{widget-click-signal-sources-DulRkNvZ.js → widget-click-signal-sources-BR82QygL.js} +3 -3
- package/dist/chunks/{widget-click-signal-sources-DulRkNvZ.js.map → widget-click-signal-sources-BR82QygL.js.map} +1 -1
- package/dist/chunks/{widget-name-resolver-BGN3HpoG.js → widget-name-resolver-BaxKaRa3.js} +2 -2
- package/dist/chunks/{widget-name-resolver-BGN3HpoG.js.map → widget-name-resolver-BaxKaRa3.js.map} +1 -1
- package/dist/client-testing.js +3 -3
- package/dist/image-render.js +4 -4
- package/dist/index.js +3 -3
- package/dist/kit.js +2 -2
- package/dist/preview.js +5 -5
- package/dist/renderer.js +7 -7
- package/dist/types/entries/widgets.d.ts +1 -0
- package/dist/types/provider/environment.d.ts +5 -1
- package/dist/widgets.js +34 -32
- package/package.json +1 -1
- package/public-api.json +2 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { c as canvasBehaviourOf } from "./canvas-behaviours-AvzKSYyv.js";
|
|
3
|
-
import { s as sameCanvasIdentity } from "./WebSearchResultsConversationWidget-
|
|
3
|
+
import { s as sameCanvasIdentity } from "./WebSearchResultsConversationWidget-tDhawe9f.js";
|
|
4
4
|
const ACCEPT = { kind: "accept" };
|
|
5
5
|
const ignore = (reason) => ({ kind: "ignore", reason });
|
|
6
6
|
const decideCanvasOpen = (behaviour, openCanvas, lastClosedCanvas, request) => {
|
|
@@ -85,4 +85,4 @@ export {
|
|
|
85
85
|
applySetCanvasCreatedEntityId as e,
|
|
86
86
|
decideCanvasOpen as f
|
|
87
87
|
};
|
|
88
|
-
//# sourceMappingURL=canvas-reducers-
|
|
88
|
+
//# sourceMappingURL=canvas-reducers-BdIPZW_6.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canvas-reducers-Bfp_i7lc.js","sources":["../../src/renderer/canvas/decide-canvas-open.ts","../../src/renderer/canvas/canvas-reducers.ts"],"sourcesContent":["import type { CanvasBehaviour } from \"./canvas-behaviours\";\nimport { CanvasOpenRequest, CanvasState, LastClosedCanvas, sameCanvasIdentity } from \"./canvas-state\";\n\n/**\n * Why an open request is ignored. Every reason is a sentence the shell could log:\n * - `unknownCanvas` no behaviour is declared for the id (a stale stored pointer, a typo)\n * - `noSurface` the host renders no split (`disableSplitView`), so there is nowhere to open\n * - `replay` a delivery-origin request for a message that was NOT just delivered — history\n * replay, a reload, scroll-back; rejected BEFORE anything is read or written\n * - `alreadyOpen` a delivery-origin request for the identity that is already open (the agent re-emits\n * an editor widget after a rebuild) — the open canvas is kept, never remounted\n * - `customerClosedIt` the customer closed exactly this identity and nothing has cleared the veto yet\n * - `noTakeoverOnNarrowViewport` a live delivery on a narrow viewport of a canvas that declares no overlay — the\n * card stays, the customer taps it\n */\nexport type CanvasOpenIgnoreReason =\n | \"unknownCanvas\"\n | \"noSurface\"\n | \"replay\"\n | \"alreadyOpen\"\n | \"customerClosedIt\"\n | \"noTakeoverOnNarrowViewport\";\n\nexport type CanvasOpenDecision =\n | { readonly kind: \"accept\" }\n | { readonly kind: \"ignore\"; readonly reason: CanvasOpenIgnoreReason };\n\nconst ACCEPT: CanvasOpenDecision = { kind: \"accept\" };\n\nconst ignore = (reason: CanvasOpenIgnoreReason): CanvasOpenDecision => ({ kind: \"ignore\", reason });\n\n/**\n * THE opening rule — the one place that answers \"may this canvas open now?\". Pure: it reads the behaviour, the open\n * canvas, the last closed one and the request, and returns Accept or Ignore. It never mutates; the reducer\n * (`canvas-reducers.ts`) applies an Accept. There is no merge rung: the same identity opened again from a card click\n * is a fresh Accept (remount), and the refresh contract of a pinned work surface is a value the body derives from the\n * message list, not a reducer merge.\n *\n * A `cardClick`, an `openedByPage` and a `restoredAfterReload` request always open (the customer, the page or the\n * stored pointer decided); only `deliveredInMessage` is judged.\n */\nexport const decideCanvasOpen = (\n behaviour: CanvasBehaviour | undefined,\n openCanvas: CanvasState | null,\n lastClosedCanvas: LastClosedCanvas | null,\n request: CanvasOpenRequest,\n): CanvasOpenDecision => {\n if (behaviour === undefined) return ignore(\"unknownCanvas\");\n if (!request.hostHasCanvasSurface) return ignore(\"noSurface\");\n if (request.origin !== \"deliveredInMessage\") return ACCEPT;\n\n // Replay is rejected first: a replayed message must not touch the open canvas in any way.\n if (!request.justDelivered) return ignore(\"replay\");\n if (openCanvas !== null && sameCanvasIdentity(openCanvas, request)) return ignore(\"alreadyOpen\");\n if (lastClosedCanvas !== null && lastClosedCanvas.closedByCustomer && sameCanvasIdentity(lastClosedCanvas, request)) {\n return ignore(\"customerClosedIt\");\n }\n if (!request.viewportViable && behaviour.narrowViewport === \"none\") return ignore(\"noTakeoverOnNarrowViewport\");\n return ACCEPT;\n};\n","import { canvasBehaviourOf } from \"./canvas-behaviours\";\nimport { CanvasOpenRequest, CanvasState, LastClosedCanvas, sameCanvasIdentity } from \"./canvas-state\";\nimport { CanvasOpenDecision, decideCanvasOpen } from \"./decide-canvas-open\";\n\n/**\n * The canvas part of a chat slice partition — the two fields every transition reads and writes. Both chat doors carry\n * them (`ConversationState`); the shell is shared, so the state must have the same shape in both partitions.\n */\nexport interface CanvasSliceState {\n canvas: CanvasState | null;\n lastClosedCanvas: LastClosedCanvas | null;\n /**\n * How many canvases this partition has mounted so far — the source of `mountGeneration`. Never reset by a close,\n * a send or a clear (and exempt from `resetState`), so a late asynchronous write from a body that was replaced,\n * cleared or belonged to the previous conversation can never match a new canvas's generation.\n */\n canvasMountCount: number;\n}\n\n/**\n * The lifetime state machine as REDUCERS. Hand-written, not generated setters:\n * a generated setter is a blind overwrite of a snapshot the caller read a render earlier, and two opens in one commit\n * would both see the same stale state. Each function mutates the Immer draft it receives and returns the decision it\n * applied, so the slice can expose them as case reducers and a spec can assert every transition on a plain object.\n */\n\nconst toLastClosed = (canvas: CanvasState, closedByCustomer: boolean): LastClosedCanvas => ({\n canvasId: canvas.canvasId,\n instanceId: canvas.instanceId,\n anchor: canvas.anchor,\n mountGeneration: canvas.mountGeneration,\n closedByCustomer,\n ...(canvas.createdEntityId !== undefined ? { createdEntityId: canvas.createdEntityId } : {}),\n});\n\n/** Next render key: strictly increasing for the partition's lifetime, so no two mounts ever share a generation. */\nconst nextMountGeneration = (state: CanvasSliceState): number => {\n state.canvasMountCount += 1;\n return state.canvasMountCount;\n};\n\n/**\n * Open a canvas — the ONE way to open, for all four origins. On Accept: the replaced canvas (a different identity)\n * becomes `lastClosedCanvas`; a `lastClosedCanvas` of the accepted identity is consumed (its veto is cleared — the\n * customer, the page or the restore decided to have it back); the created entity survives a re-open of the same\n * identity so a restored editor keeps its draft.\n */\nexport const applyOpenCanvas = (state: CanvasSliceState, request: CanvasOpenRequest): CanvasOpenDecision => {\n const decision = decideCanvasOpen(canvasBehaviourOf(request.canvasId), state.canvas, state.lastClosedCanvas, request);\n if (decision.kind === \"ignore\") return decision;\n\n const previous = state.canvas;\n const mountGeneration = nextMountGeneration(state);\n const carriedCreatedEntityId =\n request.createdEntityId ??\n (previous !== null && sameCanvasIdentity(previous, request) ? previous.createdEntityId : undefined) ??\n (state.lastClosedCanvas !== null && sameCanvasIdentity(state.lastClosedCanvas, request)\n ? state.lastClosedCanvas.createdEntityId\n : undefined);\n\n if (previous !== null && !sameCanvasIdentity(previous, request)) {\n state.lastClosedCanvas = toLastClosed(previous, false);\n } else if (state.lastClosedCanvas !== null && sameCanvasIdentity(state.lastClosedCanvas, request)) {\n state.lastClosedCanvas = null;\n }\n state.canvas = {\n canvasId: request.canvasId,\n instanceId: request.instanceId,\n anchor: request.anchor,\n origin: request.origin,\n mountGeneration,\n ...(carriedCreatedEntityId !== undefined ? { createdEntityId: carriedCreatedEntityId } : {}),\n };\n return decision;\n};\n\n/**\n * Close the open canvas but keep it re-openable: it becomes `lastClosedCanvas`. `byCustomer` marks the customer's own\n * close (the canvas close control) — a live delivery of the same identity is then ignored until a send, a card click\n * or a page hand-over. A shell-driven close (compact mode, the side panel opening, a narrow crossing) passes false.\n */\nexport const applyCloseCanvas = (state: CanvasSliceState, byCustomer: boolean): void => {\n if (state.canvas === null) return;\n state.lastClosedCanvas = toLastClosed(state.canvas, byCustomer);\n state.canvas = null;\n};\n\n/**\n * The SEND boundary: a new user message starts a new turn. A `turn` canvas is over for good — it leaves the open slot\n * AND `lastClosedCanvas` (the card in the transcript is the way back). A `pinned` canvas stays open,\n * and a closed pinned one stays re-openable with its customer veto cleared (the send is a clearing edge).\n */\nexport const applyResetCanvasForNewTurn = (state: CanvasSliceState): void => {\n if (state.canvas !== null && canvasBehaviourOf(state.canvas.canvasId)?.lifetime === \"turn\") {\n state.canvas = null;\n }\n if (state.lastClosedCanvas !== null) {\n if (canvasBehaviourOf(state.lastClosedCanvas.canvasId)?.lifetime === \"turn\") {\n state.lastClosedCanvas = null;\n } else if (state.lastClosedCanvas.closedByCustomer) {\n state.lastClosedCanvas = { ...state.lastClosedCanvas, closedByCustomer: false };\n }\n }\n};\n\n/** Forget the canvas entirely — a conversation switch, `closeAgent`, the modal unmount. Nothing is re-openable. */\nexport const applyClearCanvas = (state: CanvasSliceState): void => {\n state.canvas = null;\n state.lastClosedCanvas = null;\n};\n\nexport interface CanvasCreatedEntity {\n readonly canvasId: CanvasState[\"canvasId\"];\n readonly instanceId: string;\n /** The generation the body was mounted with — a late write from a body that was replaced meanwhile is dropped. */\n readonly mountGeneration: number;\n readonly createdEntityId: number;\n}\n\n/** A body created its entity (the post editor's draft): remember the id on the canvas it was created for. */\nexport const applySetCanvasCreatedEntityId = (state: CanvasSliceState, created: CanvasCreatedEntity): boolean => {\n const canvas = state.canvas;\n if (canvas === null || !sameCanvasIdentity(canvas, created) || canvas.mountGeneration !== created.mountGeneration) {\n return false;\n }\n state.canvas = { ...canvas, createdEntityId: created.createdEntityId };\n return true;\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"canvas-reducers-BdIPZW_6.js","sources":["../../src/renderer/canvas/decide-canvas-open.ts","../../src/renderer/canvas/canvas-reducers.ts"],"sourcesContent":["import type { CanvasBehaviour } from \"./canvas-behaviours\";\nimport { CanvasOpenRequest, CanvasState, LastClosedCanvas, sameCanvasIdentity } from \"./canvas-state\";\n\n/**\n * Why an open request is ignored. Every reason is a sentence the shell could log:\n * - `unknownCanvas` no behaviour is declared for the id (a stale stored pointer, a typo)\n * - `noSurface` the host renders no split (`disableSplitView`), so there is nowhere to open\n * - `replay` a delivery-origin request for a message that was NOT just delivered — history\n * replay, a reload, scroll-back; rejected BEFORE anything is read or written\n * - `alreadyOpen` a delivery-origin request for the identity that is already open (the agent re-emits\n * an editor widget after a rebuild) — the open canvas is kept, never remounted\n * - `customerClosedIt` the customer closed exactly this identity and nothing has cleared the veto yet\n * - `noTakeoverOnNarrowViewport` a live delivery on a narrow viewport of a canvas that declares no overlay — the\n * card stays, the customer taps it\n */\nexport type CanvasOpenIgnoreReason =\n | \"unknownCanvas\"\n | \"noSurface\"\n | \"replay\"\n | \"alreadyOpen\"\n | \"customerClosedIt\"\n | \"noTakeoverOnNarrowViewport\";\n\nexport type CanvasOpenDecision =\n | { readonly kind: \"accept\" }\n | { readonly kind: \"ignore\"; readonly reason: CanvasOpenIgnoreReason };\n\nconst ACCEPT: CanvasOpenDecision = { kind: \"accept\" };\n\nconst ignore = (reason: CanvasOpenIgnoreReason): CanvasOpenDecision => ({ kind: \"ignore\", reason });\n\n/**\n * THE opening rule — the one place that answers \"may this canvas open now?\". Pure: it reads the behaviour, the open\n * canvas, the last closed one and the request, and returns Accept or Ignore. It never mutates; the reducer\n * (`canvas-reducers.ts`) applies an Accept. There is no merge rung: the same identity opened again from a card click\n * is a fresh Accept (remount), and the refresh contract of a pinned work surface is a value the body derives from the\n * message list, not a reducer merge.\n *\n * A `cardClick`, an `openedByPage` and a `restoredAfterReload` request always open (the customer, the page or the\n * stored pointer decided); only `deliveredInMessage` is judged.\n */\nexport const decideCanvasOpen = (\n behaviour: CanvasBehaviour | undefined,\n openCanvas: CanvasState | null,\n lastClosedCanvas: LastClosedCanvas | null,\n request: CanvasOpenRequest,\n): CanvasOpenDecision => {\n if (behaviour === undefined) return ignore(\"unknownCanvas\");\n if (!request.hostHasCanvasSurface) return ignore(\"noSurface\");\n if (request.origin !== \"deliveredInMessage\") return ACCEPT;\n\n // Replay is rejected first: a replayed message must not touch the open canvas in any way.\n if (!request.justDelivered) return ignore(\"replay\");\n if (openCanvas !== null && sameCanvasIdentity(openCanvas, request)) return ignore(\"alreadyOpen\");\n if (lastClosedCanvas !== null && lastClosedCanvas.closedByCustomer && sameCanvasIdentity(lastClosedCanvas, request)) {\n return ignore(\"customerClosedIt\");\n }\n if (!request.viewportViable && behaviour.narrowViewport === \"none\") return ignore(\"noTakeoverOnNarrowViewport\");\n return ACCEPT;\n};\n","import { canvasBehaviourOf } from \"./canvas-behaviours\";\nimport { CanvasOpenRequest, CanvasState, LastClosedCanvas, sameCanvasIdentity } from \"./canvas-state\";\nimport { CanvasOpenDecision, decideCanvasOpen } from \"./decide-canvas-open\";\n\n/**\n * The canvas part of a chat slice partition — the two fields every transition reads and writes. Both chat doors carry\n * them (`ConversationState`); the shell is shared, so the state must have the same shape in both partitions.\n */\nexport interface CanvasSliceState {\n canvas: CanvasState | null;\n lastClosedCanvas: LastClosedCanvas | null;\n /**\n * How many canvases this partition has mounted so far — the source of `mountGeneration`. Never reset by a close,\n * a send or a clear (and exempt from `resetState`), so a late asynchronous write from a body that was replaced,\n * cleared or belonged to the previous conversation can never match a new canvas's generation.\n */\n canvasMountCount: number;\n}\n\n/**\n * The lifetime state machine as REDUCERS. Hand-written, not generated setters:\n * a generated setter is a blind overwrite of a snapshot the caller read a render earlier, and two opens in one commit\n * would both see the same stale state. Each function mutates the Immer draft it receives and returns the decision it\n * applied, so the slice can expose them as case reducers and a spec can assert every transition on a plain object.\n */\n\nconst toLastClosed = (canvas: CanvasState, closedByCustomer: boolean): LastClosedCanvas => ({\n canvasId: canvas.canvasId,\n instanceId: canvas.instanceId,\n anchor: canvas.anchor,\n mountGeneration: canvas.mountGeneration,\n closedByCustomer,\n ...(canvas.createdEntityId !== undefined ? { createdEntityId: canvas.createdEntityId } : {}),\n});\n\n/** Next render key: strictly increasing for the partition's lifetime, so no two mounts ever share a generation. */\nconst nextMountGeneration = (state: CanvasSliceState): number => {\n state.canvasMountCount += 1;\n return state.canvasMountCount;\n};\n\n/**\n * Open a canvas — the ONE way to open, for all four origins. On Accept: the replaced canvas (a different identity)\n * becomes `lastClosedCanvas`; a `lastClosedCanvas` of the accepted identity is consumed (its veto is cleared — the\n * customer, the page or the restore decided to have it back); the created entity survives a re-open of the same\n * identity so a restored editor keeps its draft.\n */\nexport const applyOpenCanvas = (state: CanvasSliceState, request: CanvasOpenRequest): CanvasOpenDecision => {\n const decision = decideCanvasOpen(canvasBehaviourOf(request.canvasId), state.canvas, state.lastClosedCanvas, request);\n if (decision.kind === \"ignore\") return decision;\n\n const previous = state.canvas;\n const mountGeneration = nextMountGeneration(state);\n const carriedCreatedEntityId =\n request.createdEntityId ??\n (previous !== null && sameCanvasIdentity(previous, request) ? previous.createdEntityId : undefined) ??\n (state.lastClosedCanvas !== null && sameCanvasIdentity(state.lastClosedCanvas, request)\n ? state.lastClosedCanvas.createdEntityId\n : undefined);\n\n if (previous !== null && !sameCanvasIdentity(previous, request)) {\n state.lastClosedCanvas = toLastClosed(previous, false);\n } else if (state.lastClosedCanvas !== null && sameCanvasIdentity(state.lastClosedCanvas, request)) {\n state.lastClosedCanvas = null;\n }\n state.canvas = {\n canvasId: request.canvasId,\n instanceId: request.instanceId,\n anchor: request.anchor,\n origin: request.origin,\n mountGeneration,\n ...(carriedCreatedEntityId !== undefined ? { createdEntityId: carriedCreatedEntityId } : {}),\n };\n return decision;\n};\n\n/**\n * Close the open canvas but keep it re-openable: it becomes `lastClosedCanvas`. `byCustomer` marks the customer's own\n * close (the canvas close control) — a live delivery of the same identity is then ignored until a send, a card click\n * or a page hand-over. A shell-driven close (compact mode, the side panel opening, a narrow crossing) passes false.\n */\nexport const applyCloseCanvas = (state: CanvasSliceState, byCustomer: boolean): void => {\n if (state.canvas === null) return;\n state.lastClosedCanvas = toLastClosed(state.canvas, byCustomer);\n state.canvas = null;\n};\n\n/**\n * The SEND boundary: a new user message starts a new turn. A `turn` canvas is over for good — it leaves the open slot\n * AND `lastClosedCanvas` (the card in the transcript is the way back). A `pinned` canvas stays open,\n * and a closed pinned one stays re-openable with its customer veto cleared (the send is a clearing edge).\n */\nexport const applyResetCanvasForNewTurn = (state: CanvasSliceState): void => {\n if (state.canvas !== null && canvasBehaviourOf(state.canvas.canvasId)?.lifetime === \"turn\") {\n state.canvas = null;\n }\n if (state.lastClosedCanvas !== null) {\n if (canvasBehaviourOf(state.lastClosedCanvas.canvasId)?.lifetime === \"turn\") {\n state.lastClosedCanvas = null;\n } else if (state.lastClosedCanvas.closedByCustomer) {\n state.lastClosedCanvas = { ...state.lastClosedCanvas, closedByCustomer: false };\n }\n }\n};\n\n/** Forget the canvas entirely — a conversation switch, `closeAgent`, the modal unmount. Nothing is re-openable. */\nexport const applyClearCanvas = (state: CanvasSliceState): void => {\n state.canvas = null;\n state.lastClosedCanvas = null;\n};\n\nexport interface CanvasCreatedEntity {\n readonly canvasId: CanvasState[\"canvasId\"];\n readonly instanceId: string;\n /** The generation the body was mounted with — a late write from a body that was replaced meanwhile is dropped. */\n readonly mountGeneration: number;\n readonly createdEntityId: number;\n}\n\n/** A body created its entity (the post editor's draft): remember the id on the canvas it was created for. */\nexport const applySetCanvasCreatedEntityId = (state: CanvasSliceState, created: CanvasCreatedEntity): boolean => {\n const canvas = state.canvas;\n if (canvas === null || !sameCanvasIdentity(canvas, created) || canvas.mountGeneration !== created.mountGeneration) {\n return false;\n }\n state.canvas = { ...canvas, createdEntityId: created.createdEntityId };\n return true;\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useMemo, useCallback, useContext, createContext, useState } from "react";
|
|
4
|
-
import { p as payloadHashOfInstanceId, E as useConversationWidgetContext,
|
|
5
|
-
import { m as findWidgetFenceByPayloadHash, n as findWidgetFencesInMarkdown, K as readEntityDetailInstanceId, L as readMapNodeKeyOfInstanceId, M as findMapNodeInMarkdown, D as readOpenEntityActionTarget, N as canvasInstanceIdForEntityDetail, O as mapStyles, P as MapPresentationContext, e as ComposedViewRenderer } from "./widget-name-resolver-
|
|
4
|
+
import { p as payloadHashOfInstanceId, E as useConversationWidgetContext, as as parseConversationSearchResultsPayload, at as WebSearchAnswer, au as WebSearchSourcesList, av as parseWebSearchResultsPayload, aw as ENTITY_MENTION_WIDGET_NAME, ax as buildEntityMentionFields, ay as normalizeEntityMentionFields, az as entityMentionKey, aA as MAX_ENTITY_MENTIONS_PER_MESSAGE, aB as toEntityMentionWireFields, F as useIsEmailWidgetRender, aC as ConversationWidgetButton } from "./WebSearchResultsConversationWidget-tDhawe9f.js";
|
|
5
|
+
import { m as findWidgetFenceByPayloadHash, n as findWidgetFencesInMarkdown, K as readEntityDetailInstanceId, L as readMapNodeKeyOfInstanceId, M as findMapNodeInMarkdown, D as readOpenEntityActionTarget, N as canvasInstanceIdForEntityDetail, O as mapStyles, P as MapPresentationContext, e as ComposedViewRenderer } from "./widget-name-resolver-BaxKaRa3.js";
|
|
6
6
|
import { q as Text, a as ConversationSearchResultsList } from "./index-7Qc_3GbG.js";
|
|
7
7
|
import { E as EntityDetailNameReportContext } from "./entity-detail-name-3A82gDAp.js";
|
|
8
8
|
const useAnchorWidgetPayload = (canvas, anchorMessageMarkdown, widgetName) => useMemo(() => {
|
|
@@ -292,4 +292,4 @@ export {
|
|
|
292
292
|
readEntityDetailBodyDefinitions as r,
|
|
293
293
|
useAnchorWidgetPayload as u
|
|
294
294
|
};
|
|
295
|
-
//# sourceMappingURL=canvasBodies-
|
|
295
|
+
//# sourceMappingURL=canvasBodies-BiUt8MUG.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canvasBodies-Cvu3l38p.js","sources":["../../src/renderer/canvas/use-anchor-widget-payload.ts","../../src/widgets/ConversationSearchResultsConversationWidget/ConversationSearchResultsCanvas.tsx","../../src/widgets/ConversationSearchResultsConversationWidget/ConversationSearchResultsCanvasBody.tsx","../../src/widgets/WebSearchResultsConversationWidget/WebSearchResultsCanvas.tsx","../../src/widgets/WebSearchResultsConversationWidget/WebSearchResultsCanvasBody.tsx","../../src/widgets/EntityMentionConversationWidget/shared/use-entity-mention-composer.ts","../../src/widgets/EntityMentionConversationWidget/EntityMentionAskButton/EntityMentionAskButton.tsx","../../src/kit/entity-detail/entity-detail-bodies.ts","../../src/kit/entity-detail/EntityDetailCanvasBody.tsx","../../src/kit/map-full-screen/MapFullScreenCanvasBody.tsx","../../src/renderer/canvas/canvasBodies.tsx"],"sourcesContent":["import { useMemo } from \"react\";\nimport type { CanvasState } from \"./canvas-state\";\nimport { payloadHashOfInstanceId } from \"./canvas-state\";\nimport { findWidgetFenceByPayloadHash, findWidgetFencesInMarkdown } from \"./find-widget-fences-in-markdown\";\n\n/**\n * The payload string of the widget a message-anchored canvas was opened from: the fence of `widgetName` in the anchor\n * message whose payload hash the canvas instance id carries (`canvasInstanceIdForMessagePayload`); when the instance\n * id carries no hash (one canvas per message), the first fence of that name. Undefined for a page anchor, a missing\n * anchor message, or a message that no longer carries the fence — the body then renders nothing.\n */\nexport const useAnchorWidgetPayload = (\n canvas: CanvasState,\n anchorMessageMarkdown: string | null,\n widgetName: string,\n): string | undefined =>\n useMemo(() => {\n if (canvas.anchor.kind !== \"message\" || anchorMessageMarkdown === null) return undefined;\n const payloadHash = payloadHashOfInstanceId(canvas.instanceId);\n if (payloadHash !== undefined) {\n return findWidgetFenceByPayloadHash(anchorMessageMarkdown, widgetName, payloadHash)?.payload;\n }\n return findWidgetFencesInMarkdown(anchorMessageMarkdown).find((fence) => fence.name === widgetName)?.payload;\n }, [canvas.anchor, canvas.instanceId, anchorMessageMarkdown, widgetName]);\n","import { ConversationSearchResultsList, Text } from \"../../provider/components\";\nimport React from \"react\";\nimport { parseConversationSearchResultsPayload } from \"./shared/conversation-search-results-widget-payload\";\n\ntype ConversationSearchResultsCanvasProps = {\n query: string;\n groups: ReturnType<typeof parseConversationSearchResultsPayload>[\"groups\"];\n onOpenConversation: (conversationId: number, messageId?: number) => void;\n};\n\n// Canvas body styles — the same as every list canvas body, so the full-screen panel behaves the same:\n// a full-height flex column whose inner area SCROLLS (scrollStyle: flex 1 + overflowY auto — without it the content\n// overflows the panel with no scrollbar), plus a horizontal inset (contentStyle) because the results list is built\n// for the narrow inline chat column where the bubble provides the gutter — in the canvas there is no bubble, so it would\n// otherwise render edge-to-edge.\nconst canvasStyle: React.CSSProperties = {\n width: \"100%\",\n height: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n minHeight: 0,\n background: \"var(--agents-bg)\",\n};\nconst scrollStyle: React.CSSProperties = {\n flex: 1,\n minHeight: 0,\n overflowY: \"auto\",\n};\nconst contentStyle: React.CSSProperties = {\n padding: \"16px 24px 24px\",\n};\n\n/** The canvas body — a titled wrapper around the same grouped results, scrollable + inset like the other canvas widgets. */\nexport const ConversationSearchResultsCanvas = (props: ConversationSearchResultsCanvasProps) => (\n <div style={canvasStyle} data-testid=\"conversation-search-results-widget-canvas\">\n <div style={scrollStyle}>\n <div style={contentStyle} data-testid=\"conversation-search-results-widget-canvas-results\">\n <Text\n role=\"title\"\n replacements={{ query: props.query }}\n testId=\"conversation-search-results-widget-canvas-title\"\n >\n {'Search results for \"%query%\"'}\n </Text>\n <ConversationSearchResultsList groups={props.groups} query={props.query} onOpenConversation={props.onOpenConversation} />\n </div>\n </div>\n </div>\n);\n","import React, { useMemo } from \"react\";\nimport type { CanvasBodyProps } from \"../../renderer/canvas/canvas-body-props\";\nimport { useConversationWidgetContext } from \"../../renderer/ConversationWidgetCallbacksContext\";\nimport { useAnchorWidgetPayload } from \"../../renderer/canvas/use-anchor-widget-payload\";\nimport { parseConversationSearchResultsPayload } from \"./shared/conversation-search-results-widget-payload\";\nimport { ConversationSearchResultsCanvas } from \"./ConversationSearchResultsCanvas\";\n\n/**\n * The `conversationSearchResults` CANVAS BODY (`canvasBodies.tsx`): re-reads the `ConversationSearchResults` fence of\n * the anchor message — the same payload the inline widget rendered from — and shows the grouped results. Nothing was\n * stored for it but the pointer. Renders nothing when the anchor message no longer carries the fence.\n */\nexport const ConversationSearchResultsCanvasBody = ({ canvas, anchorMessageMarkdown }: CanvasBodyProps) => {\n const { onOpenConversation } = useConversationWidgetContext();\n const payload = useAnchorWidgetPayload(canvas, anchorMessageMarkdown, \"ConversationSearchResults\");\n const parsed = useMemo(\n () => (payload === undefined ? null : parseConversationSearchResultsPayload(payload)),\n [payload],\n );\n if (parsed === null || parsed.groups.length === 0) return null;\n return (\n <ConversationSearchResultsCanvas\n query={parsed.query}\n groups={parsed.groups}\n onOpenConversation={(conversationId, messageId) => onOpenConversation?.(conversationId, messageId)}\n />\n );\n};\n","import { Text } from \"../../provider/components\";\nimport React from \"react\";\nimport { WebSearchResultSource } from \"./shared/web-search-results-widget-payload\";\nimport { WebSearchAnswer } from \"./WebSearchAnswer\";\nimport { WebSearchSourcesList } from \"./WebSearchSourcesList\";\n\ntype WebSearchResultsCanvasProps = {\n query: string;\n answer: string;\n sources: WebSearchResultSource[];\n provider?: string;\n};\n\n// Canvas body styles — mirror the ConversationSearchResults / listReviews drawer widgets: a full-height flex column\n// whose inner area SCROLLS (flex 1 + overflowY auto) with a horizontal inset (there is no chat bubble gutter in the canvas).\nconst canvasStyle: React.CSSProperties = {\n width: \"100%\",\n height: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n minHeight: 0,\n background: \"var(--agents-bg)\",\n};\nconst scrollStyle: React.CSSProperties = { flex: 1, minHeight: 0, overflowY: \"auto\" };\nconst contentStyle: React.CSSProperties = { padding: \"16px 24px 24px\" };\n\n/** The canvas body — the full answer + sources, scrollable + inset like the other canvas widgets. */\nexport const WebSearchResultsCanvas = (props: WebSearchResultsCanvasProps) => (\n <div style={canvasStyle} data-testid=\"web-search-results-widget-canvas\">\n <div style={scrollStyle}>\n <div style={contentStyle}>\n {props.query ? (\n <Text\n role=\"title\"\n replacements={{ query: props.query }}\n testId=\"web-search-results-widget-canvas-title\"\n >\n {'\"%query%\"'}\n </Text>\n ) : (\n <Text role=\"title\" testId=\"web-search-results-widget-canvas-title\">\n Web search\n </Text>\n )}\n <div style={{ marginTop: 12 }}>\n <WebSearchAnswer answer={props.answer} />\n </div>\n <WebSearchSourcesList\n sources={props.sources}\n provider={props.provider}\n testId=\"web-search-results-widget-canvas\"\n />\n </div>\n </div>\n </div>\n);\n","import React, { useMemo } from \"react\";\nimport type { CanvasBodyProps } from \"../../renderer/canvas/canvas-body-props\";\nimport { useAnchorWidgetPayload } from \"../../renderer/canvas/use-anchor-widget-payload\";\nimport { parseWebSearchResultsPayload } from \"./shared/web-search-results-widget-payload\";\nimport { WebSearchResultsCanvas } from \"./WebSearchResultsCanvas\";\n\n/**\n * The `webSearchResults` CANVAS BODY (`canvasBodies.tsx`): re-reads the `WebSearchResults` fence of the anchor message\n * — the answer and its cited sources the inline widget rendered from — and shows them in the canvas. Renders nothing\n * when the anchor message no longer carries the fence.\n */\nexport const WebSearchResultsCanvasBody = ({ canvas, anchorMessageMarkdown }: CanvasBodyProps) => {\n const payload = useAnchorWidgetPayload(canvas, anchorMessageMarkdown, \"WebSearchResults\");\n const parsed = useMemo(() => (payload === undefined ? null : parseWebSearchResultsPayload(payload)), [payload]);\n if (parsed === null || (parsed.answer.trim() === \"\" && parsed.sources.length === 0)) return null;\n return (\n <WebSearchResultsCanvas\n query={parsed.query}\n answer={parsed.answer}\n sources={parsed.sources}\n provider={parsed.provider}\n />\n );\n};\n","import { useCallback } from \"react\";\nimport { useConversationWidgetContext } from \"../../../renderer/ConversationWidgetCallbacksContext\";\nimport {\n buildEntityMentionFields,\n ENTITY_MENTION_WIDGET_NAME,\n entityMentionKey,\n EntityMentionTarget,\n MAX_ENTITY_MENTIONS_PER_MESSAGE,\n normalizeEntityMentionFields,\n toEntityMentionWireFields,\n} from \"./entity-mention\";\n\nexport interface UseEntityMentionComposerResult {\n /** Whether this entity is already mentioned in the composer. */\n isMentioned: (target: EntityMentionTarget) => boolean;\n /**\n * Puts the entity into the composer as an `EntityMention` chip — once per entity (a second click is a no-op); past\n * {@link MAX_ENTITY_MENTIONS_PER_MESSAGE} the new entity takes the place of the oldest mention (one write: a remove\n * and an add in one event would both read the list before either). Sends nothing: the owner writes the question.\n * Returns false for a target that names no entity.\n */\n mentionEntity: (target: EntityMentionTarget) => boolean;\n}\n\n/**\n * The opener side of the `EntityMention` composer widget: what the detail panel's \"Ask about this\"\n * button calls. Reads and writes the composer widgets of the chat's widget context; the composer strip renders them.\n */\nexport const useEntityMentionComposer = (): UseEntityMentionComposerResult => {\n const { composerWidgets, addComposerWidget, replaceComposerWidgetFields } = useConversationWidgetContext();\n\n const findMentionWidgets = useCallback(\n () => composerWidgets.filter((composerWidget) => composerWidget.widgetName === ENTITY_MENTION_WIDGET_NAME),\n [composerWidgets],\n );\n\n const isMentioned = useCallback(\n (target: EntityMentionTarget) => {\n const mention = buildEntityMentionFields(target);\n if (mention === null) return false;\n return findMentionWidgets().some((composerWidget) => {\n const heldMention = normalizeEntityMentionFields(composerWidget.fields);\n return heldMention !== null && entityMentionKey(heldMention) === entityMentionKey(mention);\n });\n },\n [findMentionWidgets],\n );\n\n const mentionEntity = useCallback(\n (target: EntityMentionTarget) => {\n const mention = buildEntityMentionFields(target);\n if (mention === null) return false;\n if (isMentioned(target)) return true;\n const mentionWidgets = findMentionWidgets();\n if (mentionWidgets.length >= MAX_ENTITY_MENTIONS_PER_MESSAGE) {\n replaceComposerWidgetFields(mentionWidgets[0].composerWidgetId, toEntityMentionWireFields(mention));\n } else {\n addComposerWidget(ENTITY_MENTION_WIDGET_NAME, toEntityMentionWireFields(mention));\n }\n return true;\n },\n [isMentioned, findMentionWidgets, replaceComposerWidgetFields, addComposerWidget],\n );\n\n return { isMentioned, mentionEntity };\n};\n","import { useIsEmailWidgetRender } from \"../../../renderer/ConversationWidgetRenderContext\";\nimport { ConversationWidgetButton } from \"../../_shared/ConversationWidgetButton\";\nimport type { EntityMentionTarget } from \"../shared/entity-mention\";\nimport { useEntityMentionComposer } from \"../shared/use-entity-mention-composer\";\n\nexport interface EntityMentionAskButtonProps extends EntityMentionTarget {\n testId?: string;\n}\n\n/**\n * The detail panel's \"Ask about this\" button (ChatGPT's \"Anschlussfrage stellen\"):\n * puts the entity into the chat input as an `EntityMention` chip and sends NOTHING — the owner writes the question,\n * the chip rides in that message as a fence, and the backend reads which entity the question is about. Not a\n * next-step CTA: it posts no prompt. A second click on the same entity changes nothing; the\n * label turns into \"Added to your message\". Mounted by the `entityDetail` canvas (the shell or a domain body) with\n * the entity the panel shows; renders nothing in the e-mail capture or for a target that names no entity.\n */\nexport const EntityMentionAskButton = (props: EntityMentionAskButtonProps) => {\n const { entityType, entityId, label, agentSpaceKey, testId = \"entity-mention-ask\" } = props;\n const isEmailRender = useIsEmailWidgetRender();\n const { isMentioned, mentionEntity } = useEntityMentionComposer();\n const target = { entityType, entityId, label, agentSpaceKey };\n if (isEmailRender) return null;\n const isAlreadyMentioned = isMentioned(target);\n return (\n <ConversationWidgetButton\n variant=\"primary\"\n size=\"medium\"\n icon={isAlreadyMentioned ? \"check\" : \"message\"}\n disabled={isAlreadyMentioned}\n onClick={() => mentionEntity(target)}\n testId={testId}\n >\n {isAlreadyMentioned ? \"Added to your message\" : \"Ask about this\"}\n </ConversationWidgetButton>\n );\n};\n","import type React from \"react\";\nimport { createContext, useContext } from \"react\";\n\n/**\n * The bodies of the `entityDetail` canvas, one per entity type: every `*.entity-detail-body.tsx` below\n * `widgets/` that exports `entityDetailBody` registers itself by folder glob — an entity type is added with\n * the backend `<Type>EntityReferenceResolver` and this one file, and edits no list. A second body for one entity type\n * is a build error (thrown at module load).\n */\n\nexport interface EntityDetailBodyProps {\n entityType: string;\n /** The id as the backend resolved it (a row id or an external id). */\n entityId: string;\n /** The key of the agent space the chat is scoped to, for a body whose read endpoint is agent-space-scoped. */\n agentSpaceKey?: number;\n}\n\nexport interface EntityDetailBodyDefinition {\n /** The backend resolver's `ENTITY_TYPE`. */\n entityType: string;\n /** Self-hydrates the entity by id through its own read endpoint (the endpoint's entity rights apply). */\n component: React.ComponentType<EntityDetailBodyProps>;\n}\n\nconst bodyModules = import.meta.glob<{ entityDetailBody?: EntityDetailBodyDefinition }>(\n [\"../../widgets/**/*.entity-detail-body.tsx\", \"../**/*.entity-detail-body.tsx\"],\n { eager: true },\n);\n\nexport const buildEntityDetailBodyRegistry = (\n definitions: EntityDetailBodyDefinition[],\n): Readonly<Record<string, EntityDetailBodyDefinition>> => {\n const registry: Record<string, EntityDetailBodyDefinition> = {};\n for (const definition of definitions) {\n if (Object.prototype.hasOwnProperty.call(registry, definition.entityType)) {\n throw new Error(`Two entity detail bodies register the entity type \"${definition.entityType}\".`);\n }\n registry[definition.entityType] = definition;\n }\n return registry;\n};\n\n/** The body definitions a set of `*.entity-detail-body.tsx` modules export (the package's or an app's glob). */\nexport const readEntityDetailBodyDefinitions = (\n modules: Record<string, { entityDetailBody?: EntityDetailBodyDefinition }>,\n): EntityDetailBodyDefinition[] =>\n Object.values(modules)\n .map((bodyModule) => bodyModule.entityDetailBody)\n .filter((definition): definition is EntityDetailBodyDefinition => definition !== undefined);\n\n/** Entity type → body: the package's folder, then what an app registers (`registerEntityDetailBodies`). */\nexport const entityDetailBodies: Record<string, EntityDetailBodyDefinition> = {\n ...buildEntityDetailBodyRegistry(readEntityDetailBodyDefinitions(bodyModules)),\n};\n\n/** Adds an app's entity detail bodies. Runs outside React, before the first render; an entity type registers once. */\nexport const registerEntityDetailBodies = (definitions: readonly EntityDetailBodyDefinition[]): void => {\n Object.assign(\n entityDetailBodies,\n buildEntityDetailBodyRegistry([...Object.values(entityDetailBodies), ...definitions]),\n );\n};\n\n/** The body registered for one entity type (the package's or an app's), or undefined when none is. */\nexport const getEntityDetailBody = (entityType: string): EntityDetailBodyDefinition | undefined =>\n Object.prototype.hasOwnProperty.call(entityDetailBodies, entityType) ? entityDetailBodies[entityType] : undefined;\n\n/** The registry the canvas body uses — the folder's by default; a spec or a story may provide stubs. */\nexport const EntityDetailBodiesContext =\n createContext<Readonly<Record<string, EntityDetailBodyDefinition>>>(entityDetailBodies);\n\nexport const useEntityDetailBodies = () => useContext(EntityDetailBodiesContext);\n","import { Text } from \"../../provider/components\";\nimport { useCallback, useState } from \"react\";\nimport type { CanvasBodyProps } from \"../../renderer/canvas/canvas-body-props\";\nimport { readEntityDetailInstanceId } from \"../../renderer/canvas/entity-detail-instance\";\nimport { EntityMentionAskButton } from \"../../widgets/EntityMentionConversationWidget/EntityMentionAskButton/EntityMentionAskButton\";\nimport { useEntityDetailBodies } from \"./entity-detail-bodies\";\nimport { EntityDetailNameReportContext } from \"./entity-detail-name\";\nimport styles from \"./EntityDetailCanvasBody.module.scss\";\n\n/**\n * The `entityDetail` CANVAS BODY (`canvasBodies.tsx`): the shell around one entity's detail. It reads\n * WHICH entity from the canvas instance id (`entityDetail:<entityType>:<id>`) and mounts the body registered for that\n * entity type; the body self-hydrates by id. An entity type without a body renders a short notice instead of nothing,\n * so a click never lands on an empty pane. \"Ask about this\" stays at the pane's foot while the detail scrolls and\n * names the entity in its chip once the body reported the name (`useReportEntityDetailName`).\n */\nexport const EntityDetailCanvasBody = ({ canvas, agentSpaceKey }: CanvasBodyProps) => {\n const bodies = useEntityDetailBodies();\n const [reportedEntity, setReportedEntity] = useState<{ instanceId: string; name: string | undefined }>();\n const reportEntityName = useCallback(\n (entityName: string | undefined) => setReportedEntity({ instanceId: canvas.instanceId, name: entityName }),\n [canvas.instanceId],\n );\n const target = readEntityDetailInstanceId(canvas.instanceId);\n if (target === undefined) return null;\n const definition = Object.prototype.hasOwnProperty.call(bodies, target.entityType)\n ? bodies[target.entityType]\n : undefined;\n if (!definition) {\n return (\n <div className={styles.entityDetail} data-testid=\"entity-detail-canvas\">\n <Text role=\"help\" color=\"var(--agents-fg-light)\" testId=\"entity-detail-canvas-unsupported\">\n {\"This detail cannot be shown here yet.\"}\n </Text>\n </div>\n );\n }\n const Body = definition.component;\n // A name reported for the previous entity never labels the next one's chip.\n const entityName = reportedEntity?.instanceId === canvas.instanceId ? reportedEntity.name : undefined;\n return (\n <div className={styles.entityDetail} data-testid=\"entity-detail-canvas\">\n <EntityDetailNameReportContext.Provider value={reportEntityName}>\n <Body entityType={target.entityType} entityId={target.entityId} agentSpaceKey={agentSpaceKey} />\n </EntityDetailNameReportContext.Provider>\n <div className={styles.entityDetailFooter}>\n <EntityMentionAskButton\n entityType={target.entityType}\n entityId={target.entityId}\n label={entityName}\n agentSpaceKey={agentSpaceKey}\n />\n </div>\n </div>\n );\n};\n","import { Text } from \"../../provider/components\";\nimport { useCallback, useMemo } from \"react\";\nimport type { CanvasBodyProps } from \"../../renderer/canvas/canvas-body-props\";\nimport { useConversationWidgetContext } from \"../../renderer/ConversationWidgetCallbacksContext\";\nimport {\n canvasInstanceIdForEntityDetail,\n readOpenEntityActionTarget,\n} from \"../../renderer/canvas/entity-detail-instance\";\nimport type {\n ComposedViewAction,\n ComposedViewTree,\n} from \"../../renderer/widget-tree/composed-view-tree\";\nimport type { ExpressionValue } from \"../../renderer/widget-tree/expression/evaluate-expression\";\nimport { ComposedViewRenderer } from \"../ComposedViewRenderer\";\nimport { findMapNodeInMarkdown, readMapNodeKeyOfInstanceId } from \"../components/map/map-full-screen-instance\";\nimport { MapPresentationContext } from \"../components/map/map-presentation-context\";\nimport mapStyles from \"../components/map/Map.module.scss\";\n\n/** The body reports nothing of its own: the inline block already reported this map to the model. */\nconst ignoreRenderReport = () => {};\n\n/**\n * The `mapFullScreen` CANVAS BODY (`canvasBodies.tsx`): one `Map` node of the anchor\n * message, full screen — the map filling the pane beside the list of its points. It finds the node through the\n * message's `ComposedView` fences and the node key its instance id carries (`map-full-screen-instance.ts`), then\n * renders it through the same `ComposedViewRenderer` with the node's own tree, so its bindings (`$data`, `$from`,\n * `$source`, `$computed`, `$state` at its initial value) and its actions resolve exactly as inline; the\n * `MapPresentationContext` switches the node to its full-screen layout. A point's `openEntity` action opens the\n * `entityDetail` canvas on the same anchor message (it replaces this canvas, as a click on an inline point would).\n */\nexport const MapFullScreenCanvasBody = (props: CanvasBodyProps) => {\n const { canvas, anchorMessageMarkdown, agentSpaceKey } = props;\n const { openCanvas } = useConversationWidgetContext();\n const mapNodeKey = readMapNodeKeyOfInstanceId(canvas.instanceId);\n\n const mapTree = useMemo<ComposedViewTree | undefined>(() => {\n if (anchorMessageMarkdown === null || mapNodeKey === undefined) return undefined;\n const mapNodeInComposedView = findMapNodeInMarkdown(anchorMessageMarkdown, mapNodeKey);\n if (!mapNodeInComposedView) return undefined;\n // The map alone, with its tree's state, data, computed values and actions; the tree's findings were the inline\n // block's to report.\n return { ...mapNodeInComposedView.tree, title: null, view: mapNodeInComposedView.mapNode, findings: [] };\n }, [anchorMessageMarkdown, mapNodeKey]);\n\n const anchor = canvas.anchor;\n const onOpenEntity = useCallback(\n (action: ComposedViewAction, currentRow?: ExpressionValue) => {\n const target = readOpenEntityActionTarget(action, currentRow);\n if (target === undefined || anchor.kind !== \"message\") return;\n openCanvas({\n canvasId: \"entityDetail\",\n instanceId: canvasInstanceIdForEntityDetail(target),\n anchor,\n origin: \"cardClick\",\n justDelivered: false,\n });\n },\n [openCanvas, anchor],\n );\n\n if (!mapTree) {\n return (\n <div\n className={mapStyles.fullScreenNotice}\n data-canvas-instance={canvas.instanceId}\n data-testid=\"map-full-screen-canvas-unavailable\"\n >\n <Text role=\"help\" color=\"var(--agents-fg-light)\">\n {\"This map is no longer available.\"}\n </Text>\n </div>\n );\n }\n return (\n <div\n className={mapStyles.fullScreenBody}\n data-canvas-instance={canvas.instanceId}\n data-testid=\"map-full-screen-canvas\"\n >\n <MapPresentationContext.Provider value=\"fullScreen\">\n <ComposedViewRenderer\n tree={mapTree}\n interactive\n isEmailRender={false}\n messageId={anchor.kind === \"message\" ? anchor.messageId : undefined}\n agentSpaceKey={agentSpaceKey}\n onReport={ignoreRenderReport}\n onOpenEntity={onOpenEntity}\n testId=\"map-full-screen-canvas-view\"\n />\n </MapPresentationContext.Provider>\n </div>\n );\n};\n","import type React from \"react\";\nimport type { CanvasId } from \"./canvas-behaviours\";\nimport type { CanvasBodyProps } from \"./canvas-body-props\";\nimport { ConversationSearchResultsCanvasBody } from \"../../widgets/ConversationSearchResultsConversationWidget/ConversationSearchResultsCanvasBody\";\nimport { WebSearchResultsCanvasBody } from \"../../widgets/WebSearchResultsConversationWidget/WebSearchResultsCanvasBody\";\nimport { EntityDetailCanvasBody } from \"../../kit/entity-detail/EntityDetailCanvasBody\";\nimport { MapFullScreenCanvasBody } from \"../../kit/map-full-screen/MapFullScreenCanvasBody\";\n\nexport type { CanvasBodyProps } from \"./canvas-body-props\";\nexport { canvasFeatureFlagOf } from \"./canvas-feature-flags\";\n\n/**\n * THE CANVAS BODIES — canvas id → the React component the shell mounts in the canvas pane. The one module that knows\n * both the canvas ids and React components, and it is imported ONLY by `CanvasPane` (the shell), never by\n * the slice, the behaviours or a widget — that is the import layering that keeps the store-init temporal-dead-zone\n * cycle away. The bodies themselves are small: a body that hosts a heavy page (an app's list page or editor)\n * lazy-loads that page, exactly as its widget did. Every canvas has a body; nothing\n * else hands the pane a rendered node.\n *\n * The package's own bodies are listed here; an app adds the bodies of its canvases with `registerCanvasBodies` before\n * the first render. The object is filled in place, so the shell reads every registration.\n */\nexport const canvasBodies = {\n conversationSearchResults: ConversationSearchResultsCanvasBody,\n webSearchResults: WebSearchResultsCanvasBody,\n entityDetail: EntityDetailCanvasBody,\n mapFullScreen: MapFullScreenCanvasBody,\n} as Record<CanvasId, React.ComponentType<CanvasBodyProps>>;\n\n/** Adds an app's canvas bodies (canvas id → body). Runs outside React, before the first render. */\nexport const registerCanvasBodies = (\n bodies: Readonly<Partial<Record<CanvasId, React.ComponentType<CanvasBodyProps>>>>,\n): void => {\n Object.assign(canvasBodies, bodies);\n};\n"],"names":["canvasStyle","scrollStyle","contentStyle","entityName"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"canvasBodies-BiUt8MUG.js","sources":["../../src/renderer/canvas/use-anchor-widget-payload.ts","../../src/widgets/ConversationSearchResultsConversationWidget/ConversationSearchResultsCanvas.tsx","../../src/widgets/ConversationSearchResultsConversationWidget/ConversationSearchResultsCanvasBody.tsx","../../src/widgets/WebSearchResultsConversationWidget/WebSearchResultsCanvas.tsx","../../src/widgets/WebSearchResultsConversationWidget/WebSearchResultsCanvasBody.tsx","../../src/widgets/EntityMentionConversationWidget/shared/use-entity-mention-composer.ts","../../src/widgets/EntityMentionConversationWidget/EntityMentionAskButton/EntityMentionAskButton.tsx","../../src/kit/entity-detail/entity-detail-bodies.ts","../../src/kit/entity-detail/EntityDetailCanvasBody.tsx","../../src/kit/map-full-screen/MapFullScreenCanvasBody.tsx","../../src/renderer/canvas/canvasBodies.tsx"],"sourcesContent":["import { useMemo } from \"react\";\nimport type { CanvasState } from \"./canvas-state\";\nimport { payloadHashOfInstanceId } from \"./canvas-state\";\nimport { findWidgetFenceByPayloadHash, findWidgetFencesInMarkdown } from \"./find-widget-fences-in-markdown\";\n\n/**\n * The payload string of the widget a message-anchored canvas was opened from: the fence of `widgetName` in the anchor\n * message whose payload hash the canvas instance id carries (`canvasInstanceIdForMessagePayload`); when the instance\n * id carries no hash (one canvas per message), the first fence of that name. Undefined for a page anchor, a missing\n * anchor message, or a message that no longer carries the fence — the body then renders nothing.\n */\nexport const useAnchorWidgetPayload = (\n canvas: CanvasState,\n anchorMessageMarkdown: string | null,\n widgetName: string,\n): string | undefined =>\n useMemo(() => {\n if (canvas.anchor.kind !== \"message\" || anchorMessageMarkdown === null) return undefined;\n const payloadHash = payloadHashOfInstanceId(canvas.instanceId);\n if (payloadHash !== undefined) {\n return findWidgetFenceByPayloadHash(anchorMessageMarkdown, widgetName, payloadHash)?.payload;\n }\n return findWidgetFencesInMarkdown(anchorMessageMarkdown).find((fence) => fence.name === widgetName)?.payload;\n }, [canvas.anchor, canvas.instanceId, anchorMessageMarkdown, widgetName]);\n","import { ConversationSearchResultsList, Text } from \"../../provider/components\";\nimport React from \"react\";\nimport { parseConversationSearchResultsPayload } from \"./shared/conversation-search-results-widget-payload\";\n\ntype ConversationSearchResultsCanvasProps = {\n query: string;\n groups: ReturnType<typeof parseConversationSearchResultsPayload>[\"groups\"];\n onOpenConversation: (conversationId: number, messageId?: number) => void;\n};\n\n// Canvas body styles — the same as every list canvas body, so the full-screen panel behaves the same:\n// a full-height flex column whose inner area SCROLLS (scrollStyle: flex 1 + overflowY auto — without it the content\n// overflows the panel with no scrollbar), plus a horizontal inset (contentStyle) because the results list is built\n// for the narrow inline chat column where the bubble provides the gutter — in the canvas there is no bubble, so it would\n// otherwise render edge-to-edge.\nconst canvasStyle: React.CSSProperties = {\n width: \"100%\",\n height: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n minHeight: 0,\n background: \"var(--agents-bg)\",\n};\nconst scrollStyle: React.CSSProperties = {\n flex: 1,\n minHeight: 0,\n overflowY: \"auto\",\n};\nconst contentStyle: React.CSSProperties = {\n padding: \"16px 24px 24px\",\n};\n\n/** The canvas body — a titled wrapper around the same grouped results, scrollable + inset like the other canvas widgets. */\nexport const ConversationSearchResultsCanvas = (props: ConversationSearchResultsCanvasProps) => (\n <div style={canvasStyle} data-testid=\"conversation-search-results-widget-canvas\">\n <div style={scrollStyle}>\n <div style={contentStyle} data-testid=\"conversation-search-results-widget-canvas-results\">\n <Text\n role=\"title\"\n replacements={{ query: props.query }}\n testId=\"conversation-search-results-widget-canvas-title\"\n >\n {'Search results for \"%query%\"'}\n </Text>\n <ConversationSearchResultsList groups={props.groups} query={props.query} onOpenConversation={props.onOpenConversation} />\n </div>\n </div>\n </div>\n);\n","import React, { useMemo } from \"react\";\nimport type { CanvasBodyProps } from \"../../renderer/canvas/canvas-body-props\";\nimport { useConversationWidgetContext } from \"../../renderer/ConversationWidgetCallbacksContext\";\nimport { useAnchorWidgetPayload } from \"../../renderer/canvas/use-anchor-widget-payload\";\nimport { parseConversationSearchResultsPayload } from \"./shared/conversation-search-results-widget-payload\";\nimport { ConversationSearchResultsCanvas } from \"./ConversationSearchResultsCanvas\";\n\n/**\n * The `conversationSearchResults` CANVAS BODY (`canvasBodies.tsx`): re-reads the `ConversationSearchResults` fence of\n * the anchor message — the same payload the inline widget rendered from — and shows the grouped results. Nothing was\n * stored for it but the pointer. Renders nothing when the anchor message no longer carries the fence.\n */\nexport const ConversationSearchResultsCanvasBody = ({ canvas, anchorMessageMarkdown }: CanvasBodyProps) => {\n const { onOpenConversation } = useConversationWidgetContext();\n const payload = useAnchorWidgetPayload(canvas, anchorMessageMarkdown, \"ConversationSearchResults\");\n const parsed = useMemo(\n () => (payload === undefined ? null : parseConversationSearchResultsPayload(payload)),\n [payload],\n );\n if (parsed === null || parsed.groups.length === 0) return null;\n return (\n <ConversationSearchResultsCanvas\n query={parsed.query}\n groups={parsed.groups}\n onOpenConversation={(conversationId, messageId) => onOpenConversation?.(conversationId, messageId)}\n />\n );\n};\n","import { Text } from \"../../provider/components\";\nimport React from \"react\";\nimport { WebSearchResultSource } from \"./shared/web-search-results-widget-payload\";\nimport { WebSearchAnswer } from \"./WebSearchAnswer\";\nimport { WebSearchSourcesList } from \"./WebSearchSourcesList\";\n\ntype WebSearchResultsCanvasProps = {\n query: string;\n answer: string;\n sources: WebSearchResultSource[];\n provider?: string;\n};\n\n// Canvas body styles — mirror the ConversationSearchResults / listReviews drawer widgets: a full-height flex column\n// whose inner area SCROLLS (flex 1 + overflowY auto) with a horizontal inset (there is no chat bubble gutter in the canvas).\nconst canvasStyle: React.CSSProperties = {\n width: \"100%\",\n height: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n minHeight: 0,\n background: \"var(--agents-bg)\",\n};\nconst scrollStyle: React.CSSProperties = { flex: 1, minHeight: 0, overflowY: \"auto\" };\nconst contentStyle: React.CSSProperties = { padding: \"16px 24px 24px\" };\n\n/** The canvas body — the full answer + sources, scrollable + inset like the other canvas widgets. */\nexport const WebSearchResultsCanvas = (props: WebSearchResultsCanvasProps) => (\n <div style={canvasStyle} data-testid=\"web-search-results-widget-canvas\">\n <div style={scrollStyle}>\n <div style={contentStyle}>\n {props.query ? (\n <Text\n role=\"title\"\n replacements={{ query: props.query }}\n testId=\"web-search-results-widget-canvas-title\"\n >\n {'\"%query%\"'}\n </Text>\n ) : (\n <Text role=\"title\" testId=\"web-search-results-widget-canvas-title\">\n Web search\n </Text>\n )}\n <div style={{ marginTop: 12 }}>\n <WebSearchAnswer answer={props.answer} />\n </div>\n <WebSearchSourcesList\n sources={props.sources}\n provider={props.provider}\n testId=\"web-search-results-widget-canvas\"\n />\n </div>\n </div>\n </div>\n);\n","import React, { useMemo } from \"react\";\nimport type { CanvasBodyProps } from \"../../renderer/canvas/canvas-body-props\";\nimport { useAnchorWidgetPayload } from \"../../renderer/canvas/use-anchor-widget-payload\";\nimport { parseWebSearchResultsPayload } from \"./shared/web-search-results-widget-payload\";\nimport { WebSearchResultsCanvas } from \"./WebSearchResultsCanvas\";\n\n/**\n * The `webSearchResults` CANVAS BODY (`canvasBodies.tsx`): re-reads the `WebSearchResults` fence of the anchor message\n * — the answer and its cited sources the inline widget rendered from — and shows them in the canvas. Renders nothing\n * when the anchor message no longer carries the fence.\n */\nexport const WebSearchResultsCanvasBody = ({ canvas, anchorMessageMarkdown }: CanvasBodyProps) => {\n const payload = useAnchorWidgetPayload(canvas, anchorMessageMarkdown, \"WebSearchResults\");\n const parsed = useMemo(() => (payload === undefined ? null : parseWebSearchResultsPayload(payload)), [payload]);\n if (parsed === null || (parsed.answer.trim() === \"\" && parsed.sources.length === 0)) return null;\n return (\n <WebSearchResultsCanvas\n query={parsed.query}\n answer={parsed.answer}\n sources={parsed.sources}\n provider={parsed.provider}\n />\n );\n};\n","import { useCallback } from \"react\";\nimport { useConversationWidgetContext } from \"../../../renderer/ConversationWidgetCallbacksContext\";\nimport {\n buildEntityMentionFields,\n ENTITY_MENTION_WIDGET_NAME,\n entityMentionKey,\n EntityMentionTarget,\n MAX_ENTITY_MENTIONS_PER_MESSAGE,\n normalizeEntityMentionFields,\n toEntityMentionWireFields,\n} from \"./entity-mention\";\n\nexport interface UseEntityMentionComposerResult {\n /** Whether this entity is already mentioned in the composer. */\n isMentioned: (target: EntityMentionTarget) => boolean;\n /**\n * Puts the entity into the composer as an `EntityMention` chip — once per entity (a second click is a no-op); past\n * {@link MAX_ENTITY_MENTIONS_PER_MESSAGE} the new entity takes the place of the oldest mention (one write: a remove\n * and an add in one event would both read the list before either). Sends nothing: the owner writes the question.\n * Returns false for a target that names no entity.\n */\n mentionEntity: (target: EntityMentionTarget) => boolean;\n}\n\n/**\n * The opener side of the `EntityMention` composer widget: what the detail panel's \"Ask about this\"\n * button calls. Reads and writes the composer widgets of the chat's widget context; the composer strip renders them.\n */\nexport const useEntityMentionComposer = (): UseEntityMentionComposerResult => {\n const { composerWidgets, addComposerWidget, replaceComposerWidgetFields } = useConversationWidgetContext();\n\n const findMentionWidgets = useCallback(\n () => composerWidgets.filter((composerWidget) => composerWidget.widgetName === ENTITY_MENTION_WIDGET_NAME),\n [composerWidgets],\n );\n\n const isMentioned = useCallback(\n (target: EntityMentionTarget) => {\n const mention = buildEntityMentionFields(target);\n if (mention === null) return false;\n return findMentionWidgets().some((composerWidget) => {\n const heldMention = normalizeEntityMentionFields(composerWidget.fields);\n return heldMention !== null && entityMentionKey(heldMention) === entityMentionKey(mention);\n });\n },\n [findMentionWidgets],\n );\n\n const mentionEntity = useCallback(\n (target: EntityMentionTarget) => {\n const mention = buildEntityMentionFields(target);\n if (mention === null) return false;\n if (isMentioned(target)) return true;\n const mentionWidgets = findMentionWidgets();\n if (mentionWidgets.length >= MAX_ENTITY_MENTIONS_PER_MESSAGE) {\n replaceComposerWidgetFields(mentionWidgets[0].composerWidgetId, toEntityMentionWireFields(mention));\n } else {\n addComposerWidget(ENTITY_MENTION_WIDGET_NAME, toEntityMentionWireFields(mention));\n }\n return true;\n },\n [isMentioned, findMentionWidgets, replaceComposerWidgetFields, addComposerWidget],\n );\n\n return { isMentioned, mentionEntity };\n};\n","import { useIsEmailWidgetRender } from \"../../../renderer/ConversationWidgetRenderContext\";\nimport { ConversationWidgetButton } from \"../../_shared/ConversationWidgetButton\";\nimport type { EntityMentionTarget } from \"../shared/entity-mention\";\nimport { useEntityMentionComposer } from \"../shared/use-entity-mention-composer\";\n\nexport interface EntityMentionAskButtonProps extends EntityMentionTarget {\n testId?: string;\n}\n\n/**\n * The detail panel's \"Ask about this\" button (ChatGPT's \"Anschlussfrage stellen\"):\n * puts the entity into the chat input as an `EntityMention` chip and sends NOTHING — the owner writes the question,\n * the chip rides in that message as a fence, and the backend reads which entity the question is about. Not a\n * next-step CTA: it posts no prompt. A second click on the same entity changes nothing; the\n * label turns into \"Added to your message\". Mounted by the `entityDetail` canvas (the shell or a domain body) with\n * the entity the panel shows; renders nothing in the e-mail capture or for a target that names no entity.\n */\nexport const EntityMentionAskButton = (props: EntityMentionAskButtonProps) => {\n const { entityType, entityId, label, agentSpaceKey, testId = \"entity-mention-ask\" } = props;\n const isEmailRender = useIsEmailWidgetRender();\n const { isMentioned, mentionEntity } = useEntityMentionComposer();\n const target = { entityType, entityId, label, agentSpaceKey };\n if (isEmailRender) return null;\n const isAlreadyMentioned = isMentioned(target);\n return (\n <ConversationWidgetButton\n variant=\"primary\"\n size=\"medium\"\n icon={isAlreadyMentioned ? \"check\" : \"message\"}\n disabled={isAlreadyMentioned}\n onClick={() => mentionEntity(target)}\n testId={testId}\n >\n {isAlreadyMentioned ? \"Added to your message\" : \"Ask about this\"}\n </ConversationWidgetButton>\n );\n};\n","import type React from \"react\";\nimport { createContext, useContext } from \"react\";\n\n/**\n * The bodies of the `entityDetail` canvas, one per entity type: every `*.entity-detail-body.tsx` below\n * `widgets/` that exports `entityDetailBody` registers itself by folder glob — an entity type is added with\n * the backend `<Type>EntityReferenceResolver` and this one file, and edits no list. A second body for one entity type\n * is a build error (thrown at module load).\n */\n\nexport interface EntityDetailBodyProps {\n entityType: string;\n /** The id as the backend resolved it (a row id or an external id). */\n entityId: string;\n /** The key of the agent space the chat is scoped to, for a body whose read endpoint is agent-space-scoped. */\n agentSpaceKey?: number;\n}\n\nexport interface EntityDetailBodyDefinition {\n /** The backend resolver's `ENTITY_TYPE`. */\n entityType: string;\n /** Self-hydrates the entity by id through its own read endpoint (the endpoint's entity rights apply). */\n component: React.ComponentType<EntityDetailBodyProps>;\n}\n\nconst bodyModules = import.meta.glob<{ entityDetailBody?: EntityDetailBodyDefinition }>(\n [\"../../widgets/**/*.entity-detail-body.tsx\", \"../**/*.entity-detail-body.tsx\"],\n { eager: true },\n);\n\nexport const buildEntityDetailBodyRegistry = (\n definitions: EntityDetailBodyDefinition[],\n): Readonly<Record<string, EntityDetailBodyDefinition>> => {\n const registry: Record<string, EntityDetailBodyDefinition> = {};\n for (const definition of definitions) {\n if (Object.prototype.hasOwnProperty.call(registry, definition.entityType)) {\n throw new Error(`Two entity detail bodies register the entity type \"${definition.entityType}\".`);\n }\n registry[definition.entityType] = definition;\n }\n return registry;\n};\n\n/** The body definitions a set of `*.entity-detail-body.tsx` modules export (the package's or an app's glob). */\nexport const readEntityDetailBodyDefinitions = (\n modules: Record<string, { entityDetailBody?: EntityDetailBodyDefinition }>,\n): EntityDetailBodyDefinition[] =>\n Object.values(modules)\n .map((bodyModule) => bodyModule.entityDetailBody)\n .filter((definition): definition is EntityDetailBodyDefinition => definition !== undefined);\n\n/** Entity type → body: the package's folder, then what an app registers (`registerEntityDetailBodies`). */\nexport const entityDetailBodies: Record<string, EntityDetailBodyDefinition> = {\n ...buildEntityDetailBodyRegistry(readEntityDetailBodyDefinitions(bodyModules)),\n};\n\n/** Adds an app's entity detail bodies. Runs outside React, before the first render; an entity type registers once. */\nexport const registerEntityDetailBodies = (definitions: readonly EntityDetailBodyDefinition[]): void => {\n Object.assign(\n entityDetailBodies,\n buildEntityDetailBodyRegistry([...Object.values(entityDetailBodies), ...definitions]),\n );\n};\n\n/** The body registered for one entity type (the package's or an app's), or undefined when none is. */\nexport const getEntityDetailBody = (entityType: string): EntityDetailBodyDefinition | undefined =>\n Object.prototype.hasOwnProperty.call(entityDetailBodies, entityType) ? entityDetailBodies[entityType] : undefined;\n\n/** The registry the canvas body uses — the folder's by default; a spec or a story may provide stubs. */\nexport const EntityDetailBodiesContext =\n createContext<Readonly<Record<string, EntityDetailBodyDefinition>>>(entityDetailBodies);\n\nexport const useEntityDetailBodies = () => useContext(EntityDetailBodiesContext);\n","import { Text } from \"../../provider/components\";\nimport { useCallback, useState } from \"react\";\nimport type { CanvasBodyProps } from \"../../renderer/canvas/canvas-body-props\";\nimport { readEntityDetailInstanceId } from \"../../renderer/canvas/entity-detail-instance\";\nimport { EntityMentionAskButton } from \"../../widgets/EntityMentionConversationWidget/EntityMentionAskButton/EntityMentionAskButton\";\nimport { useEntityDetailBodies } from \"./entity-detail-bodies\";\nimport { EntityDetailNameReportContext } from \"./entity-detail-name\";\nimport styles from \"./EntityDetailCanvasBody.module.scss\";\n\n/**\n * The `entityDetail` CANVAS BODY (`canvasBodies.tsx`): the shell around one entity's detail. It reads\n * WHICH entity from the canvas instance id (`entityDetail:<entityType>:<id>`) and mounts the body registered for that\n * entity type; the body self-hydrates by id. An entity type without a body renders a short notice instead of nothing,\n * so a click never lands on an empty pane. \"Ask about this\" stays at the pane's foot while the detail scrolls and\n * names the entity in its chip once the body reported the name (`useReportEntityDetailName`).\n */\nexport const EntityDetailCanvasBody = ({ canvas, agentSpaceKey }: CanvasBodyProps) => {\n const bodies = useEntityDetailBodies();\n const [reportedEntity, setReportedEntity] = useState<{ instanceId: string; name: string | undefined }>();\n const reportEntityName = useCallback(\n (entityName: string | undefined) => setReportedEntity({ instanceId: canvas.instanceId, name: entityName }),\n [canvas.instanceId],\n );\n const target = readEntityDetailInstanceId(canvas.instanceId);\n if (target === undefined) return null;\n const definition = Object.prototype.hasOwnProperty.call(bodies, target.entityType)\n ? bodies[target.entityType]\n : undefined;\n if (!definition) {\n return (\n <div className={styles.entityDetail} data-testid=\"entity-detail-canvas\">\n <Text role=\"help\" color=\"var(--agents-fg-light)\" testId=\"entity-detail-canvas-unsupported\">\n {\"This detail cannot be shown here yet.\"}\n </Text>\n </div>\n );\n }\n const Body = definition.component;\n // A name reported for the previous entity never labels the next one's chip.\n const entityName = reportedEntity?.instanceId === canvas.instanceId ? reportedEntity.name : undefined;\n return (\n <div className={styles.entityDetail} data-testid=\"entity-detail-canvas\">\n <EntityDetailNameReportContext.Provider value={reportEntityName}>\n <Body entityType={target.entityType} entityId={target.entityId} agentSpaceKey={agentSpaceKey} />\n </EntityDetailNameReportContext.Provider>\n <div className={styles.entityDetailFooter}>\n <EntityMentionAskButton\n entityType={target.entityType}\n entityId={target.entityId}\n label={entityName}\n agentSpaceKey={agentSpaceKey}\n />\n </div>\n </div>\n );\n};\n","import { Text } from \"../../provider/components\";\nimport { useCallback, useMemo } from \"react\";\nimport type { CanvasBodyProps } from \"../../renderer/canvas/canvas-body-props\";\nimport { useConversationWidgetContext } from \"../../renderer/ConversationWidgetCallbacksContext\";\nimport {\n canvasInstanceIdForEntityDetail,\n readOpenEntityActionTarget,\n} from \"../../renderer/canvas/entity-detail-instance\";\nimport type {\n ComposedViewAction,\n ComposedViewTree,\n} from \"../../renderer/widget-tree/composed-view-tree\";\nimport type { ExpressionValue } from \"../../renderer/widget-tree/expression/evaluate-expression\";\nimport { ComposedViewRenderer } from \"../ComposedViewRenderer\";\nimport { findMapNodeInMarkdown, readMapNodeKeyOfInstanceId } from \"../components/map/map-full-screen-instance\";\nimport { MapPresentationContext } from \"../components/map/map-presentation-context\";\nimport mapStyles from \"../components/map/Map.module.scss\";\n\n/** The body reports nothing of its own: the inline block already reported this map to the model. */\nconst ignoreRenderReport = () => {};\n\n/**\n * The `mapFullScreen` CANVAS BODY (`canvasBodies.tsx`): one `Map` node of the anchor\n * message, full screen — the map filling the pane beside the list of its points. It finds the node through the\n * message's `ComposedView` fences and the node key its instance id carries (`map-full-screen-instance.ts`), then\n * renders it through the same `ComposedViewRenderer` with the node's own tree, so its bindings (`$data`, `$from`,\n * `$source`, `$computed`, `$state` at its initial value) and its actions resolve exactly as inline; the\n * `MapPresentationContext` switches the node to its full-screen layout. A point's `openEntity` action opens the\n * `entityDetail` canvas on the same anchor message (it replaces this canvas, as a click on an inline point would).\n */\nexport const MapFullScreenCanvasBody = (props: CanvasBodyProps) => {\n const { canvas, anchorMessageMarkdown, agentSpaceKey } = props;\n const { openCanvas } = useConversationWidgetContext();\n const mapNodeKey = readMapNodeKeyOfInstanceId(canvas.instanceId);\n\n const mapTree = useMemo<ComposedViewTree | undefined>(() => {\n if (anchorMessageMarkdown === null || mapNodeKey === undefined) return undefined;\n const mapNodeInComposedView = findMapNodeInMarkdown(anchorMessageMarkdown, mapNodeKey);\n if (!mapNodeInComposedView) return undefined;\n // The map alone, with its tree's state, data, computed values and actions; the tree's findings were the inline\n // block's to report.\n return { ...mapNodeInComposedView.tree, title: null, view: mapNodeInComposedView.mapNode, findings: [] };\n }, [anchorMessageMarkdown, mapNodeKey]);\n\n const anchor = canvas.anchor;\n const onOpenEntity = useCallback(\n (action: ComposedViewAction, currentRow?: ExpressionValue) => {\n const target = readOpenEntityActionTarget(action, currentRow);\n if (target === undefined || anchor.kind !== \"message\") return;\n openCanvas({\n canvasId: \"entityDetail\",\n instanceId: canvasInstanceIdForEntityDetail(target),\n anchor,\n origin: \"cardClick\",\n justDelivered: false,\n });\n },\n [openCanvas, anchor],\n );\n\n if (!mapTree) {\n return (\n <div\n className={mapStyles.fullScreenNotice}\n data-canvas-instance={canvas.instanceId}\n data-testid=\"map-full-screen-canvas-unavailable\"\n >\n <Text role=\"help\" color=\"var(--agents-fg-light)\">\n {\"This map is no longer available.\"}\n </Text>\n </div>\n );\n }\n return (\n <div\n className={mapStyles.fullScreenBody}\n data-canvas-instance={canvas.instanceId}\n data-testid=\"map-full-screen-canvas\"\n >\n <MapPresentationContext.Provider value=\"fullScreen\">\n <ComposedViewRenderer\n tree={mapTree}\n interactive\n isEmailRender={false}\n messageId={anchor.kind === \"message\" ? anchor.messageId : undefined}\n agentSpaceKey={agentSpaceKey}\n onReport={ignoreRenderReport}\n onOpenEntity={onOpenEntity}\n testId=\"map-full-screen-canvas-view\"\n />\n </MapPresentationContext.Provider>\n </div>\n );\n};\n","import type React from \"react\";\nimport type { CanvasId } from \"./canvas-behaviours\";\nimport type { CanvasBodyProps } from \"./canvas-body-props\";\nimport { ConversationSearchResultsCanvasBody } from \"../../widgets/ConversationSearchResultsConversationWidget/ConversationSearchResultsCanvasBody\";\nimport { WebSearchResultsCanvasBody } from \"../../widgets/WebSearchResultsConversationWidget/WebSearchResultsCanvasBody\";\nimport { EntityDetailCanvasBody } from \"../../kit/entity-detail/EntityDetailCanvasBody\";\nimport { MapFullScreenCanvasBody } from \"../../kit/map-full-screen/MapFullScreenCanvasBody\";\n\nexport type { CanvasBodyProps } from \"./canvas-body-props\";\nexport { canvasFeatureFlagOf } from \"./canvas-feature-flags\";\n\n/**\n * THE CANVAS BODIES — canvas id → the React component the shell mounts in the canvas pane. The one module that knows\n * both the canvas ids and React components, and it is imported ONLY by `CanvasPane` (the shell), never by\n * the slice, the behaviours or a widget — that is the import layering that keeps the store-init temporal-dead-zone\n * cycle away. The bodies themselves are small: a body that hosts a heavy page (an app's list page or editor)\n * lazy-loads that page, exactly as its widget did. Every canvas has a body; nothing\n * else hands the pane a rendered node.\n *\n * The package's own bodies are listed here; an app adds the bodies of its canvases with `registerCanvasBodies` before\n * the first render. The object is filled in place, so the shell reads every registration.\n */\nexport const canvasBodies = {\n conversationSearchResults: ConversationSearchResultsCanvasBody,\n webSearchResults: WebSearchResultsCanvasBody,\n entityDetail: EntityDetailCanvasBody,\n mapFullScreen: MapFullScreenCanvasBody,\n} as Record<CanvasId, React.ComponentType<CanvasBodyProps>>;\n\n/** Adds an app's canvas bodies (canvas id → body). Runs outside React, before the first render. */\nexport const registerCanvasBodies = (\n bodies: Readonly<Partial<Record<CanvasId, React.ComponentType<CanvasBodyProps>>>>,\n): void => {\n Object.assign(canvasBodies, bodies);\n};\n"],"names":["canvasStyle","scrollStyle","contentStyle","entityName"],"mappings":"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"}
|