@reforma/components 0.4.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/RichInput/RichInput.d.ts +1 -1
- package/dist/RichInput/RichInput.d.ts.map +1 -1
- package/dist/RichInput/RichInput.js +126 -123
- package/dist/RichInput/RichInput.js.map +1 -1
- package/dist/SortableList/SortableList.d.ts +9 -3
- package/dist/SortableList/SortableList.d.ts.map +1 -1
- package/dist/SortableList/SortableList.js +178 -163
- package/dist/SortableList/SortableList.js.map +1 -1
- package/dist/chat/ComposerBanner/ComposerBanner.d.ts +6 -1
- package/dist/chat/ComposerBanner/ComposerBanner.d.ts.map +1 -1
- package/dist/chat/ComposerBanner/ComposerBanner.js +60 -40
- package/dist/chat/ComposerBanner/ComposerBanner.js.map +1 -1
- package/dist/chat/ComposerBanner/ComposerBanner.module.css +1 -1
- package/dist/chat/ComposerBanner/ComposerBanner.module.css.js +13 -9
- package/dist/chat/ComposerBanner/ComposerBanner.module.css.js.map +1 -1
- package/dist/chat/Conversation/ConversationPendingLoader.d.ts.map +1 -1
- package/dist/chat/Conversation/ConversationPendingLoader.js +1 -1
- package/dist/chat/Conversation/ConversationPendingLoader.js.map +1 -1
- package/dist/chat/Message/normalize/normalizeMessageParts.d.ts +1 -1
- package/dist/chat/Message/normalize/normalizeMessageParts.d.ts.map +1 -1
- package/dist/chat/Message/normalize/normalizeMessageParts.js +1 -1
- package/dist/chat/Message/normalize/normalizeMessageParts.js.map +1 -1
- package/dist/chat/Message/parts/MessagePart.d.ts.map +1 -1
- package/dist/chat/Message/parts/MessagePart.js +1 -1
- package/dist/chat/Message/parts/MessagePart.js.map +1 -1
- package/dist/chat/Message/parts/backgroundResultPart.js +1 -1
- package/dist/chat/Message/parts/backgroundResultPart.js.map +1 -1
- package/dist/chat/Message/parts/collectMessageSources.d.ts +1 -1
- package/dist/chat/Message/parts/collectMessageSources.d.ts.map +1 -1
- package/dist/chat/Message/parts/collectMessageSources.js +1 -1
- package/dist/chat/Message/parts/collectMessageSources.js.map +1 -1
- package/dist/chat/Message/parts/contextCompactionPart.js +1 -1
- package/dist/chat/Message/parts/contextCompactionPart.js.map +1 -1
- package/dist/chat/Message/segments/analyzeGroupedSegment.js +5 -5
- package/dist/chat/Message/segments/analyzeGroupedSegment.js.map +1 -1
- package/dist/chat/Message/segments/recentStreamingPhaseToolGroups.js +1 -1
- package/dist/chat/Message/segments/recentStreamingPhaseToolGroups.js.map +1 -1
- package/dist/chat/Message/turn/workedCollapse.js +1 -1
- package/dist/chat/Message/turn/workedCollapse.js.map +1 -1
- package/dist/chat/Tool/Tool.js +1 -1
- package/dist/chat/Tool/Tool.js.map +1 -1
- package/dist/chat/Tool/agent/AgentTool.d.ts.map +1 -1
- package/dist/chat/Tool/agent/AgentTool.js +73 -73
- package/dist/chat/Tool/agent/AgentTool.js.map +1 -1
- package/dist/chat/Tool/bash/BashTool.d.ts.map +1 -1
- package/dist/chat/Tool/bash/BashTool.js +42 -48
- package/dist/chat/Tool/bash/BashTool.js.map +1 -1
- package/dist/chat/Tool/bash/BashTool.module.css +1 -1
- package/dist/chat/Tool/bash/BashTool.module.css.js +6 -8
- package/dist/chat/Tool/bash/BashTool.module.css.js.map +1 -1
- package/dist/chat/Tool/create-directory/CreateDirectoryTool.js +1 -1
- package/dist/chat/Tool/create-directory/CreateDirectoryTool.js.map +1 -1
- package/dist/chat/Tool/default/Default.d.ts.map +1 -1
- package/dist/chat/Tool/default/Default.js +1 -1
- package/dist/chat/Tool/default/Default.js.map +1 -1
- package/dist/chat/Tool/dev-server/DevServerRestartTool.js +1 -1
- package/dist/chat/Tool/dev-server/DevServerRestartTool.js.map +1 -1
- package/dist/chat/Tool/dev-server/DevServerStatusTool.js +1 -1
- package/dist/chat/Tool/dev-server/DevServerStatusTool.js.map +1 -1
- package/dist/chat/Tool/edit/EditTool.js +1 -1
- package/dist/chat/Tool/edit/EditTool.js.map +1 -1
- package/dist/chat/Tool/fetch/FetchTool.js +1 -1
- package/dist/chat/Tool/fetch/FetchTool.js.map +1 -1
- package/dist/chat/Tool/fileChangesFromToolParts.js +1 -1
- package/dist/chat/Tool/fileChangesFromToolParts.js.map +1 -1
- package/dist/chat/Tool/get-background-result/GetBackgroundResultTool.js +1 -1
- package/dist/chat/Tool/get-background-result/GetBackgroundResultTool.js.map +1 -1
- package/dist/chat/Tool/get-errors/GetErrorsTool.js +1 -1
- package/dist/chat/Tool/get-errors/GetErrorsTool.js.map +1 -1
- package/dist/chat/Tool/glob/GlobTool.js +1 -1
- package/dist/chat/Tool/glob/GlobTool.js.map +1 -1
- package/dist/chat/Tool/grep/GrepTool.js +1 -1
- package/dist/chat/Tool/grep/GrepTool.js.map +1 -1
- package/dist/chat/Tool/helpers.d.ts +1 -1
- package/dist/chat/Tool/helpers.d.ts.map +1 -1
- package/dist/chat/Tool/helpers.js +1 -1
- package/dist/chat/Tool/helpers.js.map +1 -1
- package/dist/chat/Tool/image-asset/ImageAssetTool.js +1 -1
- package/dist/chat/Tool/image-asset/ImageAssetTool.js.map +1 -1
- package/dist/chat/Tool/install-dependencies/InstallDependenciesTool.js +1 -1
- package/dist/chat/Tool/install-dependencies/InstallDependenciesTool.js.map +1 -1
- package/dist/chat/Tool/install-plugin/InstallPlugin.js +1 -1
- package/dist/chat/Tool/install-plugin/InstallPlugin.js.map +1 -1
- package/dist/chat/Tool/integration-card/IntegrationActionCard.d.ts +3 -1
- package/dist/chat/Tool/integration-card/IntegrationActionCard.d.ts.map +1 -1
- package/dist/chat/Tool/integration-card/IntegrationActionCard.js +88 -82
- package/dist/chat/Tool/integration-card/IntegrationActionCard.js.map +1 -1
- package/dist/chat/Tool/list-directory/normalizeListDirectoryTools.js +1 -1
- package/dist/chat/Tool/list-directory/normalizeListDirectoryTools.js.map +1 -1
- package/dist/chat/Tool/mcp-tools/CallDynamicTool.js +1 -1
- package/dist/chat/Tool/mcp-tools/CallDynamicTool.js.map +1 -1
- package/dist/chat/Tool/mcp-tools/GetDynamicToolsTool.js +1 -1
- package/dist/chat/Tool/mcp-tools/GetDynamicToolsTool.js.map +1 -1
- package/dist/chat/Tool/mcp-tools/GetMcpResourcesTool.js +1 -1
- package/dist/chat/Tool/mcp-tools/GetMcpResourcesTool.js.map +1 -1
- package/dist/chat/Tool/mcp-tools/McpAuth.js +1 -1
- package/dist/chat/Tool/mcp-tools/McpAuth.js.map +1 -1
- package/dist/chat/Tool/memory/MemoryTool.js +1 -1
- package/dist/chat/Tool/memory/MemoryTool.js.map +1 -1
- package/dist/chat/Tool/move-file/MoveFileTool.js +1 -1
- package/dist/chat/Tool/move-file/MoveFileTool.js.map +1 -1
- package/dist/chat/Tool/plan/CreatePlanTool.js +1 -1
- package/dist/chat/Tool/plan/CreatePlanTool.js.map +1 -1
- package/dist/chat/Tool/preamble/PreambleTool.js +1 -1
- package/dist/chat/Tool/preamble/PreambleTool.js.map +1 -1
- package/dist/chat/Tool/project-build/BuildTool.js +1 -1
- package/dist/chat/Tool/project-build/BuildTool.js.map +1 -1
- package/dist/chat/Tool/project-env/ProjectEnvTool.js +1 -1
- package/dist/chat/Tool/project-env/ProjectEnvTool.js.map +1 -1
- package/dist/chat/Tool/read/normalizeReadTools.js +1 -1
- package/dist/chat/Tool/read/normalizeReadTools.js.map +1 -1
- package/dist/chat/Tool/read-lints/ReadLintsTool.js +1 -1
- package/dist/chat/Tool/read-lints/ReadLintsTool.js.map +1 -1
- package/dist/chat/Tool/remove-file/RemoveFileTool.js +1 -1
- package/dist/chat/Tool/remove-file/RemoveFileTool.js.map +1 -1
- package/dist/chat/Tool/scaffold-project/ScaffoldProjectTool.js +1 -1
- package/dist/chat/Tool/scaffold-project/ScaffoldProjectTool.js.map +1 -1
- package/dist/chat/Tool/screenshot/CaptureScreenshotTool.js +3 -3
- package/dist/chat/Tool/screenshot/CaptureScreenshotTool.js.map +1 -1
- package/dist/chat/Tool/skill/SkillTool.js +1 -1
- package/dist/chat/Tool/skill/SkillTool.js.map +1 -1
- package/dist/chat/Tool/waiting/WaitingTool.js +1 -1
- package/dist/chat/Tool/waiting/WaitingTool.js.map +1 -1
- package/dist/chat/Tool/web-search/WebSearchTool.js +1 -1
- package/dist/chat/Tool/web-search/WebSearchTool.js.map +1 -1
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SortableList.js","sources":["../../src/SortableList/SortableList.tsx"],"sourcesContent":["import {\n DragDropProvider,\n DragOverlay,\n PointerSensor,\n useDroppable,\n type DragEndEvent,\n} from '@dnd-kit/react';\nimport { isSortable, useSortable } from '@dnd-kit/react/sortable';\nimport { DotsDrag } from '@reforma/icons/14';\nimport { cn } from '@reforma/lib';\nimport { useCallback, useMemo, useRef } from 'react';\n\nimport { For } from '../For';\nimport styles from './SortableList.module.css';\nimport {\n buildSortableTree,\n findSortableTreeNode,\n moveSortableTreeNodeToIndex,\n restoreSortableTree,\n type SortableTreeNode,\n} from './sortableTree';\n\nimport type { ReactElement, ReactNode } from 'react';\n\nexport type SortableListDragHandleAlignment = 'center' | 'top';\nexport type SortableListDragHandleEdgeOffset = 'none' | 'sm' | 'md';\nexport type SortableListDragHandleVariant = 'plain' | 'surface';\n\nexport interface SortableListDragHandleOptions {\n alignment?: SortableListDragHandleAlignment;\n edgeOffset?: SortableListDragHandleEdgeOffset;\n variant?: SortableListDragHandleVariant;\n}\n\nexport interface SortableListItemContext<T> {\n level: number;\n parent: T | null;\n index: number;\n siblingCount: number;\n isFirst: boolean;\n isLast: boolean;\n hasChildren: boolean;\n canHaveChildren: boolean;\n}\n\nexport interface SortableListItemRenderProps<T> extends SortableListItemContext<T> {\n nestedItems: ReactNode;\n isDragging: boolean;\n isDropTarget: boolean;\n}\n\nexport interface SortableListDropContext<T> {\n items: readonly T[];\n target: T | null;\n sourceParent: T | null;\n sourceLevel: number;\n parent: T | null;\n targetLevel: number;\n dropPosition: 'on' | 'before' | 'after' | 'end';\n}\n\ninterface SortableListBaseProps<T> {\n items: readonly T[];\n getKey?: (item: T, path: readonly number[]) => string;\n getTextValue: (item: T) => string;\n onChange: (items: T[]) => void;\n children: (item: T, props: SortableListItemRenderProps<T>) => ReactNode;\n canDrop?: (context: SortableListDropContext<T>) => boolean;\n getDragHandleOptions?: (\n item: T,\n context: SortableListItemContext<T>\n ) => SortableListDragHandleOptions;\n className?: string;\n gap?: 'sm' | 'md';\n nestedGap?: 'sm' | 'md';\n 'aria-label': string;\n}\n\ninterface FlatSortableListProps {\n getChildren?: never;\n setChildren?: never;\n canHaveChildren?: never;\n}\n\ninterface NestedSortableListProps<T> {\n getChildren: (item: T) => readonly T[];\n setChildren: (item: T, children: T[]) => T;\n canHaveChildren?: (item: T) => boolean;\n}\n\nexport type SortableListProps<T> = SortableListBaseProps<T>\n & (FlatSortableListProps | NestedSortableListProps<T>);\n\ninterface SortableNodeData<T> {\n kind: 'node';\n node: SortableTreeNode<T>;\n}\n\ninterface SortableCollectionData<T> {\n kind: 'collection';\n parentNode: SortableTreeNode<T> | null;\n}\n\ninterface SortableCollectionProps<T> {\n nodes: readonly SortableTreeNode<T>[];\n rootNodes: readonly SortableTreeNode<T>[];\n parentNode: SortableTreeNode<T> | null;\n renderItem: (item: T, props: SortableListItemRenderProps<T>) => ReactNode;\n canDrop?: (context: SortableListDropContext<T>) => boolean;\n getDragHandleOptions?: (\n item: T,\n context: SortableListItemContext<T>\n ) => SortableListDragHandleOptions;\n className?: string;\n gap: 'sm' | 'md';\n nestedGap: 'sm' | 'md';\n ariaLabel: string;\n}\n\ninterface SortableItemProps<T> extends Omit<SortableCollectionProps<T>, 'nodes' | 'className' | 'gap' | 'ariaLabel' | 'parentNode'> {\n node: SortableTreeNode<T>;\n}\n\ninterface SortableDestination<T> {\n parentNode: SortableTreeNode<T> | null;\n index: number;\n dropPosition: 'before' | 'after' | 'end';\n}\n\nconst ROOT_COLLECTION_ID = 'reforma-sortable:root';\nconst CHILD_COLLECTION_PREFIX = 'reforma-sortable:children:';\nconst SORTABLE_ITEM_TYPE = 'reforma-sortable:item';\nconst SORTABLE_COLLECTION_TYPE = 'reforma-sortable:collection';\nconst POINTER_SENSORS = [PointerSensor];\nconst PRIMITIVE_KEY_PREFIX = 'sortable:primitive:';\n\n/**\n * Sortable collection with a dedicated pointer handle and optional child groups.\n *\n * The rendered item is the complete draggable surface. Child collections can\n * accept moves when the caller's drop rules allow it.\n */\nexport function SortableList<T>({\n items,\n getKey: getItemKey,\n getTextValue,\n getChildren,\n setChildren,\n canHaveChildren,\n onChange,\n children,\n canDrop,\n getDragHandleOptions,\n className,\n gap = 'md',\n nestedGap = gap,\n 'aria-label': ariaLabel,\n}: SortableListProps<T>) {\n const keyState = useRef({\n nextId: 0,\n objectKeys: new WeakMap<object, string>(),\n });\n const getNodeKey = useCallback((item: T, path: readonly number[]) => {\n const itemKey = getItemKey?.(item, path);\n\n if (itemKey != null) {\n return itemKey;\n }\n\n if (typeof item !== 'object' || item == null) {\n return `${ PRIMITIVE_KEY_PREFIX }${ path.join('.') }`;\n }\n\n const existingKey = keyState.current.objectKeys.get(item);\n\n if (existingKey) {\n return existingKey;\n }\n\n const key = `sortable:item:${ keyState.current.nextId }`;\n\n keyState.current.nextId += 1;\n keyState.current.objectKeys.set(item, key);\n\n return key;\n }, [getItemKey]);\n const nodes = useMemo(() => buildSortableTree(items, {\n getKey: getNodeKey,\n getTextValue,\n getChildren,\n canHaveChildren,\n }), [canHaveChildren, getChildren, getNodeKey, getTextValue, items]);\n const renderState = useRef({ items, revision: 0 });\n\n if (renderState.current.items !== items) {\n renderState.current = {\n items,\n revision: renderState.current.revision + 1,\n };\n }\n\n function handleDragEnd(event: DragEndEvent) {\n const { canceled, operation } = event;\n const { source, target } = operation;\n\n if (canceled || !source || !isSortable(source)) {\n return;\n }\n\n const sourceNode = nodeData<T>(source)?.node;\n\n if (!sourceNode) {\n return;\n }\n\n const targetData = entityData<T>(target);\n const targetNode = targetData?.kind === 'node' ? targetData.node : null;\n let destination: SortableDestination<T> | null;\n\n if (targetData?.kind === 'collection') {\n destination = {\n parentNode: targetData.parentNode,\n index: targetData.parentNode?.children.length ?? nodes.length,\n dropPosition: 'end' as const,\n };\n }\n else if (targetNode\n && target\n && isSortable(target)) {\n destination = destinationFromSortable(\n nodes,\n target.group,\n source.index,\n targetNode\n );\n }\n else {\n destination = null;\n }\n\n if (!destination) {\n return;\n }\n\n const context = createDropContext(\n sourceNode,\n destination.parentNode,\n targetNode,\n destination.dropPosition\n );\n\n if (!canMoveToParent(sourceNode, destination.parentNode)\n || (canDrop && !canDrop(context))) {\n return;\n }\n\n const initialParentKey = parentKeyFromCollectionId(source.initialGroup);\n const destinationParentKey = destination.parentNode?.id ?? null;\n const isSamePosition = initialParentKey !== undefined\n && initialParentKey === destinationParentKey\n && source.initialIndex === destination.index;\n\n if (isSamePosition) {\n return;\n }\n\n const movedNodes = moveSortableTreeNodeToIndex(\n nodes,\n sourceNode.id,\n destinationParentKey,\n destination.index\n );\n\n onChange(restoreSortableTree(movedNodes, setChildren));\n }\n\n return (\n <DragDropProvider\n key={ renderState.current.revision }\n sensors={ POINTER_SENSORS }\n onDragEnd={ handleDragEnd }\n >\n <SortableCollection\n nodes={ nodes }\n rootNodes={ nodes }\n parentNode={ null }\n renderItem={ children }\n canDrop={ canDrop }\n getDragHandleOptions={ getDragHandleOptions }\n className={ className }\n gap={ gap }\n nestedGap={ nestedGap }\n ariaLabel={ ariaLabel }\n />\n\n <DragOverlay\n className={ styles.dragOverlay }\n dropAnimation={ {\n duration: 160,\n easing: 'cubic-bezier(0.25, 1, 0.5, 1)',\n } }\n >\n { (source) => {\n const node = nodeData<T>(source)?.node;\n\n return node\n ? (\n <SortablePreview\n node={ node }\n renderItem={ children }\n nestedGap={ nestedGap }\n />\n )\n : null;\n } }\n </DragOverlay>\n </DragDropProvider>\n );\n}\n\nfunction SortableCollection<T>({\n nodes,\n rootNodes,\n parentNode,\n renderItem,\n canDrop,\n getDragHandleOptions,\n className,\n gap,\n nestedGap,\n ariaLabel,\n}: SortableCollectionProps<T>) {\n const { ref, isDropTarget } = useDroppable<SortableCollectionData<T>>({\n id: collectionId(parentNode),\n type: SORTABLE_COLLECTION_TYPE,\n data: { kind: 'collection', parentNode },\n disabled: nodes.length > 0,\n collisionPriority: 1,\n accept: source => canAcceptDrop(\n source,\n parentNode,\n null,\n 'end',\n canDrop\n ),\n });\n\n return (\n <div\n ref={ ref }\n role=\"list\"\n className={ cn(styles.list, className) }\n data-gap={ gap }\n data-drop-target={ isDropTarget || undefined }\n aria-label={ ariaLabel }\n >\n <For each={ nodes }>\n { node => (\n <SortableItem\n key={ node.id }\n node={ node }\n rootNodes={ rootNodes }\n renderItem={ renderItem }\n canDrop={ canDrop }\n getDragHandleOptions={ getDragHandleOptions }\n nestedGap={ nestedGap }\n />\n ) }\n </For>\n </div>\n );\n}\n\nfunction SortableItem<T>({\n node,\n rootNodes,\n renderItem,\n canDrop,\n getDragHandleOptions,\n nestedGap,\n}: SortableItemProps<T>) {\n const context = itemContext(node);\n const {\n alignment = 'center',\n edgeOffset = 'none',\n variant = 'plain',\n } = getDragHandleOptions?.(node.value, context) ?? {};\n const {\n handleRef,\n ref,\n targetRef,\n isDragging,\n isDropTarget,\n } = useSortable<SortableNodeData<T>>({\n id: node.id,\n index: node.index,\n group: collectionIdFromParentKey(nodeParentKey(rootNodes, node)),\n type: SORTABLE_ITEM_TYPE,\n data: { kind: 'node', node },\n accept: source => canAcceptDrop(\n source,\n node.parent == null\n ? null\n : findParentNode(rootNodes, node),\n node,\n 'before',\n canDrop\n ),\n });\n const nestedItems = node.canHaveChildren\n ? (\n <SortableCollection\n nodes={ node.children }\n rootNodes={ rootNodes }\n parentNode={ node }\n renderItem={ renderItem }\n canDrop={ canDrop }\n getDragHandleOptions={ getDragHandleOptions }\n gap={ nestedGap }\n nestedGap={ nestedGap }\n ariaLabel={ `${ node.textValue } items` }\n />\n )\n : null;\n\n return (\n <div\n ref={ ref }\n role=\"listitem\"\n className={ styles.item }\n data-level={ node.level }\n data-dragging={ isDragging || undefined }\n data-drop-target={ isDropTarget || undefined }\n >\n <div\n ref={ targetRef }\n className={ styles.dropTarget }\n data-container={ node.canHaveChildren || undefined }\n aria-hidden\n />\n\n <span\n ref={ handleRef }\n className={ styles.dragHandle }\n data-alignment={ alignment }\n data-edge-offset={ edgeOffset }\n data-variant={ variant }\n aria-hidden\n >\n <DotsDrag aria-hidden width={ 14 } height={ 14 } />\n </span>\n\n <div className={ styles.content }>\n { renderItem(node.value, {\n ...context,\n nestedItems,\n isDragging,\n isDropTarget,\n }) }\n </div>\n </div>\n );\n}\n\nfunction SortablePreview<T>({\n node,\n renderItem,\n nestedGap,\n}: {\n node: SortableTreeNode<T>;\n renderItem: (item: T, props: SortableListItemRenderProps<T>) => ReactNode;\n nestedGap: 'sm' | 'md';\n}): ReactElement {\n const nestedItems = node.canHaveChildren\n ? (\n <div className={ styles.previewList } data-gap={ nestedGap }>\n <For each={ node.children }>\n { child => (\n <SortablePreview\n key={ child.id }\n node={ child }\n renderItem={ renderItem }\n nestedGap={ nestedGap }\n />\n ) }\n </For>\n </div>\n )\n : null;\n\n return (\n <div className={ styles.dragPreviewItem }>\n { renderItem(node.value, {\n ...itemContext(node),\n nestedItems,\n isDragging: false,\n isDropTarget: false,\n }) }\n </div>\n );\n}\n\nfunction itemContext<T>(node: SortableTreeNode<T>): SortableListItemContext<T> {\n return {\n level: node.level,\n parent: node.parent,\n index: node.index,\n siblingCount: node.siblingCount,\n isFirst: node.index === 0,\n isLast: node.index === node.siblingCount - 1,\n hasChildren: node.children.length > 0,\n canHaveChildren: node.canHaveChildren,\n };\n}\n\nfunction canAcceptDrop<T>(\n source: { data: Record<string, unknown> },\n parentNode: SortableTreeNode<T> | null,\n targetNode: SortableTreeNode<T> | null,\n dropPosition: SortableListDropContext<T>['dropPosition'],\n canDrop?: (context: SortableListDropContext<T>) => boolean\n): boolean {\n const sourceNode = nodeData<T>(source)?.node;\n\n if (!sourceNode || !canMoveToParent(sourceNode, parentNode)) {\n return false;\n }\n\n return canDrop?.(\n createDropContext(sourceNode, parentNode, targetNode, dropPosition)\n ) ?? true;\n}\n\nfunction createDropContext<T>(\n sourceNode: SortableTreeNode<T>,\n parentNode: SortableTreeNode<T> | null,\n targetNode: SortableTreeNode<T> | null,\n dropPosition: SortableListDropContext<T>['dropPosition']\n): SortableListDropContext<T> {\n return {\n items: [sourceNode.value],\n target: targetNode?.value ?? null,\n sourceParent: sourceNode.parent,\n sourceLevel: sourceNode.level,\n parent: parentNode?.value ?? null,\n targetLevel: parentNode ? parentNode.level + 1 : 1,\n dropPosition,\n };\n}\n\nfunction canMoveToParent<T>(\n sourceNode: SortableTreeNode<T>,\n parentNode: SortableTreeNode<T> | null\n): boolean {\n return parentNode == null\n || (parentNode.id !== sourceNode.id\n && findSortableTreeNode(sourceNode.children, parentNode.id) == null);\n}\n\nfunction destinationFromSortable<T>(\n nodes: readonly SortableTreeNode<T>[],\n group: string | number | undefined,\n index: number,\n targetNode: SortableTreeNode<T> | null\n): SortableDestination<T> | null {\n const parentKey = parentKeyFromCollectionId(group);\n\n if (parentKey === undefined) {\n return null;\n }\n\n const parentNode = parentKey == null\n ? null\n : findSortableTreeNode(nodes, parentKey);\n\n if (parentKey != null && !parentNode) {\n return null;\n }\n\n const isAfterTarget = targetNode != null && index > targetNode.index;\n\n return {\n parentNode,\n index,\n dropPosition: isAfterTarget ? 'after' : 'before',\n };\n}\n\nfunction collectionId<T>(parentNode: SortableTreeNode<T> | null): string {\n return collectionIdFromParentKey(parentNode?.id ?? null);\n}\n\nfunction collectionIdFromParentKey(parentKey: string | null): string {\n return parentKey == null\n ? ROOT_COLLECTION_ID\n : `${ CHILD_COLLECTION_PREFIX }${ parentKey }`;\n}\n\nfunction parentKeyFromCollectionId(\n collectionId: string | number | undefined\n): string | null | undefined {\n if (collectionId === ROOT_COLLECTION_ID) {\n return null;\n }\n\n if (typeof collectionId === 'string'\n && collectionId.startsWith(CHILD_COLLECTION_PREFIX)) {\n return collectionId.slice(CHILD_COLLECTION_PREFIX.length);\n }\n\n return undefined;\n}\n\nfunction nodeParentKey<T>(\n nodes: readonly SortableTreeNode<T>[],\n target: SortableTreeNode<T>\n): string | null {\n return findParentNode(nodes, target)?.id ?? null;\n}\n\nfunction findParentNode<T>(\n nodes: readonly SortableTreeNode<T>[],\n target: SortableTreeNode<T>\n): SortableTreeNode<T> | null {\n for (const node of nodes) {\n if (node.children.some(child => child.id === target.id)) {\n return node;\n }\n\n const parent = findParentNode(node.children, target);\n\n if (parent) {\n return parent;\n }\n }\n\n return null;\n}\n\nfunction entityData<T>(\n entity: { data: Record<string, unknown> } | null\n): SortableNodeData<T> | SortableCollectionData<T> | null {\n const data = entity?.data;\n\n if (data?.kind === 'node' && 'node' in data) {\n return {\n kind: 'node',\n node: data.node as SortableTreeNode<T>,\n };\n }\n\n if (data?.kind === 'collection' && 'parentNode' in data) {\n return {\n kind: 'collection',\n parentNode: data.parentNode as SortableTreeNode<T> | null,\n };\n }\n\n return null;\n}\n\nfunction nodeData<T>(\n entity: { data: Record<string, unknown> } | null\n): SortableNodeData<T> | null {\n const data = entityData<T>(entity);\n\n return data?.kind === 'node' ? data : null;\n}\n\nSortableList.displayName = 'SortableList';\n"],"names":["ROOT_COLLECTION_ID","CHILD_COLLECTION_PREFIX","SORTABLE_ITEM_TYPE","SORTABLE_COLLECTION_TYPE","POINTER_SENSORS","PointerSensor","PRIMITIVE_KEY_PREFIX","SortableList","items","getItemKey","getTextValue","getChildren","setChildren","canHaveChildren","onChange","children","canDrop","getDragHandleOptions","className","gap","nestedGap","ariaLabel","keyState","useRef","getNodeKey","useCallback","item","path","itemKey","existingKey","key","nodes","useMemo","buildSortableTree","renderState","handleDragEnd","event","canceled","operation","source","target","isSortable","sourceNode","nodeData","targetData","entityData","targetNode","destination","destinationFromSortable","context","createDropContext","canMoveToParent","initialParentKey","parentKeyFromCollectionId","destinationParentKey","movedNodes","moveSortableTreeNodeToIndex","restoreSortableTree","DragDropProvider","_jsx","SortableCollection","DragOverlay","styles","node","SortablePreview","rootNodes","parentNode","renderItem","ref","isDropTarget","useDroppable","collectionId","canAcceptDrop","cn","For","SortableItem","itemContext","alignment","edgeOffset","variant","handleRef","targetRef","isDragging","useSortable","collectionIdFromParentKey","nodeParentKey","findParentNode","nestedItems","DotsDrag","child","dropPosition","findSortableTreeNode","group","index","parentKey","isAfterTarget","parent","entity","data"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SortableList.js","sources":["../../src/SortableList/SortableList.tsx"],"sourcesContent":["import {\n DragDropProvider,\n DragOverlay,\n PointerSensor,\n useDroppable,\n type DragEndEvent,\n} from '@dnd-kit/react';\nimport { isSortable, useSortable } from '@dnd-kit/react/sortable';\nimport { DotsDrag } from '@reforma/icons/14';\nimport { cn } from '@reforma/lib';\nimport { useCallback, useMemo, useState } from 'react';\n\nimport { For } from '../For';\nimport { Show } from '../Show';\nimport styles from './SortableList.module.css';\nimport {\n buildSortableTree,\n findSortableTreeNode,\n moveSortableTreeNodeToIndex,\n restoreSortableTree,\n type SortableTreeNode,\n} from './sortableTree';\n\nimport type { ReactElement, ReactNode } from 'react';\n\nexport type SortableListDragHandleAlignment = 'center' | 'top';\nexport type SortableListDragHandleEdgeOffset = 'none' | 'sm' | 'md';\nexport type SortableListDragHandleVariant = 'plain' | 'surface';\n\nexport interface SortableListDragHandleOptions {\n alignment?: SortableListDragHandleAlignment;\n edgeOffset?: SortableListDragHandleEdgeOffset;\n variant?: SortableListDragHandleVariant;\n}\n\nexport interface SortableListItemContext<T> {\n level: number;\n parent: T | null;\n index: number;\n siblingCount: number;\n isFirst: boolean;\n isLast: boolean;\n hasChildren: boolean;\n canHaveChildren: boolean;\n}\n\nexport interface SortableListItemRenderProps<T> extends SortableListItemContext<T> {\n nestedItems: ReactNode;\n isDragging: boolean;\n isDropTarget: boolean;\n}\n\nexport interface SortableListDropContext<T> {\n items: readonly T[];\n target: T | null;\n sourceParent: T | null;\n sourceLevel: number;\n parent: T | null;\n targetLevel: number;\n dropPosition: 'on' | 'before' | 'after' | 'end';\n}\n\ninterface SortableListBaseProps<T> {\n items: readonly T[];\n getKey?: (item: T, path: readonly number[]) => string;\n getTextValue: (item: T) => string;\n /** `move` is the dragged item and its index among its new siblings. */\n onChange: (items: T[], move: { item: T; index: number }) => void;\n children: (item: T, props: SortableListItemRenderProps<T>) => ReactNode;\n canDrop?: (context: SortableListDropContext<T>) => boolean;\n getDragHandleOptions?: (\n item: T,\n context: SortableListItemContext<T>\n ) => SortableListDragHandleOptions;\n className?: string;\n gap?: 'sm' | 'md';\n nestedGap?: 'sm' | 'md';\n /** `false` drops the grip: the whole item starts a drag. Default `true`. */\n handle?: boolean;\n 'aria-label': string;\n}\n\ninterface FlatSortableListProps {\n getChildren?: never;\n setChildren?: never;\n canHaveChildren?: never;\n}\n\ninterface NestedSortableListProps<T> {\n getChildren: (item: T) => readonly T[];\n setChildren: (item: T, children: T[]) => T;\n canHaveChildren?: (item: T) => boolean;\n}\n\nexport type SortableListProps<T> = SortableListBaseProps<T>\n & (FlatSortableListProps | NestedSortableListProps<T>);\n\ninterface SortableNodeData<T> {\n kind: 'node';\n node: SortableTreeNode<T>;\n}\n\ninterface SortableCollectionData<T> {\n kind: 'collection';\n parentNode: SortableTreeNode<T> | null;\n}\n\ninterface SortableCollectionProps<T> {\n nodes: readonly SortableTreeNode<T>[];\n rootNodes: readonly SortableTreeNode<T>[];\n parentNode: SortableTreeNode<T> | null;\n renderItem: (item: T, props: SortableListItemRenderProps<T>) => ReactNode;\n canDrop?: (context: SortableListDropContext<T>) => boolean;\n getDragHandleOptions?: (\n item: T,\n context: SortableListItemContext<T>\n ) => SortableListDragHandleOptions;\n className?: string;\n gap: 'sm' | 'md';\n nestedGap: 'sm' | 'md';\n handle: boolean;\n ariaLabel: string;\n}\n\ninterface SortableItemProps<T> extends Omit<SortableCollectionProps<T>, 'nodes' | 'className' | 'gap' | 'ariaLabel' | 'parentNode'> {\n node: SortableTreeNode<T>;\n}\n\ninterface SortableDestination<T> {\n parentNode: SortableTreeNode<T> | null;\n index: number;\n dropPosition: 'before' | 'after' | 'end';\n}\n\nconst ROOT_COLLECTION_ID = 'reforma-sortable:root';\nconst CHILD_COLLECTION_PREFIX = 'reforma-sortable:children:';\nconst SORTABLE_ITEM_TYPE = 'reforma-sortable:item';\nconst SORTABLE_COLLECTION_TYPE = 'reforma-sortable:collection';\nconst POINTER_SENSORS = [PointerSensor];\nconst PRIMITIVE_KEY_PREFIX = 'sortable:primitive:';\n\n/** Keys for items without `getKey`: stable per object, unique across lists. */\nconst objectKeys = new WeakMap<object, string>();\nlet nextObjectKey = 0;\n\n/**\n * Sortable collection with a pointer handle (or whole-item drag) and optional child groups.\n *\n * The rendered item is the complete draggable surface. Child collections can\n * accept moves when the caller's drop rules allow it.\n */\nexport function SortableList<T>({\n items,\n getKey: getItemKey,\n getTextValue,\n getChildren,\n setChildren,\n canHaveChildren,\n onChange,\n children,\n canDrop,\n getDragHandleOptions,\n className,\n gap = 'md',\n nestedGap = gap,\n handle = true,\n 'aria-label': ariaLabel,\n}: SortableListProps<T>) {\n const getNodeKey = useCallback((item: T, path: readonly number[]) => {\n const itemKey = getItemKey?.(item, path);\n\n if (itemKey != null) {\n return itemKey;\n }\n\n if (typeof item !== 'object' || item == null) {\n return `${ PRIMITIVE_KEY_PREFIX }${ path.join('.') }`;\n }\n\n const existingKey = objectKeys.get(item);\n\n if (existingKey) {\n return existingKey;\n }\n\n const key = `sortable:item:${ nextObjectKey }`;\n\n nextObjectKey += 1;\n objectKeys.set(item, key);\n\n return key;\n }, [getItemKey]);\n const nodes = useMemo(() => buildSortableTree(items, {\n getKey: getNodeKey,\n getTextValue,\n getChildren,\n canHaveChildren,\n }), [canHaveChildren, getChildren, getNodeKey, getTextValue, items]);\n const [renderState, setRenderState] = useState({ items, revision: 0 });\n\n if (renderState.items !== items) {\n setRenderState({ items, revision: renderState.revision + 1 });\n }\n\n function handleDragEnd(event: DragEndEvent) {\n const { canceled, operation } = event;\n const { source, target } = operation;\n\n if (canceled || !source || !isSortable(source)) {\n return;\n }\n\n const sourceNode = nodeData<T>(source)?.node;\n\n if (!sourceNode) {\n return;\n }\n\n const targetData = entityData<T>(target);\n const targetNode = targetData?.kind === 'node' ? targetData.node : null;\n let destination: SortableDestination<T> | null;\n\n if (targetData?.kind === 'collection') {\n destination = {\n parentNode: targetData.parentNode,\n index: targetData.parentNode?.children.length ?? nodes.length,\n dropPosition: 'end' as const,\n };\n }\n else if (targetNode\n && target\n && isSortable(target)) {\n destination = destinationFromSortable(\n nodes,\n target.group,\n source.index,\n targetNode\n );\n }\n else {\n destination = null;\n }\n\n if (!destination) {\n return;\n }\n\n const context = createDropContext(\n sourceNode,\n destination.parentNode,\n targetNode,\n destination.dropPosition\n );\n\n if (!canMoveToParent(sourceNode, destination.parentNode)\n || (canDrop && !canDrop(context))) {\n return;\n }\n\n const initialParentKey = parentKeyFromCollectionId(source.initialGroup);\n const destinationParentKey = destination.parentNode?.id ?? null;\n const isSamePosition = initialParentKey !== undefined\n && initialParentKey === destinationParentKey\n && source.initialIndex === destination.index;\n\n if (isSamePosition) {\n return;\n }\n\n const movedNodes = moveSortableTreeNodeToIndex(\n nodes,\n sourceNode.id,\n destinationParentKey,\n destination.index\n );\n\n onChange(restoreSortableTree(movedNodes, setChildren), {\n item: sourceNode.value,\n index: destination.index,\n });\n }\n\n return (\n <DragDropProvider\n // A cross-parent drop moves DOM nodes React does not own: remount nested trees on change.\n // Flat lists reconcile the optimistic order in place; a remount would cut the drop animation.\n key={ getChildren ? renderState.revision : undefined }\n sensors={ POINTER_SENSORS }\n onDragEnd={ handleDragEnd }\n >\n <SortableCollection\n nodes={ nodes }\n rootNodes={ nodes }\n parentNode={ null }\n renderItem={ children }\n canDrop={ canDrop }\n getDragHandleOptions={ getDragHandleOptions }\n className={ className }\n gap={ gap }\n nestedGap={ nestedGap }\n handle={ handle }\n ariaLabel={ ariaLabel }\n />\n\n <DragOverlay\n className={ styles.dragOverlay }\n dropAnimation={ {\n duration: 160,\n easing: 'cubic-bezier(0.25, 1, 0.5, 1)',\n } }\n >\n { (source) => {\n const node = nodeData<T>(source)?.node;\n\n return node\n ? (\n <SortablePreview\n node={ node }\n renderItem={ children }\n nestedGap={ nestedGap }\n />\n )\n : null;\n } }\n </DragOverlay>\n </DragDropProvider>\n );\n}\n\nfunction SortableCollection<T>({\n nodes,\n rootNodes,\n parentNode,\n renderItem,\n canDrop,\n getDragHandleOptions,\n className,\n gap,\n nestedGap,\n handle,\n ariaLabel,\n}: SortableCollectionProps<T>) {\n const { ref, isDropTarget } = useDroppable<SortableCollectionData<T>>({\n id: collectionId(parentNode),\n type: SORTABLE_COLLECTION_TYPE,\n data: { kind: 'collection', parentNode },\n disabled: nodes.length > 0,\n collisionPriority: 1,\n accept: source => canAcceptDrop(\n source,\n parentNode,\n null,\n 'end',\n canDrop\n ),\n });\n\n return (\n <div\n ref={ ref }\n role=\"list\"\n className={ cn(styles.list, className) }\n data-gap={ gap }\n data-drop-target={ isDropTarget || undefined }\n aria-label={ ariaLabel }\n >\n <For each={ nodes }>\n { node => (\n <SortableItem\n key={ node.id }\n node={ node }\n rootNodes={ rootNodes }\n renderItem={ renderItem }\n canDrop={ canDrop }\n getDragHandleOptions={ getDragHandleOptions }\n nestedGap={ nestedGap }\n handle={ handle }\n />\n ) }\n </For>\n </div>\n );\n}\n\nfunction SortableItem<T>({\n node,\n rootNodes,\n renderItem,\n canDrop,\n getDragHandleOptions,\n nestedGap,\n handle,\n}: SortableItemProps<T>) {\n const context = itemContext(node);\n const {\n alignment = 'center',\n edgeOffset = 'none',\n variant = 'plain',\n } = getDragHandleOptions?.(node.value, context) ?? {};\n const {\n handleRef,\n ref,\n targetRef,\n isDragging,\n isDropTarget,\n } = useSortable<SortableNodeData<T>>({\n id: node.id,\n index: node.index,\n group: collectionIdFromParentKey(nodeParentKey(rootNodes, node)),\n type: SORTABLE_ITEM_TYPE,\n data: { kind: 'node', node },\n accept: source => canAcceptDrop(\n source,\n node.parent == null\n ? null\n : findParentNode(rootNodes, node),\n node,\n 'before',\n canDrop\n ),\n });\n const nestedItems = node.canHaveChildren\n ? (\n <SortableCollection\n nodes={ node.children }\n rootNodes={ rootNodes }\n parentNode={ node }\n renderItem={ renderItem }\n canDrop={ canDrop }\n getDragHandleOptions={ getDragHandleOptions }\n gap={ nestedGap }\n nestedGap={ nestedGap }\n handle={ handle }\n ariaLabel={ `${ node.textValue } items` }\n />\n )\n : null;\n\n return (\n <div\n ref={ ref }\n role=\"listitem\"\n className={ styles.item }\n data-level={ node.level }\n data-dragging={ isDragging || undefined }\n data-drop-target={ isDropTarget || undefined }\n >\n <div\n ref={ targetRef }\n className={ styles.dropTarget }\n data-container={ node.canHaveChildren || undefined }\n aria-hidden\n />\n\n <Show when={ handle }>\n <span\n ref={ handleRef }\n className={ styles.dragHandle }\n data-alignment={ alignment }\n data-edge-offset={ edgeOffset }\n data-variant={ variant }\n aria-hidden\n >\n <DotsDrag aria-hidden width={ 14 } height={ 14 } />\n </span>\n </Show>\n\n <div className={ styles.content }>\n { renderItem(node.value, {\n ...context,\n nestedItems,\n isDragging,\n isDropTarget,\n }) }\n </div>\n </div>\n );\n}\n\nfunction SortablePreview<T>({\n node,\n renderItem,\n nestedGap,\n}: {\n node: SortableTreeNode<T>;\n renderItem: (item: T, props: SortableListItemRenderProps<T>) => ReactNode;\n nestedGap: 'sm' | 'md';\n}): ReactElement {\n const nestedItems = node.canHaveChildren\n ? (\n <div className={ styles.previewList } data-gap={ nestedGap }>\n <For each={ node.children }>\n { child => (\n <SortablePreview\n key={ child.id }\n node={ child }\n renderItem={ renderItem }\n nestedGap={ nestedGap }\n />\n ) }\n </For>\n </div>\n )\n : null;\n\n return (\n <div className={ styles.dragPreviewItem }>\n { renderItem(node.value, {\n ...itemContext(node),\n nestedItems,\n isDragging: false,\n isDropTarget: false,\n }) }\n </div>\n );\n}\n\nfunction itemContext<T>(node: SortableTreeNode<T>): SortableListItemContext<T> {\n return {\n level: node.level,\n parent: node.parent,\n index: node.index,\n siblingCount: node.siblingCount,\n isFirst: node.index === 0,\n isLast: node.index === node.siblingCount - 1,\n hasChildren: node.children.length > 0,\n canHaveChildren: node.canHaveChildren,\n };\n}\n\nfunction canAcceptDrop<T>(\n source: { data: Record<string, unknown> },\n parentNode: SortableTreeNode<T> | null,\n targetNode: SortableTreeNode<T> | null,\n dropPosition: SortableListDropContext<T>['dropPosition'],\n canDrop?: (context: SortableListDropContext<T>) => boolean\n): boolean {\n const sourceNode = nodeData<T>(source)?.node;\n\n if (!sourceNode || !canMoveToParent(sourceNode, parentNode)) {\n return false;\n }\n\n return canDrop?.(\n createDropContext(sourceNode, parentNode, targetNode, dropPosition)\n ) ?? true;\n}\n\nfunction createDropContext<T>(\n sourceNode: SortableTreeNode<T>,\n parentNode: SortableTreeNode<T> | null,\n targetNode: SortableTreeNode<T> | null,\n dropPosition: SortableListDropContext<T>['dropPosition']\n): SortableListDropContext<T> {\n return {\n items: [sourceNode.value],\n target: targetNode?.value ?? null,\n sourceParent: sourceNode.parent,\n sourceLevel: sourceNode.level,\n parent: parentNode?.value ?? null,\n targetLevel: parentNode ? parentNode.level + 1 : 1,\n dropPosition,\n };\n}\n\nfunction canMoveToParent<T>(\n sourceNode: SortableTreeNode<T>,\n parentNode: SortableTreeNode<T> | null\n): boolean {\n return parentNode == null\n || (parentNode.id !== sourceNode.id\n && findSortableTreeNode(sourceNode.children, parentNode.id) == null);\n}\n\nfunction destinationFromSortable<T>(\n nodes: readonly SortableTreeNode<T>[],\n group: string | number | undefined,\n index: number,\n targetNode: SortableTreeNode<T> | null\n): SortableDestination<T> | null {\n const parentKey = parentKeyFromCollectionId(group);\n\n if (parentKey === undefined) {\n return null;\n }\n\n const parentNode = parentKey == null\n ? null\n : findSortableTreeNode(nodes, parentKey);\n\n if (parentKey != null && !parentNode) {\n return null;\n }\n\n const isAfterTarget = targetNode != null && index > targetNode.index;\n\n return {\n parentNode,\n index,\n dropPosition: isAfterTarget ? 'after' : 'before',\n };\n}\n\nfunction collectionId<T>(parentNode: SortableTreeNode<T> | null): string {\n return collectionIdFromParentKey(parentNode?.id ?? null);\n}\n\nfunction collectionIdFromParentKey(parentKey: string | null): string {\n return parentKey == null\n ? ROOT_COLLECTION_ID\n : `${ CHILD_COLLECTION_PREFIX }${ parentKey }`;\n}\n\nfunction parentKeyFromCollectionId(\n collectionId: string | number | undefined\n): string | null | undefined {\n if (collectionId === ROOT_COLLECTION_ID) {\n return null;\n }\n\n if (typeof collectionId === 'string'\n && collectionId.startsWith(CHILD_COLLECTION_PREFIX)) {\n return collectionId.slice(CHILD_COLLECTION_PREFIX.length);\n }\n\n return undefined;\n}\n\nfunction nodeParentKey<T>(\n nodes: readonly SortableTreeNode<T>[],\n target: SortableTreeNode<T>\n): string | null {\n return findParentNode(nodes, target)?.id ?? null;\n}\n\nfunction findParentNode<T>(\n nodes: readonly SortableTreeNode<T>[],\n target: SortableTreeNode<T>\n): SortableTreeNode<T> | null {\n for (const node of nodes) {\n if (node.children.some(child => child.id === target.id)) {\n return node;\n }\n\n const parent = findParentNode(node.children, target);\n\n if (parent) {\n return parent;\n }\n }\n\n return null;\n}\n\nfunction entityData<T>(\n entity: { data: Record<string, unknown> } | null\n): SortableNodeData<T> | SortableCollectionData<T> | null {\n const data = entity?.data;\n\n if (data?.kind === 'node' && 'node' in data) {\n return {\n kind: 'node',\n node: data.node as SortableTreeNode<T>,\n };\n }\n\n if (data?.kind === 'collection' && 'parentNode' in data) {\n return {\n kind: 'collection',\n parentNode: data.parentNode as SortableTreeNode<T> | null,\n };\n }\n\n return null;\n}\n\nfunction nodeData<T>(\n entity: { data: Record<string, unknown> } | null\n): SortableNodeData<T> | null {\n const data = entityData<T>(entity);\n\n return data?.kind === 'node' ? data : null;\n}\n\nSortableList.displayName = 'SortableList';\n"],"names":["ROOT_COLLECTION_ID","CHILD_COLLECTION_PREFIX","SORTABLE_ITEM_TYPE","SORTABLE_COLLECTION_TYPE","POINTER_SENSORS","PointerSensor","PRIMITIVE_KEY_PREFIX","objectKeys","nextObjectKey","SortableList","items","getItemKey","getTextValue","getChildren","setChildren","canHaveChildren","onChange","children","canDrop","getDragHandleOptions","className","gap","nestedGap","handle","ariaLabel","getNodeKey","useCallback","item","path","itemKey","existingKey","key","nodes","useMemo","buildSortableTree","renderState","setRenderState","useState","handleDragEnd","event","canceled","operation","source","target","isSortable","sourceNode","nodeData","targetData","entityData","targetNode","destination","destinationFromSortable","context","createDropContext","canMoveToParent","initialParentKey","parentKeyFromCollectionId","destinationParentKey","movedNodes","moveSortableTreeNodeToIndex","restoreSortableTree","_jsxs","DragDropProvider","_jsx","SortableCollection","DragOverlay","styles","node","SortablePreview","rootNodes","parentNode","renderItem","ref","isDropTarget","useDroppable","collectionId","canAcceptDrop","cn","For","SortableItem","itemContext","alignment","edgeOffset","variant","handleRef","targetRef","isDragging","useSortable","collectionIdFromParentKey","nodeParentKey","findParentNode","nestedItems","Show","DotsDrag","child","dropPosition","findSortableTreeNode","group","index","parentKey","isAfterTarget","parent","entity","data"],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ButtonColor } from '../../Button';
|
|
1
2
|
import type { HTMLAttributes, ReactNode } from 'react';
|
|
2
3
|
export type ComposerBannerProps = Omit<HTMLAttributes<HTMLDivElement>, 'color'> & {
|
|
3
4
|
children?: ReactNode;
|
|
@@ -10,8 +11,12 @@ export type ComposerBannerStatusProps = HTMLAttributes<HTMLDivElement> & {
|
|
|
10
11
|
children: ReactNode;
|
|
11
12
|
action: string;
|
|
12
13
|
onAction?: () => void;
|
|
14
|
+
/** Action button tint. Default `secondary`. */
|
|
15
|
+
actionColor?: ButtonColor;
|
|
16
|
+
/** Press anywhere on the row except the action. The action then shows on hover or focus. */
|
|
17
|
+
onPress?: () => void;
|
|
13
18
|
icon?: ReactNode;
|
|
14
19
|
};
|
|
15
20
|
/** One status row inside {@link ComposerBanner} — message + action. */
|
|
16
|
-
export declare function ComposerBannerStatus({ children, action, onAction, icon, className, ...props }: ComposerBannerStatusProps): import("react").JSX.Element;
|
|
21
|
+
export declare function ComposerBannerStatus({ children, action, onAction, actionColor, onPress, icon, className, ...props }: ComposerBannerStatusProps): import("react").JSX.Element;
|
|
17
22
|
//# sourceMappingURL=ComposerBanner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComposerBanner.d.ts","sourceRoot":"","sources":["../../../src/chat/ComposerBanner/ComposerBanner.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ComposerBanner.d.ts","sourceRoot":"","sources":["../../../src/chat/ComposerBanner/ComposerBanner.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAU,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAMxD,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvD,MAAM,MAAM,mBAAmB,GAAG,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC,GAAG;IAC9E,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,yDAAyD;IACzD,KAAK,CAAC,EAAE,QAAQ,CAAC;CACpB,CAAC;AAEF,qDAAqD;AACrD,wBAAgB,cAAc,CAAC,EAC3B,QAAQ,EACR,SAAS,EACT,KAAK,EACL,IAAI,EACJ,GAAG,KAAK,EACX,EAAE,mBAAmB,+BAYrB;AAED,MAAM,MAAM,yBAAyB,GAAG,cAAc,CAAC,cAAc,CAAC,GAAG;IACrE,QAAQ,EAAE,SAAS,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,4FAA4F;IAC5F,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,IAAI,CAAC,EAAE,SAAS,CAAC;CACpB,CAAC;AAEF,uEAAuE;AACvE,wBAAgB,oBAAoB,CAAC,EACjC,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,WAAyB,EACzB,OAAO,EACP,IAAI,EACJ,SAAS,EACT,GAAG,KAAK,EACX,EAAE,yBAAyB,+BAsC3B"}
|
|
@@ -1,58 +1,78 @@
|
|
|
1
|
-
import { cn as
|
|
2
|
-
import { Button as
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { cn as d } from "@reforma/lib";
|
|
2
|
+
import { Button as u } from "../../Button/Button.js";
|
|
3
|
+
import { Pressable as x } from "react-aria-components";
|
|
4
|
+
import { Show as m } from "../../Show/Show.js";
|
|
5
|
+
import { Text as b } from "../../Text/Text.js";
|
|
5
6
|
import e from "./ComposerBanner.module.css.js";
|
|
6
|
-
import { jsx as
|
|
7
|
-
function
|
|
8
|
-
children:
|
|
9
|
-
className:
|
|
10
|
-
color:
|
|
11
|
-
role:
|
|
12
|
-
...
|
|
7
|
+
import { jsx as r, jsxs as c, Fragment as v } from "react/jsx-runtime";
|
|
8
|
+
function P({
|
|
9
|
+
children: o,
|
|
10
|
+
className: t,
|
|
11
|
+
color: s,
|
|
12
|
+
role: n,
|
|
13
|
+
...a
|
|
13
14
|
}) {
|
|
14
|
-
return /* @__PURE__ */
|
|
15
|
+
return /* @__PURE__ */ r("div", {
|
|
15
16
|
"data-slot": "composer-banner",
|
|
16
|
-
"data-color":
|
|
17
|
-
role:
|
|
18
|
-
className:
|
|
19
|
-
...
|
|
20
|
-
children:
|
|
17
|
+
"data-color": s,
|
|
18
|
+
role: n ?? (s === "danger" ? "alert" : void 0),
|
|
19
|
+
className: d(e.root, t),
|
|
20
|
+
...a,
|
|
21
|
+
children: o
|
|
21
22
|
});
|
|
22
23
|
}
|
|
23
|
-
function
|
|
24
|
-
children:
|
|
25
|
-
action:
|
|
26
|
-
onAction:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
function S({
|
|
25
|
+
children: o,
|
|
26
|
+
action: t,
|
|
27
|
+
onAction: s,
|
|
28
|
+
actionColor: n = "secondary",
|
|
29
|
+
onPress: a,
|
|
30
|
+
icon: i,
|
|
31
|
+
className: p,
|
|
32
|
+
...h
|
|
30
33
|
}) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
when: s,
|
|
36
|
-
children: /* @__PURE__ */ o("span", {
|
|
34
|
+
const l = /* @__PURE__ */ c(v, {
|
|
35
|
+
children: [/* @__PURE__ */ r(m, {
|
|
36
|
+
when: i,
|
|
37
|
+
children: /* @__PURE__ */ r("span", {
|
|
37
38
|
className: e.icon,
|
|
38
|
-
children:
|
|
39
|
+
children: i
|
|
39
40
|
})
|
|
40
|
-
}), /* @__PURE__ */
|
|
41
|
+
}), /* @__PURE__ */ r(b, {
|
|
41
42
|
variant: "xs",
|
|
42
43
|
className: e.text,
|
|
43
|
-
children:
|
|
44
|
-
})
|
|
44
|
+
children: o
|
|
45
|
+
})]
|
|
46
|
+
});
|
|
47
|
+
return /* @__PURE__ */ c("div", {
|
|
48
|
+
className: d(e.status, p),
|
|
49
|
+
"data-pressable": a ? !0 : void 0,
|
|
50
|
+
...h,
|
|
51
|
+
children: [/* @__PURE__ */ r(m, {
|
|
52
|
+
when: a,
|
|
53
|
+
fallback: l,
|
|
54
|
+
children: (f) => /* @__PURE__ */ r(x, {
|
|
55
|
+
onPress: f,
|
|
56
|
+
children: /* @__PURE__ */ r("span", {
|
|
57
|
+
role: "button",
|
|
58
|
+
tabIndex: 0,
|
|
59
|
+
className: e.press,
|
|
60
|
+
children: l
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
}), /* @__PURE__ */ r(u, {
|
|
45
64
|
size: "xs",
|
|
46
65
|
variant: "ghost",
|
|
47
|
-
color:
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
66
|
+
color: n,
|
|
67
|
+
className: e.action,
|
|
68
|
+
isDisabled: !s,
|
|
69
|
+
onPress: s,
|
|
70
|
+
children: t
|
|
51
71
|
})]
|
|
52
72
|
});
|
|
53
73
|
}
|
|
54
74
|
export {
|
|
55
|
-
|
|
56
|
-
|
|
75
|
+
P as ComposerBanner,
|
|
76
|
+
S as ComposerBannerStatus
|
|
57
77
|
};
|
|
58
78
|
//# sourceMappingURL=ComposerBanner.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComposerBanner.js","sources":["../../../src/chat/ComposerBanner/ComposerBanner.tsx"],"sourcesContent":["import { cn } from '@reforma/lib';\n\nimport { Button } from '../../Button';\nimport { Show } from '../../Show';\nimport { Text } from '../../Text';\nimport styles from './ComposerBanner.module.css';\n\nimport type { HTMLAttributes, ReactNode } from 'react';\n\nexport type ComposerBannerProps = Omit<HTMLAttributes<HTMLDivElement>, 'color'> & {\n children?: ReactNode;\n /** Plate tint. Default is the muted interrupt chrome. */\n color?: 'danger';\n};\n\n/** Shared plate above the composer — chrome only. */\nexport function ComposerBanner({\n children,\n className,\n color,\n role,\n ...props\n}: ComposerBannerProps) {\n return (\n <div\n data-slot=\"composer-banner\"\n data-color={ color }\n role={ role ?? (color === 'danger' ? 'alert' : undefined) }\n className={ cn(styles.root, className) }\n { ...props }\n >\n { children }\n </div>\n );\n}\n\nexport type ComposerBannerStatusProps = HTMLAttributes<HTMLDivElement> & {\n children: ReactNode;\n action: string;\n onAction?: () => void;\n icon?: ReactNode;\n};\n\n/** One status row inside {@link ComposerBanner} — message + action. */\nexport function ComposerBannerStatus({\n children,\n action,\n onAction,\n icon,\n className,\n ...props\n}: ComposerBannerStatusProps) {\n
|
|
1
|
+
{"version":3,"file":"ComposerBanner.js","sources":["../../../src/chat/ComposerBanner/ComposerBanner.tsx"],"sourcesContent":["import { cn } from '@reforma/lib';\n\nimport { Button, type ButtonColor } from '../../Button';\nimport { Pressable } from '../../Pressable';\nimport { Show } from '../../Show';\nimport { Text } from '../../Text';\nimport styles from './ComposerBanner.module.css';\n\nimport type { HTMLAttributes, ReactNode } from 'react';\n\nexport type ComposerBannerProps = Omit<HTMLAttributes<HTMLDivElement>, 'color'> & {\n children?: ReactNode;\n /** Plate tint. Default is the muted interrupt chrome. */\n color?: 'danger';\n};\n\n/** Shared plate above the composer — chrome only. */\nexport function ComposerBanner({\n children,\n className,\n color,\n role,\n ...props\n}: ComposerBannerProps) {\n return (\n <div\n data-slot=\"composer-banner\"\n data-color={ color }\n role={ role ?? (color === 'danger' ? 'alert' : undefined) }\n className={ cn(styles.root, className) }\n { ...props }\n >\n { children }\n </div>\n );\n}\n\nexport type ComposerBannerStatusProps = HTMLAttributes<HTMLDivElement> & {\n children: ReactNode;\n action: string;\n onAction?: () => void;\n /** Action button tint. Default `secondary`. */\n actionColor?: ButtonColor;\n /** Press anywhere on the row except the action. The action then shows on hover or focus. */\n onPress?: () => void;\n icon?: ReactNode;\n};\n\n/** One status row inside {@link ComposerBanner} — message + action. */\nexport function ComposerBannerStatus({\n children,\n action,\n onAction,\n actionColor = 'secondary',\n onPress,\n icon,\n className,\n ...props\n}: ComposerBannerStatusProps) {\n const message = (\n <>\n <Show when={ icon }>\n <span className={ styles.icon }>\n { icon }\n </span>\n </Show>\n <Text variant=\"xs\" className={ styles.text }>\n { children }\n </Text>\n </>\n );\n\n return (\n <div className={ cn(styles.status, className) } data-pressable={ onPress ? true : undefined } { ...props }>\n <Show when={ onPress } fallback={ message }>\n { press => (\n <Pressable onPress={ press }>\n <span role=\"button\" tabIndex={ 0 } className={ styles.press }>\n { message }\n </span>\n </Pressable>\n ) }\n </Show>\n\n <Button\n size=\"xs\"\n variant=\"ghost\"\n color={ actionColor }\n className={ styles.action }\n isDisabled={ !onAction }\n onPress={ onAction }\n >\n { action }\n </Button>\n </div>\n );\n}\n"],"names":["ComposerBanner","children","className","color","role","props","cn","styles","ComposerBannerStatus","action","onAction","actionColor","onPress","icon","message","_Fragment","_jsx","Show","Text","press","Pressable","Button"],"mappings":";;;;;;;AAQO,SAASA,EAAe;AAAA,EAC7B,UAAAC;AAAA,EACA,WAAAC;AAAA,EACA,OAAAC;AAAA,EACA,MAAAC;AAAA,EACA,GAAGC;AACL,GAAG;AACD,2BAAyB,OAAO;AAAA,IAC9B,aAAa;AAAA,IACb,cAAcF;AAAA,IACd,MAAMC,MAASD,MAAU,WAAW,UAAU;AAAA,IAC9C,WAAWG,EAAGC,EAAO,MAAML,CAAS;AAAA,IACpC,GAAGG;AAAA,IACH,UAAAJ;AAAA,EAAA,CACD;AACH;AAEO,SAASO,EAAqB;AAAA,EACnC,UAAAP;AAAA,EACA,QAAAQ;AAAA,EACA,UAAAC;AAAA,EACA,aAAAC,IAAc;AAAA,EACd,SAAAC;AAAA,EACA,MAAAC;AAAA,EACA,WAAAX;AAAA,EACA,GAAGG;AACL,GAAG;AACD,QAAMS,sBAA6BC,GAAW;AAAA,IAC5C,UAAU,CAAcC,gBAAAA,EAAKC,GAAM;AAAA,MACjC,MAAMJ;AAAA,MACN,4BAA4B,QAAQ;AAAA,QAClC,WAAWN,EAAO;AAAA,QAClB,UAAUM;AAAA,MAAA,CACX;AAAA,IAAA,CACF,GAAgBG,gBAAAA,EAAKE,GAAM;AAAA,MAC1B,SAAS;AAAA,MACT,WAAWX,EAAO;AAAA,MAClB,UAAAN;AAAA,IAAA,CACD,CAAC;AAAA,EAAA,CACH;AACD,2BAA0B,OAAO;AAAA,IAC/B,WAAWK,EAAGC,EAAO,QAAQL,CAAS;AAAA,IACtC,kBAAkBU,IAAU,KAAO;AAAA,IACnC,GAAGP;AAAA,IACH,UAAU,CAAcW,gBAAAA,EAAKC,GAAM;AAAA,MACjC,MAAML;AAAA,MACN,UAAUE;AAAA,MACV,UAAU,CAAAK,MAAsBH,gBAAAA,EAAKI,GAAW;AAAA,QAC9C,SAASD;AAAA,QACT,4BAA4B,QAAQ;AAAA,UAClC,MAAM;AAAA,UACN,UAAU;AAAA,UACV,WAAWZ,EAAO;AAAA,UAClB,UAAUO;AAAA,QAAA,CACX;AAAA,MAAA,CACF;AAAA,IAAA,CACF,GAAgBE,gBAAAA,EAAKK,GAAQ;AAAA,MAC5B,MAAM;AAAA,MACN,SAAS;AAAA,MACT,OAAOV;AAAA,MACP,WAAWJ,EAAO;AAAA,MAClB,YAAY,CAACG;AAAA,MACb,SAASA;AAAA,MACT,UAAUD;AAAA,IAAA,CACX,CAAC;AAAA,EAAA,CACH;AACH;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
@layer components{.ComposerBanner_root_HyjFf2{display:flex;flex-direction:column;margin:0 var(--spacing-md);border-top-right-radius:calc(var(--radius-md) * var(--squircle-radius-factor));border-top-left-radius:calc(var(--radius-md) * var(--squircle-radius-factor));min-width:0;corner-shape:superellipse(var(--squircle-value)) superellipse(var(--squircle-value)) square square;background-color:var(--color-secondary-muted-light);overflow:hidden}.dark .ComposerBanner_root_HyjFf2:not([data-color]){background-color:var(--color-light-700)}.ComposerBanner_root_HyjFf2[data-color=danger]{background-color:var(--color-danger-muted-light);color:var(--color-danger-text)}.ComposerBanner_status_EIdxnS+.ComposerBanner_status_EIdxnS{position:relative}.ComposerBanner_status_EIdxnS+.ComposerBanner_status_EIdxnS:before{position:absolute;top:0;right:var(--spacing-sm);left:var(--spacing-sm);border-top:1px solid var(--color-secondary-muted-border);content:""}.ComposerBanner_root_HyjFf2[data-color=danger] .ComposerBanner_status_EIdxnS+.ComposerBanner_status_EIdxnS:before{border-top-color:var(--color-danger-muted-border)}.ComposerBanner_status_EIdxnS{display:flex;justify-content:space-between;align-items:center;gap:var(--spacing-sm);padding:var(--spacing-sm) var(--spacing-sm) var(--spacing-sm) var(--spacing-lg);word-wrap:break-word}.ComposerBanner_icon_5Md4lZ{display:flex;flex-shrink:0;color:var(--color-secondary-muted-text)}.ComposerBanner_text_UFktfG{flex:1;max-height:3lh;overflow:hidden}}
|
|
1
|
+
@layer components{.ComposerBanner_root_HyjFf2{display:flex;flex-direction:column;margin:0 var(--spacing-md);border-top-right-radius:calc(var(--radius-md) * var(--squircle-radius-factor));border-top-left-radius:calc(var(--radius-md) * var(--squircle-radius-factor));min-width:0;corner-shape:superellipse(var(--squircle-value)) superellipse(var(--squircle-value)) square square;background-color:var(--color-secondary-muted-light);overflow:hidden}.dark .ComposerBanner_root_HyjFf2:not([data-color]){background-color:var(--color-light-700)}.ComposerBanner_root_HyjFf2[data-color=danger]{background-color:var(--color-danger-muted-light);color:var(--color-danger-text)}.ComposerBanner_status_EIdxnS+.ComposerBanner_status_EIdxnS{position:relative}.ComposerBanner_status_EIdxnS+.ComposerBanner_status_EIdxnS:before{position:absolute;top:0;right:var(--spacing-sm);left:var(--spacing-sm);border-top:1px solid var(--color-secondary-muted-border);content:""}.ComposerBanner_root_HyjFf2[data-color=danger] .ComposerBanner_status_EIdxnS+.ComposerBanner_status_EIdxnS:before{border-top-color:var(--color-danger-muted-border)}.ComposerBanner_status_EIdxnS{display:flex;justify-content:space-between;align-items:center;gap:var(--spacing-sm);padding:var(--spacing-sm) var(--spacing-sm) var(--spacing-sm) var(--spacing-lg);word-wrap:break-word}.ComposerBanner_icon_5Md4lZ{display:flex;flex-shrink:0;color:var(--color-secondary-muted-text)}.ComposerBanner_text_UFktfG{flex:1;max-height:3lh;overflow:hidden}.ComposerBanner_status_EIdxnS[data-pressable]{position:relative;isolation:isolate;min-height:calc(var(--spacing-30) + var(--spacing-xs) * 2)}.ComposerBanner_status_EIdxnS[data-pressable]:after{position:absolute;z-index:-1;inset:var(--spacing-xs);border-radius:calc(var(--radius-sm) * var(--squircle-radius-factor));content:"";corner-shape:superellipse(var(--squircle-value));transition:background-color var(--transition-duration-fast);pointer-events:none}.ComposerBanner_status_EIdxnS[data-pressable]:hover:after{background-color:var(--color-secondary-muted-light)}@media(hover:hover){.ComposerBanner_status_EIdxnS[data-pressable] .ComposerBanner_action_EUqshm{opacity:0;transition:opacity var(--transition-duration-fast)}.ComposerBanner_status_EIdxnS[data-pressable]:hover .ComposerBanner_action_EUqshm,.ComposerBanner_status_EIdxnS[data-pressable]:focus-within .ComposerBanner_action_EUqshm{opacity:1}}.ComposerBanner_press_FFVYdF{display:flex;flex:1;align-items:center;gap:var(--spacing-sm);cursor:pointer;outline:none;min-width:0}.ComposerBanner_press_FFVYdF:after{position:absolute;inset:0;content:""}.ComposerBanner_press_FFVYdF:focus-visible:after{outline:var(--spacing-4) solid var(--color-primary-muted-border);outline-offset:calc(var(--spacing-4) * -1)}.ComposerBanner_action_EUqshm{position:relative}}
|
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
const
|
|
2
|
-
root:
|
|
3
|
-
status:
|
|
4
|
-
icon:
|
|
5
|
-
text: n
|
|
1
|
+
const o = "ComposerBanner_root_HyjFf2", s = "ComposerBanner_status_EIdxnS", t = "ComposerBanner_icon_5Md4lZ", n = "ComposerBanner_text_UFktfG", e = "ComposerBanner_action_EUqshm", r = "ComposerBanner_press_FFVYdF", a = {
|
|
2
|
+
root: o,
|
|
3
|
+
status: s,
|
|
4
|
+
icon: t,
|
|
5
|
+
text: n,
|
|
6
|
+
action: e,
|
|
7
|
+
press: r
|
|
6
8
|
};
|
|
7
9
|
export {
|
|
8
|
-
e as
|
|
9
|
-
|
|
10
|
-
t as
|
|
11
|
-
|
|
10
|
+
e as action,
|
|
11
|
+
a as default,
|
|
12
|
+
t as icon,
|
|
13
|
+
r as press,
|
|
14
|
+
o as root,
|
|
15
|
+
s as status,
|
|
12
16
|
n as text
|
|
13
17
|
};
|
|
14
18
|
//# sourceMappingURL=ComposerBanner.module.css.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComposerBanner.module.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ComposerBanner.module.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConversationPendingLoader.d.ts","sourceRoot":"","sources":["../../../src/chat/Conversation/ConversationPendingLoader.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ConversationPendingLoader.d.ts","sourceRoot":"","sources":["../../../src/chat/Conversation/ConversationPendingLoader.tsx"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAE7D,MAAM,MAAM,8BAA8B,GAAG;IACzC,sFAAsF;IACtF,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,sGAAsG;IACtG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,SAAS,oBAAoB,EAAE,CAAC;IACxC,wEAAwE;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,oFAAoF;AACpF,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAmBnF;AAkDD,qEAAqE;AACrE,wBAAgB,yBAAyB,CAAC,EACtC,QAAQ,EACR,SAAS,EACT,KAAK,EACL,KAAK,EACL,IAAY,EACZ,SAAS,GACZ,EAAE,8BAA8B,sCAsChC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ProgressLoader as h } from "@reforma/icons/assets";
|
|
2
2
|
import { cn as p } from "@reforma/lib";
|
|
3
|
-
import { isReasoningUIPart as g, isTextUIPart as P, isToolUIPart as w } from "
|
|
3
|
+
import { isReasoningUIPart as g, isTextUIPart as P, isToolUIPart as w } from "@reforma/types";
|
|
4
4
|
import { useSyncExternalStore as v, useEffect as L } from "react";
|
|
5
5
|
import { Shimmer as S } from "../../Shimmer/Shimmer.js";
|
|
6
6
|
import { Show as T } from "../../Show/Show.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConversationPendingLoader.js","sources":["../../../src/chat/Conversation/ConversationPendingLoader.tsx"],"sourcesContent":["'use client';\n\nimport { ProgressLoader } from '@reforma/icons/assets';\nimport { cn } from '@reforma/lib';\nimport {
|
|
1
|
+
{"version":3,"file":"ConversationPendingLoader.js","sources":["../../../src/chat/Conversation/ConversationPendingLoader.tsx"],"sourcesContent":["'use client';\n\nimport { ProgressLoader } from '@reforma/icons/assets';\nimport { cn } from '@reforma/lib';\nimport { isReasoningUIPart, isTextUIPart, isToolUIPart } from '@reforma/types';\nimport { useEffect, useSyncExternalStore } from 'react';\n\nimport { Shimmer } from '../../Shimmer';\nimport { Show } from '../../Show';\nimport { Text } from '../../Text/Text';\nimport { isContextCompactionUIPart } from '../Message/parts/contextCompactionPart';\nimport { isToolInvocationInProgress } from '../Tool/helpers';\nimport { ToolShell, ToolShellHeader } from '../Tool/shell';\nimport styles from './ConversationPendingLoader.module.css';\nimport {\n appearPendingLoaderPhrase,\n getPendingLoaderPhraseSnapshot,\n hidePendingLoaderPhrase,\n msUntilPendingLoaderLongUpgrade,\n pendingLoaderScope,\n subscribePendingLoaderPhrase,\n upgradePendingLoaderPhrase,\n} from './pendingLoaderPhrase';\n\nimport type { ReformaUIMessagePart } from '../Message/types';\n\nexport type ConversationPendingLoaderProps = {\n /** Live assistant tail while streaming; omit for the pre-response submitted state. */\n lastPart?: ReformaUIMessagePart;\n /** Assistant message the wait belongs to. With `parts`, scopes the phrase to the current LLM step. */\n messageId?: string;\n /** Raw assistant parts, including invisible `step-start`. */\n parts?: readonly ReformaUIMessagePart[];\n /** Fixed shimmer label. Omit to rotate short / long pending phrases. */\n label?: string;\n /** Text-only shimmer (compact activity card). */\n bare?: boolean;\n className?: string;\n};\n\n/** True when the part already shows live UI, so the pending shimmer should hide. */\nexport function messagePartShowsPendingActivity(part: ReformaUIMessagePart): boolean {\n if (isContextCompactionUIPart(part)) {\n return !part.data.done;\n }\n\n // Streaming reasoning always shows chrome (\"Thinking...\" or a title), even with no body yet.\n if (isReasoningUIPart(part)) {\n return part.state !== 'done';\n }\n\n if (isTextUIPart(part)) {\n return part.state !== 'done' && part.text.trim().length > 0;\n }\n\n if (isToolUIPart(part)) {\n return isToolInvocationInProgress(part.state);\n }\n\n return false;\n}\n\nfunction usePendingLoaderPhrase(\n visible: boolean,\n label: string | undefined,\n messageId: string | undefined,\n parts: readonly ReformaUIMessagePart[] | undefined\n): string {\n const phrase = useSyncExternalStore(\n subscribePendingLoaderPhrase,\n getPendingLoaderPhraseSnapshot,\n getPendingLoaderPhraseSnapshot\n );\n const scope = parts ? pendingLoaderScope(messageId, parts) : undefined;\n const stepKey = scope?.stepKey;\n const progressKey = scope?.progressKey;\n\n useEffect(() => {\n if (label !== undefined || !visible) {\n return;\n }\n\n appearPendingLoaderPhrase(\n Date.now(),\n stepKey !== undefined && progressKey !== undefined\n ? { stepKey, progressKey }\n : undefined\n );\n\n const wait = msUntilPendingLoaderLongUpgrade(Date.now());\n\n if (wait === null) {\n return () => {\n hidePendingLoaderPhrase(Date.now());\n };\n }\n\n const timer = window.setTimeout(() => {\n upgradePendingLoaderPhrase(Date.now());\n }, wait);\n\n return () => {\n window.clearTimeout(timer);\n hidePendingLoaderPhrase(Date.now());\n };\n }, [label, progressKey, stepKey, visible]);\n\n return label ?? phrase;\n}\n\n/** Pending indicator at the bottom of a live conversation thread. */\nexport function ConversationPendingLoader({\n lastPart,\n messageId,\n parts,\n label,\n bare = false,\n className,\n}: ConversationPendingLoaderProps) {\n const visible = !(lastPart && messagePartShowsPendingActivity(lastPart));\n const phrase = usePendingLoaderPhrase(visible, label, messageId, parts);\n const shown = visible && Boolean(phrase);\n\n if (bare) {\n return (\n <Text\n className={ cn(styles.root, className) }\n data-hidden={ shown ? undefined : true }\n role=\"status\"\n aria-hidden={ shown ? undefined : true }\n aria-label={ shown ? phrase : undefined }\n >\n <Show when={ phrase }>\n { text => (\n <span className={ styles.phrase } key={ text }>\n <Shimmer duration={ 1 }>{text}</Shimmer>\n </span>\n ) }\n </Show>\n </Text>\n );\n }\n\n if (!shown) {\n return null;\n }\n\n return (\n <ToolShell className={ className } role=\"status\" aria-label={ phrase }>\n <ToolShellHeader\n state=\"input-streaming\"\n title={ phrase }\n icon={ <ProgressLoader size={ 14 } aria-hidden /> }\n />\n </ToolShell>\n );\n}\n"],"names":["messagePartShowsPendingActivity","part","isContextCompactionUIPart","isReasoningUIPart","isTextUIPart","isToolUIPart","isToolInvocationInProgress","usePendingLoaderPhrase","visible","label","messageId","parts","phrase","useSyncExternalStore","subscribePendingLoaderPhrase","getPendingLoaderPhraseSnapshot","scope","pendingLoaderScope","stepKey","progressKey","useEffect","appearPendingLoaderPhrase","wait","msUntilPendingLoaderLongUpgrade","hidePendingLoaderPhrase","timer","upgradePendingLoaderPhrase","ConversationPendingLoader","lastPart","bare","className","shown","Text","cn","styles","Show","text","_jsx","Shimmer","ToolShell","ToolShellHeader","ProgressLoader"],"mappings":";;;;;;;;;;;;;AAgBO,SAASA,EAAgCC,GAAM;AACpD,SAAIC,EAA0BD,CAAI,IACzB,CAACA,EAAK,KAAK,OAIhBE,EAAkBF,CAAI,IACjBA,EAAK,UAAU,SAEpBG,EAAaH,CAAI,IACZA,EAAK,UAAU,UAAUA,EAAK,KAAK,KAAA,EAAO,SAAS,IAExDI,EAAaJ,CAAI,IACZK,EAA2BL,EAAK,KAAK,IAEvC;AACT;AACA,SAASM,EAAuBC,GAASC,GAAOC,GAAWC,GAAO;AAChE,QAAMC,IAASC,EAAqBC,GAA8BC,GAAgCA,CAA8B,GAC1HC,IAAQL,IAAQM,EAAmBP,GAAWC,CAAK,IAAI,QACvDO,IAAUF,GAAO,SACjBG,IAAcH,GAAO;AAC3B,SAAAI,EAAU,MAAM;AACd,QAAIX,MAAU,UAAa,CAACD;AAC1B;AAEF,IAAAa,EAA0B,KAAK,IAAA,GAAOH,MAAY,UAAaC,MAAgB,SAAY;AAAA,MACzF,SAAAD;AAAA,MACA,aAAAC;AAAA,IAAA,IACE,MAAS;AACb,UAAMG,IAAOC,EAAgC,KAAK,IAAA,CAAK;AACvD,QAAID,MAAS;AACX,aAAO,MAAM;AACX,QAAAE,EAAwB,KAAK,KAAK;AAAA,MACpC;AAEF,UAAMC,IAAQ,OAAO,WAAW,MAAM;AACpC,MAAAC,EAA2B,KAAK,KAAK;AAAA,IACvC,GAAGJ,CAAI;AACP,WAAO,MAAM;AACX,aAAO,aAAaG,CAAK,GACzBD,EAAwB,KAAK,KAAK;AAAA,IACpC;AAAA,EACF,GAAG,CAACf,GAAOU,GAAaD,GAASV,CAAO,CAAC,GAClCC,KAASG;AAClB;AAGO,SAASe,EAA0B;AAAA,EACxC,UAAAC;AAAA,EACA,WAAAlB;AAAA,EACA,OAAAC;AAAA,EACA,OAAAF;AAAA,EACA,MAAAoB,IAAO;AAAA,EACP,WAAAC;AACF,GAAG;AACD,QAAMtB,IAAU,EAAEoB,KAAY5B,EAAgC4B,CAAQ,IAChEhB,IAASL,EAAuBC,GAASC,GAAOC,GAAWC,CAAK,GAChEoB,IAAQvB,KAAW,EAAQI;AACjC,SAAIiB,sBACuBG,GAAM;AAAA,IAC7B,WAAWC,EAAGC,EAAO,MAAMJ,CAAS;AAAA,IACpC,eAAeC,IAAQ,SAAY;AAAA,IACnC,MAAM;AAAA,IACN,eAAeA,IAAQ,SAAY;AAAA,IACnC,cAAcA,IAAQnB,IAAS;AAAA,IAC/B,4BAA4BuB,GAAM;AAAA,MAChC,MAAMvB;AAAA,MACN,UAAU,CAAAwB,MAAqBC,gBAAAA,EAAK,QAAQ;AAAA,QAC1C,WAAWH,EAAO;AAAA,QAClB,4BAA4BI,GAAS;AAAA,UACnC,UAAU;AAAA,UACV,UAAUF;AAAA,QAAA,CACX;AAAA,MAAA,GACAA,CAAI;AAAA,IAAA,CACR;AAAA,EAAA,CACF,IAEEL,sBAGoBQ,GAAW;AAAA,IAClC,WAAAT;AAAA,IACA,MAAM;AAAA,IACN,cAAclB;AAAA,IACd,4BAA4B4B,GAAiB;AAAA,MAC3C,OAAO;AAAA,MACP,OAAO5B;AAAA,MACP,wBAAwB6B,GAAgB;AAAA,QACtC,MAAM;AAAA,QACN,eAAe;AAAA,MAAA,CAChB;AAAA,IAAA,CACF;AAAA,EAAA,CACF,IAdQ;AAeX;"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type FileUIPart, type ReasoningUIPart, type SourceDocumentUIPart, type SourceUrlUIPart, type ToolUIPart } from 'ai';
|
|
2
1
|
import { type ContextCompactionUIPart } from '../parts/contextCompactionPart';
|
|
2
|
+
import type { FileUIPart, ReasoningUIPart, SourceDocumentUIPart, SourceUrlUIPart, ToolUIPart } from 'ai';
|
|
3
3
|
import type { ReformaUIMessagePart } from '../types';
|
|
4
4
|
export type MessageSegmentLayout = 'grouped' | 'ungrouped';
|
|
5
5
|
/** Step markers and UI-less tools — dropped before normalization. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"normalizeMessageParts.d.ts","sourceRoot":"","sources":["../../../../src/chat/Message/normalize/normalizeMessageParts.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"normalizeMessageParts.d.ts","sourceRoot":"","sources":["../../../../src/chat/Message/normalize/normalizeMessageParts.ts"],"names":[],"mappings":"AAcA,OAAO,EAA6B,KAAK,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAGzG,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,oBAAoB,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AACzG,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAErD,MAAM,MAAM,oBAAoB,GAAG,SAAS,GAAG,WAAW,CAAC;AAE3D,qEAAqE;AACrE,eAAO,MAAM,oBAAoB,aAY/B,CAAC;AAEH,oFAAoF;AACpF,MAAM,MAAM,gBAAgB,GACpB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,UAAU,EAAE,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,CAAC,eAAe,GAAG,oBAAoB,CAAC,EAAE,CAAA;CAAE,GACtE;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,uBAAuB,EAAE,CAAA;CAAE,GACxD;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,eAAe,EAAE,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,oBAAoB,CAAA;CAAE,CAAC;AAEvD,MAAM,MAAM,cAAc,GAAG;IACzB,MAAM,EAAE,oBAAoB,CAAC;IAC7B,MAAM,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACpC,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,kGAAkG;AAClG,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,GAAG,oBAAoB,EAAE,CAElG;AAwBD;;GAEG;AACH,wBAAgB,8BAA8B,CAC1C,KAAK,EAAE,SAAS,oBAAoB,EAAE,GACvC,UAAU,GAAG,SAAS,CAcxB;AAQD;;GAEG;AACH,wBAAgB,oCAAoC,CAChD,KAAK,EAAE,SAAS,oBAAoB,EAAE,GACvC,UAAU,GAAG,SAAS,CAcxB;AAuBD,gGAAgG;AAChG,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,SAAS,oBAAoB,EAAE,GAAG,OAAO,CAEtF;AAED,0FAA0F;AAC1F,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,SAAS,oBAAoB,EAAE,GAAG,OAAO,CAQtF;AAED,wFAAwF;AACxF,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,GAAG,OAAO,CAEtF;AAaD,wBAAgB,aAAa,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CA0CjE;AA2DD,qEAAqE;AACrE,wBAAgB,yBAAyB,CACrC,QAAQ,EAAE,SAAS,cAAc,EAAE,EACnC,WAAW,EAAE,OAAO,GACrB,MAAM,CAgBR;AAwCD,2FAA2F;AAC3F,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,SAAS,oBAAoB,EAAE,GAAG,gBAAgB,EAAE,CAmB5F;AAED,0DAA0D;AAC1D,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,SAAS,oBAAoB,EAAE,GAAG;IAC3E,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CAChB,CAcA;AAED,wCAAwC;AACxC,wBAAgB,yBAAyB,CACrC,MAAM,EAAE,SAAS,gBAAgB,EAAE,GACpC,oBAAoB,GAAG,SAAS,CAQlC;AAoCD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,GAAG,cAAc,EAAE,CA8CpF;AA2BD,uGAAuG;AACvG,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,oBAAoB,EAAE,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAuCnG"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isStaticToolUIPart as s, getToolName as l, isDataUIPart as b, isTextUIPart as a, isReasoningUIPart as d, isToolUIPart as f, isFileUIPart as T } from "
|
|
1
|
+
import { isStaticToolUIPart as s, getToolName as l, isDataUIPart as b, isTextUIPart as a, isReasoningUIPart as d, isToolUIPart as f, isFileUIPart as T } from "@reforma/types";
|
|
2
2
|
import { parseReasoningText as A } from "../../Reasoning/normalizeReasoningBody.js";
|
|
3
3
|
import { isToolInvocationTerminal as P } from "../../Tool/helpers.js";
|
|
4
4
|
import { parseCallDynamicToolInput as M } from "../../Tool/mcp-tools/parseCallDynamicToolInput.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"normalizeMessageParts.js","sources":["../../../../src/chat/Message/normalize/normalizeMessageParts.ts"],"sourcesContent":["import {\n getToolName,\n isDataUIPart,\n isFileUIPart,\n isReasoningUIPart,\n isStaticToolUIPart,\n isTextUIPart,\n isToolUIPart,\n type FileUIPart,\n type ReasoningUIPart,\n type SourceDocumentUIPart,\n type SourceUrlUIPart,\n type ToolUIPart,\n} from 'ai';\n\nimport { parseReasoningText } from '../../Reasoning/normalizeReasoningBody';\nimport { isToolInvocationTerminal } from '../../Tool/helpers';\nimport { parseCallDynamicToolInput } from '../../Tool/mcp-tools/parseCallDynamicToolInput';\nimport { isBackgroundResultUIPart } from '../parts/backgroundResultPart';\nimport { isContextCompactionUIPart, type ContextCompactionUIPart } from '../parts/contextCompactionPart';\nimport { isRedactedReasoningUIPart } from '../parts/redactedReasoningPart';\n\nimport type { ReformaUIMessagePart } from '../types';\n\nexport type MessageSegmentLayout = 'grouped' | 'ungrouped';\n\n/** Step markers and UI-less tools — dropped before normalization. */\nexport const INVISIBLE_PART_TYPES = new Set([\n 'step-start',\n 'tool-SetPhase',\n 'tool-TodoWrite',\n 'tool-ReadTodo',\n 'tool-Commit',\n // Frontend tools without chat UI — executed silently in the editor.\n 'tool-Navigate',\n // Direction phase exit. The reading stays on the thread for the model.\n 'tool-CommitDesignRead',\n // Reveals the preview. The status change is the UI; the thread stays quiet.\n 'tool-MarkProjectReady',\n]);\n\n/** Render unit: merged file/source/compaction siblings, or one SDK part per row. */\nexport type MessagePartGroup\n = | { kind: 'files'; parts: FileUIPart[] }\n | { kind: 'sources'; parts: (SourceUrlUIPart | SourceDocumentUIPart)[] }\n | { kind: 'compaction'; parts: ContextCompactionUIPart[] }\n | { kind: 'reasoning'; parts: ReasoningUIPart[] }\n | { kind: 'single'; part: ReformaUIMessagePart };\n\nexport type MessageSegment = {\n layout: MessageSegmentLayout;\n groups: readonly MessagePartGroup[];\n /** Start index in the grouped sequence (keys / DOM id prefixes). */\n index: number;\n};\n\n/** Single tool/text rows from a segment's groups (skips merged file/source/compaction groups). */\nexport function partsFromSegmentGroups(groups: readonly MessagePartGroup[]): ReformaUIMessagePart[] {\n return groups.flatMap(group => group.kind === 'single' ? [group.part] : []);\n}\n\nfunction partRequiresUserAction(part: ReformaUIMessagePart): boolean {\n if (!isStaticToolUIPart(part)) {\n return false;\n }\n\n // Answered Ask / design picker folds into the work phase; pending stays outside.\n const name = getToolName(part);\n\n return part.state === 'approval-requested'\n || (\n (name === 'AskUserQuestion' || name === 'ChooseDesignDirection')\n && part.state !== 'output-available'\n );\n}\n\n/** Pending AskUserQuestion — answered in the composer; thread shows a pointer row. */\nfunction isPendingAskUserQuestionPart(part: ReformaUIMessagePart): boolean {\n return isStaticToolUIPart(part)\n && getToolName(part) === 'AskUserQuestion'\n && (part.state === 'input-streaming' || part.state === 'input-available');\n}\n\n/**\n * Last unfinished tool on the assistant turn, when that tool is a pending AskUserQuestion.\n */\nexport function lastPendingAskUserQuestionPart(\n parts: readonly ReformaUIMessagePart[]\n): ToolUIPart | undefined {\n const part = parts.findLast((entry) => {\n if (!isToolUIPart(entry)) {\n return false;\n }\n\n return !isToolInvocationTerminal(entry.state);\n });\n\n if (!part || !isToolUIPart(part) || !isPendingAskUserQuestionPart(part)) {\n return undefined;\n }\n\n return part as ToolUIPart;\n}\n\nfunction isPendingChooseDesignDirectionPart(part: ReformaUIMessagePart): boolean {\n return isStaticToolUIPart(part)\n && getToolName(part) === 'ChooseDesignDirection'\n && (part.state === 'input-streaming' || part.state === 'input-available');\n}\n\n/**\n * Last unfinished tool on the assistant turn, when that tool is a pending ChooseDesignDirection.\n */\nexport function lastPendingChooseDesignDirectionPart(\n parts: readonly ReformaUIMessagePart[]\n): ToolUIPart | undefined {\n const part = parts.findLast((entry) => {\n if (!isToolUIPart(entry)) {\n return false;\n }\n\n return !isToolInvocationTerminal(entry.state);\n });\n\n if (!part || !isToolUIPart(part) || !isPendingChooseDesignDirectionPart(part)) {\n return undefined;\n }\n\n return part as ToolUIPart;\n}\n\n/** Tools that never join Explored/Edited/Setup chrome. */\nconst OUTSIDE_PHASE_TOOLS = new Set([\n 'Preamble',\n 'ReadPlan',\n 'CreatePlan',\n 'EditPlan',\n]);\n\n/** Pending ask/approval, Preamble, and plan cards. */\nfunction toolStaysOutsidePhase(part: ReformaUIMessagePart): boolean {\n if (partRequiresUserAction(part)) {\n return true;\n }\n\n if (!isStaticToolUIPart(part)) {\n return false;\n }\n\n return OUTSIDE_PHASE_TOOLS.has(getToolName(part));\n}\n\n/** True when any tool call is still open (including invisible frontend tools like Navigate). */\nexport function partsHaveOpenToolCalls(parts: readonly ReformaUIMessagePart[]): boolean {\n return parts.some(part => isToolUIPart(part) && !isToolInvocationTerminal(part.state));\n}\n\n/** True when the turn awaits approval, a pending question, or a design-direction pick. */\nexport function partsRequireUserAction(parts: readonly ReformaUIMessagePart[]): boolean {\n if (lastPendingAskUserQuestionPart(parts) || lastPendingChooseDesignDirectionPart(parts)) {\n return true;\n }\n\n const tail = parts.findLast(isVisiblePart);\n\n return tail ? partRequiresUserAction(tail) : false;\n}\n\n/** True when a grouped segment contains a tool awaiting user confirmation or answer. */\nexport function segmentRequiresUserAction(groups: readonly MessagePartGroup[]): boolean {\n return groups.some(group => group.kind === 'single' && partRequiresUserAction(group.part));\n}\n\n/** Gateway call whose inner tool has no chat row (Navigate, and the other silent tools). */\nfunction isInvisibleDynamicTool(part: ReformaUIMessagePart): boolean {\n if (!isStaticToolUIPart(part) || getToolName(part) !== 'CallDynamicTool') {\n return false;\n }\n\n const { toolName } = parseCallDynamicToolInput(part.input);\n\n return INVISIBLE_PART_TYPES.has(`tool-${ toolName }`);\n}\n\nexport function isVisiblePart(part: ReformaUIMessagePart): boolean {\n if (INVISIBLE_PART_TYPES.has(part.type) || isInvisibleDynamicTool(part)) {\n return false;\n }\n\n // Login plaque only; after the user responds the part stays in the thread for the model.\n if (isStaticToolUIPart(part) && getToolName(part) === 'McpAuth') {\n return part.state === 'approval-requested';\n }\n\n // Citations render in the message footer, not the body.\n if (part.type === 'source-url' || part.type === 'source-document') {\n return false;\n }\n\n if (isContextCompactionUIPart(part) || isBackgroundResultUIPart(part)) {\n return true;\n }\n\n if (isDataUIPart(part)) {\n return false;\n }\n\n // Empty / whitespace-only text — no Streamdown shell (avoids empty prose gap before pending).\n if (isTextUIPart(part) && !part.text.trim()) {\n return false;\n }\n\n if (isReasoningUIPart(part) && part.state === 'done') {\n const { body } = parseReasoningText(part.text);\n\n // Drop settled reasoning with no body — including title-only `**Heading**`.\n if (!body.trim()) {\n return false;\n }\n }\n\n if (isRedactedReasoningUIPart(part)) {\n return false;\n }\n\n return true;\n}\n\nfunction isSourceUIPart(part: ReformaUIMessagePart): part is SourceUrlUIPart | SourceDocumentUIPart {\n return part.type === 'source-url' || part.type === 'source-document';\n}\n\nfunction isReasoningGroup(group: MessagePartGroup): boolean {\n return group.kind === 'reasoning';\n}\n\n/** Text, Preamble, pending ask/approval, plan cards, files, or trailing compaction. */\nfunction isOutsideGroup(\n group: MessagePartGroup,\n groupIndex: number,\n groups: readonly MessagePartGroup[]\n): boolean {\n if (group.kind === 'files' || group.kind === 'sources') {\n return true;\n }\n\n if (group.kind === 'compaction') {\n return groupIndex === groups.length - 1;\n }\n\n if (group.kind !== 'single') {\n return false;\n }\n\n const { part } = group;\n\n return isTextUIPart(part) || toolStaysOutsidePhase(part);\n}\n\n/** Reasoning follows the next in-phase group. */\nfunction laterJoinsPhase(\n from: number,\n groups: readonly MessagePartGroup[]\n): boolean {\n for (let index = from + 1; index < groups.length; index++) {\n if (isReasoningGroup(groups[index])) {\n continue;\n }\n\n return !isOutsideGroup(groups[index], index, groups);\n }\n\n return false;\n}\n\n/** Text, Preamble, pending ask, plan, or files after a phase — ends streaming phase chrome. */\nfunction sealsStreamingPhase(group: MessagePartGroup): boolean {\n if (group.kind === 'files' || group.kind === 'sources' || group.kind === 'compaction') {\n return true;\n }\n\n return group.kind === 'single'\n && (isTextUIPart(group.part) || toolStaysOutsidePhase(group.part));\n}\n\n/** Last grouped phase that should keep streaming chrome, or `-1`. */\nexport function streamingPhaseActiveIndex(\n segments: readonly MessageSegment[],\n isStreaming: boolean\n): number {\n if (!isStreaming) {\n return -1;\n }\n\n const lastGrouped = segments.findLastIndex(segment => segment.layout === 'grouped');\n\n if (lastGrouped < 0) {\n return -1;\n }\n\n const sealed = segments\n .slice(lastGrouped + 1)\n .some(segment => segment.groups.some(sealsStreamingPhase));\n\n return sealed ? -1 : lastGrouped;\n}\n\ntype MergeableGroupKind = Exclude<MessagePartGroup['kind'], 'single'>;\n\nfunction mergeableGroupKind(part: ReformaUIMessagePart): MergeableGroupKind | null {\n if (isFileUIPart(part)) {\n return 'files';\n }\n\n if (isSourceUIPart(part)) {\n return 'sources';\n }\n\n if (isContextCompactionUIPart(part)) {\n return 'compaction';\n }\n\n if (isReasoningUIPart(part)) {\n return 'reasoning';\n }\n\n return null;\n}\n\nfunction appendToMergeableGroup(\n groups: MessagePartGroup[],\n kind: MergeableGroupKind,\n part: ReformaUIMessagePart\n): void {\n const last = groups.at(-1);\n\n if (last?.kind === kind) {\n last.parts.push(part as never);\n\n return;\n }\n\n groups.push({ kind, parts: [part] } as MessagePartGroup);\n}\n\n/** Filter invisible parts; merge consecutive files, sources, compaction, and reasoning. */\nexport function groupMessageParts(parts: readonly ReformaUIMessagePart[]): MessagePartGroup[] {\n const groups: MessagePartGroup[] = [];\n\n for (const part of parts) {\n if (!isVisiblePart(part)) {\n continue;\n }\n\n const kind = mergeableGroupKind(part);\n\n if (kind !== null) {\n appendToMergeableGroup(groups, kind, part);\n }\n else {\n groups.push({ kind: 'single', part });\n }\n }\n\n return groups;\n}\n\n/** User turns only carry file attachments and/or text. */\nexport function splitUserMessageParts(parts: readonly ReformaUIMessagePart[]): {\n files: FileUIPart[];\n text: string;\n} {\n const files: FileUIPart[] = [];\n const textChunks: string[] = [];\n\n for (const part of parts) {\n if (isFileUIPart(part)) {\n files.push(part);\n }\n else if (isTextUIPart(part) && part.text.trim()) {\n textChunks.push(part.text);\n }\n }\n\n return { files, text: textChunks.join('\\n') };\n}\n\n/** Last visible part in render order */\nexport function lastVisiblePartFromGroups(\n groups: readonly MessagePartGroup[]\n): ReformaUIMessagePart | undefined {\n const lastGroup = groups.at(-1);\n\n if (!lastGroup) {\n return undefined;\n }\n\n return lastGroup.kind === 'single' ? lastGroup.part : lastGroup.parts.at(-1);\n}\n\nfunction flushSegment(\n segments: MessageSegment[],\n layout: MessageSegmentLayout,\n slice: MessagePartGroup[],\n index: number\n): number {\n if (slice.length === 0) {\n return index;\n }\n\n const groups = slice.splice(0);\n\n segments.push({ layout, groups, index });\n\n return index + groups.length;\n}\n\nfunction phaseLayout(groups: readonly MessagePartGroup[]): MessageSegmentLayout {\n let tools = 0;\n\n for (const group of groups) {\n if (group.kind === 'single' && isToolUIPart(group.part)) {\n tools++;\n }\n }\n\n if (tools === 0) {\n return 'ungrouped';\n }\n\n // 2+ rows: two tools, or a tool plus reasoning.\n return groups.length >= 2 ? 'grouped' : 'ungrouped';\n}\n\n/**\n * One work phase vs ungrouped separators (text, Preamble, pending ask/approval, plan).\n * Answered Ask joins the phase.\n * `grouped` chrome when a phase has 2+ rows (tools and/or reasoning) and at least one tool.\n */\nexport function segmentMessage(groups: readonly MessagePartGroup[]): MessageSegment[] {\n if (groups.length === 0) {\n return [];\n }\n\n const segments: MessageSegment[] = [];\n let index = 0;\n const phaseRun: MessagePartGroup[] = [];\n const outsideRun: MessagePartGroup[] = [];\n\n const intoPhase = (group: MessagePartGroup) => {\n index = flushSegment(segments, 'ungrouped', outsideRun, index);\n phaseRun.push(group);\n };\n\n const outsidePhase = (group: MessagePartGroup) => {\n index = flushSegment(segments, phaseLayout(phaseRun), phaseRun, index);\n outsideRun.push(group);\n };\n\n for (const [groupIndex, group] of groups.entries()) {\n const phaseOpen = phaseRun.length > 0;\n\n if (isReasoningGroup(group)) {\n if (phaseOpen || laterJoinsPhase(groupIndex, groups)) {\n intoPhase(group);\n }\n else {\n outsidePhase(group);\n }\n\n continue;\n }\n\n if (isOutsideGroup(group, groupIndex, groups)) {\n outsidePhase(group);\n }\n else {\n intoPhase(group);\n }\n }\n\n index = flushSegment(segments, phaseLayout(phaseRun), phaseRun, index);\n flushSegment(segments, 'ungrouped', outsideRun, index);\n\n return segments;\n}\n\n/** Value equality: same reference first, then a cached JSON fingerprint for streaming inputs. */\nconst inputFingerprintCache = new WeakMap<object, string>();\n\nfunction streamingInputFingerprint(input: unknown): string {\n if (input === null || input === undefined) {\n return '';\n }\n\n if (typeof input !== 'object') {\n return `${ typeof input }:${ String(input) }`;\n }\n\n const cached = inputFingerprintCache.get(input);\n\n if (cached !== undefined) {\n return cached;\n }\n\n const fingerprint = JSON.stringify(input);\n\n inputFingerprintCache.set(input, fingerprint);\n\n return fingerprint;\n}\n\n/** Shallow part equality; text/reasoning also compare content (streaming may replace part objects). */\nexport function uiMessagePartEqual(left: ReformaUIMessagePart, right: ReformaUIMessagePart): boolean {\n if (left === right) {\n return true;\n }\n\n if (left.type !== right.type) {\n return false;\n }\n\n if (isTextUIPart(left) && isTextUIPart(right)) {\n return left.text === right.text;\n }\n\n if (isReasoningUIPart(left) && isReasoningUIPart(right)) {\n return left.text === right.text && left.state === right.state;\n }\n\n if (isContextCompactionUIPart(left) && isContextCompactionUIPart(right)) {\n return left.data.done === right.data.done;\n }\n\n if (isBackgroundResultUIPart(left) && isBackgroundResultUIPart(right)) {\n return left.data.text === right.data.text;\n }\n\n if (isStaticToolUIPart(left) && isStaticToolUIPart(right)) {\n if (left.toolCallId !== right.toolCallId || left.state !== right.state) {\n return false;\n }\n\n if (left.state === 'input-streaming') {\n return left.input === right.input\n || streamingInputFingerprint(left.input) === streamingInputFingerprint(right.input);\n }\n\n return true;\n }\n\n return false;\n}\n"],"names":["INVISIBLE_PART_TYPES","partsFromSegmentGroups","groups","group","partRequiresUserAction","part","isStaticToolUIPart","name","getToolName","isPendingAskUserQuestionPart","lastPendingAskUserQuestionPart","parts","entry","isToolUIPart","isToolInvocationTerminal","isPendingChooseDesignDirectionPart","lastPendingChooseDesignDirectionPart","OUTSIDE_PHASE_TOOLS","toolStaysOutsidePhase","partsHaveOpenToolCalls","partsRequireUserAction","tail","isVisiblePart","segmentRequiresUserAction","isInvisibleDynamicTool","toolName","parseCallDynamicToolInput","isContextCompactionUIPart","isBackgroundResultUIPart","isDataUIPart","isTextUIPart","isReasoningUIPart","body","parseReasoningText","isRedactedReasoningUIPart","isSourceUIPart","isReasoningGroup","isOutsideGroup","groupIndex","laterJoinsPhase","from","index","sealsStreamingPhase","streamingPhaseActiveIndex","segments","isStreaming","lastGrouped","segment","mergeableGroupKind","isFileUIPart","appendToMergeableGroup","kind","last","groupMessageParts","splitUserMessageParts","files","textChunks","lastVisiblePartFromGroups","lastGroup","flushSegment","layout","slice","phaseLayout","tools","segmentMessage","phaseRun","outsideRun","intoPhase","outsidePhase","phaseOpen","inputFingerprintCache","streamingInputFingerprint","input","cached","fingerprint","uiMessagePartEqual","left","right"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"normalizeMessageParts.js","sources":["../../../../src/chat/Message/normalize/normalizeMessageParts.ts"],"sourcesContent":["import {\n getToolName,\n isDataUIPart,\n isFileUIPart,\n isReasoningUIPart,\n isStaticToolUIPart,\n isTextUIPart,\n isToolUIPart,\n} from '@reforma/types';\n\nimport { parseReasoningText } from '../../Reasoning/normalizeReasoningBody';\nimport { isToolInvocationTerminal } from '../../Tool/helpers';\nimport { parseCallDynamicToolInput } from '../../Tool/mcp-tools/parseCallDynamicToolInput';\nimport { isBackgroundResultUIPart } from '../parts/backgroundResultPart';\nimport { isContextCompactionUIPart, type ContextCompactionUIPart } from '../parts/contextCompactionPart';\nimport { isRedactedReasoningUIPart } from '../parts/redactedReasoningPart';\n\nimport type { FileUIPart, ReasoningUIPart, SourceDocumentUIPart, SourceUrlUIPart, ToolUIPart } from 'ai';\nimport type { ReformaUIMessagePart } from '../types';\n\nexport type MessageSegmentLayout = 'grouped' | 'ungrouped';\n\n/** Step markers and UI-less tools — dropped before normalization. */\nexport const INVISIBLE_PART_TYPES = new Set([\n 'step-start',\n 'tool-SetPhase',\n 'tool-TodoWrite',\n 'tool-ReadTodo',\n 'tool-Commit',\n // Frontend tools without chat UI — executed silently in the editor.\n 'tool-Navigate',\n // Direction phase exit. The reading stays on the thread for the model.\n 'tool-CommitDesignRead',\n // Reveals the preview. The status change is the UI; the thread stays quiet.\n 'tool-MarkProjectReady',\n]);\n\n/** Render unit: merged file/source/compaction siblings, or one SDK part per row. */\nexport type MessagePartGroup\n = | { kind: 'files'; parts: FileUIPart[] }\n | { kind: 'sources'; parts: (SourceUrlUIPart | SourceDocumentUIPart)[] }\n | { kind: 'compaction'; parts: ContextCompactionUIPart[] }\n | { kind: 'reasoning'; parts: ReasoningUIPart[] }\n | { kind: 'single'; part: ReformaUIMessagePart };\n\nexport type MessageSegment = {\n layout: MessageSegmentLayout;\n groups: readonly MessagePartGroup[];\n /** Start index in the grouped sequence (keys / DOM id prefixes). */\n index: number;\n};\n\n/** Single tool/text rows from a segment's groups (skips merged file/source/compaction groups). */\nexport function partsFromSegmentGroups(groups: readonly MessagePartGroup[]): ReformaUIMessagePart[] {\n return groups.flatMap(group => group.kind === 'single' ? [group.part] : []);\n}\n\nfunction partRequiresUserAction(part: ReformaUIMessagePart): boolean {\n if (!isStaticToolUIPart(part)) {\n return false;\n }\n\n // Answered Ask / design picker folds into the work phase; pending stays outside.\n const name = getToolName(part);\n\n return part.state === 'approval-requested'\n || (\n (name === 'AskUserQuestion' || name === 'ChooseDesignDirection')\n && part.state !== 'output-available'\n );\n}\n\n/** Pending AskUserQuestion — answered in the composer; thread shows a pointer row. */\nfunction isPendingAskUserQuestionPart(part: ReformaUIMessagePart): boolean {\n return isStaticToolUIPart(part)\n && getToolName(part) === 'AskUserQuestion'\n && (part.state === 'input-streaming' || part.state === 'input-available');\n}\n\n/**\n * Last unfinished tool on the assistant turn, when that tool is a pending AskUserQuestion.\n */\nexport function lastPendingAskUserQuestionPart(\n parts: readonly ReformaUIMessagePart[]\n): ToolUIPart | undefined {\n const part = parts.findLast((entry) => {\n if (!isToolUIPart(entry)) {\n return false;\n }\n\n return !isToolInvocationTerminal(entry.state);\n });\n\n if (!part || !isToolUIPart(part) || !isPendingAskUserQuestionPart(part)) {\n return undefined;\n }\n\n return part as ToolUIPart;\n}\n\nfunction isPendingChooseDesignDirectionPart(part: ReformaUIMessagePart): boolean {\n return isStaticToolUIPart(part)\n && getToolName(part) === 'ChooseDesignDirection'\n && (part.state === 'input-streaming' || part.state === 'input-available');\n}\n\n/**\n * Last unfinished tool on the assistant turn, when that tool is a pending ChooseDesignDirection.\n */\nexport function lastPendingChooseDesignDirectionPart(\n parts: readonly ReformaUIMessagePart[]\n): ToolUIPart | undefined {\n const part = parts.findLast((entry) => {\n if (!isToolUIPart(entry)) {\n return false;\n }\n\n return !isToolInvocationTerminal(entry.state);\n });\n\n if (!part || !isToolUIPart(part) || !isPendingChooseDesignDirectionPart(part)) {\n return undefined;\n }\n\n return part as ToolUIPart;\n}\n\n/** Tools that never join Explored/Edited/Setup chrome. */\nconst OUTSIDE_PHASE_TOOLS = new Set([\n 'Preamble',\n 'ReadPlan',\n 'CreatePlan',\n 'EditPlan',\n]);\n\n/** Pending ask/approval, Preamble, and plan cards. */\nfunction toolStaysOutsidePhase(part: ReformaUIMessagePart): boolean {\n if (partRequiresUserAction(part)) {\n return true;\n }\n\n if (!isStaticToolUIPart(part)) {\n return false;\n }\n\n return OUTSIDE_PHASE_TOOLS.has(getToolName(part));\n}\n\n/** True when any tool call is still open (including invisible frontend tools like Navigate). */\nexport function partsHaveOpenToolCalls(parts: readonly ReformaUIMessagePart[]): boolean {\n return parts.some(part => isToolUIPart(part) && !isToolInvocationTerminal(part.state));\n}\n\n/** True when the turn awaits approval, a pending question, or a design-direction pick. */\nexport function partsRequireUserAction(parts: readonly ReformaUIMessagePart[]): boolean {\n if (lastPendingAskUserQuestionPart(parts) || lastPendingChooseDesignDirectionPart(parts)) {\n return true;\n }\n\n const tail = parts.findLast(isVisiblePart);\n\n return tail ? partRequiresUserAction(tail) : false;\n}\n\n/** True when a grouped segment contains a tool awaiting user confirmation or answer. */\nexport function segmentRequiresUserAction(groups: readonly MessagePartGroup[]): boolean {\n return groups.some(group => group.kind === 'single' && partRequiresUserAction(group.part));\n}\n\n/** Gateway call whose inner tool has no chat row (Navigate, and the other silent tools). */\nfunction isInvisibleDynamicTool(part: ReformaUIMessagePart): boolean {\n if (!isStaticToolUIPart(part) || getToolName(part) !== 'CallDynamicTool') {\n return false;\n }\n\n const { toolName } = parseCallDynamicToolInput(part.input);\n\n return INVISIBLE_PART_TYPES.has(`tool-${ toolName }`);\n}\n\nexport function isVisiblePart(part: ReformaUIMessagePart): boolean {\n if (INVISIBLE_PART_TYPES.has(part.type) || isInvisibleDynamicTool(part)) {\n return false;\n }\n\n // Login plaque only; after the user responds the part stays in the thread for the model.\n if (isStaticToolUIPart(part) && getToolName(part) === 'McpAuth') {\n return part.state === 'approval-requested';\n }\n\n // Citations render in the message footer, not the body.\n if (part.type === 'source-url' || part.type === 'source-document') {\n return false;\n }\n\n if (isContextCompactionUIPart(part) || isBackgroundResultUIPart(part)) {\n return true;\n }\n\n if (isDataUIPart(part)) {\n return false;\n }\n\n // Empty / whitespace-only text — no Streamdown shell (avoids empty prose gap before pending).\n if (isTextUIPart(part) && !part.text.trim()) {\n return false;\n }\n\n if (isReasoningUIPart(part) && part.state === 'done') {\n const { body } = parseReasoningText(part.text);\n\n // Drop settled reasoning with no body — including title-only `**Heading**`.\n if (!body.trim()) {\n return false;\n }\n }\n\n if (isRedactedReasoningUIPart(part)) {\n return false;\n }\n\n return true;\n}\n\nfunction isSourceUIPart(part: ReformaUIMessagePart): part is SourceUrlUIPart | SourceDocumentUIPart {\n return part.type === 'source-url' || part.type === 'source-document';\n}\n\nfunction isReasoningGroup(group: MessagePartGroup): boolean {\n return group.kind === 'reasoning';\n}\n\n/** Text, Preamble, pending ask/approval, plan cards, files, or trailing compaction. */\nfunction isOutsideGroup(\n group: MessagePartGroup,\n groupIndex: number,\n groups: readonly MessagePartGroup[]\n): boolean {\n if (group.kind === 'files' || group.kind === 'sources') {\n return true;\n }\n\n if (group.kind === 'compaction') {\n return groupIndex === groups.length - 1;\n }\n\n if (group.kind !== 'single') {\n return false;\n }\n\n const { part } = group;\n\n return isTextUIPart(part) || toolStaysOutsidePhase(part);\n}\n\n/** Reasoning follows the next in-phase group. */\nfunction laterJoinsPhase(\n from: number,\n groups: readonly MessagePartGroup[]\n): boolean {\n for (let index = from + 1; index < groups.length; index++) {\n if (isReasoningGroup(groups[index])) {\n continue;\n }\n\n return !isOutsideGroup(groups[index], index, groups);\n }\n\n return false;\n}\n\n/** Text, Preamble, pending ask, plan, or files after a phase — ends streaming phase chrome. */\nfunction sealsStreamingPhase(group: MessagePartGroup): boolean {\n if (group.kind === 'files' || group.kind === 'sources' || group.kind === 'compaction') {\n return true;\n }\n\n return group.kind === 'single'\n && (isTextUIPart(group.part) || toolStaysOutsidePhase(group.part));\n}\n\n/** Last grouped phase that should keep streaming chrome, or `-1`. */\nexport function streamingPhaseActiveIndex(\n segments: readonly MessageSegment[],\n isStreaming: boolean\n): number {\n if (!isStreaming) {\n return -1;\n }\n\n const lastGrouped = segments.findLastIndex(segment => segment.layout === 'grouped');\n\n if (lastGrouped < 0) {\n return -1;\n }\n\n const sealed = segments\n .slice(lastGrouped + 1)\n .some(segment => segment.groups.some(sealsStreamingPhase));\n\n return sealed ? -1 : lastGrouped;\n}\n\ntype MergeableGroupKind = Exclude<MessagePartGroup['kind'], 'single'>;\n\nfunction mergeableGroupKind(part: ReformaUIMessagePart): MergeableGroupKind | null {\n if (isFileUIPart(part)) {\n return 'files';\n }\n\n if (isSourceUIPart(part)) {\n return 'sources';\n }\n\n if (isContextCompactionUIPart(part)) {\n return 'compaction';\n }\n\n if (isReasoningUIPart(part)) {\n return 'reasoning';\n }\n\n return null;\n}\n\nfunction appendToMergeableGroup(\n groups: MessagePartGroup[],\n kind: MergeableGroupKind,\n part: ReformaUIMessagePart\n): void {\n const last = groups.at(-1);\n\n if (last?.kind === kind) {\n last.parts.push(part as never);\n\n return;\n }\n\n groups.push({ kind, parts: [part] } as MessagePartGroup);\n}\n\n/** Filter invisible parts; merge consecutive files, sources, compaction, and reasoning. */\nexport function groupMessageParts(parts: readonly ReformaUIMessagePart[]): MessagePartGroup[] {\n const groups: MessagePartGroup[] = [];\n\n for (const part of parts) {\n if (!isVisiblePart(part)) {\n continue;\n }\n\n const kind = mergeableGroupKind(part);\n\n if (kind !== null) {\n appendToMergeableGroup(groups, kind, part);\n }\n else {\n groups.push({ kind: 'single', part });\n }\n }\n\n return groups;\n}\n\n/** User turns only carry file attachments and/or text. */\nexport function splitUserMessageParts(parts: readonly ReformaUIMessagePart[]): {\n files: FileUIPart[];\n text: string;\n} {\n const files: FileUIPart[] = [];\n const textChunks: string[] = [];\n\n for (const part of parts) {\n if (isFileUIPart(part)) {\n files.push(part);\n }\n else if (isTextUIPart(part) && part.text.trim()) {\n textChunks.push(part.text);\n }\n }\n\n return { files, text: textChunks.join('\\n') };\n}\n\n/** Last visible part in render order */\nexport function lastVisiblePartFromGroups(\n groups: readonly MessagePartGroup[]\n): ReformaUIMessagePart | undefined {\n const lastGroup = groups.at(-1);\n\n if (!lastGroup) {\n return undefined;\n }\n\n return lastGroup.kind === 'single' ? lastGroup.part : lastGroup.parts.at(-1);\n}\n\nfunction flushSegment(\n segments: MessageSegment[],\n layout: MessageSegmentLayout,\n slice: MessagePartGroup[],\n index: number\n): number {\n if (slice.length === 0) {\n return index;\n }\n\n const groups = slice.splice(0);\n\n segments.push({ layout, groups, index });\n\n return index + groups.length;\n}\n\nfunction phaseLayout(groups: readonly MessagePartGroup[]): MessageSegmentLayout {\n let tools = 0;\n\n for (const group of groups) {\n if (group.kind === 'single' && isToolUIPart(group.part)) {\n tools++;\n }\n }\n\n if (tools === 0) {\n return 'ungrouped';\n }\n\n // 2+ rows: two tools, or a tool plus reasoning.\n return groups.length >= 2 ? 'grouped' : 'ungrouped';\n}\n\n/**\n * One work phase vs ungrouped separators (text, Preamble, pending ask/approval, plan).\n * Answered Ask joins the phase.\n * `grouped` chrome when a phase has 2+ rows (tools and/or reasoning) and at least one tool.\n */\nexport function segmentMessage(groups: readonly MessagePartGroup[]): MessageSegment[] {\n if (groups.length === 0) {\n return [];\n }\n\n const segments: MessageSegment[] = [];\n let index = 0;\n const phaseRun: MessagePartGroup[] = [];\n const outsideRun: MessagePartGroup[] = [];\n\n const intoPhase = (group: MessagePartGroup) => {\n index = flushSegment(segments, 'ungrouped', outsideRun, index);\n phaseRun.push(group);\n };\n\n const outsidePhase = (group: MessagePartGroup) => {\n index = flushSegment(segments, phaseLayout(phaseRun), phaseRun, index);\n outsideRun.push(group);\n };\n\n for (const [groupIndex, group] of groups.entries()) {\n const phaseOpen = phaseRun.length > 0;\n\n if (isReasoningGroup(group)) {\n if (phaseOpen || laterJoinsPhase(groupIndex, groups)) {\n intoPhase(group);\n }\n else {\n outsidePhase(group);\n }\n\n continue;\n }\n\n if (isOutsideGroup(group, groupIndex, groups)) {\n outsidePhase(group);\n }\n else {\n intoPhase(group);\n }\n }\n\n index = flushSegment(segments, phaseLayout(phaseRun), phaseRun, index);\n flushSegment(segments, 'ungrouped', outsideRun, index);\n\n return segments;\n}\n\n/** Value equality: same reference first, then a cached JSON fingerprint for streaming inputs. */\nconst inputFingerprintCache = new WeakMap<object, string>();\n\nfunction streamingInputFingerprint(input: unknown): string {\n if (input === null || input === undefined) {\n return '';\n }\n\n if (typeof input !== 'object') {\n return `${ typeof input }:${ String(input) }`;\n }\n\n const cached = inputFingerprintCache.get(input);\n\n if (cached !== undefined) {\n return cached;\n }\n\n const fingerprint = JSON.stringify(input);\n\n inputFingerprintCache.set(input, fingerprint);\n\n return fingerprint;\n}\n\n/** Shallow part equality; text/reasoning also compare content (streaming may replace part objects). */\nexport function uiMessagePartEqual(left: ReformaUIMessagePart, right: ReformaUIMessagePart): boolean {\n if (left === right) {\n return true;\n }\n\n if (left.type !== right.type) {\n return false;\n }\n\n if (isTextUIPart(left) && isTextUIPart(right)) {\n return left.text === right.text;\n }\n\n if (isReasoningUIPart(left) && isReasoningUIPart(right)) {\n return left.text === right.text && left.state === right.state;\n }\n\n if (isContextCompactionUIPart(left) && isContextCompactionUIPart(right)) {\n return left.data.done === right.data.done;\n }\n\n if (isBackgroundResultUIPart(left) && isBackgroundResultUIPart(right)) {\n return left.data.text === right.data.text;\n }\n\n if (isStaticToolUIPart(left) && isStaticToolUIPart(right)) {\n if (left.toolCallId !== right.toolCallId || left.state !== right.state) {\n return false;\n }\n\n if (left.state === 'input-streaming') {\n return left.input === right.input\n || streamingInputFingerprint(left.input) === streamingInputFingerprint(right.input);\n }\n\n return true;\n }\n\n return false;\n}\n"],"names":["INVISIBLE_PART_TYPES","partsFromSegmentGroups","groups","group","partRequiresUserAction","part","isStaticToolUIPart","name","getToolName","isPendingAskUserQuestionPart","lastPendingAskUserQuestionPart","parts","entry","isToolUIPart","isToolInvocationTerminal","isPendingChooseDesignDirectionPart","lastPendingChooseDesignDirectionPart","OUTSIDE_PHASE_TOOLS","toolStaysOutsidePhase","partsHaveOpenToolCalls","partsRequireUserAction","tail","isVisiblePart","segmentRequiresUserAction","isInvisibleDynamicTool","toolName","parseCallDynamicToolInput","isContextCompactionUIPart","isBackgroundResultUIPart","isDataUIPart","isTextUIPart","isReasoningUIPart","body","parseReasoningText","isRedactedReasoningUIPart","isSourceUIPart","isReasoningGroup","isOutsideGroup","groupIndex","laterJoinsPhase","from","index","sealsStreamingPhase","streamingPhaseActiveIndex","segments","isStreaming","lastGrouped","segment","mergeableGroupKind","isFileUIPart","appendToMergeableGroup","kind","last","groupMessageParts","splitUserMessageParts","files","textChunks","lastVisiblePartFromGroups","lastGroup","flushSegment","layout","slice","phaseLayout","tools","segmentMessage","phaseRun","outsideRun","intoPhase","outsidePhase","phaseOpen","inputFingerprintCache","streamingInputFingerprint","input","cached","fingerprint","uiMessagePartEqual","left","right"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessagePart.d.ts","sourceRoot":"","sources":["../../../../src/chat/Message/parts/MessagePart.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MessagePart.d.ts","sourceRoot":"","sources":["../../../../src/chat/Message/parts/MessagePart.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAErD,MAAM,MAAM,gBAAgB,GAAG;IAC3B,IAAI,EAAE,oBAAoB,CAAC;IAC3B,4FAA4F;IAC5F,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,gEAAgE;IAChE,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,2CAA2C;IAC3C,aAAa,CAAC,EAAE,OAAO,CAAC;CAC3B,CAAC;AAiBF;;;GAGG;AACH,iBAAS,eAAe,CAAC,EACrB,IAAI,EACJ,OAAO,EACP,WAAW,EACX,aAAa,EAAE,cAAc,EAC7B,aAAa,GAChB,EAAE,gBAAgB,sCA+ClB;AAED,eAAO,MAAM,WAAW,6DAA+C,CAAC"}
|