@assistant-ui/react 0.15.17 → 0.15.19
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/README.md +8 -2
- package/dist/context/providers/ThreadViewportProvider.js +2 -2
- package/dist/context/providers/ThreadViewportProvider.js.map +1 -1
- package/dist/hooks/useToolCallElapsed.js.map +1 -1
- package/dist/index.d.ts +7 -4
- package/dist/index.js +5 -3
- package/dist/mcp-apps/McpAppRenderer.d.ts +30 -8
- package/dist/mcp-apps/McpAppRenderer.d.ts.map +1 -1
- package/dist/mcp-apps/McpAppRenderer.js +91 -47
- package/dist/mcp-apps/McpAppRenderer.js.map +1 -1
- package/dist/mcp-apps/app-frame.d.ts.map +1 -1
- package/dist/mcp-apps/app-frame.js +57 -33
- package/dist/mcp-apps/app-frame.js.map +1 -1
- package/dist/mcp-apps/bridge.js +9 -4
- package/dist/mcp-apps/bridge.js.map +1 -1
- package/dist/mcp-apps/index.d.ts +2 -2
- package/dist/primitives/assistantModal/AssistantModalRoot.d.ts.map +1 -1
- package/dist/primitives/assistantModal/AssistantModalRoot.js +47 -79
- package/dist/primitives/assistantModal/AssistantModalRoot.js.map +1 -1
- package/dist/primitives/composer/ComposerAttachmentDropzone.d.ts.map +1 -1
- package/dist/primitives/composer/ComposerAttachmentDropzone.js +61 -138
- package/dist/primitives/composer/ComposerAttachmentDropzone.js.map +1 -1
- package/dist/primitives/composer/ComposerInput.js +3 -8
- package/dist/primitives/composer/ComposerInput.js.map +1 -1
- package/dist/primitives/composer/ComposerInputPluginContext.d.ts +1 -2
- package/dist/primitives/composer/ComposerInputPluginContext.d.ts.map +1 -1
- package/dist/primitives/composer/ComposerInputPluginContext.js +1 -6
- package/dist/primitives/composer/ComposerInputPluginContext.js.map +1 -1
- package/dist/primitives/composer/trigger/TriggerPopoverAction.js +46 -15
- package/dist/primitives/composer/trigger/TriggerPopoverAction.js.map +1 -1
- package/dist/primitives/composer/trigger/TriggerPopoverDirective.js +40 -10
- package/dist/primitives/composer/trigger/TriggerPopoverDirective.js.map +1 -1
- package/dist/primitives/composer/trigger/matchesTriggerItemQuery.d.ts +6 -0
- package/dist/primitives/composer/trigger/matchesTriggerItemQuery.d.ts.map +1 -0
- package/dist/primitives/composer/trigger/matchesTriggerItemQuery.js +9 -0
- package/dist/primitives/composer/trigger/matchesTriggerItemQuery.js.map +1 -0
- package/dist/primitives/composer/trigger/triggerKeyboardResource.d.ts.map +1 -1
- package/dist/primitives/composer/trigger/triggerKeyboardResource.js +53 -61
- package/dist/primitives/composer/trigger/triggerKeyboardResource.js.map +1 -1
- package/dist/primitives/composer/trigger/triggerNavigationResource.d.ts.map +1 -1
- package/dist/primitives/composer/trigger/triggerNavigationResource.js +129 -141
- package/dist/primitives/composer/trigger/triggerNavigationResource.js.map +1 -1
- package/dist/primitives/message/MessageParts.js +2 -14
- package/dist/primitives/message/MessageParts.js.map +1 -1
- package/dist/primitives/message/MessagePartsGrouped.d.ts +3 -3
- package/dist/primitives/message/MessagePartsGrouped.js +2 -2
- package/dist/primitives/message/MessagePartsGrouped.js.map +1 -1
- package/dist/primitives/messagePart/MessagePartText.d.ts +2 -0
- package/dist/primitives/messagePart/MessagePartText.d.ts.map +1 -1
- package/dist/primitives/messagePart/MessagePartText.js +13 -36
- package/dist/primitives/messagePart/MessagePartText.js.map +1 -1
- package/dist/primitives/reasoning/useScrollLock.js +3 -1
- package/dist/primitives/reasoning/useScrollLock.js.map +1 -1
- package/dist/primitives/thread/useThreadViewportAutoScroll.d.ts.map +1 -1
- package/dist/primitives/thread/useThreadViewportAutoScroll.js +3 -3
- package/dist/primitives/thread/useThreadViewportAutoScroll.js.map +1 -1
- package/dist/sandbox-host/SandboxHost.d.ts.map +1 -1
- package/dist/sandbox-host/SandboxHost.js +36 -9
- package/dist/sandbox-host/SandboxHost.js.map +1 -1
- package/dist/unstable/useLiveCompletionAdapter.js +24 -2
- package/dist/unstable/useLiveCompletionAdapter.js.map +1 -1
- package/dist/unstable/useMentionAdapter.d.ts +9 -3
- package/dist/unstable/useMentionAdapter.d.ts.map +1 -1
- package/dist/unstable/useMentionAdapter.js +50 -43
- package/dist/unstable/useMentionAdapter.js.map +1 -1
- package/dist/unstable/useMessageStallDetection.d.ts +4 -5
- package/dist/unstable/useMessageStallDetection.d.ts.map +1 -1
- package/dist/unstable/useMessageStallDetection.js +16 -15
- package/dist/unstable/useMessageStallDetection.js.map +1 -1
- package/dist/unstable/useModelContextSnapshot.d.ts +34 -0
- package/dist/unstable/useModelContextSnapshot.d.ts.map +1 -0
- package/dist/unstable/useModelContextSnapshot.js +61 -0
- package/dist/unstable/useModelContextSnapshot.js.map +1 -0
- package/dist/unstable/useSlashCommandAdapter.d.ts.map +1 -1
- package/dist/unstable/useSlashCommandAdapter.js +2 -8
- package/dist/unstable/useSlashCommandAdapter.js.map +1 -1
- package/dist/unstable/webmcp/WebMcpRegistrationResource.d.ts +14 -0
- package/dist/unstable/webmcp/WebMcpRegistrationResource.d.ts.map +1 -0
- package/dist/unstable/webmcp/WebMcpRegistrationResource.js +85 -0
- package/dist/unstable/webmcp/WebMcpRegistrationResource.js.map +1 -0
- package/dist/unstable/webmcp/convertTools.d.ts +21 -0
- package/dist/unstable/webmcp/convertTools.d.ts.map +1 -0
- package/dist/unstable/webmcp/convertTools.js +161 -0
- package/dist/unstable/webmcp/convertTools.js.map +1 -0
- package/dist/unstable/webmcp/useWebMcpProvider.d.ts +21 -0
- package/dist/unstable/webmcp/useWebMcpProvider.d.ts.map +1 -0
- package/dist/unstable/webmcp/useWebMcpProvider.js +106 -0
- package/dist/unstable/webmcp/useWebMcpProvider.js.map +1 -0
- package/dist/unstable/webmcp/webmcp-host.d.ts +39 -0
- package/dist/unstable/webmcp/webmcp-host.d.ts.map +1 -0
- package/dist/unstable/webmcp/webmcp-host.js +29 -0
- package/dist/unstable/webmcp/webmcp-host.js.map +1 -0
- package/dist/utils/Primitive.d.ts +10 -2
- package/dist/utils/Primitive.d.ts.map +1 -1
- package/dist/utils/Primitive.js +25 -6
- package/dist/utils/Primitive.js.map +1 -1
- package/dist/utils/getSelectionMessageId.d.ts.map +1 -1
- package/dist/utils/getSelectionMessageId.js +17 -3
- package/dist/utils/getSelectionMessageId.js.map +1 -1
- package/package.json +13 -13
- package/src/context/providers/ThreadViewportProvider.tsx +2 -2
- package/src/hooks/useToolCallElapsed.ts +3 -0
- package/src/index.ts +14 -1
- package/src/mcp-apps/McpAppRenderer.test.tsx +253 -5
- package/src/mcp-apps/McpAppRenderer.tsx +147 -52
- package/src/mcp-apps/app-frame.test.tsx +437 -1
- package/src/mcp-apps/app-frame.tsx +76 -21
- package/src/mcp-apps/bridge.test.ts +98 -0
- package/src/mcp-apps/bridge.ts +14 -3
- package/src/mcp-apps/index.ts +5 -1
- package/src/primitives/assistantModal/AssistantModalRoot.test.tsx +123 -0
- package/src/primitives/assistantModal/AssistantModalRoot.tsx +11 -31
- package/src/primitives/assistantModal/AssistantModalTrigger.test.tsx +1 -16
- package/src/primitives/composer/ComposerAttachmentDropzone.test.tsx +43 -0
- package/src/primitives/composer/ComposerAttachmentDropzone.tsx +2 -10
- package/src/primitives/composer/ComposerInput.test.tsx +22 -0
- package/src/primitives/composer/ComposerInput.tsx +5 -9
- package/src/primitives/composer/ComposerInputPluginContext.tsx +0 -10
- package/src/primitives/composer/trigger/TriggerPopoverAction.tsx +4 -2
- package/src/primitives/composer/trigger/TriggerPopoverBehavior.test.tsx +109 -0
- package/src/primitives/composer/trigger/TriggerPopoverDirective.tsx +4 -2
- package/src/primitives/composer/trigger/matchesTriggerItemQuery.test.ts +52 -0
- package/src/primitives/composer/trigger/matchesTriggerItemQuery.ts +13 -0
- package/src/primitives/composer/trigger/triggerKeyboardResource.ts +13 -7
- package/src/primitives/composer/trigger/triggerNavigationResource.ts +8 -13
- package/src/primitives/message/MessageParts.tsx +1 -21
- package/src/primitives/message/MessagePartsGrouped.test.tsx +93 -0
- package/src/primitives/message/MessagePartsGrouped.tsx +6 -6
- package/src/primitives/messagePart/MessagePartText.test.tsx +69 -0
- package/src/primitives/messagePart/MessagePartText.tsx +22 -9
- package/src/primitives/reasoning/useScrollLock.test.tsx +129 -0
- package/src/primitives/reasoning/useScrollLock.ts +15 -1
- package/src/primitives/thread/useThreadViewportAutoScroll.test.tsx +38 -1
- package/src/primitives/thread/useThreadViewportAutoScroll.ts +7 -6
- package/src/sandbox-host/SandboxHost.test.tsx +160 -2
- package/src/sandbox-host/SandboxHost.tsx +50 -10
- package/src/tests/MessageParts.rendererOptions.test.tsx +117 -0
- package/src/tests/toolCallTiming.test.tsx +55 -1
- package/src/unstable/useComposerInputHistory.test.tsx +2 -1
- package/src/unstable/useLiveCompletionAdapter.test.tsx +202 -1
- package/src/unstable/useLiveCompletionAdapter.ts +38 -8
- package/src/unstable/useMentionAdapter.test.tsx +383 -0
- package/src/unstable/useMentionAdapter.ts +94 -57
- package/src/unstable/useMessageStallDetection.ts +26 -19
- package/src/unstable/useModelContextSnapshot.test.tsx +132 -0
- package/src/unstable/useModelContextSnapshot.ts +67 -0
- package/src/unstable/useSlashCommandAdapter.ts +2 -9
- package/src/unstable/webmcp/WebMcpRegistrationResource.ts +92 -0
- package/src/unstable/webmcp/__tests__/webmcp.fake.tsx +168 -0
- package/src/unstable/webmcp/convertTools.test.ts +553 -0
- package/src/unstable/webmcp/convertTools.ts +260 -0
- package/src/unstable/webmcp/useWebMcpProvider.test.tsx +466 -0
- package/src/unstable/webmcp/useWebMcpProvider.ts +148 -0
- package/src/unstable/webmcp/webmcp-host.test.ts +142 -0
- package/src/unstable/webmcp/webmcp-host.ts +83 -0
- package/src/utils/Primitive.test.tsx +46 -1
- package/src/utils/Primitive.tsx +37 -7
- package/src/utils/getSelectionMessageId.test.ts +176 -1
- package/src/utils/getSelectionMessageId.ts +21 -3
- package/dist/utils/invokeCallbackSafely.d.ts +0 -5
- package/dist/utils/invokeCallbackSafely.d.ts.map +0 -1
- package/dist/utils/invokeCallbackSafely.js +0 -15
- package/dist/utils/invokeCallbackSafely.js.map +0 -1
- package/dist/utils/useToolArgsFieldStatus.d.ts +0 -19
- package/dist/utils/useToolArgsFieldStatus.d.ts.map +0 -1
- package/dist/utils/useToolArgsFieldStatus.js +0 -23
- package/dist/utils/useToolArgsFieldStatus.js.map +0 -1
- package/src/utils/invokeCallbackSafely.ts +0 -11
- package/src/utils/useToolArgsFieldStatus.ts +0 -18
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessagePartsGrouped.js","names":["c","_c","ComponentType","FC","memo","PropsWithChildren","useMemo","useAuiState","useAui","PartByIndexProvider","TextMessagePartProvider","MessagePartPrimitiveText","MessagePartPrimitiveImage","Unstable_AudioMessagePartComponent","DataMessagePartComponent","DataMessagePartProps","EmptyMessagePartComponent","TextMessagePartComponent","ImageMessagePartComponent","SourceMessagePartComponent","ToolCallMessagePartComponent","ToolCallMessagePartProps","FileMessagePartComponent","ReasoningMessagePartComponent","MessagePartPrimitiveInProgress","MessagePartStatus","MessagePartGroup","groupKey","indices","GroupingFunction","parts","groupMessagePartsByParentId","groupMap","Map","i","length","part","parentId","groupId","get","push","set","groups","startsWith","undefined","useMessagePartsGrouped","groupingFunction","$","_temp","t0","bb0","t1","Symbol","for","MessagePrimitiveUnstable_PartsGrouped","Props","components","Empty","Text","Reasoning","Source","Image","File","Unstable_Audio","data","by_name","Record","Fallback","tools","Override","Group","ToolUIDisplay","props","toolName","s","toolUIs","render","Render","t2","DataUIDisplay","name","dataRenderers","renderers","Array","isArray","Render_0","defaultComponents","whiteSpace","fontFamily","children","MessagePartComponentProps","MessagePartComponent","t3","t4","t5","t6","t7","t8","t9","Audio","t10","aui","_temp2","type","addResult","addToolResult","resume","resumeToolCall","respondToApproval","respondToToolApproval","t11","Tool","status","Error","Data","console","warn","MessagePartProps","partIndex","MessagePartImpl","MessagePart","prev","next","EmptyPartFallback","component","Component","COMPLETE_STATUS","Object","freeze","EmptyPartsImpl","_temp3","EmptyParts","contentLength","_temp4","messageGroups","group","groupIndex","GroupComponent","map","partsElements","displayName","MessagePrimitiveUnstable_PartsGroupedByParentId","Omit","message"],"sources":["../../../src/primitives/message/MessagePartsGrouped.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n type ComponentType,\n type FC,\n memo,\n type PropsWithChildren,\n useMemo,\n} from \"react\";\nimport { useAuiState, useAui } from \"@assistant-ui/store\";\nimport { PartByIndexProvider } from \"../../context/providers/PartByIndexProvider\";\nimport { TextMessagePartProvider } from \"../../context/providers/TextMessagePartProvider\";\nimport { MessagePartPrimitiveText } from \"../messagePart/MessagePartText\";\nimport { MessagePartPrimitiveImage } from \"../messagePart/MessagePartImage\";\nimport type {\n Unstable_AudioMessagePartComponent,\n DataMessagePartComponent,\n DataMessagePartProps,\n EmptyMessagePartComponent,\n TextMessagePartComponent,\n ImageMessagePartComponent,\n SourceMessagePartComponent,\n ToolCallMessagePartComponent,\n ToolCallMessagePartProps,\n FileMessagePartComponent,\n ReasoningMessagePartComponent,\n} from \"@assistant-ui/core/react\";\nimport { MessagePartPrimitiveInProgress } from \"../messagePart/MessagePartInProgress\";\nimport type { MessagePartStatus } from \"@assistant-ui/core\";\n\ntype MessagePartGroup = {\n groupKey: string | undefined;\n indices: number[];\n};\n\nexport type GroupingFunction = (parts: readonly any[]) => MessagePartGroup[];\n\n/**\n * Groups message parts by their parent ID.\n * Parts without a parent ID appear in their chronological position as individual groups.\n * Parts with the same parent ID are grouped together at the position of their first occurrence.\n */\nconst groupMessagePartsByParentId: GroupingFunction = (\n parts: readonly any[],\n): MessagePartGroup[] => {\n // Map maintains insertion order, so groups appear in order of first occurrence\n const groupMap = new Map<string, number[]>();\n\n // Process each part in order\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n const parentId = part?.parentId as string | undefined;\n\n // For parts without parentId, assign a unique group ID to maintain their position\n const groupId = parentId ?? `__ungrouped_${i}`;\n\n // Get or create the indices array for this group\n const indices = groupMap.get(groupId) ?? [];\n indices.push(i);\n groupMap.set(groupId, indices);\n }\n\n // Convert map to array of groups\n const groups: MessagePartGroup[] = [];\n for (const [groupId, indices] of groupMap) {\n // Extract parentId (undefined for ungrouped parts)\n const groupKey = groupId.startsWith(\"__ungrouped_\") ? undefined : groupId;\n groups.push({ groupKey, indices });\n }\n\n return groups;\n};\n\nconst useMessagePartsGrouped = (\n groupingFunction: GroupingFunction,\n): MessagePartGroup[] => {\n const parts = useAuiState((s) => s.message.parts);\n\n return useMemo(() => {\n if (parts.length === 0) {\n return [];\n }\n return groupingFunction(parts);\n }, [parts, groupingFunction]);\n};\n\nexport namespace MessagePrimitiveUnstable_PartsGrouped {\n export type Props = {\n /**\n * Function that takes an array of message parts and returns an array of groups.\n * Each group contains a key (for identification) and an array of indices.\n *\n * @example\n * ```tsx\n * // Group by parent ID (default behavior)\n * groupingFunction={(parts) => {\n * const groups = new Map<string, number[]>();\n * parts.forEach((part, i) => {\n * const key = part.parentId ?? `__ungrouped_${i}`;\n * const indices = groups.get(key) ?? [];\n * indices.push(i);\n * groups.set(key, indices);\n * });\n * return Array.from(groups.entries()).map(([key, indices]) => ({\n * key: key.startsWith(\"__ungrouped_\") ? undefined : key,\n * indices\n * }));\n * }}\n * ```\n *\n * @example\n * ```tsx\n * // Group by tool name\n * import { groupMessagePartsByToolName } from \"@assistant-ui/react\";\n *\n * <MessagePrimitive.Unstable_PartsGrouped\n * groupingFunction={groupMessagePartsByToolName}\n * components={{\n * Group: ({ key, indices, children }) => {\n * if (!key) return <>{children}</>;\n * return (\n * <div className=\"tool-group\">\n * <h4>Tool: {key}</h4>\n * {children}\n * </div>\n * );\n * }\n * }}\n * />\n * ```\n */\n groupingFunction: GroupingFunction;\n\n /**\n * Component configuration for rendering different types of message content.\n *\n * You can provide custom components for each content type (text, image, file, etc.)\n * and configure tool rendering behavior. If not provided, default components will be used.\n */\n components:\n | {\n /** Component for rendering empty messages */\n Empty?: EmptyMessagePartComponent | undefined;\n /** Component for rendering text content */\n Text?: TextMessagePartComponent | undefined;\n /** Component for rendering reasoning content (typically hidden) */\n Reasoning?: ReasoningMessagePartComponent | undefined;\n /** Component for rendering source content */\n Source?: SourceMessagePartComponent | undefined;\n /** Component for rendering image content */\n Image?: ImageMessagePartComponent | undefined;\n /** Component for rendering file content */\n File?: FileMessagePartComponent | undefined;\n /**\n * Component for rendering audio content.\n *\n * @deprecated Render audio through the `File` slot instead, branching\n * on an `audio/*` mime type.\n */\n Unstable_Audio?: Unstable_AudioMessagePartComponent | undefined;\n /** Configuration for data part rendering */\n data?:\n | {\n /** Map data event names to specific components */\n by_name?:\n | Record<string, DataMessagePartComponent | undefined>\n | undefined;\n /** Fallback component for unmatched data events */\n Fallback?: DataMessagePartComponent | undefined;\n }\n | undefined;\n /** Configuration for tool call rendering */\n tools?:\n | {\n /** Map of tool names to their specific components */\n by_name?:\n | Record<string, ToolCallMessagePartComponent | undefined>\n | undefined;\n /** Fallback component for unregistered tools */\n Fallback?: ComponentType<ToolCallMessagePartProps> | undefined;\n }\n | {\n /** Override component that handles all tool calls */\n Override: ComponentType<ToolCallMessagePartProps>;\n }\n | undefined;\n\n /**\n * Component for rendering grouped message parts.\n *\n * When provided, this component will automatically wrap message parts that share\n * the same group key as determined by the groupingFunction.\n *\n * The component receives:\n * - `groupKey`: The group key (or undefined for ungrouped parts)\n * - `indices`: Array of indices for the parts in this group\n * - `children`: The rendered message part components\n *\n * @example\n * ```tsx\n * // Collapsible group\n * Group: ({ groupKey, indices, children }) => {\n * if (!groupKey) return <>{children}</>;\n * return (\n * <details className=\"message-group\">\n * <summary>\n * Group {groupKey} ({indices.length} parts)\n * </summary>\n * <div className=\"group-content\">\n * {children}\n * </div>\n * </details>\n * );\n * }\n * ```\n *\n * @param groupKey - The group key (undefined for ungrouped parts)\n * @param indices - Array of indices for the parts in this group\n * @param children - Rendered message part components to display within the group\n */\n Group?: ComponentType<\n PropsWithChildren<{\n groupKey: string | undefined;\n indices: number[];\n }>\n >;\n }\n | undefined;\n };\n}\n\nconst ToolUIDisplay = ({\n Fallback,\n ...props\n}: {\n Fallback: ToolCallMessagePartComponent | undefined;\n} & ToolCallMessagePartProps) => {\n const Render = useAuiState(\n (s) => s.tools.toolUIs[props.toolName]?.[0]?.render ?? Fallback,\n );\n if (!Render) return null;\n return <Render {...props} />;\n};\n\nconst DataUIDisplay = ({\n Fallback,\n ...props\n}: {\n Fallback: DataMessagePartComponent | undefined;\n} & DataMessagePartProps) => {\n const Render = useAuiState((s) => {\n const Render = s.dataRenderers.renderers[props.name] ?? Fallback;\n if (Array.isArray(Render)) return Render[0] ?? Fallback;\n return Render;\n });\n if (!Render) return null;\n return <Render {...props} />;\n};\n\nconst defaultComponents = {\n Text: () => (\n <p style={{ whiteSpace: \"pre-line\" }}>\n <MessagePartPrimitiveText />\n <MessagePartPrimitiveInProgress>\n <span style={{ fontFamily: \"revert\" }}>{\" \\u25CF\"}</span>\n </MessagePartPrimitiveInProgress>\n </p>\n ),\n Reasoning: () => null,\n Source: () => null,\n Image: () => <MessagePartPrimitiveImage />,\n File: () => null,\n Unstable_Audio: () => null,\n Group: ({ children }) => children,\n} satisfies MessagePrimitiveUnstable_PartsGrouped.Props[\"components\"];\n\ntype MessagePartComponentProps = {\n components: MessagePrimitiveUnstable_PartsGrouped.Props[\"components\"];\n};\n\nconst MessagePartComponent: FC<MessagePartComponentProps> = ({\n components: {\n Text = defaultComponents.Text,\n Reasoning = defaultComponents.Reasoning,\n Image = defaultComponents.Image,\n Source = defaultComponents.Source,\n File = defaultComponents.File,\n Unstable_Audio: Audio = defaultComponents.Unstable_Audio,\n tools = {},\n data,\n } = {},\n}) => {\n const aui = useAui();\n const part = useAuiState((s) => s.part);\n\n const type = part.type;\n if (type === \"tool-call\") {\n const addResult = aui.part.addToolResult;\n const resume = aui.part.resumeToolCall;\n const respondToApproval = aui.part.respondToToolApproval;\n if (\"Override\" in tools)\n return (\n <tools.Override\n {...part}\n addResult={addResult}\n resume={resume}\n respondToApproval={respondToApproval}\n />\n );\n const Tool = tools.by_name?.[part.toolName] ?? tools.Fallback;\n return (\n <ToolUIDisplay\n {...part}\n Fallback={Tool}\n addResult={addResult}\n resume={resume}\n respondToApproval={respondToApproval}\n />\n );\n }\n\n if (part.status?.type === \"requires-action\")\n throw new Error(\"Encountered unexpected requires-action status\");\n\n switch (type) {\n case \"text\":\n return <Text {...part} />;\n\n case \"reasoning\":\n return <Reasoning {...part} />;\n\n case \"source\":\n return <Source {...part} />;\n\n case \"image\":\n return <Image {...part} />;\n\n case \"file\":\n return <File {...part} />;\n\n case \"audio\":\n return <Audio {...part} />;\n\n case \"data\": {\n const Data = data?.by_name?.[part.name] ?? data?.Fallback;\n return <DataUIDisplay {...part} Fallback={Data} />;\n }\n\n default:\n console.warn(`Unknown message part type: ${type}`);\n return null;\n }\n};\n\ntype MessagePartProps = {\n partIndex: number;\n components: MessagePrimitiveUnstable_PartsGrouped.Props[\"components\"];\n};\n\nconst MessagePartImpl: FC<MessagePartProps> = ({ partIndex, components }) => {\n return (\n <PartByIndexProvider index={partIndex}>\n <MessagePartComponent components={components} />\n </PartByIndexProvider>\n );\n};\n\nconst MessagePart = memo(\n MessagePartImpl,\n (prev, next) =>\n prev.partIndex === next.partIndex &&\n prev.components?.Text === next.components?.Text &&\n prev.components?.Reasoning === next.components?.Reasoning &&\n prev.components?.Source === next.components?.Source &&\n prev.components?.Image === next.components?.Image &&\n prev.components?.File === next.components?.File &&\n prev.components?.Unstable_Audio === next.components?.Unstable_Audio &&\n prev.components?.tools === next.components?.tools &&\n prev.components?.data === next.components?.data &&\n prev.components?.Group === next.components?.Group,\n);\n\nconst EmptyPartFallback: FC<{\n status: MessagePartStatus;\n component: TextMessagePartComponent;\n}> = ({ status, component: Component }) => {\n return (\n <TextMessagePartProvider text=\"\" isRunning={status.type === \"running\"}>\n <Component type=\"text\" text=\"\" status={status} />\n </TextMessagePartProvider>\n );\n};\n\nconst COMPLETE_STATUS: MessagePartStatus = Object.freeze({\n type: \"complete\",\n});\n\nconst EmptyPartsImpl: FC<MessagePartComponentProps> = ({ components }) => {\n const status = useAuiState(\n (s) => (s.message.status ?? COMPLETE_STATUS) as MessagePartStatus,\n );\n\n if (components?.Empty) return <components.Empty status={status} />;\n\n return (\n <EmptyPartFallback\n status={status}\n component={components?.Text ?? defaultComponents.Text}\n />\n );\n};\n\nconst EmptyParts = memo(\n EmptyPartsImpl,\n (prev, next) =>\n prev.components?.Empty === next.components?.Empty &&\n prev.components?.Text === next.components?.Text,\n);\n\n/**\n * Renders the parts of a message grouped by a custom grouping function.\n *\n * This component allows you to group message parts based on any criteria you define.\n * The grouping function receives all message parts and returns an array of groups,\n * where each group has a key and an array of part indices.\n *\n * @deprecated Prefer `<MessagePrimitive.GroupedParts>` for adjacent\n * grouping — it dispatches all rendering through one `switch (part.type)`\n * and supports nested group paths. Keep this primitive only for\n * non-adjacent clustering (e.g., gathering parts with the same parent-id\n * across the message).\n *\n * @example\n * ```tsx\n * // Group by parent ID (default behavior)\n * <MessagePrimitive.Unstable_PartsGrouped\n * components={{\n * Text: ({ text }) => <p className=\"message-text\">{text}</p>,\n * Image: ({ image }) => <img src={image} alt=\"Message image\" />,\n * Group: ({ groupKey, indices, children }) => {\n * if (!groupKey) return <>{children}</>;\n * return (\n * <div className=\"parent-group border rounded p-4\">\n * <h4>Parent ID: {groupKey}</h4>\n * {children}\n * </div>\n * );\n * }\n * }}\n * />\n * ```\n */\nexport const MessagePrimitiveUnstable_PartsGrouped: FC<\n MessagePrimitiveUnstable_PartsGrouped.Props\n> = ({ groupingFunction, components }) => {\n const contentLength = useAuiState((s) => s.message.parts.length);\n const messageGroups = useMessagePartsGrouped(groupingFunction);\n\n const partsElements = useMemo(() => {\n if (contentLength === 0) {\n return <EmptyParts components={components} />;\n }\n\n return messageGroups.map((group, groupIndex) => {\n const GroupComponent = components?.Group ?? defaultComponents.Group;\n\n return (\n <GroupComponent\n key={`group-${groupIndex}-${group.groupKey ?? \"ungrouped\"}`}\n groupKey={group.groupKey}\n indices={group.indices}\n >\n {group.indices.map((partIndex) => (\n <MessagePart\n key={partIndex}\n partIndex={partIndex}\n components={components}\n />\n ))}\n </GroupComponent>\n );\n });\n }, [messageGroups, components, contentLength]);\n\n return <>{partsElements}</>;\n};\n\nMessagePrimitiveUnstable_PartsGrouped.displayName =\n \"MessagePrimitive.Unstable_PartsGrouped\";\n\n/**\n * Renders the parts of a message grouped by their parent ID.\n * This is a convenience wrapper around Unstable_PartsGrouped with parent ID grouping.\n *\n * @deprecated Use MessagePrimitive.Unstable_PartsGrouped instead for more flexibility\n */\nexport const MessagePrimitiveUnstable_PartsGroupedByParentId: FC<\n Omit<MessagePrimitiveUnstable_PartsGrouped.Props, \"groupingFunction\">\n> = ({ components, ...props }) => {\n return (\n <MessagePrimitiveUnstable_PartsGrouped\n {...props}\n components={components}\n groupingFunction={groupMessagePartsByParentId}\n />\n );\n};\n\nMessagePrimitiveUnstable_PartsGroupedByParentId.displayName =\n \"MessagePrimitive.Unstable_PartsGroupedByParentId\";\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MessagePartsGrouped.js","names":["c","_c","ComponentType","FC","memo","PropsWithChildren","useMemo","useAuiState","useAui","PartByIndexProvider","TextMessagePartProvider","MessagePartPrimitiveText","MessagePartPrimitiveImage","Unstable_AudioMessagePartComponent","DataMessagePartComponent","DataMessagePartProps","EmptyMessagePartComponent","TextMessagePartComponent","ImageMessagePartComponent","SourceMessagePartComponent","ToolCallMessagePartComponent","ToolCallMessagePartProps","FileMessagePartComponent","ReasoningMessagePartComponent","MessagePartPrimitiveInProgress","MessagePartStatus","MessagePartGroup","groupKey","indices","GroupingFunction","parts","groupMessagePartsByParentId","groupMap","Map","i","length","part","parentId","groupId","get","push","set","groups","undefined","useMessagePartsGrouped","groupingFunction","$","_temp","t0","bb0","t1","Symbol","for","MessagePrimitiveUnstable_PartsGrouped","Props","components","Empty","Text","Reasoning","Source","Image","File","Unstable_Audio","data","by_name","Record","Fallback","tools","Override","Group","ToolUIDisplay","props","toolName","s","toolUIs","render","Render","t2","DataUIDisplay","name","dataRenderers","renderers","Array","isArray","Render_0","defaultComponents","whiteSpace","fontFamily","children","MessagePartComponentProps","MessagePartComponent","t3","t4","t5","t6","t7","t8","t9","Audio","t10","aui","_temp2","type","addResult","addToolResult","resume","resumeToolCall","respondToApproval","respondToToolApproval","t11","Tool","status","Error","Data","console","warn","MessagePartProps","partIndex","MessagePartImpl","MessagePart","prev","next","EmptyPartFallback","component","Component","COMPLETE_STATUS","Object","freeze","EmptyPartsImpl","_temp3","EmptyParts","contentLength","_temp4","messageGroups","group","groupIndex","GroupComponent","map","partsElements","displayName","MessagePrimitiveUnstable_PartsGroupedByParentId","Omit","message"],"sources":["../../../src/primitives/message/MessagePartsGrouped.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n type ComponentType,\n type FC,\n memo,\n type PropsWithChildren,\n useMemo,\n} from \"react\";\nimport { useAuiState, useAui } from \"@assistant-ui/store\";\nimport { PartByIndexProvider } from \"../../context/providers/PartByIndexProvider\";\nimport { TextMessagePartProvider } from \"../../context/providers/TextMessagePartProvider\";\nimport { MessagePartPrimitiveText } from \"../messagePart/MessagePartText\";\nimport { MessagePartPrimitiveImage } from \"../messagePart/MessagePartImage\";\nimport type {\n Unstable_AudioMessagePartComponent,\n DataMessagePartComponent,\n DataMessagePartProps,\n EmptyMessagePartComponent,\n TextMessagePartComponent,\n ImageMessagePartComponent,\n SourceMessagePartComponent,\n ToolCallMessagePartComponent,\n ToolCallMessagePartProps,\n FileMessagePartComponent,\n ReasoningMessagePartComponent,\n} from \"@assistant-ui/core/react\";\nimport { MessagePartPrimitiveInProgress } from \"../messagePart/MessagePartInProgress\";\nimport type { MessagePartStatus } from \"@assistant-ui/core\";\n\ntype MessagePartGroup = {\n groupKey: string | undefined;\n indices: number[];\n};\n\nexport type GroupingFunction = (parts: readonly any[]) => MessagePartGroup[];\n\n/**\n * Groups message parts by their parent ID.\n * Parts without a parent ID appear in their chronological position as individual groups.\n * Parts with the same parent ID are grouped together at the position of their first occurrence.\n */\nconst groupMessagePartsByParentId: GroupingFunction = (\n parts: readonly any[],\n): MessagePartGroup[] => {\n // Map maintains insertion order, so groups appear in order of first occurrence\n const groupMap = new Map<string | number, number[]>();\n\n // Process each part in order\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n const parentId = part?.parentId as string | undefined;\n\n // For parts without parentId, assign a unique group ID to maintain their position\n const groupId = parentId ?? i;\n\n // Get or create the indices array for this group\n const indices = groupMap.get(groupId) ?? [];\n indices.push(i);\n groupMap.set(groupId, indices);\n }\n\n // Convert map to array of groups\n const groups: MessagePartGroup[] = [];\n for (const [groupId, indices] of groupMap) {\n // Extract parentId (undefined for ungrouped parts)\n const groupKey = typeof groupId === \"string\" ? groupId : undefined;\n groups.push({ groupKey, indices });\n }\n\n return groups;\n};\n\nconst useMessagePartsGrouped = (\n groupingFunction: GroupingFunction,\n): MessagePartGroup[] => {\n const parts = useAuiState((s) => s.message.parts);\n\n return useMemo(() => {\n if (parts.length === 0) {\n return [];\n }\n return groupingFunction(parts);\n }, [parts, groupingFunction]);\n};\n\nexport namespace MessagePrimitiveUnstable_PartsGrouped {\n export type Props = {\n /**\n * Function that takes an array of message parts and returns an array of groups.\n * Each group contains a key (for identification) and an array of indices.\n *\n * @example\n * ```tsx\n * // Group by parent ID (default behavior)\n * groupingFunction={(parts) => {\n * const groups = new Map<string | number, number[]>();\n * parts.forEach((part, i) => {\n * const key = part.parentId ?? i;\n * const indices = groups.get(key) ?? [];\n * indices.push(i);\n * groups.set(key, indices);\n * });\n * return Array.from(groups.entries()).map(([key, indices]) => ({\n * groupKey: typeof key === \"string\" ? key : undefined,\n * indices\n * }));\n * }}\n * ```\n *\n * @example\n * ```tsx\n * // Group by tool name\n * import { groupMessagePartsByToolName } from \"@assistant-ui/react\";\n *\n * <MessagePrimitive.Unstable_PartsGrouped\n * groupingFunction={groupMessagePartsByToolName}\n * components={{\n * Group: ({ key, indices, children }) => {\n * if (!key) return <>{children}</>;\n * return (\n * <div className=\"tool-group\">\n * <h4>Tool: {key}</h4>\n * {children}\n * </div>\n * );\n * }\n * }}\n * />\n * ```\n */\n groupingFunction: GroupingFunction;\n\n /**\n * Component configuration for rendering different types of message content.\n *\n * You can provide custom components for each content type (text, image, file, etc.)\n * and configure tool rendering behavior. If not provided, default components will be used.\n */\n components:\n | {\n /** Component for rendering empty messages */\n Empty?: EmptyMessagePartComponent | undefined;\n /** Component for rendering text content */\n Text?: TextMessagePartComponent | undefined;\n /** Component for rendering reasoning content (typically hidden) */\n Reasoning?: ReasoningMessagePartComponent | undefined;\n /** Component for rendering source content */\n Source?: SourceMessagePartComponent | undefined;\n /** Component for rendering image content */\n Image?: ImageMessagePartComponent | undefined;\n /** Component for rendering file content */\n File?: FileMessagePartComponent | undefined;\n /**\n * Component for rendering audio content.\n *\n * @deprecated Render audio through the `File` slot instead, branching\n * on an `audio/*` mime type.\n */\n Unstable_Audio?: Unstable_AudioMessagePartComponent | undefined;\n /** Configuration for data part rendering */\n data?:\n | {\n /** Map data event names to specific components */\n by_name?:\n | Record<string, DataMessagePartComponent | undefined>\n | undefined;\n /** Fallback component for unmatched data events */\n Fallback?: DataMessagePartComponent | undefined;\n }\n | undefined;\n /** Configuration for tool call rendering */\n tools?:\n | {\n /** Map of tool names to their specific components */\n by_name?:\n | Record<string, ToolCallMessagePartComponent | undefined>\n | undefined;\n /** Fallback component for unregistered tools */\n Fallback?: ComponentType<ToolCallMessagePartProps> | undefined;\n }\n | {\n /** Override component that handles all tool calls */\n Override: ComponentType<ToolCallMessagePartProps>;\n }\n | undefined;\n\n /**\n * Component for rendering grouped message parts.\n *\n * When provided, this component will automatically wrap message parts that share\n * the same group key as determined by the groupingFunction.\n *\n * The component receives:\n * - `groupKey`: The group key (or undefined for ungrouped parts)\n * - `indices`: Array of indices for the parts in this group\n * - `children`: The rendered message part components\n *\n * @example\n * ```tsx\n * // Collapsible group\n * Group: ({ groupKey, indices, children }) => {\n * if (!groupKey) return <>{children}</>;\n * return (\n * <details className=\"message-group\">\n * <summary>\n * Group {groupKey} ({indices.length} parts)\n * </summary>\n * <div className=\"group-content\">\n * {children}\n * </div>\n * </details>\n * );\n * }\n * ```\n *\n * @param groupKey - The group key (undefined for ungrouped parts)\n * @param indices - Array of indices for the parts in this group\n * @param children - Rendered message part components to display within the group\n */\n Group?: ComponentType<\n PropsWithChildren<{\n groupKey: string | undefined;\n indices: number[];\n }>\n >;\n }\n | undefined;\n };\n}\n\nconst ToolUIDisplay = ({\n Fallback,\n ...props\n}: {\n Fallback: ToolCallMessagePartComponent | undefined;\n} & ToolCallMessagePartProps) => {\n const Render = useAuiState(\n (s) => s.tools.toolUIs[props.toolName]?.[0]?.render ?? Fallback,\n );\n if (!Render) return null;\n return <Render {...props} />;\n};\n\nconst DataUIDisplay = ({\n Fallback,\n ...props\n}: {\n Fallback: DataMessagePartComponent | undefined;\n} & DataMessagePartProps) => {\n const Render = useAuiState((s) => {\n const Render = s.dataRenderers.renderers[props.name] ?? Fallback;\n if (Array.isArray(Render)) return Render[0] ?? Fallback;\n return Render;\n });\n if (!Render) return null;\n return <Render {...props} />;\n};\n\nconst defaultComponents = {\n Text: () => (\n <p style={{ whiteSpace: \"pre-line\" }}>\n <MessagePartPrimitiveText />\n <MessagePartPrimitiveInProgress>\n <span style={{ fontFamily: \"revert\" }}>{\" \\u25CF\"}</span>\n </MessagePartPrimitiveInProgress>\n </p>\n ),\n Reasoning: () => null,\n Source: () => null,\n Image: () => <MessagePartPrimitiveImage />,\n File: () => null,\n Unstable_Audio: () => null,\n Group: ({ children }) => children,\n} satisfies MessagePrimitiveUnstable_PartsGrouped.Props[\"components\"];\n\ntype MessagePartComponentProps = {\n components: MessagePrimitiveUnstable_PartsGrouped.Props[\"components\"];\n};\n\nconst MessagePartComponent: FC<MessagePartComponentProps> = ({\n components: {\n Text = defaultComponents.Text,\n Reasoning = defaultComponents.Reasoning,\n Image = defaultComponents.Image,\n Source = defaultComponents.Source,\n File = defaultComponents.File,\n Unstable_Audio: Audio = defaultComponents.Unstable_Audio,\n tools = {},\n data,\n } = {},\n}) => {\n const aui = useAui();\n const part = useAuiState((s) => s.part);\n\n const type = part.type;\n if (type === \"tool-call\") {\n const addResult = aui.part.addToolResult;\n const resume = aui.part.resumeToolCall;\n const respondToApproval = aui.part.respondToToolApproval;\n if (\"Override\" in tools)\n return (\n <tools.Override\n {...part}\n addResult={addResult}\n resume={resume}\n respondToApproval={respondToApproval}\n />\n );\n const Tool = tools.by_name?.[part.toolName] ?? tools.Fallback;\n return (\n <ToolUIDisplay\n {...part}\n Fallback={Tool}\n addResult={addResult}\n resume={resume}\n respondToApproval={respondToApproval}\n />\n );\n }\n\n if (part.status?.type === \"requires-action\")\n throw new Error(\"Encountered unexpected requires-action status\");\n\n switch (type) {\n case \"text\":\n return <Text {...part} />;\n\n case \"reasoning\":\n return <Reasoning {...part} />;\n\n case \"source\":\n return <Source {...part} />;\n\n case \"image\":\n return <Image {...part} />;\n\n case \"file\":\n return <File {...part} />;\n\n case \"audio\":\n return <Audio {...part} />;\n\n case \"data\": {\n const Data = data?.by_name?.[part.name] ?? data?.Fallback;\n return <DataUIDisplay {...part} Fallback={Data} />;\n }\n\n default:\n console.warn(`Unknown message part type: ${type}`);\n return null;\n }\n};\n\ntype MessagePartProps = {\n partIndex: number;\n components: MessagePrimitiveUnstable_PartsGrouped.Props[\"components\"];\n};\n\nconst MessagePartImpl: FC<MessagePartProps> = ({ partIndex, components }) => {\n return (\n <PartByIndexProvider index={partIndex}>\n <MessagePartComponent components={components} />\n </PartByIndexProvider>\n );\n};\n\nconst MessagePart = memo(\n MessagePartImpl,\n (prev, next) =>\n prev.partIndex === next.partIndex &&\n prev.components?.Text === next.components?.Text &&\n prev.components?.Reasoning === next.components?.Reasoning &&\n prev.components?.Source === next.components?.Source &&\n prev.components?.Image === next.components?.Image &&\n prev.components?.File === next.components?.File &&\n prev.components?.Unstable_Audio === next.components?.Unstable_Audio &&\n prev.components?.tools === next.components?.tools &&\n prev.components?.data === next.components?.data &&\n prev.components?.Group === next.components?.Group,\n);\n\nconst EmptyPartFallback: FC<{\n status: MessagePartStatus;\n component: TextMessagePartComponent;\n}> = ({ status, component: Component }) => {\n return (\n <TextMessagePartProvider text=\"\" isRunning={status.type === \"running\"}>\n <Component type=\"text\" text=\"\" status={status} />\n </TextMessagePartProvider>\n );\n};\n\nconst COMPLETE_STATUS: MessagePartStatus = Object.freeze({\n type: \"complete\",\n});\n\nconst EmptyPartsImpl: FC<MessagePartComponentProps> = ({ components }) => {\n const status = useAuiState(\n (s) => (s.message.status ?? COMPLETE_STATUS) as MessagePartStatus,\n );\n\n if (components?.Empty) return <components.Empty status={status} />;\n\n return (\n <EmptyPartFallback\n status={status}\n component={components?.Text ?? defaultComponents.Text}\n />\n );\n};\n\nconst EmptyParts = memo(\n EmptyPartsImpl,\n (prev, next) =>\n prev.components?.Empty === next.components?.Empty &&\n prev.components?.Text === next.components?.Text,\n);\n\n/**\n * Renders the parts of a message grouped by a custom grouping function.\n *\n * This component allows you to group message parts based on any criteria you define.\n * The grouping function receives all message parts and returns an array of groups,\n * where each group has a key and an array of part indices.\n *\n * @deprecated Prefer `<MessagePrimitive.GroupedParts>` for adjacent\n * grouping — it dispatches all rendering through one `switch (part.type)`\n * and supports nested group paths. Keep this primitive only for\n * non-adjacent clustering (e.g., gathering parts with the same parent-id\n * across the message).\n *\n * @example\n * ```tsx\n * // Group by parent ID (default behavior)\n * <MessagePrimitive.Unstable_PartsGrouped\n * components={{\n * Text: ({ text }) => <p className=\"message-text\">{text}</p>,\n * Image: ({ image }) => <img src={image} alt=\"Message image\" />,\n * Group: ({ groupKey, indices, children }) => {\n * if (!groupKey) return <>{children}</>;\n * return (\n * <div className=\"parent-group border rounded p-4\">\n * <h4>Parent ID: {groupKey}</h4>\n * {children}\n * </div>\n * );\n * }\n * }}\n * />\n * ```\n */\nexport const MessagePrimitiveUnstable_PartsGrouped: FC<\n MessagePrimitiveUnstable_PartsGrouped.Props\n> = ({ groupingFunction, components }) => {\n const contentLength = useAuiState((s) => s.message.parts.length);\n const messageGroups = useMessagePartsGrouped(groupingFunction);\n\n const partsElements = useMemo(() => {\n if (contentLength === 0) {\n return <EmptyParts components={components} />;\n }\n\n return messageGroups.map((group, groupIndex) => {\n const GroupComponent = components?.Group ?? defaultComponents.Group;\n\n return (\n <GroupComponent\n key={`group-${groupIndex}-${group.groupKey ?? \"ungrouped\"}`}\n groupKey={group.groupKey}\n indices={group.indices}\n >\n {group.indices.map((partIndex) => (\n <MessagePart\n key={partIndex}\n partIndex={partIndex}\n components={components}\n />\n ))}\n </GroupComponent>\n );\n });\n }, [messageGroups, components, contentLength]);\n\n return <>{partsElements}</>;\n};\n\nMessagePrimitiveUnstable_PartsGrouped.displayName =\n \"MessagePrimitive.Unstable_PartsGrouped\";\n\n/**\n * Renders the parts of a message grouped by their parent ID.\n * This is a convenience wrapper around Unstable_PartsGrouped with parent ID grouping.\n *\n * @deprecated Use MessagePrimitive.Unstable_PartsGrouped instead for more flexibility\n */\nexport const MessagePrimitiveUnstable_PartsGroupedByParentId: FC<\n Omit<MessagePrimitiveUnstable_PartsGrouped.Props, \"groupingFunction\">\n> = ({ components, ...props }) => {\n return (\n <MessagePrimitiveUnstable_PartsGrouped\n {...props}\n components={components}\n groupingFunction={groupMessagePartsByParentId}\n />\n );\n};\n\nMessagePrimitiveUnstable_PartsGroupedByParentId.displayName =\n \"MessagePrimitive.Unstable_PartsGroupedByParentId\";\n"],"mappings":"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"}
|
|
@@ -15,6 +15,7 @@ declare namespace MessagePartPrimitiveText {
|
|
|
15
15
|
smooth?: boolean | SmoothOptions;
|
|
16
16
|
/**
|
|
17
17
|
* The HTML element or React component to render as.
|
|
18
|
+
* Ignored when a valid `render` element is supplied.
|
|
18
19
|
* @default "span"
|
|
19
20
|
*/
|
|
20
21
|
component?: ElementType;
|
|
@@ -51,6 +52,7 @@ declare const MessagePartPrimitiveText: import("react").ForwardRefExoticComponen
|
|
|
51
52
|
smooth?: boolean | SmoothOptions;
|
|
52
53
|
/**
|
|
53
54
|
* The HTML element or React component to render as.
|
|
55
|
+
* Ignored when a valid `render` element is supplied.
|
|
54
56
|
* @default "span"
|
|
55
57
|
*/
|
|
56
58
|
component?: ElementType;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessagePartText.d.ts","names":[],"sources":["../../../src/primitives/messagePart/MessagePartText.tsx"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"MessagePartText.d.ts","names":[],"sources":["../../../src/primitives/messagePart/MessagePartText.tsx"],"mappings":";;;;kBAaiB;OACH,UAAU,oBAAoB,UAAU;OACxC,QAAQ,KAClB,gCAAgC,UAAU;;;;;;;;IAU1C,mBAAmB;;;;;;IAMnB,YAAY;;;;;;;;;;;;;;;;;;;cAoBH,0CAAwB,0BAAA,KAAA,KAAA,qBAAA,gBAAA,mCAAA,eAAA;;;;;;;;;;;;EA1BxB,mBAAU;;;;;;EAMP,YAAA;oBA0Cf,cAAA"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { Primitive, renderSlot } from "../../utils/Primitive.js";
|
|
2
3
|
import { useMessagePartText } from "./useMessagePartText.js";
|
|
3
4
|
import { useSmooth } from "../../utils/smooth/useSmooth.js";
|
|
4
|
-
import {
|
|
5
|
-
import { forwardRef } from "@assistant-ui/tap/react-shim";
|
|
5
|
+
import { forwardRef, isValidElement } from "@assistant-ui/tap/react-shim";
|
|
6
6
|
import { jsx } from "react/jsx-runtime";
|
|
7
7
|
//#region src/primitives/messagePart/MessagePartText.tsx
|
|
8
8
|
/**
|
|
@@ -21,41 +21,18 @@ import { jsx } from "react/jsx-runtime";
|
|
|
21
21
|
* />
|
|
22
22
|
* ```
|
|
23
23
|
*/
|
|
24
|
-
const MessagePartPrimitiveText = forwardRef((
|
|
25
|
-
const $ = c(10);
|
|
26
|
-
let rest;
|
|
27
|
-
let t1;
|
|
28
|
-
let t2;
|
|
29
|
-
if ($[0] !== t0) {
|
|
30
|
-
({smooth: t1, component: t2, ...rest} = t0);
|
|
31
|
-
$[0] = t0;
|
|
32
|
-
$[1] = rest;
|
|
33
|
-
$[2] = t1;
|
|
34
|
-
$[3] = t2;
|
|
35
|
-
} else {
|
|
36
|
-
rest = $[1];
|
|
37
|
-
t1 = $[2];
|
|
38
|
-
t2 = $[3];
|
|
39
|
-
}
|
|
40
|
-
const smooth = t1 === void 0 ? true : t1;
|
|
41
|
-
const Component = t2 === void 0 ? "span" : t2;
|
|
24
|
+
const MessagePartPrimitiveText = forwardRef(({ smooth = true, component: Component = Primitive.span, render, ...rest }, forwardedRef) => {
|
|
42
25
|
const { text, status } = useSmooth(useMessagePartText(), smooth);
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
$[6] = rest;
|
|
54
|
-
$[7] = status.type;
|
|
55
|
-
$[8] = text;
|
|
56
|
-
$[9] = t3;
|
|
57
|
-
} else t3 = $[9];
|
|
58
|
-
return t3;
|
|
26
|
+
const mergedProps = {
|
|
27
|
+
"data-status": status.type,
|
|
28
|
+
...rest,
|
|
29
|
+
ref: forwardedRef
|
|
30
|
+
};
|
|
31
|
+
if (render && isValidElement(render)) return renderSlot(render, text, mergedProps);
|
|
32
|
+
return /* @__PURE__ */ jsx(Component, {
|
|
33
|
+
...mergedProps,
|
|
34
|
+
children: text
|
|
35
|
+
});
|
|
59
36
|
});
|
|
60
37
|
MessagePartPrimitiveText.displayName = "MessagePartPrimitive.Text";
|
|
61
38
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessagePartText.js","names":["
|
|
1
|
+
{"version":3,"file":"MessagePartText.js","names":["Primitive","renderSlot","ComponentRef","forwardRef","ComponentPropsWithoutRef","ElementType","isValidElement","useMessagePartText","useSmooth","SmoothOptions","MessagePartPrimitiveText","Element","span","Props","Omit","smooth","component","Component","render","rest","forwardedRef","text","status","mergedProps","type","ref","displayName"],"sources":["../../../src/primitives/messagePart/MessagePartText.tsx"],"sourcesContent":["\"use client\";\n\nimport { Primitive, renderSlot } from \"../../utils/Primitive\";\nimport {\n type ComponentRef,\n forwardRef,\n type ComponentPropsWithoutRef,\n type ElementType,\n isValidElement,\n} from \"react\";\nimport { useMessagePartText } from \"./useMessagePartText\";\nimport { useSmooth, type SmoothOptions } from \"../../utils/smooth/useSmooth\";\n\nexport namespace MessagePartPrimitiveText {\n export type Element = ComponentRef<typeof Primitive.span>;\n export type Props = Omit<\n ComponentPropsWithoutRef<typeof Primitive.span>,\n \"children\" | \"asChild\"\n > & {\n /**\n * Whether to enable smooth text streaming animation.\n * When enabled, text appears with a typing effect as it streams in.\n * Pass a `SmoothOptions` object to tune the reveal rate.\n * Auto-disables under `prefers-reduced-motion: reduce`.\n * @default true\n */\n smooth?: boolean | SmoothOptions;\n /**\n * The HTML element or React component to render as.\n * Ignored when a valid `render` element is supplied.\n * @default \"span\"\n */\n component?: ElementType;\n };\n}\n\n/**\n * Renders the text content of a message part with optional smooth streaming.\n *\n * This component displays text content from the current message part context,\n * with support for smooth streaming animation that shows text appearing\n * character by character as it's generated.\n *\n * @example\n * ```tsx\n * <MessagePartPrimitive.Text\n * smooth={true}\n * component=\"p\"\n * className=\"message-text\"\n * />\n * ```\n */\nexport const MessagePartPrimitiveText = forwardRef<\n MessagePartPrimitiveText.Element,\n MessagePartPrimitiveText.Props\n>(\n (\n { smooth = true, component: Component = Primitive.span, render, ...rest },\n forwardedRef,\n ) => {\n const { text, status } = useSmooth(useMessagePartText(), smooth);\n\n const mergedProps = {\n \"data-status\": status.type,\n ...rest,\n ref: forwardedRef,\n };\n\n if (render && isValidElement(render)) {\n return renderSlot(render, text, mergedProps);\n }\n\n return <Component {...mergedProps}>{text}</Component>;\n },\n);\n\nMessagePartPrimitiveText.displayName = \"MessagePartPrimitive.Text\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAoDA,MAAaU,2BAA2BP,YAKpC,EAAEY,SAAS,MAAMC,WAAWC,YAAYjB,UAAUY,MAAMM,QAAQ,GAAGC,QACnEC,iBACG;CACH,MAAM,EAAEC,MAAMC,WAAWd,UAAUD,mBAAmB,GAAGQ,MAAM;CAE/D,MAAMQ,cAAc;EAClB,eAAeD,OAAOE;EACtB,GAAGL;EACHM,KAAKL;CACP;CAEA,IAAIF,UAAUZ,eAAeY,MAAM,GACjC,OAAOjB,WAAWiB,QAAQG,MAAME,WAAW;CAG7C,OAAO,oBAAC,WAAD;EAAW,GAAIA;EAAcF,UAAAA;CAAgB,CAAA;AACtD,CACF;AAEAX,yBAAyBgB,cAAc"}
|
|
@@ -69,7 +69,9 @@ const useScrollLock = (animatedElementRef, animationDuration) => {
|
|
|
69
69
|
const computed = getComputedStyle(scrollContainer);
|
|
70
70
|
const paddingSide = computed.direction === "rtl" ? "paddingLeft" : "paddingRight";
|
|
71
71
|
const previousPadding = scrollContainer.style[paddingSide];
|
|
72
|
-
const
|
|
72
|
+
const elementScrollbarSize = scrollContainer.offsetWidth - scrollContainer.clientWidth - parseFloat(computed.borderLeftWidth) - parseFloat(computed.borderRightWidth);
|
|
73
|
+
const ownerDocument = scrollContainer.ownerDocument;
|
|
74
|
+
const scrollbarSize = (scrollContainer === ownerDocument.documentElement || scrollContainer === ownerDocument.body) && elementScrollbarSize <= 0 ? (ownerDocument.defaultView?.innerWidth ?? 0) - ownerDocument.documentElement.clientWidth : elementScrollbarSize;
|
|
73
75
|
scrollContainer.style.scrollbarWidth = "none";
|
|
74
76
|
if (scrollbarSize > 0) scrollContainer.style[paddingSide] = `${parseFloat(computed[paddingSide]) + scrollbarSize}px`;
|
|
75
77
|
const restoreStyles = () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useScrollLock.js","names":["c","_c","RefObject","useCallback","useEffect","useRef","useScrollLock","animatedElementRef","animationDuration","$","scrollContainerRef","cleanupRef","t0","t1","Symbol","for","current","t2","findScrollableAncestor","el","overflowY","getComputedStyle","parentElement","scrollContainer","scrollPosition","scrollTop","scrollbarWidth","style","computed","paddingSide","direction","previousPadding","
|
|
1
|
+
{"version":3,"file":"useScrollLock.js","names":["c","_c","RefObject","useCallback","useEffect","useRef","useScrollLock","animatedElementRef","animationDuration","$","scrollContainerRef","cleanupRef","t0","t1","Symbol","for","current","t2","findScrollableAncestor","el","overflowY","getComputedStyle","parentElement","scrollContainer","scrollPosition","scrollTop","scrollbarWidth","style","computed","paddingSide","direction","previousPadding","elementScrollbarSize","offsetWidth","clientWidth","parseFloat","borderLeftWidth","borderRightWidth","ownerDocument","isRootScroller","documentElement","body","scrollbarSize","defaultView","innerWidth","restoreStyles","resetPosition","addEventListener","timeoutId","setTimeout","removeEventListener","clearTimeout","lockScroll"],"sources":["../../../src/primitives/reasoning/useScrollLock.ts"],"sourcesContent":["\"use client\";\n\nimport { type RefObject, useCallback, useEffect, useRef } from \"react\";\n\n/**\n * Locks scroll position during collapsible/height animations and hides scrollbar.\n *\n * This utility prevents page jumps when content height changes during animations,\n * providing a smooth user experience. It finds the nearest scrollable ancestor and\n * temporarily locks its scroll position while the animation completes.\n *\n * - Prevents forced reflows: no layout reads, mutations scoped to scrollable parent only\n * - Reactive: only intercepts scroll events when browser actually adjusts\n * - Cleans up automatically after animation duration\n *\n * @param animatedElementRef - Ref to the animated element\n * @param animationDuration - Lock duration in milliseconds\n * @returns Function to activate the scroll lock\n *\n * @example\n * ```tsx\n * const collapsibleRef = useRef<HTMLDivElement>(null);\n * const lockScroll = useScrollLock(collapsibleRef, 200);\n *\n * const handleCollapse = () => {\n * lockScroll(); // Lock scroll before collapsing\n * setIsOpen(false);\n * };\n * ```\n */\nexport const useScrollLock = <T extends HTMLElement = HTMLElement>(\n animatedElementRef: RefObject<T | null>,\n animationDuration: number,\n) => {\n const scrollContainerRef = useRef<HTMLElement | null>(null);\n const cleanupRef = useRef<(() => void) | null>(null);\n\n useEffect(() => {\n return () => {\n cleanupRef.current?.();\n };\n }, []);\n\n const lockScroll = useCallback(() => {\n cleanupRef.current?.();\n\n (function findScrollableAncestor() {\n if (scrollContainerRef.current || !animatedElementRef.current) return;\n\n let el: HTMLElement | null = animatedElementRef.current;\n while (el) {\n const { overflowY } = getComputedStyle(el);\n if (overflowY === \"scroll\" || overflowY === \"auto\") {\n scrollContainerRef.current = el;\n break;\n }\n el = el.parentElement;\n }\n })();\n\n const scrollContainer = scrollContainerRef.current;\n if (!scrollContainer) return;\n\n const scrollPosition = scrollContainer.scrollTop;\n const scrollbarWidth = scrollContainer.style.scrollbarWidth;\n\n // Hiding the scrollbar collapses its gutter on classic scrollbars, which\n // shifts centered content horizontally; compensate with padding on the\n // side the scrollbar occupies (the left side in RTL).\n const computed = getComputedStyle(scrollContainer);\n const paddingSide =\n computed.direction === \"rtl\" ? \"paddingLeft\" : \"paddingRight\";\n const previousPadding = scrollContainer.style[paddingSide];\n const elementScrollbarSize =\n scrollContainer.offsetWidth -\n scrollContainer.clientWidth -\n parseFloat(computed.borderLeftWidth) -\n parseFloat(computed.borderRightWidth);\n // A root element's offsetWidth already excludes the viewport scrollbar, so\n // the element formula reports zero once the scroll propagates to the\n // viewport, and only then does the viewport measure apply. A body that\n // scrolls in its own right is measured by the element formula like any\n // other scroller, whether or not the viewport is scrolling too.\n const ownerDocument = scrollContainer.ownerDocument;\n const isRootScroller =\n scrollContainer === ownerDocument.documentElement ||\n scrollContainer === ownerDocument.body;\n const scrollbarSize =\n isRootScroller && elementScrollbarSize <= 0\n ? (ownerDocument.defaultView?.innerWidth ?? 0) -\n ownerDocument.documentElement.clientWidth\n : elementScrollbarSize;\n\n scrollContainer.style.scrollbarWidth = \"none\";\n if (scrollbarSize > 0) {\n scrollContainer.style[paddingSide] = `${\n parseFloat(computed[paddingSide]) + scrollbarSize\n }px`;\n }\n\n const restoreStyles = () => {\n scrollContainer.style.scrollbarWidth = scrollbarWidth;\n scrollContainer.style[paddingSide] = previousPadding;\n };\n\n const resetPosition = () => (scrollContainer.scrollTop = scrollPosition);\n scrollContainer.addEventListener(\"scroll\", resetPosition);\n\n const timeoutId = setTimeout(() => {\n scrollContainer.removeEventListener(\"scroll\", resetPosition);\n restoreStyles();\n cleanupRef.current = null;\n }, animationDuration);\n\n cleanupRef.current = () => {\n clearTimeout(timeoutId);\n scrollContainer.removeEventListener(\"scroll\", resetPosition);\n restoreStyles();\n };\n }, [animationDuration, animatedElementRef]);\n\n return lockScroll;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,MAAaM,iBAAgBC,oBAAAC,sBAAA;CAAA,MAAAC,IAAAR,EAAA,CAAA;CAI3B,MAAAS,qBAA2BL,OAA2B,IAAI;CAC1D,MAAAM,aAAmBN,OAA4B,IAAI;CAAE,IAAAO;CAAA,IAAAC;CAAA,IAAAJ,EAAA,OAAAK,OAAAC,IAAA,2BAAA,GAAA;EAE3CH,iBACD;GACLD,WAAUK,UAAW;EAAC;EAEvBH,KAAA,CAAA;EAAEJ,EAAA,KAAAG;EAAAH,EAAA,KAAAI;CAAA,OAAA;EAAAD,KAAAH,EAAA;EAAAI,KAAAJ,EAAA;CAAA;CAJLL,UAAUQ,IAIPC,EAAE;CAAC,IAAAI;CAAA,IAAAR,EAAA,OAAAF,sBAAAE,EAAA,OAAAD,mBAAA;EAEyBS,WAAA;GAC7BN,WAAUK,UAAW;GAErB,CAAC,SAAAE,yBAAA;IACC,IAAIR,mBAAkBM,WAAlB,CAA+BT,mBAAkBS,SAAQ;IAE7D,IAAAG,KAA6BZ,mBAAkBS;IAC/C,OAAOG,IAAE;KACP,MAAA,EAAAC,cAAsBC,iBAAiBF,EAAE;KACzC,IAAIC,cAAc,YAAYA,cAAc,QAAM;MAChDV,mBAAkBM,UAAWG;MAC7B;KAAM;KAERA,KAAKA,GAAEG;IAAL;GACH,EAAA,CACA;GAEH,MAAAC,kBAAwBb,mBAAkBM;GAC1C,IAAI,CAACO,iBAAe;GAEpB,MAAAC,iBAAuBD,gBAAeE;GACtC,MAAAC,iBAAuBH,gBAAeI,MAAMD;GAK5C,MAAAE,WAAiBP,iBAAiBE,eAAe;GACjD,MAAAM,cACED,SAAQE,cAAe,QAAvB,gBAAA;GACF,MAAAC,kBAAwBR,gBAAeI,MAAOE;GAC9C,MAAAG,uBACET,gBAAeU,cACfV,gBAAeW,cACfC,WAAWP,SAAQQ,eAAgB,IACnCD,WAAWP,SAAQS,gBAAiB;GAMtC,MAAAC,gBAAsBf,gBAAee;GAIrC,MAAAI,iBAFEnB,oBAAoBe,cAAaE,mBACjCjB,oBAAoBe,cAAaG,SAEfT,wBAAwB,KACrCM,cAAaK,aAAwBC,cAArC,KACDN,cAAaE,gBAAgBN,cAFjCF;GAKFT,gBAAeI,MAAMD,iBAAkB;GACvC,IAAIgB,gBAAgB,GAClBnB,gBAAeI,MAAOE,eAAe,GACnCM,WAAWP,SAASC,YAAY,IAAIa,cAAa;GAIrD,MAAAG,sBAAsB;IACpBtB,gBAAeI,MAAMD,iBAAkBA;IACvCH,gBAAeI,MAAOE,eAAeE;GAAH;GAGpC,MAAAe,sBAA6BvB,gBAAeE,YAAaD;GACzDD,gBAAewB,iBAAkB,UAAUD,aAAa;GAExD,MAAAE,YAAkBC,iBAAW;IAC3B1B,gBAAe2B,oBAAqB,UAAUJ,aAAa;IAC3DD,cAAc;IACdlC,WAAUK,UAAW;GAAH,GACjBR,iBAAiB;GAEpBG,WAAUK,gBAAW;IACnBmC,aAAaH,SAAS;IACtBzB,gBAAe2B,oBAAqB,UAAUJ,aAAa;IAC3DD,cAAc;GAAC;EAHC;EAKnBpC,EAAA,KAAAF;EAAAE,EAAA,KAAAD;EAAAC,EAAA,KAAAQ;CAAA,OAAAA,KAAAR,EAAA;CAA2C,OAErC2C;AAAU"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useThreadViewportAutoScroll.d.ts","names":[],"sources":["../../../src/primitives/thread/useThreadViewportAutoScroll.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"useThreadViewportAutoScroll.d.ts","names":[],"sources":["../../../src/primitives/thread/useThreadViewportAutoScroll.ts"],"mappings":";;kBAgBiB;OACH;;;;;;;IAOV;;;;;;IAOA;;;;;;IAOA;;;;;;IAOA;;;cAIS,8BAA+B,iBAAiB,eAAa,YAAA,0BAAA,4BAAA,gCAKvE,4BAA4B,YAAU,YAAY"}
|
|
@@ -7,7 +7,7 @@ import { useOnResizeContent } from "../../utils/hooks/useOnResizeContent.js";
|
|
|
7
7
|
import { useAuiEvent, useAuiState } from "@assistant-ui/store";
|
|
8
8
|
import { useCallback, useLayoutEffect, useRef } from "@assistant-ui/tap/react-shim";
|
|
9
9
|
import { useComposedRefs } from "radix-ui/internal";
|
|
10
|
-
import { isUserScrollUp } from "@assistant-ui/store/client";
|
|
10
|
+
import { isUserScrollUp, isViewportAtBottom, viewportOverflows } from "@assistant-ui/store/client";
|
|
11
11
|
//#region src/primitives/thread/useThreadViewportAutoScroll.ts
|
|
12
12
|
const useThreadViewportAutoScroll = ({ autoScroll, scrollToBottomOnRunStart = true, scrollToBottomOnInitialize = true, scrollToBottomOnThreadSwitch = true }) => {
|
|
13
13
|
const divRef = useRef(null);
|
|
@@ -55,14 +55,14 @@ const useThreadViewportAutoScroll = ({ autoScroll, scrollToBottomOnRunStart = tr
|
|
|
55
55
|
const div_0 = divRef.current;
|
|
56
56
|
if (!div_0) return;
|
|
57
57
|
const isAtBottom = threadViewportStore.getState().isAtBottom;
|
|
58
|
-
const newIsAtBottom =
|
|
58
|
+
const newIsAtBottom = isViewportAtBottom(div_0);
|
|
59
59
|
if (!newIsAtBottom && lastScrollTop.current < div_0.scrollTop) {} else {
|
|
60
60
|
const userScrolledUp = isUserScrollUp({
|
|
61
61
|
scrollTop: lastScrollTop.current,
|
|
62
62
|
scrollHeight: lastScrollHeight.current
|
|
63
63
|
}, div_0);
|
|
64
64
|
if (newIsAtBottom) {
|
|
65
|
-
if (div_0
|
|
65
|
+
if (viewportOverflows(div_0)) scrollingToBottomBehaviorRef.current = null;
|
|
66
66
|
if (autoScroll) followBottomRef.current = true;
|
|
67
67
|
} else if (userScrolledUp) {
|
|
68
68
|
cancelScheduledFrame();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useThreadViewportAutoScroll.js","names":["useComposedRefs","useCallback","useLayoutEffect","useRef","RefCallback","useAuiEvent","useAuiState","isUserScrollUp","useOnResizeContent","useOnScrollToBottom","useManagedRef","writableStore","useThreadViewportStore","useThreadViewportAutoScroll","Options","autoScroll","scrollToBottomOnRunStart","scrollToBottomOnInitialize","scrollToBottomOnThreadSwitch","HTMLElement","TElement","divRef","hasMessages","s","thread","messages","length","isRunning","initializeScrollRequestedRef","scheduledFrameRef","threadViewportStore","undefined","getState","turnAnchor","lastScrollTop","lastScrollHeight","lastObservedScrollHeight","lastObservedClientHeight","scrollingToBottomBehaviorRef","ScrollBehavior","followBottomRef","scrollToBottom","behavior","div","current","scrollTo","top","scrollHeight","cancelScheduledFrame","cancelAnimationFrame","scheduleScrollToBottom","requestAnimationFrame","hasActiveTopAnchor","state","element","viewport","anchor","handleScroll","isAtBottom","newIsAtBottom","Math","abs","scrollTop","clientHeight","isInFlightDownwardScroll","userScrolledUp","viewportOverflows","shouldUpdate","setState","resizeRef","scrollBehavior","scrollRef","el","cancelPendingScrollToBottom","addEventListener","removeEventListener","autoScrollRef"],"sources":["../../../src/primitives/thread/useThreadViewportAutoScroll.ts"],"sourcesContent":["\"use client\";\n\nimport { useComposedRefs } from \"radix-ui/internal\";\nimport { useCallback, useLayoutEffect, useRef, type RefCallback } from \"react\";\nimport { useAuiEvent, useAuiState } from \"@assistant-ui/store\";\nimport { isUserScrollUp } from \"@assistant-ui/store/client\";\nimport { useOnResizeContent } from \"../../utils/hooks/useOnResizeContent\";\nimport { useOnScrollToBottom } from \"../../utils/hooks/useOnScrollToBottom\";\nimport { useManagedRef } from \"../../utils/hooks/useManagedRef\";\nimport { writableStore } from \"../../context/ReadonlyStore\";\nimport { useThreadViewportStore } from \"../../context/react/ThreadViewportContext\";\n\nexport namespace useThreadViewportAutoScroll {\n export type Options = {\n /**\n * Whether to automatically scroll to the bottom when new messages are added.\n * When enabled, the viewport will automatically scroll to show the latest content.\n *\n * Default false if `turnAnchor` is \"top\", otherwise defaults to true.\n */\n autoScroll?: boolean | undefined;\n\n /**\n * Whether to scroll to bottom when a new run starts.\n *\n * Defaults to true.\n */\n scrollToBottomOnRunStart?: boolean | undefined;\n\n /**\n * Whether to scroll to bottom when messages first appear in the thread.\n *\n * Defaults to true.\n */\n scrollToBottomOnInitialize?: boolean | undefined;\n\n /**\n * Whether to scroll to bottom when switching to a different thread.\n *\n * Defaults to true.\n */\n scrollToBottomOnThreadSwitch?: boolean | undefined;\n };\n}\n\nexport const useThreadViewportAutoScroll = <TElement extends HTMLElement>({\n autoScroll,\n scrollToBottomOnRunStart = true,\n scrollToBottomOnInitialize = true,\n scrollToBottomOnThreadSwitch = true,\n}: useThreadViewportAutoScroll.Options): RefCallback<TElement> => {\n const divRef = useRef<TElement>(null);\n const hasMessages = useAuiState((s) => s.thread.messages.length > 0);\n const isRunning = useAuiState((s) => s.thread.isRunning);\n const initializeScrollRequestedRef = useRef(false);\n const scheduledFrameRef = useRef<number | null>(null);\n\n const threadViewportStore = useThreadViewportStore();\n if (autoScroll === undefined) {\n autoScroll = threadViewportStore.getState().turnAnchor !== \"top\";\n }\n\n const lastScrollTop = useRef<number>(0);\n const lastScrollHeight = useRef<number>(0);\n const lastObservedScrollHeight = useRef<number>(0);\n const lastObservedClientHeight = useRef<number>(0);\n\n // Pending bottom-scroll intent. Planted by initialize/run-start/switch/button\n // triggers, cleared when handleScroll confirms we reached bottom, or when the\n // user actively scrolls up while content size is stable.\n const scrollingToBottomBehaviorRef = useRef<ScrollBehavior | null>(null);\n const followBottomRef = useRef(autoScroll);\n\n const scrollToBottom = useCallback((behavior: ScrollBehavior) => {\n const div = divRef.current;\n if (!div) return;\n\n followBottomRef.current = true;\n scrollingToBottomBehaviorRef.current = behavior;\n div.scrollTo({ top: div.scrollHeight, behavior });\n }, []);\n\n const cancelScheduledFrame = useCallback(() => {\n if (scheduledFrameRef.current === null) return;\n cancelAnimationFrame(scheduledFrameRef.current);\n scheduledFrameRef.current = null;\n }, []);\n\n const scheduleScrollToBottom = useCallback(\n (behavior: ScrollBehavior) => {\n scrollingToBottomBehaviorRef.current = behavior;\n cancelScheduledFrame();\n scheduledFrameRef.current = requestAnimationFrame(() => {\n scheduledFrameRef.current = null;\n scrollToBottom(behavior);\n });\n },\n [cancelScheduledFrame, scrollToBottom],\n );\n\n useLayoutEffect(() => () => cancelScheduledFrame(), [cancelScheduledFrame]);\n\n const hasActiveTopAnchor = useCallback(() => {\n const state = threadViewportStore.getState();\n return (\n state.turnAnchor === \"top\" &&\n state.element.viewport === divRef.current &&\n state.element.anchor !== null\n );\n }, [threadViewportStore]);\n\n const handleScroll = () => {\n const div = divRef.current;\n if (!div) return;\n\n const isAtBottom = threadViewportStore.getState().isAtBottom;\n const newIsAtBottom =\n Math.abs(div.scrollHeight - div.scrollTop - div.clientHeight) <= 1 ||\n div.scrollHeight <= div.clientHeight;\n\n const isInFlightDownwardScroll =\n !newIsAtBottom && lastScrollTop.current < div.scrollTop;\n if (isInFlightDownwardScroll) {\n // no-op: a smooth scroll-to-bottom fires many midpoint scroll events\n // before landing, don't flicker isAtBottom or clear intent mid-animation\n } else {\n const userScrolledUp = isUserScrollUp(\n {\n scrollTop: lastScrollTop.current,\n scrollHeight: lastScrollHeight.current,\n },\n div,\n );\n\n if (newIsAtBottom) {\n // newIsAtBottom is ambiguous when the viewport doesn't overflow —\n // keep intent alive until content can actually scroll\n const viewportOverflows = div.scrollHeight > div.clientHeight + 1;\n if (viewportOverflows) {\n scrollingToBottomBehaviorRef.current = null;\n }\n if (autoScroll) followBottomRef.current = true;\n } else if (userScrolledUp) {\n cancelScheduledFrame();\n scrollingToBottomBehaviorRef.current = null;\n followBottomRef.current = false;\n }\n\n const shouldUpdate =\n newIsAtBottom || scrollingToBottomBehaviorRef.current === null;\n\n if (shouldUpdate && newIsAtBottom !== isAtBottom) {\n writableStore(threadViewportStore).setState({\n isAtBottom: newIsAtBottom,\n });\n }\n }\n\n lastScrollTop.current = div.scrollTop;\n lastScrollHeight.current = div.scrollHeight;\n };\n\n const resizeRef = useOnResizeContent(() => {\n const div = divRef.current;\n if (!div) return;\n\n const { scrollHeight, clientHeight } = div;\n if (\n scrollHeight === lastObservedScrollHeight.current &&\n clientHeight === lastObservedClientHeight.current\n ) {\n return;\n }\n lastObservedScrollHeight.current = scrollHeight;\n lastObservedClientHeight.current = clientHeight;\n\n const scrollBehavior = scrollingToBottomBehaviorRef.current;\n if (scrollBehavior && hasActiveTopAnchor()) {\n // Let the top-anchor reserve own scrolling while a run starts to avoid a bottom-scroll race.\n scrollingToBottomBehaviorRef.current = null;\n } else if (scrollBehavior) {\n scrollToBottom(scrollBehavior);\n } else if (\n autoScroll &&\n !(isRunning && hasActiveTopAnchor()) &&\n followBottomRef.current\n ) {\n scrollToBottom(\"instant\");\n }\n\n handleScroll();\n });\n\n const scrollRef = useManagedRef<HTMLElement>((el) => {\n // A pointer gesture invalidates pending bottom-scroll intent; otherwise an\n // intent kept alive by a non-overflowing thread (see handleScroll) hijacks\n // the next content growth, e.g. expanding a collapsible tool call.\n const cancelPendingScrollToBottom = () => {\n scrollingToBottomBehaviorRef.current = null;\n };\n el.addEventListener(\"scroll\", handleScroll);\n el.addEventListener(\"pointerdown\", cancelPendingScrollToBottom);\n return () => {\n el.removeEventListener(\"scroll\", handleScroll);\n el.removeEventListener(\"pointerdown\", cancelPendingScrollToBottom);\n };\n });\n\n useLayoutEffect(() => {\n if (!scrollToBottomOnInitialize) return;\n if (!hasMessages) {\n initializeScrollRequestedRef.current = false;\n return;\n }\n if (initializeScrollRequestedRef.current) return;\n\n initializeScrollRequestedRef.current = true;\n // defer to an in-flight run (e.g. first message on a new thread) that\n // already planted intent — otherwise we'd downgrade its \"auto\" to \"instant\"\n if (scrollingToBottomBehaviorRef.current !== null) return;\n scheduleScrollToBottom(\"instant\");\n }, [hasMessages, scheduleScrollToBottom, scrollToBottomOnInitialize]);\n\n useOnScrollToBottom(({ behavior }) => {\n scrollToBottom(behavior);\n });\n\n useAuiEvent(\"thread.runStart\", () => {\n if (!scrollToBottomOnRunStart) return;\n if (threadViewportStore.getState().turnAnchor === \"top\") return;\n scheduleScrollToBottom(\"auto\");\n });\n\n useAuiEvent(\"threads.selectionChanged\", () => {\n if (!scrollToBottomOnThreadSwitch) return;\n scheduleScrollToBottom(\"instant\");\n });\n\n const autoScrollRef = useComposedRefs<TElement>(resizeRef, scrollRef, divRef);\n return autoScrollRef as RefCallback<TElement>;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useThreadViewportAutoScroll.js","names":["useComposedRefs","useCallback","useLayoutEffect","useRef","RefCallback","useAuiEvent","useAuiState","isUserScrollUp","isViewportAtBottom","viewportOverflows","useOnResizeContent","useOnScrollToBottom","useManagedRef","writableStore","useThreadViewportStore","useThreadViewportAutoScroll","Options","autoScroll","scrollToBottomOnRunStart","scrollToBottomOnInitialize","scrollToBottomOnThreadSwitch","HTMLElement","TElement","divRef","hasMessages","s","thread","messages","length","isRunning","initializeScrollRequestedRef","scheduledFrameRef","threadViewportStore","undefined","getState","turnAnchor","lastScrollTop","lastScrollHeight","lastObservedScrollHeight","lastObservedClientHeight","scrollingToBottomBehaviorRef","ScrollBehavior","followBottomRef","scrollToBottom","behavior","div","current","scrollTo","top","scrollHeight","cancelScheduledFrame","cancelAnimationFrame","scheduleScrollToBottom","requestAnimationFrame","hasActiveTopAnchor","state","element","viewport","anchor","handleScroll","isAtBottom","newIsAtBottom","isInFlightDownwardScroll","scrollTop","userScrolledUp","shouldUpdate","setState","resizeRef","clientHeight","scrollBehavior","scrollRef","el","cancelPendingScrollToBottom","addEventListener","removeEventListener","autoScrollRef"],"sources":["../../../src/primitives/thread/useThreadViewportAutoScroll.ts"],"sourcesContent":["\"use client\";\n\nimport { useComposedRefs } from \"radix-ui/internal\";\nimport { useCallback, useLayoutEffect, useRef, type RefCallback } from \"react\";\nimport { useAuiEvent, useAuiState } from \"@assistant-ui/store\";\nimport {\n isUserScrollUp,\n isViewportAtBottom,\n viewportOverflows,\n} from \"@assistant-ui/store/client\";\nimport { useOnResizeContent } from \"../../utils/hooks/useOnResizeContent\";\nimport { useOnScrollToBottom } from \"../../utils/hooks/useOnScrollToBottom\";\nimport { useManagedRef } from \"../../utils/hooks/useManagedRef\";\nimport { writableStore } from \"../../context/ReadonlyStore\";\nimport { useThreadViewportStore } from \"../../context/react/ThreadViewportContext\";\n\nexport namespace useThreadViewportAutoScroll {\n export type Options = {\n /**\n * Whether to automatically scroll to the bottom when new messages are added.\n * When enabled, the viewport will automatically scroll to show the latest content.\n *\n * Default false if `turnAnchor` is \"top\", otherwise defaults to true.\n */\n autoScroll?: boolean | undefined;\n\n /**\n * Whether to scroll to bottom when a new run starts.\n *\n * Defaults to true.\n */\n scrollToBottomOnRunStart?: boolean | undefined;\n\n /**\n * Whether to scroll to bottom when messages first appear in the thread.\n *\n * Defaults to true.\n */\n scrollToBottomOnInitialize?: boolean | undefined;\n\n /**\n * Whether to scroll to bottom when switching to a different thread.\n *\n * Defaults to true.\n */\n scrollToBottomOnThreadSwitch?: boolean | undefined;\n };\n}\n\nexport const useThreadViewportAutoScroll = <TElement extends HTMLElement>({\n autoScroll,\n scrollToBottomOnRunStart = true,\n scrollToBottomOnInitialize = true,\n scrollToBottomOnThreadSwitch = true,\n}: useThreadViewportAutoScroll.Options): RefCallback<TElement> => {\n const divRef = useRef<TElement>(null);\n const hasMessages = useAuiState((s) => s.thread.messages.length > 0);\n const isRunning = useAuiState((s) => s.thread.isRunning);\n const initializeScrollRequestedRef = useRef(false);\n const scheduledFrameRef = useRef<number | null>(null);\n\n const threadViewportStore = useThreadViewportStore();\n if (autoScroll === undefined) {\n autoScroll = threadViewportStore.getState().turnAnchor !== \"top\";\n }\n\n const lastScrollTop = useRef<number>(0);\n const lastScrollHeight = useRef<number>(0);\n const lastObservedScrollHeight = useRef<number>(0);\n const lastObservedClientHeight = useRef<number>(0);\n\n // Pending bottom-scroll intent. Planted by initialize/run-start/switch/button\n // triggers, cleared when handleScroll confirms we reached bottom, or when the\n // user actively scrolls up while content size is stable.\n const scrollingToBottomBehaviorRef = useRef<ScrollBehavior | null>(null);\n const followBottomRef = useRef(autoScroll);\n\n const scrollToBottom = useCallback((behavior: ScrollBehavior) => {\n const div = divRef.current;\n if (!div) return;\n\n followBottomRef.current = true;\n scrollingToBottomBehaviorRef.current = behavior;\n div.scrollTo({ top: div.scrollHeight, behavior });\n }, []);\n\n const cancelScheduledFrame = useCallback(() => {\n if (scheduledFrameRef.current === null) return;\n cancelAnimationFrame(scheduledFrameRef.current);\n scheduledFrameRef.current = null;\n }, []);\n\n const scheduleScrollToBottom = useCallback(\n (behavior: ScrollBehavior) => {\n scrollingToBottomBehaviorRef.current = behavior;\n cancelScheduledFrame();\n scheduledFrameRef.current = requestAnimationFrame(() => {\n scheduledFrameRef.current = null;\n scrollToBottom(behavior);\n });\n },\n [cancelScheduledFrame, scrollToBottom],\n );\n\n useLayoutEffect(() => () => cancelScheduledFrame(), [cancelScheduledFrame]);\n\n const hasActiveTopAnchor = useCallback(() => {\n const state = threadViewportStore.getState();\n return (\n state.turnAnchor === \"top\" &&\n state.element.viewport === divRef.current &&\n state.element.anchor !== null\n );\n }, [threadViewportStore]);\n\n const handleScroll = () => {\n const div = divRef.current;\n if (!div) return;\n\n const isAtBottom = threadViewportStore.getState().isAtBottom;\n const newIsAtBottom = isViewportAtBottom(div);\n\n const isInFlightDownwardScroll =\n !newIsAtBottom && lastScrollTop.current < div.scrollTop;\n if (isInFlightDownwardScroll) {\n // no-op: a smooth scroll-to-bottom fires many midpoint scroll events\n // before landing, don't flicker isAtBottom or clear intent mid-animation\n } else {\n const userScrolledUp = isUserScrollUp(\n {\n scrollTop: lastScrollTop.current,\n scrollHeight: lastScrollHeight.current,\n },\n div,\n );\n\n if (newIsAtBottom) {\n // newIsAtBottom is ambiguous when the viewport doesn't overflow —\n // keep intent alive until content can actually scroll\n if (viewportOverflows(div)) {\n scrollingToBottomBehaviorRef.current = null;\n }\n if (autoScroll) followBottomRef.current = true;\n } else if (userScrolledUp) {\n cancelScheduledFrame();\n scrollingToBottomBehaviorRef.current = null;\n followBottomRef.current = false;\n }\n\n const shouldUpdate =\n newIsAtBottom || scrollingToBottomBehaviorRef.current === null;\n\n if (shouldUpdate && newIsAtBottom !== isAtBottom) {\n writableStore(threadViewportStore).setState({\n isAtBottom: newIsAtBottom,\n });\n }\n }\n\n lastScrollTop.current = div.scrollTop;\n lastScrollHeight.current = div.scrollHeight;\n };\n\n const resizeRef = useOnResizeContent(() => {\n const div = divRef.current;\n if (!div) return;\n\n const { scrollHeight, clientHeight } = div;\n if (\n scrollHeight === lastObservedScrollHeight.current &&\n clientHeight === lastObservedClientHeight.current\n ) {\n return;\n }\n lastObservedScrollHeight.current = scrollHeight;\n lastObservedClientHeight.current = clientHeight;\n\n const scrollBehavior = scrollingToBottomBehaviorRef.current;\n if (scrollBehavior && hasActiveTopAnchor()) {\n // Let the top-anchor reserve own scrolling while a run starts to avoid a bottom-scroll race.\n scrollingToBottomBehaviorRef.current = null;\n } else if (scrollBehavior) {\n scrollToBottom(scrollBehavior);\n } else if (\n autoScroll &&\n !(isRunning && hasActiveTopAnchor()) &&\n followBottomRef.current\n ) {\n scrollToBottom(\"instant\");\n }\n\n handleScroll();\n });\n\n const scrollRef = useManagedRef<HTMLElement>((el) => {\n // A pointer gesture invalidates pending bottom-scroll intent; otherwise an\n // intent kept alive by a non-overflowing thread (see handleScroll) hijacks\n // the next content growth, e.g. expanding a collapsible tool call.\n const cancelPendingScrollToBottom = () => {\n scrollingToBottomBehaviorRef.current = null;\n };\n el.addEventListener(\"scroll\", handleScroll);\n el.addEventListener(\"pointerdown\", cancelPendingScrollToBottom);\n return () => {\n el.removeEventListener(\"scroll\", handleScroll);\n el.removeEventListener(\"pointerdown\", cancelPendingScrollToBottom);\n };\n });\n\n useLayoutEffect(() => {\n if (!scrollToBottomOnInitialize) return;\n if (!hasMessages) {\n initializeScrollRequestedRef.current = false;\n return;\n }\n if (initializeScrollRequestedRef.current) return;\n\n initializeScrollRequestedRef.current = true;\n // defer to an in-flight run (e.g. first message on a new thread) that\n // already planted intent — otherwise we'd downgrade its \"auto\" to \"instant\"\n if (scrollingToBottomBehaviorRef.current !== null) return;\n scheduleScrollToBottom(\"instant\");\n }, [hasMessages, scheduleScrollToBottom, scrollToBottomOnInitialize]);\n\n useOnScrollToBottom(({ behavior }) => {\n scrollToBottom(behavior);\n });\n\n useAuiEvent(\"thread.runStart\", () => {\n if (!scrollToBottomOnRunStart) return;\n if (threadViewportStore.getState().turnAnchor === \"top\") return;\n scheduleScrollToBottom(\"auto\");\n });\n\n useAuiEvent(\"threads.selectionChanged\", () => {\n if (!scrollToBottomOnThreadSwitch) return;\n scheduleScrollToBottom(\"instant\");\n });\n\n const autoScrollRef = useComposedRefs<TElement>(resizeRef, scrollRef, divRef);\n return autoScrollRef as RefCallback<TElement>;\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SandboxHost.d.ts","names":[],"sources":["../../src/sandbox-host/SandboxHost.tsx"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"SandboxHost.d.ts","names":[],"sources":["../../src/sandbox-host/SandboxHost.tsx"],"mappings":";;;KAqBY;EACV,UAAU;EACV;EACA;EACA;EACA;EACA;EACA,QAAQ;EACR;;KAGU,mBAAmB,KAC7B;KAIU;EACV,YAAY;;KAGF;EACV,YAAY,OAAO;EACnB;;KAGU;EAAmB;;KAEnB;EACV,SAAS;EACT;EACA,UAAU;EACV;EACA,eACE,OAAO,kBACP,MAAM,mBACH;EACL,YAAY,OAAO;EACnB,iBAAiB;;iBAGH,sBACd,OAAO,cACP;EAAS,QAAQ;EAAmB;;iBActB,cACd,SACA,YACA,SACA,WACA,cACA,SACA,kBACC,mCAAgB,IAAA"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { invokeCallbackSafely } from "../utils/invokeCallbackSafely.js";
|
|
3
2
|
import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
|
|
4
3
|
import { useEffect, useLayoutEffect, useRef, useState } from "@assistant-ui/tap/react-shim";
|
|
5
4
|
import { jsx } from "react/jsx-runtime";
|
|
6
|
-
import {
|
|
5
|
+
import { invokeUserCallback } from "@assistant-ui/core/internal";
|
|
6
|
+
import { SafeContentFrame, isShimLoadError } from "safe-content-frame";
|
|
7
7
|
//#region src/sandbox-host/SandboxHost.tsx
|
|
8
8
|
const DEFAULT_PRODUCT = "assistant-ui-sandbox";
|
|
9
9
|
const DEFAULT_MAX_HEIGHT = 800;
|
|
10
|
+
const LOAD_TIMEOUT_MS = 1e4;
|
|
10
11
|
function isSandboxFrameMessage(event, frame) {
|
|
11
12
|
return event.source === frame.iframe.contentWindow && event.origin === frame.origin;
|
|
12
13
|
}
|
|
@@ -69,6 +70,10 @@ function SandboxHost(t0) {
|
|
|
69
70
|
let bridge = null;
|
|
70
71
|
let onMessage = null;
|
|
71
72
|
const { content: liveContent, sandbox: sb } = liveRef.current;
|
|
73
|
+
const reportError = (err) => {
|
|
74
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
75
|
+
invokeUserCallback("assistant-ui", "SandboxHost onError", liveRef.current.onError?.bind(liveRef.current), error);
|
|
76
|
+
};
|
|
72
77
|
const scf = new SafeContentFrame(sb?.product ?? DEFAULT_PRODUCT, {
|
|
73
78
|
...sb?.sandbox !== void 0 && { sandbox: sb.sandbox },
|
|
74
79
|
...sb?.useShadowDom !== void 0 && { useShadowDom: sb.useShadowDom },
|
|
@@ -94,24 +99,46 @@ function SandboxHost(t0) {
|
|
|
94
99
|
bridge?.onMessage(event);
|
|
95
100
|
};
|
|
96
101
|
window.addEventListener("message", onMessage);
|
|
97
|
-
|
|
102
|
+
rendered.fullyLoadedPromiseWithTimeout(LOAD_TIMEOUT_MS).catch((err_0) => {
|
|
103
|
+
if (cancelled) return;
|
|
104
|
+
if (isShimLoadError(err_0) && err_0.code === "render-timeout") return;
|
|
105
|
+
reportError(err_0);
|
|
106
|
+
});
|
|
107
|
+
}).catch((err_1) => {
|
|
98
108
|
if (cancelled) return;
|
|
99
109
|
frame?.dispose();
|
|
100
110
|
frame = null;
|
|
101
|
-
|
|
102
|
-
invokeCallbackSafely(() => liveRef.current.onError?.(error), "SandboxHost onError");
|
|
111
|
+
reportError(err_1);
|
|
103
112
|
});
|
|
104
113
|
return () => {
|
|
105
114
|
cancelled = true;
|
|
115
|
+
let cleanupFailed = false;
|
|
116
|
+
let cleanupError;
|
|
117
|
+
const runCleanup = (cleanup) => {
|
|
118
|
+
try {
|
|
119
|
+
cleanup();
|
|
120
|
+
} catch (t6) {
|
|
121
|
+
const error_0 = t6;
|
|
122
|
+
if (cleanupFailed) console.error(error_0);
|
|
123
|
+
else {
|
|
124
|
+
cleanupFailed = true;
|
|
125
|
+
cleanupError = error_0;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
};
|
|
106
129
|
if (onMessage) {
|
|
107
|
-
|
|
130
|
+
const listener = onMessage;
|
|
108
131
|
onMessage = null;
|
|
132
|
+
runCleanup(() => window.removeEventListener("message", listener));
|
|
109
133
|
}
|
|
110
|
-
bridge
|
|
134
|
+
const bridgeToDispose = bridge;
|
|
111
135
|
bridge = null;
|
|
112
|
-
|
|
136
|
+
if (bridgeToDispose) runCleanup(() => bridgeToDispose.dispose());
|
|
137
|
+
const frameToDispose = frame;
|
|
113
138
|
frame = null;
|
|
114
|
-
|
|
139
|
+
if (frameToDispose) runCleanup(() => frameToDispose.dispose());
|
|
140
|
+
runCleanup(() => setContentHeight(void 0));
|
|
141
|
+
if (cleanupFailed) throw cleanupError;
|
|
115
142
|
};
|
|
116
143
|
};
|
|
117
144
|
$[11] = t5;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SandboxHost.js","names":["c","_c","CSSProperties","useEffect","useLayoutEffect","useRef","useState","RenderedFrame","SafeContentFrame","SandboxOption","invokeCallbackSafely","DEFAULT_PRODUCT","DEFAULT_MAX_HEIGHT","SandboxHostConfig","sandbox","useShadowDom","enableBrowserCaching","salt","product","className","style","unsafeDocumentWrite","SandboxHostFrame","Pick","SandboxHostApi","setHeight","height","SandboxBridge","onMessage","event","MessageEvent","dispose","SandboxContent","html","SandboxHostProps","content","contentKey","maxHeight","createBridge","frame","host","onError","error","Error","containerProps","Record","isSandboxFrameMessage","iframe","HTMLIFrameElement","origin","source","contentWindow","LiveSnapshot","SandboxHost","t0","$","t1","undefined","containerRef","contentHeight","setContentHeight","t2","liveRef","t3","t4","current","t5","Symbol","for","container","cancelled","bridge","liveContent","sb","scf","renderOpts","renderHtml","then","rendered","hostApi","Number","isFinite","sendMessage","window","addEventListener","catch","err","String","removeEventListener","t6","resolvedHeight","Math","min","t7","mergedStyle","t8","t9"],"sources":["../../src/sandbox-host/SandboxHost.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n type CSSProperties,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from \"react\";\nimport {\n type RenderedFrame,\n SafeContentFrame,\n type SandboxOption,\n} from \"safe-content-frame\";\nimport { invokeCallbackSafely } from \"../utils/invokeCallbackSafely\";\n\nconst DEFAULT_PRODUCT = \"assistant-ui-sandbox\";\nconst DEFAULT_MAX_HEIGHT = 800;\n\nexport type SandboxHostConfig = {\n sandbox?: SandboxOption[];\n useShadowDom?: boolean;\n enableBrowserCaching?: boolean;\n salt?: string;\n product?: string;\n className?: string;\n style?: CSSProperties;\n unsafeDocumentWrite?: boolean;\n};\n\nexport type SandboxHostFrame = Pick<\n RenderedFrame,\n \"iframe\" | \"origin\" | \"sendMessage\"\n>;\n\nexport type SandboxHostApi = {\n setHeight: (height: number) => void;\n};\n\nexport type SandboxBridge = {\n onMessage: (event: MessageEvent) => void;\n dispose: () => void;\n};\n\nexport type SandboxContent = { html: string };\n\nexport type SandboxHostProps = {\n content: SandboxContent;\n contentKey: string;\n sandbox?: SandboxHostConfig | undefined;\n maxHeight?: number | undefined;\n createBridge: (\n frame: SandboxHostFrame,\n host: SandboxHostApi,\n ) => SandboxBridge;\n onError?: ((error: Error) => void) | undefined;\n containerProps?: Record<string, string | undefined> | undefined;\n};\n\nexport function isSandboxFrameMessage(\n event: MessageEvent,\n frame: { iframe: HTMLIFrameElement; origin: string },\n): boolean {\n return (\n event.source === frame.iframe.contentWindow && event.origin === frame.origin\n );\n}\n\ntype LiveSnapshot = {\n content: SandboxContent;\n sandbox: SandboxHostConfig | undefined;\n createBridge: SandboxHostProps[\"createBridge\"];\n onError: SandboxHostProps[\"onError\"];\n};\n\nexport function SandboxHost({\n content,\n contentKey,\n sandbox,\n maxHeight = DEFAULT_MAX_HEIGHT,\n createBridge,\n onError,\n containerProps,\n}: SandboxHostProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n const [contentHeight, setContentHeight] = useState<number | undefined>(\n undefined,\n );\n\n const liveRef = useRef<LiveSnapshot>({\n content,\n sandbox,\n createBridge,\n onError,\n });\n useLayoutEffect(() => {\n liveRef.current = { content, sandbox, createBridge, onError };\n }, [content, sandbox, createBridge, onError]);\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n let cancelled = false;\n let frame: RenderedFrame | null = null;\n let bridge: SandboxBridge | null = null;\n let onMessage: ((event: MessageEvent) => void) | null = null;\n\n const { content: liveContent, sandbox: sb } = liveRef.current;\n\n const scf = new SafeContentFrame(sb?.product ?? DEFAULT_PRODUCT, {\n ...(sb?.sandbox !== undefined && { sandbox: sb.sandbox }),\n ...(sb?.useShadowDom !== undefined && { useShadowDom: sb.useShadowDom }),\n ...(sb?.enableBrowserCaching !== undefined && {\n enableBrowserCaching: sb.enableBrowserCaching,\n }),\n ...(sb?.salt !== undefined && { salt: sb.salt }),\n });\n\n const renderOpts =\n sb?.unsafeDocumentWrite !== undefined\n ? { unsafeDocumentWrite: sb.unsafeDocumentWrite }\n : undefined;\n\n scf\n .renderHtml(liveContent.html, container, renderOpts)\n .then((rendered) => {\n if (cancelled) {\n rendered.dispose();\n return;\n }\n frame = rendered;\n\n const hostApi: SandboxHostApi = {\n setHeight: (height) => {\n if (\n typeof height === \"number\" &&\n Number.isFinite(height) &&\n height > 0\n ) {\n setContentHeight(height);\n }\n },\n };\n\n bridge = liveRef.current.createBridge(\n {\n iframe: rendered.iframe,\n origin: rendered.origin,\n sendMessage: rendered.sendMessage,\n },\n hostApi,\n );\n\n // Single owner of the window listener; the cross-origin guard runs\n // here so the bridge only sees frame-validated messages.\n onMessage = (event) => {\n if (!isSandboxFrameMessage(event, rendered)) return;\n bridge?.onMessage(event);\n };\n window.addEventListener(\"message\", onMessage);\n })\n .catch((err) => {\n if (cancelled) return;\n frame?.dispose();\n frame = null;\n const error = err instanceof Error ? err : new Error(String(err));\n invokeCallbackSafely(\n () => liveRef.current.onError?.(error),\n \"SandboxHost onError\",\n );\n });\n\n return () => {\n cancelled = true;\n if (onMessage) {\n window.removeEventListener(\"message\", onMessage);\n onMessage = null;\n }\n bridge?.dispose();\n bridge = null;\n frame?.dispose();\n frame = null;\n setContentHeight(undefined);\n };\n // oxlint-disable-next-line react/exhaustive-deps -- re-init only on contentKey change; live values flow through liveRef\n }, [contentKey]);\n\n const resolvedHeight =\n contentHeight != null ? Math.min(contentHeight, maxHeight) : undefined;\n const mergedStyle =\n resolvedHeight != null\n ? { ...sandbox?.style, height: resolvedHeight }\n : sandbox?.style;\n\n return (\n <div\n {...containerProps}\n ref={containerRef}\n className={sandbox?.className}\n style={mergedStyle}\n />\n );\n}\n"],"mappings":";;;;;;;AAgBA,MAAMW,kBAAkB;AACxB,MAAMC,qBAAqB;AA0C3B,SAAgBkC,sBACdjB,OACAU,OACS;CACT,OACEV,MAAMqB,WAAWX,MAAMQ,OAAOI,iBAAiBtB,MAAMoB,WAAWV,MAAMU;AAE1E;AASA,SAAOI,YAAAC,IAAA;CAAA,MAAAC,IAAAtD,EAAA,EAAA;CAAqB,MAAA,EAAAkC,SAAAC,YAAAtB,SAAAuB,WAAAmB,IAAAlB,cAAAG,SAAAG,mBAAAU;CAI1B,MAAAjB,YAAAmB,OAAAC,KAAAA,IAAA7C,qBAAA4C;CAKA,MAAAE,eAAqBrD,OAAuB,IAAI;CAChD,MAAA,CAAAsD,eAAAC,oBAA0CtD,SACxCmD,KAAAA,CACF;CAAE,IAAAI;CAAA,IAAAN,EAAA,OAAApB,WAAAoB,EAAA,OAAAjB,gBAAAiB,EAAA,OAAAd,WAAAc,EAAA,OAAAzC,SAAA;EAEmC+C,KAAA;GAAA1B;GAAArB;GAAAwB;GAAAG;EAKrC;EAACc,EAAA,KAAApB;EAAAoB,EAAA,KAAAjB;EAAAiB,EAAA,KAAAd;EAAAc,EAAA,KAAAzC;EAAAyC,EAAA,KAAAM;CAAA,OAAAA,KAAAN,EAAA;CALD,MAAAO,UAAgBzD,OAAqBwD,EAKpC;CAAE,IAAAE;CAAA,IAAAC;CAAA,IAAAT,EAAA,OAAApB,WAAAoB,EAAA,OAAAjB,gBAAAiB,EAAA,OAAAd,WAAAc,EAAA,OAAAzC,SAAA;EACaiD,WAAA;GACdD,QAAOG,UAAW;IAAA9B;IAAArB;IAAAwB;IAAAG;GAA0C;EAA7C;EACduB,KAAA;GAAC7B;GAASrB;GAASwB;GAAcG;EAAO;EAACc,EAAA,KAAApB;EAAAoB,EAAA,KAAAjB;EAAAiB,EAAA,KAAAd;EAAAc,EAAA,KAAAzC;EAAAyC,EAAA,KAAAQ;EAAAR,EAAA,MAAAS;CAAA,OAAA;EAAAD,KAAAR,EAAA;EAAAS,KAAAT,EAAA;CAAA;CAF5CnD,gBAAgB2D,IAEbC,EAAyC;CAAC,IAAAE;CAAA,IAAAX,EAAA,QAAAY,OAAAC,IAAA,2BAAA,GAAA;EAEnCF,WAAA;GACR,MAAAG,YAAkBX,aAAYO;GAC9B,IAAI,CAACI,WAAS;GAEd,IAAAC,YAAgB;GAChB,IAAA/B,QAAkC;GAClC,IAAAgC,SAAmC;GACnC,IAAA3C,YAAwD;GAExD,MAAA,EAAAO,SAAAqC,aAAA1D,SAAA2D,OAA8CX,QAAOG;GAErD,MAAAS,MAAY,IAAIlE,iBAAiBiE,IAAEvD,WAAFP,iBAAgC;IAAA,GAC3D8D,IAAE3D,YAAc2C,KAAAA,KAAhB,EAAA3C,SAAwC2D,GAAE3D,QAAS;IAAC,GACpD2D,IAAE1D,iBAAmB0C,KAAAA,KAArB,EAAA1C,cAAkD0D,GAAE1D,aAAc;IAAC,GACnE0D,IAAEzD,yBAA2ByC,KAAAA,KAA7B,EAAAzC,sBACoByD,GAAEzD,qBAC1B;IAAC,GACGyD,IAAExD,SAAWwC,KAAAA,KAAb,EAAAxC,MAAkCwD,GAAExD,KAAM;GAChD,CAAC;GAED,MAAA0D,aACEF,IAAEpD,wBAA0BoC,KAAAA,IAA5B,EAAApC,qBAC2BoD,GAAEpD,oBACjB,IAFZoC,KAAAA;GAIFiB,IAAGE,WACWJ,YAAWvC,MAAOoC,WAAWM,UAAU,CAAC,CAAAE,MAC9CC,aAAA;IACJ,IAAIR,WAAS;KACXQ,SAAQ/C,QAAS;KAAC;IAAA;IAGpBQ,QAAQuC;IAcRP,SAAST,QAAOG,QAAQ3B,aACtB;KAAAS,QACU+B,SAAQ/B;KAAOE,QACf6B,SAAQ7B;KAAOiC,aACVJ,SAAQI;IACvB,GACAH,EAlB8BtD,YACnBC,WAAA;KACT,IACE,OAAOA,WAAW,YAClBsD,OAAMC,SAAUvD,MAAM,KACtBA,SAAS,GAETkC,iBAAiBlC,MAAM;IACxB,EAUHqD,CACF;IAIAnD,aAAYA,UAAAA;KACVA,IAAIA,CAACkB,sBAAsBjB,OAAOiD,QAAQ,GAAC;KAC3CP,QAAM3C,UAAYC,KAAK;IAAC;IAE1BsD,OAAMC,iBAAkB,WAAWxD,SAAS;GAAC,CAC9C,CAAC,CAAAyD,OACKC,QAAA;IACL,IAAIhB,WAAS;IACb/B,OAAKR,QAAU;IACfQ,QAAQA;IACR,MAAAG,QAAc4C,eAAe3C,QAAf2C,MAAA,IAAiC3C,MAAM4C,OAAOD,GAAG,CAAC;IAChE5E,2BACQoD,QAAOG,QAAQxB,UAAWC,KAAK,GACrC,qBACF;GAAC,CACF;GAAC,aAEG;IACL4B,YAAYA;IACZ,IAAI1C,WAAS;KACXuD,OAAMK,oBAAqB,WAAW5D,SAAS;KAC/CA,YAAYA;IAAH;IAEX2C,QAAMxC,QAAU;IAChBwC,SAASA;IACThC,OAAKR,QAAU;IACfQ,QAAQA;IACRqB,iBAAiBH,KAAAA,CAAS;GAAC;EAC5B;EAEFF,EAAA,MAAAW;CAAA,OAAAA,KAAAX,EAAA;CAAA,IAAAkC;CAAA,IAAAlC,EAAA,QAAAnB,YAAA;EAAEqD,KAAA,CAACrD,UAAU;EAACmB,EAAA,MAAAnB;EAAAmB,EAAA,MAAAkC;CAAA,OAAAA,KAAAlC,EAAA;CAvFfpD,UAAU+D,IAuFPuB,EAAY;CAEf,MAAAC,iBACE/B,iBAAiB,OAAOgC,KAAIC,IAAKjC,eAAetB,SAAqB,IAArEoB,KAAAA;CAAuE,IAAAoC;CAAA,IAAAtC,EAAA,QAAAmC,kBAAAnC,EAAA,QAAAzC,SAAAM,OAAA;EAEvEyE,KAAAH,kBAAkB,OAAlB;GAAA,GACS5E,SAAOM;GAAOM,QAAUgE;EAChB,IAAb5E,SAAOM;EAAOmC,EAAA,MAAAmC;EAAAnC,EAAA,MAAAzC,SAAAM;EAAAmC,EAAA,MAAAsC;CAAA,OAAAA,KAAAtC,EAAA;CAHpB,MAAAuC,cACED;CAQa,MAAAE,KAAAjF,SAAOK;CAAW,IAAA6E;CAAA,IAAAzC,EAAA,QAAAX,kBAAAW,EAAA,QAAAuC,eAAAvC,EAAA,QAAAwC,IAAA;EAH/BC,KAAA,oBAAA,OAAA;GAKE,GAJIpD;GACCc,KAAAA;GACM,WAAAqC;GACJD,OAAAA;EAAW,CAAA;EAClBvC,EAAA,MAAAX;EAAAW,EAAA,MAAAuC;EAAAvC,EAAA,MAAAwC;EAAAxC,EAAA,MAAAyC;CAAA,OAAAA,KAAAzC,EAAA;CAAA,OALFyC;AAKE"}
|
|
1
|
+
{"version":3,"file":"SandboxHost.js","names":["c","_c","CSSProperties","useEffect","useLayoutEffect","useRef","useState","isShimLoadError","RenderedFrame","SafeContentFrame","SandboxOption","invokeUserCallback","DEFAULT_PRODUCT","DEFAULT_MAX_HEIGHT","LOAD_TIMEOUT_MS","SandboxHostConfig","sandbox","useShadowDom","enableBrowserCaching","salt","product","className","style","unsafeDocumentWrite","SandboxHostFrame","Pick","SandboxHostApi","setHeight","height","SandboxBridge","onMessage","event","MessageEvent","dispose","SandboxContent","html","SandboxHostProps","content","contentKey","maxHeight","createBridge","frame","host","onError","error","Error","containerProps","Record","isSandboxFrameMessage","iframe","HTMLIFrameElement","origin","source","contentWindow","LiveSnapshot","SandboxHost","t0","$","t1","undefined","containerRef","contentHeight","setContentHeight","t2","liveRef","t3","t4","current","t5","Symbol","for","container","cancelled","bridge","liveContent","sb","reportError","err","String","bind","scf","renderOpts","renderHtml","then","rendered","hostApi","Number","isFinite","sendMessage","window","addEventListener","fullyLoadedPromiseWithTimeout","catch","err_0","code","err_1","cleanupFailed","cleanupError","runCleanup","cleanup","t6","console","listener","removeEventListener","bridgeToDispose","frameToDispose","resolvedHeight","Math","min","t7","mergedStyle","t8","t9"],"sources":["../../src/sandbox-host/SandboxHost.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n type CSSProperties,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from \"react\";\nimport {\n isShimLoadError,\n type RenderedFrame,\n SafeContentFrame,\n type SandboxOption,\n} from \"safe-content-frame\";\nimport { invokeUserCallback } from \"@assistant-ui/core/internal\";\n\nconst DEFAULT_PRODUCT = \"assistant-ui-sandbox\";\nconst DEFAULT_MAX_HEIGHT = 800;\nconst LOAD_TIMEOUT_MS = 10_000;\n\nexport type SandboxHostConfig = {\n sandbox?: SandboxOption[];\n useShadowDom?: boolean;\n enableBrowserCaching?: boolean;\n salt?: string;\n product?: string;\n className?: string;\n style?: CSSProperties;\n unsafeDocumentWrite?: boolean;\n};\n\nexport type SandboxHostFrame = Pick<\n RenderedFrame,\n \"iframe\" | \"origin\" | \"sendMessage\"\n>;\n\nexport type SandboxHostApi = {\n setHeight: (height: number) => void;\n};\n\nexport type SandboxBridge = {\n onMessage: (event: MessageEvent) => void;\n dispose: () => void;\n};\n\nexport type SandboxContent = { html: string };\n\nexport type SandboxHostProps = {\n content: SandboxContent;\n contentKey: string;\n sandbox?: SandboxHostConfig | undefined;\n maxHeight?: number | undefined;\n createBridge: (\n frame: SandboxHostFrame,\n host: SandboxHostApi,\n ) => SandboxBridge;\n onError?: ((error: Error) => void) | undefined;\n containerProps?: Record<string, string | undefined> | undefined;\n};\n\nexport function isSandboxFrameMessage(\n event: MessageEvent,\n frame: { iframe: HTMLIFrameElement; origin: string },\n): boolean {\n return (\n event.source === frame.iframe.contentWindow && event.origin === frame.origin\n );\n}\n\ntype LiveSnapshot = {\n content: SandboxContent;\n sandbox: SandboxHostConfig | undefined;\n createBridge: SandboxHostProps[\"createBridge\"];\n onError: SandboxHostProps[\"onError\"];\n};\n\nexport function SandboxHost({\n content,\n contentKey,\n sandbox,\n maxHeight = DEFAULT_MAX_HEIGHT,\n createBridge,\n onError,\n containerProps,\n}: SandboxHostProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n const [contentHeight, setContentHeight] = useState<number | undefined>(\n undefined,\n );\n\n const liveRef = useRef<LiveSnapshot>({\n content,\n sandbox,\n createBridge,\n onError,\n });\n useLayoutEffect(() => {\n liveRef.current = { content, sandbox, createBridge, onError };\n }, [content, sandbox, createBridge, onError]);\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n let cancelled = false;\n let frame: RenderedFrame | null = null;\n let bridge: SandboxBridge | null = null;\n let onMessage: ((event: MessageEvent) => void) | null = null;\n\n const { content: liveContent, sandbox: sb } = liveRef.current;\n\n const reportError = (err: unknown) => {\n const error = err instanceof Error ? err : new Error(String(err));\n invokeUserCallback(\n \"assistant-ui\",\n \"SandboxHost onError\",\n liveRef.current.onError?.bind(liveRef.current),\n error,\n );\n };\n\n const scf = new SafeContentFrame(sb?.product ?? DEFAULT_PRODUCT, {\n ...(sb?.sandbox !== undefined && { sandbox: sb.sandbox }),\n ...(sb?.useShadowDom !== undefined && { useShadowDom: sb.useShadowDom }),\n ...(sb?.enableBrowserCaching !== undefined && {\n enableBrowserCaching: sb.enableBrowserCaching,\n }),\n ...(sb?.salt !== undefined && { salt: sb.salt }),\n });\n\n const renderOpts =\n sb?.unsafeDocumentWrite !== undefined\n ? { unsafeDocumentWrite: sb.unsafeDocumentWrite }\n : undefined;\n\n scf\n .renderHtml(liveContent.html, container, renderOpts)\n .then((rendered) => {\n if (cancelled) {\n rendered.dispose();\n return;\n }\n frame = rendered;\n\n const hostApi: SandboxHostApi = {\n setHeight: (height) => {\n if (\n typeof height === \"number\" &&\n Number.isFinite(height) &&\n height > 0\n ) {\n setContentHeight(height);\n }\n },\n };\n\n bridge = liveRef.current.createBridge(\n {\n iframe: rendered.iframe,\n origin: rendered.origin,\n sendMessage: rendered.sendMessage,\n },\n hostApi,\n );\n\n // Single owner of the window listener; the cross-origin guard runs\n // here so the bridge only sees frame-validated messages.\n onMessage = (event) => {\n if (!isSandboxFrameMessage(event, rendered)) return;\n bridge?.onMessage(event);\n };\n window.addEventListener(\"message\", onMessage);\n\n // renderHtml resolves at iframe load, which a shim that was never\n // served also reaches, so a completed render is only known once the\n // frame says so. render-timeout is excluded because the shim is\n // running and the guest may still paint, and reporting it would leave\n // a host that renders an error state showing one over a frame that\n // recovers.\n rendered.fullyLoadedPromiseWithTimeout(LOAD_TIMEOUT_MS).catch((err) => {\n if (cancelled) return;\n if (isShimLoadError(err) && err.code === \"render-timeout\") return;\n reportError(err);\n });\n })\n .catch((err) => {\n if (cancelled) return;\n frame?.dispose();\n frame = null;\n reportError(err);\n });\n\n return () => {\n cancelled = true;\n let cleanupFailed = false;\n let cleanupError: unknown;\n const runCleanup = (cleanup: () => void) => {\n try {\n cleanup();\n } catch (error) {\n if (cleanupFailed) {\n console.error(error);\n } else {\n cleanupFailed = true;\n cleanupError = error;\n }\n }\n };\n\n if (onMessage) {\n const listener = onMessage;\n onMessage = null;\n runCleanup(() => window.removeEventListener(\"message\", listener));\n }\n const bridgeToDispose = bridge;\n bridge = null;\n if (bridgeToDispose) runCleanup(() => bridgeToDispose.dispose());\n const frameToDispose = frame;\n frame = null;\n if (frameToDispose) runCleanup(() => frameToDispose.dispose());\n runCleanup(() => setContentHeight(undefined));\n\n if (cleanupFailed) throw cleanupError;\n };\n // oxlint-disable-next-line react/exhaustive-deps -- re-init only on contentKey change; live values flow through liveRef\n }, [contentKey]);\n\n const resolvedHeight =\n contentHeight != null ? Math.min(contentHeight, maxHeight) : undefined;\n const mergedStyle =\n resolvedHeight != null\n ? { ...sandbox?.style, height: resolvedHeight }\n : sandbox?.style;\n\n return (\n <div\n {...containerProps}\n ref={containerRef}\n className={sandbox?.className}\n style={mergedStyle}\n />\n );\n}\n"],"mappings":";;;;;;;AAiBA,MAAMY,kBAAkB;AACxB,MAAMC,qBAAqB;AAC3B,MAAMC,kBAAkB;AA0CxB,SAAgBkC,sBACdjB,OACAU,OACS;CACT,OACEV,MAAMqB,WAAWX,MAAMQ,OAAOI,iBAAiBtB,MAAMoB,WAAWV,MAAMU;AAE1E;AASA,SAAOI,YAAAC,IAAA;CAAA,MAAAC,IAAAxD,EAAA,EAAA;CAAqB,MAAA,EAAAoC,SAAAC,YAAAtB,SAAAuB,WAAAmB,IAAAlB,cAAAG,SAAAG,mBAAAU;CAI1B,MAAAjB,YAAAmB,OAAAC,KAAAA,IAAA9C,qBAAA6C;CAKA,MAAAE,eAAqBvD,OAAuB,IAAI;CAChD,MAAA,CAAAwD,eAAAC,oBAA0CxD,SACxCqD,KAAAA,CACF;CAAE,IAAAI;CAAA,IAAAN,EAAA,OAAApB,WAAAoB,EAAA,OAAAjB,gBAAAiB,EAAA,OAAAd,WAAAc,EAAA,OAAAzC,SAAA;EAEmC+C,KAAA;GAAA1B;GAAArB;GAAAwB;GAAAG;EAKrC;EAACc,EAAA,KAAApB;EAAAoB,EAAA,KAAAjB;EAAAiB,EAAA,KAAAd;EAAAc,EAAA,KAAAzC;EAAAyC,EAAA,KAAAM;CAAA,OAAAA,KAAAN,EAAA;CALD,MAAAO,UAAgB3D,OAAqB0D,EAKpC;CAAE,IAAAE;CAAA,IAAAC;CAAA,IAAAT,EAAA,OAAApB,WAAAoB,EAAA,OAAAjB,gBAAAiB,EAAA,OAAAd,WAAAc,EAAA,OAAAzC,SAAA;EACaiD,WAAA;GACdD,QAAOG,UAAW;IAAA9B;IAAArB;IAAAwB;IAAAG;GAA0C;EAA7C;EACduB,KAAA;GAAC7B;GAASrB;GAASwB;GAAcG;EAAO;EAACc,EAAA,KAAApB;EAAAoB,EAAA,KAAAjB;EAAAiB,EAAA,KAAAd;EAAAc,EAAA,KAAAzC;EAAAyC,EAAA,KAAAQ;EAAAR,EAAA,MAAAS;CAAA,OAAA;EAAAD,KAAAR,EAAA;EAAAS,KAAAT,EAAA;CAAA;CAF5CrD,gBAAgB6D,IAEbC,EAAyC;CAAC,IAAAE;CAAA,IAAAX,EAAA,QAAAY,OAAAC,IAAA,2BAAA,GAAA;EAEnCF,WAAA;GACR,MAAAG,YAAkBX,aAAYO;GAC9B,IAAI,CAACI,WAAS;GAEd,IAAAC,YAAgB;GAChB,IAAA/B,QAAkC;GAClC,IAAAgC,SAAmC;GACnC,IAAA3C,YAAwD;GAExD,MAAA,EAAAO,SAAAqC,aAAA1D,SAAA2D,OAA8CX,QAAOG;GAErD,MAAAS,eAAoBC,QAAA;IAClB,MAAAjC,QAAciC,eAAehC,QAAfgC,MAAA,IAAiChC,MAAMiC,OAAOD,GAAG,CAAC;IAChElE,mBACE,gBACA,uBACAqD,QAAOG,QAAQxB,SAAcoC,KAACf,QAAOG,OAAQ,GAC7CvB,KACF;GAAC;GAGH,MAAAoC,MAAY,IAAIvE,iBAAiBkE,IAAEvD,WAAFR,iBAAgC;IAAA,GAC3D+D,IAAE3D,YAAc2C,KAAAA,KAAhB,EAAA3C,SAAwC2D,GAAE3D,QAAS;IAAC,GACpD2D,IAAE1D,iBAAmB0C,KAAAA,KAArB,EAAA1C,cAAkD0D,GAAE1D,aAAc;IAAC,GACnE0D,IAAEzD,yBAA2ByC,KAAAA,KAA7B,EAAAzC,sBACoByD,GAAEzD,qBAC1B;IAAC,GACGyD,IAAExD,SAAWwC,KAAAA,KAAb,EAAAxC,MAAkCwD,GAAExD,KAAM;GAChD,CAAC;GAED,MAAA8D,aACEN,IAAEpD,wBAA0BoC,KAAAA,IAA5B,EAAApC,qBAC2BoD,GAAEpD,oBACjB,IAFZoC,KAAAA;GAIFqB,IAAGE,WACWR,YAAWvC,MAAOoC,WAAWU,UAAU,CAAC,CAAAE,MAC9CC,aAAA;IACJ,IAAIZ,WAAS;KACXY,SAAQnD,QAAS;KAAC;IAAA;IAGpBQ,QAAQ2C;IAcRX,SAAST,QAAOG,QAAQ3B,aACtB;KAAAS,QACUmC,SAAQnC;KAAOE,QACfiC,SAAQjC;KAAOqC,aACVJ,SAAQI;IACvB,GACAH,EAlB8B1D,YACnBC,WAAA;KACT,IACE,OAAOA,WAAW,YAClB0D,OAAMC,SAAU3D,MAAM,KACtBA,SAAS,GAETkC,iBAAiBlC,MAAM;IACxB,EAUHyD,CACF;IAIAvD,aAAYA,UAAAA;KACVA,IAAIA,CAACkB,sBAAsBjB,OAAOqD,QAAQ,GAAC;KAC3CX,QAAM3C,UAAYC,KAAK;IAAC;IAE1B0D,OAAMC,iBAAkB,WAAW5D,SAAS;IAQ5CsD,SAAQO,8BAA+B7E,eAAe,CAAC,CAAA8E,OAAOC,UAAA;KAC5D,IAAIrB,WAAS;KACb,IAAIjE,gBAAgBsE,KAAoC,KAA5BA,MAAGiB,SAAU,kBAAgB;KACzDlB,YAAYC,KAAG;IAAC,CACjB;GAAC,CACH,CAAC,CAAAe,OACKG,UAAA;IACL,IAAIvB,WAAS;IACb/B,OAAKR,QAAU;IACfQ,QAAQA;IACRmC,YAAYC,KAAG;GAAC,CACjB;GAAC,aAEG;IACLL,YAAYA;IACZ,IAAAwB,gBAAoB;IAChBC,IAAAA;IACJ,MAAAC,cAAmBC,YAAA;KACjB,IAAA;MACEA,QAAQ;KAAC,SAAAC,IAAA;MACFxD,MAAAA,UAAAA;MACP,IAAIoD,eACFK,QAAOzD,MAAOA,OAAK;WAAC;OAEpBoD,gBAAgBA;OAChBC,eAAerD;MAAH;KACb;IACF;IAGH,IAAId,WAAS;KACX,MAAAwE,WAAiBxE;KACjBA,YAAYA;KACZoE,iBAAiBT,OAAMc,oBAAqB,WAAWD,QAAQ,CAAC;IAAC;IAEnE,MAAAE,kBAAwB/B;IACxBA,SAASA;IACT,IAAI+B,iBAAiBN,iBAAiBM,gBAAevE,QAAS,CAAC;IAC/D,MAAAwE,iBAAuBhE;IACvBA,QAAQA;IACR,IAAIgE,gBAAgBP,iBAAiBO,eAAcxE,QAAS,CAAC;IAC7DiE,iBAAiBpC,iBAAiBH,KAAAA,CAAS,CAAC;IAE5C,IAAIqC,eAAe,MAAMC;GAAa;EACvC;EAEFxC,EAAA,MAAAW;CAAA,OAAAA,KAAAX,EAAA;CAAA,IAAA2C;CAAA,IAAA3C,EAAA,QAAAnB,YAAA;EAAE8D,KAAA,CAAC9D,UAAU;EAACmB,EAAA,MAAAnB;EAAAmB,EAAA,MAAA2C;CAAA,OAAAA,KAAA3C,EAAA;CA7HftD,UAAUiE,IA6HPgC,EAAY;CAEf,MAAAM,iBACE7C,iBAAiB,OAAO8C,KAAIC,IAAK/C,eAAetB,SAAqB,IAArEoB,KAAAA;CAAuE,IAAAkD;CAAA,IAAApD,EAAA,QAAAiD,kBAAAjD,EAAA,QAAAzC,SAAAM,OAAA;EAEvEuF,KAAAH,kBAAkB,OAAlB;GAAA,GACS1F,SAAOM;GAAOM,QAAU8E;EAChB,IAAb1F,SAAOM;EAAOmC,EAAA,MAAAiD;EAAAjD,EAAA,MAAAzC,SAAAM;EAAAmC,EAAA,MAAAoD;CAAA,OAAAA,KAAApD,EAAA;CAHpB,MAAAqD,cACED;CAQa,MAAAE,KAAA/F,SAAOK;CAAW,IAAA2F;CAAA,IAAAvD,EAAA,QAAAX,kBAAAW,EAAA,QAAAqD,eAAArD,EAAA,QAAAsD,IAAA;EAH/BC,KAAA,oBAAA,OAAA;GAKE,GAJIlE;GACCc,KAAAA;GACM,WAAAmD;GACJD,OAAAA;EAAW,CAAA;EAClBrD,EAAA,MAAAX;EAAAW,EAAA,MAAAqD;EAAArD,EAAA,MAAAsD;EAAAtD,EAAA,MAAAuD;CAAA,OAAAA,KAAAvD,EAAA;CAAA,OALFuD;AAKE"}
|