dishui 0.0.49 → 0.0.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/components/pro/Flow/Flow.js +419 -407
  2. package/dist/components/pro/Flow/Flow.js.map +1 -1
  3. package/dist/components/pro/Flow/archify/build.d.ts +74 -0
  4. package/dist/components/pro/Flow/archify/build.js +103 -0
  5. package/dist/components/pro/Flow/archify/build.js.map +1 -0
  6. package/dist/components/pro/Flow/archify/convert.d.ts +14 -0
  7. package/dist/components/pro/Flow/archify/convert.js +534 -0
  8. package/dist/components/pro/Flow/archify/convert.js.map +1 -0
  9. package/dist/components/pro/Flow/archify/index.d.ts +12 -0
  10. package/dist/components/pro/Flow/archify/palette.d.ts +64 -0
  11. package/dist/components/pro/Flow/archify/palette.js +112 -0
  12. package/dist/components/pro/Flow/archify/palette.js.map +1 -0
  13. package/dist/components/pro/Flow/archify/presets.d.ts +26 -0
  14. package/dist/components/pro/Flow/archify/presets.js +43 -0
  15. package/dist/components/pro/Flow/archify/presets.js.map +1 -0
  16. package/dist/components/pro/Flow/archify/spec.d.ts +283 -0
  17. package/dist/components/pro/Flow/archify/spec.js +10 -0
  18. package/dist/components/pro/Flow/archify/spec.js.map +1 -0
  19. package/dist/components/pro/Flow/constants.js +14 -0
  20. package/dist/components/pro/Flow/constants.js.map +1 -1
  21. package/dist/components/pro/Flow/hooks/useClipboard.d.ts +5 -0
  22. package/dist/components/pro/Flow/hooks/useClipboard.js +129 -73
  23. package/dist/components/pro/Flow/hooks/useClipboard.js.map +1 -1
  24. package/dist/components/pro/Flow/hooks/useFlowImportExport.d.ts +1 -0
  25. package/dist/components/pro/Flow/hooks/useFlowImportExport.js +108 -93
  26. package/dist/components/pro/Flow/hooks/useFlowImportExport.js.map +1 -1
  27. package/dist/components/pro/Flow/hooks/useKeyboardShortcuts.d.ts +1 -0
  28. package/dist/components/pro/Flow/hooks/useKeyboardShortcuts.js +7 -7
  29. package/dist/components/pro/Flow/hooks/useKeyboardShortcuts.js.map +1 -1
  30. package/dist/components/pro/Flow/index.d.ts +2 -0
  31. package/dist/components/pro/Flow/nodes/DataNodeView.d.ts +4 -1
  32. package/dist/components/pro/Flow/nodes/DataNodeView.js +127 -115
  33. package/dist/components/pro/Flow/nodes/DataNodeView.js.map +1 -1
  34. package/dist/components/pro/Flow/nodes/MediaContent.js +72 -67
  35. package/dist/components/pro/Flow/nodes/MediaContent.js.map +1 -1
  36. package/dist/components/pro/Flow/nodes/NodeRenderer.d.ts +5 -0
  37. package/dist/components/pro/Flow/nodes/NodeRenderer.js +216 -115
  38. package/dist/components/pro/Flow/nodes/NodeRenderer.js.map +1 -1
  39. package/dist/components/pro/Flow/panels/FlowToolbar.js +208 -169
  40. package/dist/components/pro/Flow/panels/FlowToolbar.js.map +1 -1
  41. package/dist/components/pro/Flow/panels/InspectorPanel.js +602 -369
  42. package/dist/components/pro/Flow/panels/InspectorPanel.js.map +1 -1
  43. package/dist/components/pro/Flow/panels/ShapePalette.js +50 -39
  44. package/dist/components/pro/Flow/panels/ShapePalette.js.map +1 -1
  45. package/dist/components/pro/Flow/panels/toolbarIcons.d.ts +1 -0
  46. package/dist/components/pro/Flow/panels/toolbarIcons.js +36 -8
  47. package/dist/components/pro/Flow/panels/toolbarIcons.js.map +1 -1
  48. package/dist/components/pro/Flow/types.d.ts +30 -0
  49. package/dist/components/pro/Flow/types.js.map +1 -1
  50. package/dist/dishui.css +1 -1
  51. package/dist/flow.js +73 -56
  52. package/package.json +18 -17
@@ -1 +1 @@
1
- {"version":3,"file":"useFlowImportExport.js","names":[],"sources":["../../../../../src/components/pro/Flow/hooks/useFlowImportExport.ts"],"sourcesContent":["import { useCallback } from 'react';\nimport { useFlowContext } from '../context/FlowContext';\nimport type { FlowDocument, FlowCanvasData, FlowNode, FlowEdge, FlowLine } from '../types';\nimport { createEmptyDocument, ROOT_CANVAS_ID } from '../constants';\nimport { generateId } from '../nodes/nodeUtils';\n\nconst PERSIST_VERSION = 1;\n\ninterface SerializedDocument {\n version: number;\n canvases: Record<string, FlowCanvasData>;\n stack: string[];\n title?: string;\n}\n\n/**\n * Sanitize a project title into a safe file base name, falling back to a\n * default when empty. Shared by all export paths so filenames stay consistent.\n */\nexport function safeFileBaseName(title: string | undefined, fallback = 'flowchart'): string {\n const name = (title ?? '').trim().replace(/[\\\\/:*?\"<>|]+/g, '-').replace(/\\s+/g, ' ').trim();\n return name || fallback;\n}\n\n/**\n * Serialize/deserialize FlowDocument to/from JSON.\n * Also includes Mermaid flowchart import.\n */\nexport function useFlowImportExport() {\n const { doc, setDoc } = useFlowContext();\n\n const exportJSON = useCallback((): string => {\n const serialized: SerializedDocument = {\n version: PERSIST_VERSION,\n canvases: doc.canvases,\n stack: doc.stack,\n title: doc.title,\n };\n return JSON.stringify(serialized, null, 2);\n }, [doc]);\n\n const importJSON = useCallback((json: string) => {\n try {\n const parsed = JSON.parse(json) as SerializedDocument;\n if (!parsed.canvases || !parsed.stack) throw new Error('Invalid document format');\n setDoc({\n canvases: parsed.canvases,\n stack: parsed.stack,\n title: parsed.title,\n });\n } catch (err) {\n console.error('Failed to import JSON:', err);\n }\n }, [setDoc]);\n\n const importMermaid = useCallback((mermaidCode: string) => {\n const doc = parseMermaidFlowchart(mermaidCode);\n setDoc(doc);\n }, [setDoc]);\n\n const exportMarkdown = useCallback((): string => {\n return documentToMarkdown(doc);\n }, [doc]);\n\n const clearDocument = useCallback(() => {\n setDoc(createEmptyDocument());\n }, [setDoc]);\n\n return { exportJSON, importJSON, importMermaid, exportMarkdown, clearDocument };\n}\n\n/**\n * Render a FlowDocument as a Markdown outline describing the node hierarchy\n * and connections. Groups become sections with their children nested beneath;\n * edges are listed as a connection summary per canvas. Sub-canvases (drill-down\n * nodes) are rendered as nested sections.\n */\nfunction documentToMarkdown(doc: FlowDocument): string {\n const lines: string[] = [];\n\n const nodeLabel = (n: FlowNode): string => {\n const raw = (n.data.label ?? '').trim();\n if (raw) return raw.replace(/\\s+/g, ' ');\n if (n.type === 'mediaNode') return `(${n.data.mediaKind ?? 'media'})`;\n return `(${n.type})`;\n };\n\n const renderCanvas = (canvasId: string, headingLevel: number, seenCanvases: Set<string>) => {\n const canvas = doc.canvases[canvasId];\n if (!canvas) return;\n\n // Index nodes by id and by parent for hierarchy traversal.\n const byId = new Map(canvas.nodes.map((n) => [n.id, n]));\n const childrenOf = new Map<string | undefined, FlowNode[]>();\n for (const n of canvas.nodes) {\n const key = n.parentId && byId.has(n.parentId) ? n.parentId : undefined;\n const list = childrenOf.get(key) ?? [];\n list.push(n);\n childrenOf.set(key, list);\n }\n\n const emitNode = (node: FlowNode, depth: number) => {\n const indent = ' '.repeat(depth);\n const isGroup = node.data.isGroup || node.type === 'flowGroup' || node.type === 'geometryGroup';\n const bullet = isGroup ? `**${nodeLabel(node)}**` : nodeLabel(node);\n lines.push(`${indent}- ${bullet}`);\n\n // Media content (markdown/data/etc.) as a short description line.\n if (node.type === 'mediaNode' && node.data.mediaKind) {\n const kind = node.data.mediaKind;\n if (kind === 'data' && node.data.dataConfig) {\n const cfg = node.data.dataConfig;\n const cols = cfg.columns.map((c) => c.label ?? c.key).join(', ');\n lines.push(`${indent} - 数据表:${cfg.rows.length} 行 · 列(${cols})`);\n } else if (node.data.mediaContent && kind !== 'image' && kind !== 'model3d') {\n const preview = node.data.mediaContent.trim().split('\\n')[0].slice(0, 80);\n if (preview) lines.push(`${indent} - ${kind}: ${preview}`);\n }\n }\n\n // Recurse into visual group children.\n const kids = childrenOf.get(node.id) ?? [];\n for (const kid of kids) emitNode(kid, depth + 1);\n\n // Recurse into a drill-down sub-canvas, if any.\n const childCanvasId = node.data.childCanvasId;\n if (childCanvasId && doc.canvases[childCanvasId] && !seenCanvases.has(childCanvasId)) {\n seenCanvases.add(childCanvasId);\n renderCanvas(childCanvasId, headingLevel + 1, seenCanvases);\n }\n };\n\n const roots = childrenOf.get(undefined) ?? [];\n for (const root of roots) emitNode(root, 0);\n\n // Connections summary.\n if (canvas.edges.length > 0) {\n lines.push('');\n lines.push(`${'#'.repeat(Math.min(6, headingLevel + 1))} 连接关系`);\n for (const edge of canvas.edges) {\n const from = byId.get(edge.source);\n const to = byId.get(edge.target);\n if (!from || !to) continue;\n const edgeLabel = edge.data.labelText ? ` (${edge.data.labelText})` : '';\n lines.push(`- ${nodeLabel(from)} → ${nodeLabel(to)}${edgeLabel}`);\n }\n }\n };\n\n const seen = new Set<string>([ROOT_CANVAS_ID]);\n lines.push('# 流程图');\n lines.push('');\n renderCanvas(ROOT_CANVAS_ID, 1, seen);\n\n // Any orphan canvases not reached via drill-down nodes.\n for (const canvasId of Object.keys(doc.canvases)) {\n if (seen.has(canvasId)) continue;\n seen.add(canvasId);\n lines.push('');\n lines.push(`## 画布 ${canvasId}`);\n lines.push('');\n renderCanvas(canvasId, 2, seen);\n }\n\n return lines.join('\\n').replace(/\\n{3,}/g, '\\n\\n').trim() + '\\n';\n}\n\n/**\n * Simple Mermaid flowchart parser.\n * Handles basic `graph TD` / `flowchart LR` syntax with node definitions and edges.\n */\nfunction parseMermaidFlowchart(code: string): FlowDocument {\n const lines = code.split('\\n').map(l => l.trim()).filter(l => l && !l.startsWith('%%'));\n\n const nodeMap = new Map<string, { id: string; label: string }>();\n const edges: Array<{ from: string; to: string; label?: string }> = [];\n\n let isHorizontal = false;\n\n for (const line of lines) {\n // Detect direction\n if (/^(graph|flowchart)\\s+(LR|RL)/i.test(line)) {\n isHorizontal = true;\n continue;\n }\n if (/^(graph|flowchart)\\s+/i.test(line)) continue;\n\n // Edge patterns: A --> B, A -->|label| B, A --- B\n const edgeMatch = line.match(/^(\\w+)(?:\\[([^\\]]*)\\])?\\s*(-->|---|-\\.->|==>)(?:\\|([^|]*)\\|)?\\s*(\\w+)(?:\\[([^\\]]*)\\])?/);\n if (edgeMatch) {\n const [, fromId, fromLabel, , edgeLabel, toId, toLabel] = edgeMatch;\n if (fromLabel && !nodeMap.has(fromId)) nodeMap.set(fromId, { id: fromId, label: fromLabel });\n if (toLabel && !nodeMap.has(toId)) nodeMap.set(toId, { id: toId, label: toLabel });\n if (!nodeMap.has(fromId)) nodeMap.set(fromId, { id: fromId, label: fromId });\n if (!nodeMap.has(toId)) nodeMap.set(toId, { id: toId, label: toId });\n edges.push({ from: fromId, to: toId, label: edgeLabel?.trim() });\n continue;\n }\n\n // Standalone node: A[Label]\n const nodeMatch = line.match(/^(\\w+)\\[([^\\]]*)\\]/);\n if (nodeMatch) {\n const [, id, label] = nodeMatch;\n if (!nodeMap.has(id)) nodeMap.set(id, { id, label });\n }\n }\n\n // Layout: simple grid placement\n const nodeIds = [...nodeMap.keys()];\n const cols = isHorizontal ? nodeIds.length : Math.ceil(Math.sqrt(nodeIds.length));\n const spacing = { x: 200, y: 120 };\n\n const nodes: FlowNode[] = nodeIds.map((id, i) => {\n const col = i % cols;\n const row = Math.floor(i / cols);\n const data = nodeMap.get(id)!;\n return {\n id: data.id,\n type: 'shapeRoundRect' as const,\n position: { x: 100 + col * spacing.x, y: 100 + row * spacing.y },\n width: 140,\n height: 60,\n data: {\n label: data.label,\n fill: 'theme:base-100',\n stroke: 'theme:base-content',\n strokeWidth: 2,\n color: 'theme:base-content',\n fontSize: 14,\n },\n };\n });\n\n const flowEdges: FlowEdge[] = edges.map((e) => ({\n id: generateId('edge'),\n source: e.from,\n target: e.to,\n type: 'smoothstep' as const,\n data: {\n strokeColor: 'theme:base-content',\n strokeWidth: 2,\n lineStyle: 'solid' as const,\n markerEnd: 'arrowclosed' as const,\n labelText: e.label,\n },\n }));\n\n return {\n canvases: {\n [ROOT_CANVAS_ID]: { nodes, edges: flowEdges, lines: [] },\n },\n stack: [ROOT_CANVAS_ID],\n };\n}\n\n/**\n * Export the PixiJS canvas as PNG data URL.\n */\nexport async function exportCanvasToPNG(canvas: HTMLCanvasElement): Promise<string> {\n return canvas.toDataURL('image/png');\n}\n\n/**\n * Download a data URL as a file.\n */\nexport function downloadDataURL(dataUrl: string, filename: string): void {\n const a = document.createElement('a');\n a.href = dataUrl;\n a.download = filename;\n document.body.appendChild(a);\n a.click();\n document.body.removeChild(a);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"useFlowImportExport.js","names":[],"sources":["../../../../../src/components/pro/Flow/hooks/useFlowImportExport.ts"],"sourcesContent":["import { useCallback } from 'react';\nimport { useFlowContext } from '../context/FlowContext';\nimport type { FlowDocument, FlowCanvasData, FlowNode, FlowEdge, FlowLine } from '../types';\nimport { createEmptyDocument, ROOT_CANVAS_ID } from '../constants';\nimport { generateId } from '../nodes/nodeUtils';\nimport { isArchifySpec, archifyToFlowDocument } from '../archify';\n\nconst PERSIST_VERSION = 1;\n\ninterface SerializedDocument {\n version: number;\n canvases: Record<string, FlowCanvasData>;\n stack: string[];\n title?: string;\n}\n\n/**\n * Sanitize a project title into a safe file base name, falling back to a\n * default when empty. Shared by all export paths so filenames stay consistent.\n */\nexport function safeFileBaseName(title: string | undefined, fallback = 'flowchart'): string {\n const name = (title ?? '').trim().replace(/[\\\\/:*?\"<>|]+/g, '-').replace(/\\s+/g, ' ').trim();\n return name || fallback;\n}\n\n/**\n * Serialize/deserialize FlowDocument to/from JSON.\n * Also includes Mermaid flowchart import.\n */\nexport function useFlowImportExport() {\n const { doc, setDoc } = useFlowContext();\n\n const exportJSON = useCallback((): string => {\n const serialized: SerializedDocument = {\n version: PERSIST_VERSION,\n canvases: doc.canvases,\n stack: doc.stack,\n title: doc.title,\n };\n return JSON.stringify(serialized, null, 2);\n }, [doc]);\n\n const importJSON = useCallback((json: string) => {\n try {\n const parsed = JSON.parse(json) as unknown;\n // Auto-detect an Archify spec and convert it to a Flow document so the\n // same \"import JSON\" entry point accepts both native and Archify files.\n if (isArchifySpec(parsed)) {\n setDoc(archifyToFlowDocument(parsed));\n return;\n }\n const doc = parsed as SerializedDocument;\n if (!doc.canvases || !doc.stack) throw new Error('Invalid document format');\n setDoc({\n canvases: doc.canvases,\n stack: doc.stack,\n title: doc.title,\n });\n } catch (err) {\n console.error('Failed to import JSON:', err);\n }\n }, [setDoc]);\n\n /**\n * Import an Archify diagram spec (architecture / workflow / sequence /\n * dataflow / lifecycle), converting it to a native Flow document. Accepts a\n * JSON string or an already-parsed object. Returns true on success.\n */\n const importArchify = useCallback((input: string | object): boolean => {\n try {\n const spec = typeof input === 'string' ? JSON.parse(input) : input;\n if (!isArchifySpec(spec)) return false;\n setDoc(archifyToFlowDocument(spec));\n return true;\n } catch (err) {\n console.error('Failed to import Archify spec:', err);\n return false;\n }\n }, [setDoc]);\n\n const importMermaid = useCallback((mermaidCode: string) => {\n const doc = parseMermaidFlowchart(mermaidCode);\n setDoc(doc);\n }, [setDoc]);\n\n const exportMarkdown = useCallback((): string => {\n return documentToMarkdown(doc);\n }, [doc]);\n\n const clearDocument = useCallback(() => {\n setDoc(createEmptyDocument());\n }, [setDoc]);\n\n return { exportJSON, importJSON, importArchify, importMermaid, exportMarkdown, clearDocument };\n}\n\n/**\n * Render a FlowDocument as a Markdown outline describing the node hierarchy\n * and connections. Groups become sections with their children nested beneath;\n * edges are listed as a connection summary per canvas. Sub-canvases (drill-down\n * nodes) are rendered as nested sections.\n */\nfunction documentToMarkdown(doc: FlowDocument): string {\n const lines: string[] = [];\n\n const nodeLabel = (n: FlowNode): string => {\n const raw = (n.data.label ?? '').trim();\n if (raw) return raw.replace(/\\s+/g, ' ');\n if (n.type === 'mediaNode') return `(${n.data.mediaKind ?? 'media'})`;\n return `(${n.type})`;\n };\n\n const renderCanvas = (canvasId: string, headingLevel: number, seenCanvases: Set<string>) => {\n const canvas = doc.canvases[canvasId];\n if (!canvas) return;\n\n // Index nodes by id and by parent for hierarchy traversal.\n const byId = new Map(canvas.nodes.map((n) => [n.id, n]));\n const childrenOf = new Map<string | undefined, FlowNode[]>();\n for (const n of canvas.nodes) {\n const key = n.parentId && byId.has(n.parentId) ? n.parentId : undefined;\n const list = childrenOf.get(key) ?? [];\n list.push(n);\n childrenOf.set(key, list);\n }\n\n const emitNode = (node: FlowNode, depth: number) => {\n const indent = ' '.repeat(depth);\n const isGroup = node.data.isGroup || node.type === 'flowGroup' || node.type === 'geometryGroup';\n const bullet = isGroup ? `**${nodeLabel(node)}**` : nodeLabel(node);\n lines.push(`${indent}- ${bullet}`);\n\n // Media content (markdown/data/etc.) as a short description line.\n if (node.type === 'mediaNode' && node.data.mediaKind) {\n const kind = node.data.mediaKind;\n if (kind === 'data' && node.data.dataConfig) {\n const cfg = node.data.dataConfig;\n const cols = cfg.columns.map((c) => c.label ?? c.key).join(', ');\n lines.push(`${indent} - 数据表:${cfg.rows.length} 行 · 列(${cols})`);\n } else if (node.data.mediaContent && kind !== 'image' && kind !== 'model3d') {\n const preview = node.data.mediaContent.trim().split('\\n')[0].slice(0, 80);\n if (preview) lines.push(`${indent} - ${kind}: ${preview}`);\n }\n }\n\n // Recurse into visual group children.\n const kids = childrenOf.get(node.id) ?? [];\n for (const kid of kids) emitNode(kid, depth + 1);\n\n // Recurse into a drill-down sub-canvas, if any.\n const childCanvasId = node.data.childCanvasId;\n if (childCanvasId && doc.canvases[childCanvasId] && !seenCanvases.has(childCanvasId)) {\n seenCanvases.add(childCanvasId);\n renderCanvas(childCanvasId, headingLevel + 1, seenCanvases);\n }\n };\n\n const roots = childrenOf.get(undefined) ?? [];\n for (const root of roots) emitNode(root, 0);\n\n // Connections summary.\n if (canvas.edges.length > 0) {\n lines.push('');\n lines.push(`${'#'.repeat(Math.min(6, headingLevel + 1))} 连接关系`);\n for (const edge of canvas.edges) {\n const from = byId.get(edge.source);\n const to = byId.get(edge.target);\n if (!from || !to) continue;\n const edgeLabel = edge.data.labelText ? ` (${edge.data.labelText})` : '';\n lines.push(`- ${nodeLabel(from)} → ${nodeLabel(to)}${edgeLabel}`);\n }\n }\n };\n\n const seen = new Set<string>([ROOT_CANVAS_ID]);\n lines.push('# 流程图');\n lines.push('');\n renderCanvas(ROOT_CANVAS_ID, 1, seen);\n\n // Any orphan canvases not reached via drill-down nodes.\n for (const canvasId of Object.keys(doc.canvases)) {\n if (seen.has(canvasId)) continue;\n seen.add(canvasId);\n lines.push('');\n lines.push(`## 画布 ${canvasId}`);\n lines.push('');\n renderCanvas(canvasId, 2, seen);\n }\n\n return lines.join('\\n').replace(/\\n{3,}/g, '\\n\\n').trim() + '\\n';\n}\n\n/**\n * Simple Mermaid flowchart parser.\n * Handles basic `graph TD` / `flowchart LR` syntax with node definitions and edges.\n */\nfunction parseMermaidFlowchart(code: string): FlowDocument {\n const lines = code.split('\\n').map(l => l.trim()).filter(l => l && !l.startsWith('%%'));\n\n const nodeMap = new Map<string, { id: string; label: string }>();\n const edges: Array<{ from: string; to: string; label?: string }> = [];\n\n let isHorizontal = false;\n\n for (const line of lines) {\n // Detect direction\n if (/^(graph|flowchart)\\s+(LR|RL)/i.test(line)) {\n isHorizontal = true;\n continue;\n }\n if (/^(graph|flowchart)\\s+/i.test(line)) continue;\n\n // Edge patterns: A --> B, A -->|label| B, A --- B\n const edgeMatch = line.match(/^(\\w+)(?:\\[([^\\]]*)\\])?\\s*(-->|---|-\\.->|==>)(?:\\|([^|]*)\\|)?\\s*(\\w+)(?:\\[([^\\]]*)\\])?/);\n if (edgeMatch) {\n const [, fromId, fromLabel, , edgeLabel, toId, toLabel] = edgeMatch;\n if (fromLabel && !nodeMap.has(fromId)) nodeMap.set(fromId, { id: fromId, label: fromLabel });\n if (toLabel && !nodeMap.has(toId)) nodeMap.set(toId, { id: toId, label: toLabel });\n if (!nodeMap.has(fromId)) nodeMap.set(fromId, { id: fromId, label: fromId });\n if (!nodeMap.has(toId)) nodeMap.set(toId, { id: toId, label: toId });\n edges.push({ from: fromId, to: toId, label: edgeLabel?.trim() });\n continue;\n }\n\n // Standalone node: A[Label]\n const nodeMatch = line.match(/^(\\w+)\\[([^\\]]*)\\]/);\n if (nodeMatch) {\n const [, id, label] = nodeMatch;\n if (!nodeMap.has(id)) nodeMap.set(id, { id, label });\n }\n }\n\n // Layout: simple grid placement\n const nodeIds = [...nodeMap.keys()];\n const cols = isHorizontal ? nodeIds.length : Math.ceil(Math.sqrt(nodeIds.length));\n const spacing = { x: 200, y: 120 };\n\n const nodes: FlowNode[] = nodeIds.map((id, i) => {\n const col = i % cols;\n const row = Math.floor(i / cols);\n const data = nodeMap.get(id)!;\n return {\n id: data.id,\n type: 'shapeRoundRect' as const,\n position: { x: 100 + col * spacing.x, y: 100 + row * spacing.y },\n width: 140,\n height: 60,\n data: {\n label: data.label,\n fill: 'theme:base-100',\n stroke: 'theme:base-content',\n strokeWidth: 2,\n color: 'theme:base-content',\n fontSize: 14,\n },\n };\n });\n\n const flowEdges: FlowEdge[] = edges.map((e) => ({\n id: generateId('edge'),\n source: e.from,\n target: e.to,\n type: 'smoothstep' as const,\n data: {\n strokeColor: 'theme:base-content',\n strokeWidth: 2,\n lineStyle: 'solid' as const,\n markerEnd: 'arrowclosed' as const,\n labelText: e.label,\n },\n }));\n\n return {\n canvases: {\n [ROOT_CANVAS_ID]: { nodes, edges: flowEdges, lines: [] },\n },\n stack: [ROOT_CANVAS_ID],\n };\n}\n\n/**\n * Export the PixiJS canvas as PNG data URL.\n */\nexport async function exportCanvasToPNG(canvas: HTMLCanvasElement): Promise<string> {\n return canvas.toDataURL('image/png');\n}\n\n/**\n * Download a data URL as a file.\n */\nexport function downloadDataURL(dataUrl: string, filename: string): void {\n const a = document.createElement('a');\n a.href = dataUrl;\n a.download = filename;\n document.body.appendChild(a);\n a.click();\n document.body.removeChild(a);\n}\n"],"mappings":"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"}
@@ -4,6 +4,7 @@ interface KeyboardShortcutActions {
4
4
  copy: () => void;
5
5
  cut: () => void;
6
6
  paste: () => void;
7
+ duplicate: () => void;
7
8
  deleteSelected: () => void;
8
9
  selectAll: () => void;
9
10
  group?: () => void;
@@ -2,11 +2,11 @@ import { useFlowContext as u } from "../context/FlowContext.js";
2
2
  import { useFlowUI as i } from "../context/FlowUIContext.js";
3
3
  import { useEffect as d } from "react";
4
4
  function D(t) {
5
- const { selection: a, setSelection: n, currentCanvas: p } = u(), { editingNodeId: f, setToolMode: s, setPendingPlacement: y } = i();
5
+ const { selection: a, setSelection: f, currentCanvas: p } = u(), { editingNodeId: n, setToolMode: y, setPendingPlacement: s } = i();
6
6
  d(() => {
7
7
  const o = (e) => {
8
8
  const l = e.target;
9
- if (l.tagName === "INPUT" || l.tagName === "TEXTAREA" || l.isContentEditable || f) return;
9
+ if (l.tagName === "INPUT" || l.tagName === "TEXTAREA" || l.isContentEditable || n) return;
10
10
  const r = e.metaKey || e.ctrlKey;
11
11
  if (r && e.key === "z" && !e.shiftKey)
12
12
  e.preventDefault(), t.undo();
@@ -18,20 +18,20 @@ function D(t) {
18
18
  e.preventDefault(), t.cut();
19
19
  else {
20
20
  if (r && e.key === "v") return;
21
- r && e.key === "a" ? (e.preventDefault(), t.selectAll()) : r && e.altKey && (e.key === "g" || e.key === "G") ? (e.preventDefault(), t.geoGroup?.()) : r && e.key === "g" && !e.shiftKey && !e.altKey ? (e.preventDefault(), t.group?.()) : r && (e.key === "G" || e.key === "g" && e.shiftKey) && !e.altKey ? (e.preventDefault(), t.ungroup?.()) : r && e.shiftKey && e.key === "ArrowUp" ? (e.preventDefault(), t.bringToFront?.()) : r && !e.shiftKey && e.key === "ArrowUp" ? (e.preventDefault(), t.bringForward?.()) : r && !e.shiftKey && e.key === "ArrowDown" ? (e.preventDefault(), t.sendBackward?.()) : r && e.shiftKey && e.key === "ArrowDown" ? (e.preventDefault(), t.sendToBack?.()) : e.key === "Delete" || e.key === "Backspace" ? (e.preventDefault(), t.deleteSelected()) : e.key === "Escape" && (n({
21
+ r && e.key === "a" ? (e.preventDefault(), t.selectAll()) : r && (e.key === "d" || e.key === "D") ? (e.preventDefault(), t.duplicate()) : r && e.altKey && (e.key === "g" || e.key === "G") ? (e.preventDefault(), t.geoGroup?.()) : r && e.key === "g" && !e.shiftKey && !e.altKey ? (e.preventDefault(), t.group?.()) : r && (e.key === "G" || e.key === "g" && e.shiftKey) && !e.altKey ? (e.preventDefault(), t.ungroup?.()) : r && e.shiftKey && e.key === "ArrowUp" ? (e.preventDefault(), t.bringToFront?.()) : r && !e.shiftKey && e.key === "ArrowUp" ? (e.preventDefault(), t.bringForward?.()) : r && !e.shiftKey && e.key === "ArrowDown" ? (e.preventDefault(), t.sendBackward?.()) : r && e.shiftKey && e.key === "ArrowDown" ? (e.preventDefault(), t.sendToBack?.()) : e.key === "Delete" || e.key === "Backspace" ? (e.preventDefault(), t.deleteSelected()) : e.key === "Escape" && (f({
22
22
  nodeIds: /* @__PURE__ */ new Set(),
23
23
  edgeIds: /* @__PURE__ */ new Set(),
24
24
  lineIds: /* @__PURE__ */ new Set()
25
- }), s("select"), y(null));
25
+ }), y("select"), s(null));
26
26
  }
27
27
  };
28
28
  return window.addEventListener("keydown", o), () => window.removeEventListener("keydown", o);
29
29
  }, [
30
30
  t,
31
- f,
32
31
  n,
33
- s,
34
- y
32
+ f,
33
+ y,
34
+ s
35
35
  ]);
36
36
  }
37
37
  export {
@@ -1 +1 @@
1
- {"version":3,"file":"useKeyboardShortcuts.js","names":[],"sources":["../../../../../src/components/pro/Flow/hooks/useKeyboardShortcuts.ts"],"sourcesContent":["import { useEffect } from 'react';\nimport { useFlowContext } from '../context/FlowContext';\nimport { useFlowUI } from '../context/FlowUIContext';\n\ninterface KeyboardShortcutActions {\n undo: () => void;\n redo: () => void;\n copy: () => void;\n cut: () => void;\n paste: () => void;\n deleteSelected: () => void;\n selectAll: () => void;\n group?: () => void;\n geoGroup?: () => void;\n ungroup?: () => void;\n bringToFront?: () => void;\n bringForward?: () => void;\n sendBackward?: () => void;\n sendToBack?: () => void;\n}\n\n/**\n * Registers global keyboard shortcuts for the flow editor.\n */\nexport function useKeyboardShortcuts(actions: KeyboardShortcutActions) {\n const { selection, setSelection, currentCanvas } = useFlowContext();\n const { editingNodeId, setToolMode, setPendingPlacement } = useFlowUI();\n\n useEffect(() => {\n const handler = (e: KeyboardEvent) => {\n // Don't intercept when editing text in inputs\n const target = e.target as HTMLElement;\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) return;\n if (editingNodeId) return;\n\n const meta = e.metaKey || e.ctrlKey;\n\n if (meta && e.key === 'z' && !e.shiftKey) {\n e.preventDefault();\n actions.undo();\n } else if (meta && (e.key === 'Z' || (e.key === 'z' && e.shiftKey))) {\n e.preventDefault();\n actions.redo();\n } else if (meta && e.key === 'c') {\n e.preventDefault();\n actions.copy();\n } else if (meta && e.key === 'x') {\n e.preventDefault();\n actions.cut();\n } else if (meta && e.key === 'v') {\n // Let the native paste event inspect image clipboard data. Structured\n // Flow clipboard fallback is handled there when no image is present.\n return;\n } else if (meta && e.key === 'a') {\n e.preventDefault();\n actions.selectAll();\n } else if (meta && e.altKey && (e.key === 'g' || e.key === 'G')) {\n e.preventDefault();\n actions.geoGroup?.();\n } else if (meta && e.key === 'g' && !e.shiftKey && !e.altKey) {\n e.preventDefault();\n actions.group?.();\n } else if (meta && (e.key === 'G' || (e.key === 'g' && e.shiftKey)) && !e.altKey) {\n e.preventDefault();\n actions.ungroup?.();\n } else if (meta && e.shiftKey && e.key === 'ArrowUp') {\n e.preventDefault();\n actions.bringToFront?.();\n } else if (meta && !e.shiftKey && e.key === 'ArrowUp') {\n e.preventDefault();\n actions.bringForward?.();\n } else if (meta && !e.shiftKey && e.key === 'ArrowDown') {\n e.preventDefault();\n actions.sendBackward?.();\n } else if (meta && e.shiftKey && e.key === 'ArrowDown') {\n e.preventDefault();\n actions.sendToBack?.();\n } else if (e.key === 'Delete' || e.key === 'Backspace') {\n e.preventDefault();\n actions.deleteSelected();\n } else if (e.key === 'Escape') {\n setSelection({ nodeIds: new Set(), edgeIds: new Set(), lineIds: new Set() });\n setToolMode('select');\n setPendingPlacement(null);\n }\n };\n\n window.addEventListener('keydown', handler);\n return () => window.removeEventListener('keydown', handler);\n }, [actions, editingNodeId, setSelection, setToolMode, setPendingPlacement]);\n}\n"],"mappings":";;;AAwBA,SAAgB,EAAqB,GAAkC;AACrE,QAAM,EAAE,WAAA,GAAW,cAAA,GAAc,eAAA,EAAA,IAAkB,EAAe,GAC5D,EAAE,eAAA,GAAe,aAAA,GAAa,qBAAA,EAAA,IAAwB,EAAU;AAEtE,EAAA,EAAA,MAAgB;AACd,UAAM,IAAA,CAAW,MAAqB;AAEpC,YAAM,IAAS,EAAE;AAEjB,UADI,EAAO,YAAY,WAAW,EAAO,YAAY,cAAc,EAAO,qBACtE,EAAe;AAEnB,YAAM,IAAO,EAAE,WAAW,EAAE;AAE5B,UAAI,KAAQ,EAAE,QAAQ,OAAO,CAAC,EAAE;AAC9B,UAAE,eAAe,GACjB,EAAQ,KAAK;AAAA,eACJ,MAAS,EAAE,QAAQ,OAAQ,EAAE,QAAQ,OAAO,EAAE;AACvD,UAAE,eAAe,GACjB,EAAQ,KAAK;AAAA,eACJ,KAAQ,EAAE,QAAQ;AAC3B,UAAE,eAAe,GACjB,EAAQ,KAAK;AAAA,eACJ,KAAQ,EAAE,QAAQ;AAC3B,UAAE,eAAe,GACjB,EAAQ,IAAI;AAAA,WACP;AAAA,YAAI,KAAQ,EAAE,QAAQ,IAG3B;AACK,QAAI,KAAQ,EAAE,QAAQ,OAC3B,EAAE,eAAe,GACjB,EAAQ,UAAU,KACT,KAAQ,EAAE,WAAW,EAAE,QAAQ,OAAO,EAAE,QAAQ,QACzD,EAAE,eAAe,GACjB,EAAQ,WAAW,KACV,KAAQ,EAAE,QAAQ,OAAO,CAAC,EAAE,YAAY,CAAC,EAAE,UACpD,EAAE,eAAe,GACjB,EAAQ,QAAQ,KACP,MAAS,EAAE,QAAQ,OAAQ,EAAE,QAAQ,OAAO,EAAE,aAAc,CAAC,EAAE,UACxE,EAAE,eAAe,GACjB,EAAQ,UAAU,KACT,KAAQ,EAAE,YAAY,EAAE,QAAQ,aACzC,EAAE,eAAe,GACjB,EAAQ,eAAe,KACd,KAAQ,CAAC,EAAE,YAAY,EAAE,QAAQ,aAC1C,EAAE,eAAe,GACjB,EAAQ,eAAe,KACd,KAAQ,CAAC,EAAE,YAAY,EAAE,QAAQ,eAC1C,EAAE,eAAe,GACjB,EAAQ,eAAe,KACd,KAAQ,EAAE,YAAY,EAAE,QAAQ,eACzC,EAAE,eAAe,GACjB,EAAQ,aAAa,KACZ,EAAE,QAAQ,YAAY,EAAE,QAAQ,eACzC,EAAE,eAAe,GACjB,EAAQ,eAAe,KACd,EAAE,QAAQ,aACnB,EAAa;AAAA,UAAE,SAAS,oBAAI,IAAI;AAAA,UAAG,SAAS,oBAAI,IAAI;AAAA,UAAG,SAAS,oBAAI,IAAI;AAAA,QAAE,CAAC,GAC3E,EAAY,QAAQ,GACpB,EAAoB,IAAI;AAAA;AAAA,IAE5B;AAEA,kBAAO,iBAAiB,WAAW,CAAO,GAC1C,MAAa,OAAO,oBAAoB,WAAW,CAAO;AAAA,EAC5D,GAAG;AAAA,IAAC;AAAA,IAAS;AAAA,IAAe;AAAA,IAAc;AAAA,IAAa;AAAA,EAAmB,CAAC;AAC7E"}
1
+ {"version":3,"file":"useKeyboardShortcuts.js","names":[],"sources":["../../../../../src/components/pro/Flow/hooks/useKeyboardShortcuts.ts"],"sourcesContent":["import { useEffect } from 'react';\nimport { useFlowContext } from '../context/FlowContext';\nimport { useFlowUI } from '../context/FlowUIContext';\n\ninterface KeyboardShortcutActions {\n undo: () => void;\n redo: () => void;\n copy: () => void;\n cut: () => void;\n paste: () => void;\n duplicate: () => void;\n deleteSelected: () => void;\n selectAll: () => void;\n group?: () => void;\n geoGroup?: () => void;\n ungroup?: () => void;\n bringToFront?: () => void;\n bringForward?: () => void;\n sendBackward?: () => void;\n sendToBack?: () => void;\n}\n\n/**\n * Registers global keyboard shortcuts for the flow editor.\n */\nexport function useKeyboardShortcuts(actions: KeyboardShortcutActions) {\n const { selection, setSelection, currentCanvas } = useFlowContext();\n const { editingNodeId, setToolMode, setPendingPlacement } = useFlowUI();\n\n useEffect(() => {\n const handler = (e: KeyboardEvent) => {\n // Don't intercept when editing text in inputs\n const target = e.target as HTMLElement;\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) return;\n if (editingNodeId) return;\n\n const meta = e.metaKey || e.ctrlKey;\n\n if (meta && e.key === 'z' && !e.shiftKey) {\n e.preventDefault();\n actions.undo();\n } else if (meta && (e.key === 'Z' || (e.key === 'z' && e.shiftKey))) {\n e.preventDefault();\n actions.redo();\n } else if (meta && e.key === 'c') {\n e.preventDefault();\n actions.copy();\n } else if (meta && e.key === 'x') {\n e.preventDefault();\n actions.cut();\n } else if (meta && e.key === 'v') {\n // Let the native paste event inspect image clipboard data. Structured\n // Flow clipboard fallback is handled there when no image is present.\n return;\n } else if (meta && e.key === 'a') {\n e.preventDefault();\n actions.selectAll();\n } else if (meta && (e.key === 'd' || e.key === 'D')) {\n e.preventDefault();\n actions.duplicate();\n } else if (meta && e.altKey && (e.key === 'g' || e.key === 'G')) {\n e.preventDefault();\n actions.geoGroup?.();\n } else if (meta && e.key === 'g' && !e.shiftKey && !e.altKey) {\n e.preventDefault();\n actions.group?.();\n } else if (meta && (e.key === 'G' || (e.key === 'g' && e.shiftKey)) && !e.altKey) {\n e.preventDefault();\n actions.ungroup?.();\n } else if (meta && e.shiftKey && e.key === 'ArrowUp') {\n e.preventDefault();\n actions.bringToFront?.();\n } else if (meta && !e.shiftKey && e.key === 'ArrowUp') {\n e.preventDefault();\n actions.bringForward?.();\n } else if (meta && !e.shiftKey && e.key === 'ArrowDown') {\n e.preventDefault();\n actions.sendBackward?.();\n } else if (meta && e.shiftKey && e.key === 'ArrowDown') {\n e.preventDefault();\n actions.sendToBack?.();\n } else if (e.key === 'Delete' || e.key === 'Backspace') {\n e.preventDefault();\n actions.deleteSelected();\n } else if (e.key === 'Escape') {\n setSelection({ nodeIds: new Set(), edgeIds: new Set(), lineIds: new Set() });\n setToolMode('select');\n setPendingPlacement(null);\n }\n };\n\n window.addEventListener('keydown', handler);\n return () => window.removeEventListener('keydown', handler);\n }, [actions, editingNodeId, setSelection, setToolMode, setPendingPlacement]);\n}\n"],"mappings":";;;AAyBA,SAAgB,EAAqB,GAAkC;AACrE,QAAM,EAAE,WAAA,GAAW,cAAA,GAAc,eAAA,EAAA,IAAkB,EAAe,GAC5D,EAAE,eAAA,GAAe,aAAA,GAAa,qBAAA,EAAA,IAAwB,EAAU;AAEtE,EAAA,EAAA,MAAgB;AACd,UAAM,IAAA,CAAW,MAAqB;AAEpC,YAAM,IAAS,EAAE;AAEjB,UADI,EAAO,YAAY,WAAW,EAAO,YAAY,cAAc,EAAO,qBACtE,EAAe;AAEnB,YAAM,IAAO,EAAE,WAAW,EAAE;AAE5B,UAAI,KAAQ,EAAE,QAAQ,OAAO,CAAC,EAAE;AAC9B,UAAE,eAAe,GACjB,EAAQ,KAAK;AAAA,eACJ,MAAS,EAAE,QAAQ,OAAQ,EAAE,QAAQ,OAAO,EAAE;AACvD,UAAE,eAAe,GACjB,EAAQ,KAAK;AAAA,eACJ,KAAQ,EAAE,QAAQ;AAC3B,UAAE,eAAe,GACjB,EAAQ,KAAK;AAAA,eACJ,KAAQ,EAAE,QAAQ;AAC3B,UAAE,eAAe,GACjB,EAAQ,IAAI;AAAA,WACP;AAAA,YAAI,KAAQ,EAAE,QAAQ,IAG3B;AACK,QAAI,KAAQ,EAAE,QAAQ,OAC3B,EAAE,eAAe,GACjB,EAAQ,UAAU,KACT,MAAS,EAAE,QAAQ,OAAO,EAAE,QAAQ,QAC7C,EAAE,eAAe,GACjB,EAAQ,UAAU,KACT,KAAQ,EAAE,WAAW,EAAE,QAAQ,OAAO,EAAE,QAAQ,QACzD,EAAE,eAAe,GACjB,EAAQ,WAAW,KACV,KAAQ,EAAE,QAAQ,OAAO,CAAC,EAAE,YAAY,CAAC,EAAE,UACpD,EAAE,eAAe,GACjB,EAAQ,QAAQ,KACP,MAAS,EAAE,QAAQ,OAAQ,EAAE,QAAQ,OAAO,EAAE,aAAc,CAAC,EAAE,UACxE,EAAE,eAAe,GACjB,EAAQ,UAAU,KACT,KAAQ,EAAE,YAAY,EAAE,QAAQ,aACzC,EAAE,eAAe,GACjB,EAAQ,eAAe,KACd,KAAQ,CAAC,EAAE,YAAY,EAAE,QAAQ,aAC1C,EAAE,eAAe,GACjB,EAAQ,eAAe,KACd,KAAQ,CAAC,EAAE,YAAY,EAAE,QAAQ,eAC1C,EAAE,eAAe,GACjB,EAAQ,eAAe,KACd,KAAQ,EAAE,YAAY,EAAE,QAAQ,eACzC,EAAE,eAAe,GACjB,EAAQ,aAAa,KACZ,EAAE,QAAQ,YAAY,EAAE,QAAQ,eACzC,EAAE,eAAe,GACjB,EAAQ,eAAe,KACd,EAAE,QAAQ,aACnB,EAAa;AAAA,UAAE,SAAS,oBAAI,IAAI;AAAA,UAAG,SAAS,oBAAI,IAAI;AAAA,UAAG,SAAS,oBAAI,IAAI;AAAA,QAAE,CAAC,GAC3E,EAAY,QAAQ,GACpB,EAAoB,IAAI;AAAA;AAAA,IAE5B;AAEA,kBAAO,iBAAiB,WAAW,CAAO,GAC1C,MAAa,OAAO,oBAAoB,WAAW,CAAO;AAAA,EAC5D,GAAG;AAAA,IAAC;AAAA,IAAS;AAAA,IAAe;AAAA,IAAc;AAAA,IAAa;AAAA,EAAmB,CAAC;AAC7E"}
@@ -20,6 +20,8 @@ export { default as Breadcrumb } from './panels/Breadcrumb';
20
20
  export { default as ProjectTitle } from './panels/ProjectTitle';
21
21
  export type { FlowProps, FlowDocument, FlowCanvasData, FlowNode, FlowNodeData, FlowEdge, FlowEdgeData, FlowLine, FlowLineType, FlowShapeType, FlowEdgeTypeName, FlowEdgeMarkerKind, FlowEdgeLineStyle, FlowEdgeDashDensity, FlowBezierControl, FlowBorderStyle, FlowToolMode, ViewportState, SelectionState, FlowNodeAttribute, GradientDirection, FlowGroupLabelPlacement, FlowGroupLabelAlign, FlowIconLabelPlacement, FlowMediaKind, FlowModelFormat, FlowDataConfig, FlowDataColumn, FlowDataColumnType, FlowDataView, FlowDataChartType, FlowDataChartConfig, FlowDataPivotConfig, FlowDataPivotPanelPlacement, FlowDataAggFn, } from './types';
22
22
  export { FLOW_NODE_TYPES } from './types';
23
+ export { archifyToFlowDocument, isArchifySpec, COMPONENT_STYLES, STATE_STYLES, ARCHIFY_BG, ARCHIFY_GRID, componentStyle, stateStyle, variantEdgeStyle, ARCHIFY_COMPONENT_ORDER, ARCHIFY_COMPONENT_LABELS, archifyStylePatch, inferComponentType, } from './archify';
24
+ export type { ArchifySpec, ArchifyDiagramType, ArchifyArchitectureSpec, ArchifyWorkflowSpec, ArchifySequenceSpec, ArchifyDataflowSpec, ArchifyLifecycleSpec, ArchifyComponentType, ArchifyStateType, ArchifyVariant, } from './archify';
23
25
  export { SVG_ICON_CATEGORIES, getSvgIcon, getSvgIconsByCategory, getAllSvgIcons, buildSvgMarkup, } from './nodes/svgIcons';
24
26
  export type { SvgIconDef, SvgIconCategory } from './nodes/svgIcons';
25
27
  export { PALETTE_ITEMS, EDGE_TYPE_OPTIONS, EDGE_MARKER_OPTIONS, EDGE_LINE_STYLE_OPTIONS, BORDER_STYLE_OPTIONS, DASH_DENSITY_OPTIONS, GRADIENT_DIRECTION_OPTIONS, DEFAULT_NODE_DATA, DEFAULT_EDGE_DATA, createEmptyDocument, ROOT_CANVAS_ID, } from './constants';
@@ -1,7 +1,10 @@
1
1
  import React from 'react';
2
2
  import type { FlowDataConfig } from '../types';
3
3
  /** Dispatches to the table or chart surface based on the node's view. */
4
- export declare function DataNodeView({ config }: {
4
+ export declare function DataNodeView({ config, surfaceColor, textColor, primaryColor, }: {
5
5
  config: FlowDataConfig;
6
+ surfaceColor?: string;
7
+ textColor?: string;
8
+ primaryColor?: string;
6
9
  }): React.JSX.Element;
7
10
  export default DataNodeView;
@@ -1,37 +1,37 @@
1
- import { usePivotExtension as y } from "../../DataTable/pivotExtension.js";
2
- import k, { createColumn as F } from "../../../../data-table.js";
3
- import A from "../../../Chart/Chart.js";
4
- import { areaY as C, barX as R, barY as T, defineChart as u, dot as M, lineY as N } from "../../../../chart.js";
5
- import { DATA_CHART_PALETTE as w, labelFor as v } from "./dataUtils.js";
6
- import { useLayoutEffect as P, useMemo as b, useRef as S, useState as z } from "react";
7
- import { jsx as c } from "react/jsx-runtime";
8
- import { scaleBand as g } from "@tanstack/charts/scales/band";
9
- import { scaleLinear as m } from "@tanstack/charts/scales/linear";
10
- import { scalePoint as x } from "@tanstack/charts/scales/point";
11
- import { pie as D, polar as E, radialArc as V } from "@tanstack/charts/polar";
12
- function B({ config: e }) {
13
- const l = b(() => e.columns.map((n) => F(n.key, n.label ?? n.key, { enableSorting: !0 })), [e.columns]), i = b(() => e.columns.map((n) => ({
14
- field: n.key,
15
- label: n.label ?? n.key,
16
- numeric: n.type === "number"
17
- })), [e.columns]), t = e.pivot, s = JSON.stringify({
1
+ import { usePivotExtension as F } from "../../DataTable/pivotExtension.js";
2
+ import A, { createColumn as R } from "../../../../data-table.js";
3
+ import C from "../../../Chart/Chart.js";
4
+ import { areaY as T, barX as M, barY as N, defineChart as p, dot as P, lineY as S } from "../../../../chart.js";
5
+ import { DATA_CHART_PALETTE as w, labelFor as y } from "./dataUtils.js";
6
+ import { useLayoutEffect as z, useMemo as v, useRef as D, useState as E } from "react";
7
+ import { jsx as u } from "react/jsx-runtime";
8
+ import { scaleBand as x } from "@tanstack/charts/scales/band";
9
+ import { scaleLinear as h } from "@tanstack/charts/scales/linear";
10
+ import { scalePoint as k } from "@tanstack/charts/scales/point";
11
+ import { pie as V, polar as B, radialArc as L } from "@tanstack/charts/polar";
12
+ function O({ config: e }) {
13
+ const o = v(() => e.columns.map((r) => R(r.key, r.label ?? r.key, { enableSorting: !0 })), [e.columns]), n = v(() => e.columns.map((r) => ({
14
+ field: r.key,
15
+ label: r.label ?? r.key,
16
+ numeric: r.type === "number"
17
+ })), [e.columns]), t = e.pivot, i = JSON.stringify({
18
18
  e: !!t?.enabled,
19
19
  r: t?.rowFields ?? [],
20
20
  c: t?.colFields ?? [],
21
21
  v: t?.values ?? []
22
22
  });
23
- return /* @__PURE__ */ c("div", {
23
+ return /* @__PURE__ */ u("div", {
24
24
  className: "flow-data-table",
25
- children: /* @__PURE__ */ c(L, {
25
+ children: /* @__PURE__ */ u(Y, {
26
26
  config: e,
27
- columns: l,
28
- pivotFields: i
29
- }, s)
27
+ columns: o,
28
+ pivotFields: n
29
+ }, i)
30
30
  });
31
31
  }
32
- function L({ config: e, columns: l, pivotFields: i }) {
33
- const t = e.pivot, s = y({
34
- fields: i,
32
+ function Y({ config: e, columns: o, pivotFields: n }) {
33
+ const t = e.pivot, i = F({
34
+ fields: n,
35
35
  initialActive: !!t?.enabled,
36
36
  initialRowFields: t?.rowFields ?? [],
37
37
  initialColFields: t?.colFields ?? [],
@@ -40,88 +40,88 @@ function L({ config: e, columns: l, pivotFields: i }) {
40
40
  lang: "zh",
41
41
  hideModeToggle: !0
42
42
  });
43
- return /* @__PURE__ */ c(k, {
43
+ return /* @__PURE__ */ u(A, {
44
44
  data: e.rows,
45
- columns: l,
45
+ columns: o,
46
46
  enableSorting: !0,
47
47
  enablePagination: e.rows.length > 50,
48
48
  pageSize: 50,
49
- extensions: [s]
49
+ extensions: [i]
50
50
  });
51
51
  }
52
- function O(e) {
53
- return b(() => {
54
- const l = e.chart;
55
- if (!l) return null;
56
- const i = l.xField, t = (l.yFields ?? []).filter(Boolean);
57
- if (!i || t.length === 0) return null;
58
- const s = e.rows, n = (r, a) => l.seriesColors?.[r] ?? w[a % w.length];
59
- switch (l.type) {
52
+ function _(e, o) {
53
+ return v(() => {
54
+ const n = e.chart;
55
+ if (!n) return null;
56
+ const t = n.xField, i = (n.yFields ?? []).filter(Boolean);
57
+ if (!t || i.length === 0) return null;
58
+ const r = e.rows, f = n.palette?.length ? n.palette : null, d = (a, l) => n.seriesColors?.[a] ?? f?.[l % f.length] ?? o ?? w[l % w.length];
59
+ switch (n.type) {
60
60
  case "line":
61
- return u({
62
- x: { scale: () => x().padding(0.35) },
61
+ return p({
62
+ x: { scale: () => k().padding(0.35) },
63
63
  y: {
64
- scale: m,
64
+ scale: h,
65
65
  nice: !0,
66
66
  grid: !0
67
67
  },
68
- marks: t.map((r, a) => N(s, {
69
- id: r,
70
- x: i,
71
- y: r,
72
- stroke: n(r, a),
68
+ marks: i.map((a, l) => S(r, {
69
+ id: a,
70
+ x: t,
71
+ y: a,
72
+ stroke: d(a, l),
73
73
  points: !0
74
74
  }))
75
75
  });
76
76
  case "area":
77
- return u({
78
- x: { scale: () => x().padding(0.35) },
77
+ return p({
78
+ x: { scale: () => k().padding(0.35) },
79
79
  y: {
80
- scale: m,
80
+ scale: h,
81
81
  nice: !0,
82
82
  grid: !0
83
83
  },
84
- marks: t.map((r, a) => C(s, {
85
- id: r,
86
- x: i,
87
- y: r,
88
- fill: n(r, a),
84
+ marks: i.map((a, l) => T(r, {
85
+ id: a,
86
+ x: t,
87
+ y: a,
88
+ fill: d(a, l),
89
89
  fillOpacity: 0.35,
90
- stroke: n(r, a)
90
+ stroke: d(a, l)
91
91
  }))
92
92
  });
93
93
  case "scatter":
94
- return u({
94
+ return p({
95
95
  x: {
96
- scale: m,
96
+ scale: h,
97
97
  nice: !0,
98
98
  grid: !0
99
99
  },
100
100
  y: {
101
- scale: m,
101
+ scale: h,
102
102
  nice: !0,
103
103
  grid: !0
104
104
  },
105
- marks: [M(s, {
105
+ marks: [P(r, {
106
106
  id: "points",
107
- x: i,
108
- y: t[0],
107
+ x: t,
108
+ y: i[0],
109
109
  r: 6,
110
- fill: n(t[0], 0)
110
+ fill: d(i[0], 0)
111
111
  })]
112
112
  });
113
113
  case "pie": {
114
- const r = t[0], a = /* @__PURE__ */ new Map();
115
- for (const o of s) {
116
- const f = String(o[i] ?? "");
117
- a.set(f, (a.get(f) ?? 0) + (Number(o[r]) || 0));
114
+ const a = i[0], l = /* @__PURE__ */ new Map();
115
+ for (const s of r) {
116
+ const m = String(s[t] ?? "");
117
+ l.set(m, (l.get(m) ?? 0) + (Number(s[a]) || 0));
118
118
  }
119
- const p = Array.from(a, ([o, f]) => ({
120
- cat: o,
121
- value: f
122
- })), h = D(p, { value: "value" }), d = l.palette?.length ? l.palette : w;
123
- return u({
124
- marks: [E({ marks: [V(h, {
119
+ const c = Array.from(l, ([s, m]) => ({
120
+ cat: s,
121
+ value: m
122
+ })), g = V(c, { value: "value" }), b = n.palette?.length ? n.palette : w;
123
+ return p({
124
+ marks: [B({ marks: [L(g, {
125
125
  startAngle: "startAngle",
126
126
  endAngle: "endAngle",
127
127
  padAngle: "padAngle",
@@ -130,88 +130,100 @@ function O(e) {
130
130
  key: "cat"
131
131
  })] })],
132
132
  color: {
133
- domain: p.map((o) => o.cat),
134
- range: d
133
+ domain: c.map((s) => s.cat),
134
+ range: b
135
135
  }
136
136
  });
137
137
  }
138
138
  case "barHorizontal":
139
- return u({
140
- y: { scale: () => g().padding(0.25) },
139
+ return p({
140
+ y: { scale: () => x().padding(0.25) },
141
141
  x: {
142
- scale: m,
142
+ scale: h,
143
143
  nice: !0,
144
144
  grid: !0
145
145
  },
146
- marks: t.map((r, a) => R(s, {
147
- id: r,
148
- y: i,
149
- x: r,
150
- fill: n(r, a),
146
+ marks: i.map((a, l) => M(r, {
147
+ id: a,
148
+ y: t,
149
+ x: a,
150
+ fill: d(a, l),
151
151
  radius: 4
152
152
  }))
153
153
  });
154
154
  default:
155
- return u({
156
- x: { scale: () => g().padding(0.25) },
155
+ return p({
156
+ x: { scale: () => x().padding(0.25) },
157
157
  y: {
158
- scale: m,
158
+ scale: h,
159
159
  nice: !0,
160
160
  grid: !0
161
161
  },
162
- marks: t.map((r, a) => T(s, {
163
- id: r,
164
- x: i,
165
- y: r,
166
- fill: n(r, a),
162
+ marks: i.map((a, l) => N(r, {
163
+ id: a,
164
+ x: t,
165
+ y: a,
166
+ fill: d(a, l),
167
167
  radius: 4
168
168
  }))
169
169
  });
170
170
  }
171
- }, [e]);
171
+ }, [e, o]);
172
172
  }
173
- function Y({ config: e }) {
174
- const l = O(e), i = e.chart, t = S(null), [s, n] = z({
173
+ function j({ config: e, surfaceColor: o, textColor: n, primaryColor: t }) {
174
+ const i = _(e, t), r = e.chart, f = D(null), [d, a] = E({
175
175
  w: 0,
176
176
  h: 0
177
177
  });
178
- if (P(() => {
179
- const a = t.current;
180
- if (!a) return;
181
- const p = () => {
182
- const d = a.getBoundingClientRect(), o = d.width && a.offsetWidth ? d.width / a.offsetWidth : 1;
183
- n({
184
- w: Math.max(1, Math.round(d.width / (o || 1))),
185
- h: Math.max(1, Math.round(d.height / (o || 1)))
178
+ if (z(() => {
179
+ const c = f.current;
180
+ if (!c) return;
181
+ const g = () => {
182
+ const s = c.getBoundingClientRect(), m = s.width && c.offsetWidth ? s.width / c.offsetWidth : 1;
183
+ a({
184
+ w: Math.max(1, Math.round(s.width / (m || 1))),
185
+ h: Math.max(1, Math.round(s.height / (m || 1)))
186
186
  });
187
187
  };
188
- p();
189
- const h = new ResizeObserver(p);
190
- return h.observe(a), () => h.disconnect();
191
- }, []), !l) return /* @__PURE__ */ c("div", {
188
+ g();
189
+ const b = new ResizeObserver(g);
190
+ return b.observe(c), () => b.disconnect();
191
+ }, []), !i) return /* @__PURE__ */ u("div", {
192
192
  className: "flow-data-empty",
193
193
  children: e.columns.length === 0 ? "尚无数据,请在属性面板上传或填写数据" : "请在属性面板选择 X 轴与至少一个数值字段"
194
194
  });
195
- const r = i && i.xField ? `${v(e.columns, i.xField)} · ${(i.yFields ?? []).map((a) => v(e.columns, a)).join(", ")}` : "Chart";
196
- return /* @__PURE__ */ c("div", {
195
+ const l = r && r.xField ? `${y(e.columns, r.xField)} · ${(r.yFields ?? []).map((c) => y(e.columns, c)).join(", ")}` : "Chart";
196
+ return /* @__PURE__ */ u("div", {
197
197
  className: "flow-data-chart",
198
- ref: t,
199
- children: s.h > 0 && /* @__PURE__ */ c(A, {
200
- definition: l,
201
- "aria-label": r,
202
- height: s.h
198
+ ref: f,
199
+ style: n ? { color: n } : void 0,
200
+ children: d.h > 0 && /* @__PURE__ */ u(C, {
201
+ definition: i,
202
+ "aria-label": l,
203
+ height: d.h,
204
+ style: {
205
+ background: o ?? "transparent",
206
+ borderColor: "transparent",
207
+ color: n ?? "inherit",
208
+ padding: 0
209
+ }
203
210
  })
204
211
  });
205
212
  }
206
- function U({ config: e }) {
207
- return !e || e.columns.length === 0 ? /* @__PURE__ */ c("div", {
213
+ function ee({ config: e, surfaceColor: o, textColor: n, primaryColor: t }) {
214
+ return !e || e.columns.length === 0 ? /* @__PURE__ */ u("div", {
208
215
  className: "flow-data-empty",
209
216
  children: "尚无数据,请在属性面板上传或填写数据"
210
- }) : e.view === "chart" ? /* @__PURE__ */ c(Y, { config: e }) : /* @__PURE__ */ c(B, { config: e });
217
+ }) : e.view === "chart" ? /* @__PURE__ */ u(j, {
218
+ config: e,
219
+ surfaceColor: o,
220
+ textColor: n,
221
+ primaryColor: t
222
+ }) : /* @__PURE__ */ u(O, { config: e });
211
223
  }
212
224
  export {
213
- U as DataNodeView,
214
- U as default
225
+ ee as DataNodeView,
226
+ ee as default
215
227
  };
216
228
 
217
229
  //# sourceMappingURL=DataNodeView.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DataNodeView.js","names":[],"sources":["../../../../../src/components/pro/Flow/nodes/DataNodeView.tsx"],"sourcesContent":["import React, { useMemo, useRef, useState, useLayoutEffect } from 'react';\nimport Chart, {\n areaY,\n barX,\n barY,\n defineChart,\n dot,\n lineY,\n} from '../../../Chart';\nimport { scaleBand } from '@tanstack/charts/scales/band';\nimport { scaleLinear } from '@tanstack/charts/scales/linear';\nimport { scalePoint } from '@tanstack/charts/scales/point';\nimport { polar, pie, radialArc } from '@tanstack/charts/polar';\nimport DataTable, {\n createColumn,\n usePivotExtension,\n type ColumnDef,\n type PivotField,\n type PivotValue,\n} from '../../DataTable';\nimport type { FlowDataConfig } from '../types';\nimport { DATA_CHART_PALETTE, labelFor } from './dataUtils';\n\n/** Renders the table (optionally pivoted) surface of a Data node. */\nfunction DataTableView({ config }: { config: FlowDataConfig }) {\n const columns = useMemo<ColumnDef<Record<string, unknown>>[]>(\n () =>\n config.columns.map((col) =>\n createColumn<Record<string, unknown>>(col.key, col.label ?? col.key, {\n enableSorting: true,\n }),\n ),\n [config.columns],\n );\n\n const pivotFields = useMemo<PivotField[]>(\n () =>\n config.columns.map((col) => ({\n field: col.key,\n label: col.label ?? col.key,\n numeric: col.type === 'number',\n })),\n [config.columns],\n );\n\n const pivot = config.pivot;\n // Remount the pivot extension when the inspector-controlled bits change, so\n // the enabled toggle / initial fields take effect (the extension keeps its\n // own interactive state otherwise). Panel placement stays reactive.\n const pivotKey = JSON.stringify({\n e: !!pivot?.enabled,\n r: pivot?.rowFields ?? [],\n c: pivot?.colFields ?? [],\n v: pivot?.values ?? [],\n });\n\n return (\n <div className=\"flow-data-table\">\n <PivotableTable\n key={pivotKey}\n config={config}\n columns={columns}\n pivotFields={pivotFields}\n />\n </div>\n );\n}\n\nfunction PivotableTable({\n config,\n columns,\n pivotFields,\n}: {\n config: FlowDataConfig;\n columns: ColumnDef<Record<string, unknown>>[];\n pivotFields: PivotField[];\n}) {\n const pivot = config.pivot;\n const pivotExtension = usePivotExtension<Record<string, unknown>>({\n fields: pivotFields,\n initialActive: !!pivot?.enabled,\n initialRowFields: pivot?.rowFields ?? [],\n initialColFields: pivot?.colFields ?? [],\n initialValues: (pivot?.values as PivotValue[] | undefined) ?? [],\n panelPlacement: pivot?.panelPlacement ?? 'top',\n lang: 'zh',\n // 透视开关由 Inspector 统一控制,节点内不再渲染开关,避免占用空间。\n hideModeToggle: true,\n });\n\n return (\n <DataTable<Record<string, unknown>>\n data={config.rows}\n columns={columns}\n enableSorting\n enablePagination={config.rows.length > 50}\n pageSize={50}\n extensions={[pivotExtension]}\n />\n );\n}\n\n/** Builds a TanStack Charts definition from the Data node's chart config. */\nfunction useChartDefinition(config: FlowDataConfig) {\n return useMemo(() => {\n const chart = config.chart;\n if (!chart) return null;\n const xField = chart.xField;\n const yFields = (chart.yFields ?? []).filter(Boolean);\n if (!xField || yFields.length === 0) return null;\n\n const rows = config.rows as any[];\n const seriesColor = (field: string, i: number) =>\n chart.seriesColors?.[field] ?? DATA_CHART_PALETTE[i % DATA_CHART_PALETTE.length];\n\n switch (chart.type) {\n case 'line':\n return defineChart({\n x: { scale: () => scalePoint<string>().padding(0.35) },\n y: { scale: scaleLinear, nice: true, grid: true },\n marks: yFields.map((yf, i) =>\n lineY(rows, { id: yf, x: xField, y: yf, stroke: seriesColor(yf, i), points: true }),\n ),\n });\n\n case 'area':\n return defineChart({\n x: { scale: () => scalePoint<string>().padding(0.35) },\n y: { scale: scaleLinear, nice: true, grid: true },\n marks: yFields.map((yf, i) =>\n areaY(rows, {\n id: yf,\n x: xField,\n y: yf,\n fill: seriesColor(yf, i),\n fillOpacity: 0.35,\n stroke: seriesColor(yf, i),\n }),\n ),\n });\n\n case 'scatter':\n // Scatter uses the first two numeric fields as x/y.\n return defineChart({\n x: { scale: scaleLinear, nice: true, grid: true },\n y: { scale: scaleLinear, nice: true, grid: true },\n marks: [\n dot(rows, {\n id: 'points',\n x: xField,\n y: yFields[0],\n r: 6,\n fill: seriesColor(yFields[0], 0),\n }),\n ],\n });\n\n case 'pie': {\n // Part-to-whole via a polar pie over the first measure. Duplicate\n // categories are aggregated (summed) so slices are unique.\n const yf = yFields[0];\n const totals = new Map<string, number>();\n for (const r of rows) {\n const k = String(r[xField] ?? '');\n totals.set(k, (totals.get(k) ?? 0) + (Number(r[yf]) || 0));\n }\n const pieRows = Array.from(totals, ([cat, value]) => ({ cat, value }));\n const arranged = pie(pieRows, { value: 'value' });\n const range = chart.palette?.length ? chart.palette : DATA_CHART_PALETTE;\n return defineChart({\n marks: [\n polar({\n marks: [\n radialArc(arranged, {\n startAngle: 'startAngle',\n endAngle: 'endAngle',\n padAngle: 'padAngle',\n innerRadius: 0,\n color: 'cat',\n key: 'cat',\n }),\n ],\n }),\n ],\n color: { domain: pieRows.map((d) => d.cat), range },\n });\n }\n\n case 'barHorizontal':\n return defineChart({\n y: { scale: () => scaleBand<string>().padding(0.25) },\n x: { scale: scaleLinear, nice: true, grid: true },\n marks: yFields.map((yf, i) =>\n barX(rows, { id: yf, y: xField, x: yf, fill: seriesColor(yf, i), radius: 4 }),\n ),\n });\n\n case 'bar':\n default:\n return defineChart({\n x: { scale: () => scaleBand<string>().padding(0.25) },\n y: { scale: scaleLinear, nice: true, grid: true },\n marks: yFields.map((yf, i) =>\n barY(rows, { id: yf, x: xField, y: yf, fill: seriesColor(yf, i), radius: 4 }),\n ),\n });\n }\n }, [config]);\n}\n\n/** Renders the chart surface of a Data node. */\nfunction DataChartView({ config }: { config: FlowDataConfig }) {\n const definition = useChartDefinition(config);\n const chart = config.chart;\n\n // TanStack Charts needs a concrete pixel height; inside the media overlay the\n // node box is a fixed size but percentage heights don't always resolve before\n // first paint (esp. in read-only / preview renders), leaving the chart blank.\n // Measure the container and pass an explicit height.\n const wrapRef = useRef<HTMLDivElement>(null);\n const [size, setSize] = useState<{ w: number; h: number }>({ w: 0, h: 0 });\n useLayoutEffect(() => {\n const el = wrapRef.current;\n if (!el) return;\n const measure = () => {\n const rect = el.getBoundingClientRect();\n // getBoundingClientRect includes the overlay's zoom scale; divide it out\n // so the chart is laid out in unscaled (world) pixels.\n const scale = rect.width && el.offsetWidth ? rect.width / el.offsetWidth : 1;\n setSize({\n w: Math.max(1, Math.round(rect.width / (scale || 1))),\n h: Math.max(1, Math.round(rect.height / (scale || 1))),\n });\n };\n measure();\n const ro = new ResizeObserver(measure);\n ro.observe(el);\n return () => ro.disconnect();\n }, []);\n\n if (!definition) {\n return (\n <div className=\"flow-data-empty\">\n {config.columns.length === 0\n ? '尚无数据,请在属性面板上传或填写数据'\n : '请在属性面板选择 X 轴与至少一个数值字段'}\n </div>\n );\n }\n\n const label =\n chart && chart.xField\n ? `${labelFor(config.columns, chart.xField)} · ${(chart.yFields ?? [])\n .map((f) => labelFor(config.columns, f))\n .join(', ')}`\n : 'Chart';\n\n return (\n <div className=\"flow-data-chart\" ref={wrapRef}>\n {size.h > 0 && (\n <Chart\n definition={definition as any}\n aria-label={label}\n height={size.h}\n />\n )}\n </div>\n );\n}\n\n/** Dispatches to the table or chart surface based on the node's view. */\nexport function DataNodeView({ config }: { config: FlowDataConfig }) {\n if (!config || config.columns.length === 0) {\n return <div className=\"flow-data-empty\">尚无数据,请在属性面板上传或填写数据</div>;\n }\n return config.view === 'chart' ? (\n <DataChartView config={config} />\n ) : (\n <DataTableView config={config} />\n );\n}\n\nexport default DataNodeView;\n"],"mappings":"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"}
1
+ {"version":3,"file":"DataNodeView.js","names":[],"sources":["../../../../../src/components/pro/Flow/nodes/DataNodeView.tsx"],"sourcesContent":["import React, { useMemo, useRef, useState, useLayoutEffect } from 'react';\nimport Chart, {\n areaY,\n barX,\n barY,\n defineChart,\n dot,\n lineY,\n} from '../../../Chart';\nimport { scaleBand } from '@tanstack/charts/scales/band';\nimport { scaleLinear } from '@tanstack/charts/scales/linear';\nimport { scalePoint } from '@tanstack/charts/scales/point';\nimport { polar, pie, radialArc } from '@tanstack/charts/polar';\nimport DataTable, {\n createColumn,\n usePivotExtension,\n type ColumnDef,\n type PivotField,\n type PivotValue,\n} from '../../DataTable';\nimport type { FlowDataConfig } from '../types';\nimport { DATA_CHART_PALETTE, labelFor } from './dataUtils';\n\n/** Renders the table (optionally pivoted) surface of a Data node. */\nfunction DataTableView({ config }: { config: FlowDataConfig }) {\n const columns = useMemo<ColumnDef<Record<string, unknown>>[]>(\n () =>\n config.columns.map((col) =>\n createColumn<Record<string, unknown>>(col.key, col.label ?? col.key, {\n enableSorting: true,\n }),\n ),\n [config.columns],\n );\n\n const pivotFields = useMemo<PivotField[]>(\n () =>\n config.columns.map((col) => ({\n field: col.key,\n label: col.label ?? col.key,\n numeric: col.type === 'number',\n })),\n [config.columns],\n );\n\n const pivot = config.pivot;\n // Remount the pivot extension when the inspector-controlled bits change, so\n // the enabled toggle / initial fields take effect (the extension keeps its\n // own interactive state otherwise). Panel placement stays reactive.\n const pivotKey = JSON.stringify({\n e: !!pivot?.enabled,\n r: pivot?.rowFields ?? [],\n c: pivot?.colFields ?? [],\n v: pivot?.values ?? [],\n });\n\n return (\n <div className=\"flow-data-table\">\n <PivotableTable\n key={pivotKey}\n config={config}\n columns={columns}\n pivotFields={pivotFields}\n />\n </div>\n );\n}\n\nfunction PivotableTable({\n config,\n columns,\n pivotFields,\n}: {\n config: FlowDataConfig;\n columns: ColumnDef<Record<string, unknown>>[];\n pivotFields: PivotField[];\n}) {\n const pivot = config.pivot;\n const pivotExtension = usePivotExtension<Record<string, unknown>>({\n fields: pivotFields,\n initialActive: !!pivot?.enabled,\n initialRowFields: pivot?.rowFields ?? [],\n initialColFields: pivot?.colFields ?? [],\n initialValues: (pivot?.values as PivotValue[] | undefined) ?? [],\n panelPlacement: pivot?.panelPlacement ?? 'top',\n lang: 'zh',\n // 透视开关由 Inspector 统一控制,节点内不再渲染开关,避免占用空间。\n hideModeToggle: true,\n });\n\n return (\n <DataTable<Record<string, unknown>>\n data={config.rows}\n columns={columns}\n enableSorting\n enablePagination={config.rows.length > 50}\n pageSize={50}\n extensions={[pivotExtension]}\n />\n );\n}\n\n/** Builds a TanStack Charts definition from the Data node's chart config. */\nfunction useChartDefinition(config: FlowDataConfig, primaryColor?: string) {\n return useMemo(() => {\n const chart = config.chart;\n if (!chart) return null;\n const xField = chart.xField;\n const yFields = (chart.yFields ?? []).filter(Boolean);\n if (!xField || yFields.length === 0) return null;\n\n const rows = config.rows as any[];\n // Series color resolution order: an explicit per-series override, then a\n // configured chart palette, then the node's own `color` (the drawing's\n // primary color), then the built-in default palette.\n const paletteRange = chart.palette?.length ? chart.palette : null;\n const seriesColor = (field: string, i: number) =>\n chart.seriesColors?.[field]\n ?? paletteRange?.[i % paletteRange.length]\n ?? primaryColor\n ?? DATA_CHART_PALETTE[i % DATA_CHART_PALETTE.length];\n\n switch (chart.type) {\n case 'line':\n return defineChart({\n x: { scale: () => scalePoint<string>().padding(0.35) },\n y: { scale: scaleLinear, nice: true, grid: true },\n marks: yFields.map((yf, i) =>\n lineY(rows, { id: yf, x: xField, y: yf, stroke: seriesColor(yf, i), points: true }),\n ),\n });\n\n case 'area':\n return defineChart({\n x: { scale: () => scalePoint<string>().padding(0.35) },\n y: { scale: scaleLinear, nice: true, grid: true },\n marks: yFields.map((yf, i) =>\n areaY(rows, {\n id: yf,\n x: xField,\n y: yf,\n fill: seriesColor(yf, i),\n fillOpacity: 0.35,\n stroke: seriesColor(yf, i),\n }),\n ),\n });\n\n case 'scatter':\n // Scatter uses the first two numeric fields as x/y.\n return defineChart({\n x: { scale: scaleLinear, nice: true, grid: true },\n y: { scale: scaleLinear, nice: true, grid: true },\n marks: [\n dot(rows, {\n id: 'points',\n x: xField,\n y: yFields[0],\n r: 6,\n fill: seriesColor(yFields[0], 0),\n }),\n ],\n });\n\n case 'pie': {\n // Part-to-whole via a polar pie over the first measure. Duplicate\n // categories are aggregated (summed) so slices are unique.\n const yf = yFields[0];\n const totals = new Map<string, number>();\n for (const r of rows) {\n const k = String(r[xField] ?? '');\n totals.set(k, (totals.get(k) ?? 0) + (Number(r[yf]) || 0));\n }\n const pieRows = Array.from(totals, ([cat, value]) => ({ cat, value }));\n const arranged = pie(pieRows, { value: 'value' });\n const range = chart.palette?.length ? chart.palette : DATA_CHART_PALETTE;\n return defineChart({\n marks: [\n polar({\n marks: [\n radialArc(arranged, {\n startAngle: 'startAngle',\n endAngle: 'endAngle',\n padAngle: 'padAngle',\n innerRadius: 0,\n color: 'cat',\n key: 'cat',\n }),\n ],\n }),\n ],\n color: { domain: pieRows.map((d) => d.cat), range },\n });\n }\n\n case 'barHorizontal':\n return defineChart({\n y: { scale: () => scaleBand<string>().padding(0.25) },\n x: { scale: scaleLinear, nice: true, grid: true },\n marks: yFields.map((yf, i) =>\n barX(rows, { id: yf, y: xField, x: yf, fill: seriesColor(yf, i), radius: 4 }),\n ),\n });\n\n case 'bar':\n default:\n return defineChart({\n x: { scale: () => scaleBand<string>().padding(0.25) },\n y: { scale: scaleLinear, nice: true, grid: true },\n marks: yFields.map((yf, i) =>\n barY(rows, { id: yf, x: xField, y: yf, fill: seriesColor(yf, i), radius: 4 }),\n ),\n });\n }\n }, [config, primaryColor]);\n}\n\n/** Renders the chart surface of a Data node. */\nfunction DataChartView({ config, surfaceColor, textColor, primaryColor }: { config: FlowDataConfig; surfaceColor?: string; textColor?: string; primaryColor?: string }) {\n const definition = useChartDefinition(config, primaryColor);\n const chart = config.chart;\n\n // TanStack Charts needs a concrete pixel height; inside the media overlay the\n // node box is a fixed size but percentage heights don't always resolve before\n // first paint (esp. in read-only / preview renders), leaving the chart blank.\n // Measure the container and pass an explicit height.\n const wrapRef = useRef<HTMLDivElement>(null);\n const [size, setSize] = useState<{ w: number; h: number }>({ w: 0, h: 0 });\n useLayoutEffect(() => {\n const el = wrapRef.current;\n if (!el) return;\n const measure = () => {\n const rect = el.getBoundingClientRect();\n // getBoundingClientRect includes the overlay's zoom scale; divide it out\n // so the chart is laid out in unscaled (world) pixels.\n const scale = rect.width && el.offsetWidth ? rect.width / el.offsetWidth : 1;\n setSize({\n w: Math.max(1, Math.round(rect.width / (scale || 1))),\n h: Math.max(1, Math.round(rect.height / (scale || 1))),\n });\n };\n measure();\n const ro = new ResizeObserver(measure);\n ro.observe(el);\n return () => ro.disconnect();\n }, []);\n\n if (!definition) {\n return (\n <div className=\"flow-data-empty\">\n {config.columns.length === 0\n ? '尚无数据,请在属性面板上传或填写数据'\n : '请在属性面板选择 X 轴与至少一个数值字段'}\n </div>\n );\n }\n\n const label =\n chart && chart.xField\n ? `${labelFor(config.columns, chart.xField)} · ${(chart.yFields ?? [])\n .map((f) => labelFor(config.columns, f))\n .join(', ')}`\n : 'Chart';\n\n return (\n <div\n className=\"flow-data-chart\"\n ref={wrapRef}\n style={textColor ? ({ color: textColor } as React.CSSProperties) : undefined}\n >\n {size.h > 0 && (\n <Chart\n definition={definition as any}\n aria-label={label}\n height={size.h}\n // Let the media node's fill show through instead of the Chart's\n // default opaque white card, and let axis/label text inherit the\n // node's text color so the chart matches Archify (or any) theming.\n style={{\n background: surfaceColor ?? 'transparent',\n borderColor: 'transparent',\n color: textColor ?? 'inherit',\n padding: 0,\n }}\n />\n )}\n </div>\n );\n}\n\n/** Dispatches to the table or chart surface based on the node's view. */\nexport function DataNodeView({\n config,\n surfaceColor,\n textColor,\n primaryColor,\n}: {\n config: FlowDataConfig;\n surfaceColor?: string;\n textColor?: string;\n primaryColor?: string;\n}) {\n if (!config || config.columns.length === 0) {\n return <div className=\"flow-data-empty\">尚无数据,请在属性面板上传或填写数据</div>;\n }\n return config.view === 'chart' ? (\n <DataChartView config={config} surfaceColor={surfaceColor} textColor={textColor} primaryColor={primaryColor} />\n ) : (\n <DataTableView config={config} />\n );\n}\n\nexport default DataNodeView;\n"],"mappings":"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"}