dishui 0.0.64 → 0.0.65

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 (177) hide show
  1. package/dist/components/Badge/index.js +12 -9
  2. package/dist/components/Badge/index.js.map +1 -1
  3. package/dist/components/Button/index.js +43 -40
  4. package/dist/components/Button/index.js.map +1 -1
  5. package/dist/components/Card/index.d.ts +11 -0
  6. package/dist/components/Card/index.js +62 -37
  7. package/dist/components/Card/index.js.map +1 -1
  8. package/dist/components/Chart/Chart.js.map +1 -1
  9. package/dist/components/Checkbox/index.js +32 -30
  10. package/dist/components/Checkbox/index.js.map +1 -1
  11. package/dist/components/Demo/index.js.map +1 -1
  12. package/dist/components/EmptyState/index.d.ts +4 -1
  13. package/dist/components/EmptyState/index.js +3 -3
  14. package/dist/components/EmptyState/index.js.map +1 -1
  15. package/dist/components/FileUploader/DropZone.js.map +1 -1
  16. package/dist/components/FileUploader/FileItem.js.map +1 -1
  17. package/dist/components/FileUploader/FileUploader.js.map +1 -1
  18. package/dist/components/FileUploader/UploadQueue.js.map +1 -1
  19. package/dist/components/Input/index.js +30 -30
  20. package/dist/components/Input/index.js.map +1 -1
  21. package/dist/components/Label/index.js +41 -40
  22. package/dist/components/Label/index.js.map +1 -1
  23. package/dist/components/List/index.js +47 -32
  24. package/dist/components/List/index.js.map +1 -1
  25. package/dist/components/Markdown/Markdown.js +61 -57
  26. package/dist/components/Markdown/Markdown.js.map +1 -1
  27. package/dist/components/Markdown/markdownComponents.js +49 -49
  28. package/dist/components/Markdown/markdownComponents.js.map +1 -1
  29. package/dist/components/Modal/index.d.ts +7 -3
  30. package/dist/components/Modal/index.js +77 -65
  31. package/dist/components/Modal/index.js.map +1 -1
  32. package/dist/components/Page/index.d.ts +58 -0
  33. package/dist/components/Page/index.js +74 -0
  34. package/dist/components/Page/index.js.map +1 -0
  35. package/dist/components/PageHeader/index.js.map +1 -1
  36. package/dist/components/Select/index.js +0 -3
  37. package/dist/components/Select/index.js.map +1 -1
  38. package/dist/components/SidebarToggleButton/index.js.map +1 -1
  39. package/dist/components/StatCard/index.d.ts +3 -1
  40. package/dist/components/StatCard/index.js +39 -11
  41. package/dist/components/StatCard/index.js.map +1 -1
  42. package/dist/components/Table/index.js +103 -85
  43. package/dist/components/Table/index.js.map +1 -1
  44. package/dist/components/Tabs/index.d.ts +19 -5
  45. package/dist/components/Tabs/index.js +32 -13
  46. package/dist/components/Tabs/index.js.map +1 -1
  47. package/dist/components/Tree/Tree.js.map +1 -1
  48. package/dist/components/pro/ArticleContextMenu/index.js.map +1 -1
  49. package/dist/components/pro/ArticleControl/ArticleControl2.js.map +1 -1
  50. package/dist/components/pro/CodeEditor/editors/CodeEditor.js +141 -134
  51. package/dist/components/pro/CodeEditor/editors/CodeEditor.js.map +1 -1
  52. package/dist/components/pro/CodeEditor/editors/MarkdownEditor.js +81 -78
  53. package/dist/components/pro/CodeEditor/editors/MarkdownEditor.js.map +1 -1
  54. package/dist/components/pro/CodeEditor/panels/FootnotePanel.js.map +1 -1
  55. package/dist/components/pro/CodeEditor/panels/HistoryPanel.js.map +1 -1
  56. package/dist/components/pro/CodeEditor/panels/OutlinePanel.js.map +1 -1
  57. package/dist/components/pro/CodeEditor/panels/TableOfContentsPanel.js.map +1 -1
  58. package/dist/components/pro/CodeEditor/panels/VariablePanel.js.map +1 -1
  59. package/dist/components/pro/CodeEditor/themes.js +59 -59
  60. package/dist/components/pro/CodeEditor/themes.js.map +1 -1
  61. package/dist/components/pro/DataTable/DataTable.js +49 -48
  62. package/dist/components/pro/DataTable/DataTable.js.map +1 -1
  63. package/dist/components/pro/DataTable/Filters.js +42 -42
  64. package/dist/components/pro/DataTable/Filters.js.map +1 -1
  65. package/dist/components/pro/DataTable/PivotPanel.js.map +1 -1
  66. package/dist/components/pro/DataTable/PivotView.js +35 -32
  67. package/dist/components/pro/DataTable/PivotView.js.map +1 -1
  68. package/dist/components/pro/DataTable/components/BulkActions.js.map +1 -1
  69. package/dist/components/pro/DataTable/components/ColumnSelector.js.map +1 -1
  70. package/dist/components/pro/DataTable/components/FilterBar.js.map +1 -1
  71. package/dist/components/pro/DataTable/components/TableBody.js.map +1 -1
  72. package/dist/components/pro/DataTable/components/TableHeader.js.map +1 -1
  73. package/dist/components/pro/DataTable/components/TablePagination.js.map +1 -1
  74. package/dist/components/pro/DataTable/components/TableToolbar.js.map +1 -1
  75. package/dist/components/pro/DataTable/pivotExtension.js.map +1 -1
  76. package/dist/components/pro/DataTable/rowDetailExtension.js.map +1 -1
  77. package/dist/components/pro/DataTable/tanstack-table.js +37 -37
  78. package/dist/components/pro/DataTable/tanstack-table.js.map +1 -1
  79. package/dist/components/pro/FileExplorer/Breadcrumb.js +53 -53
  80. package/dist/components/pro/FileExplorer/Breadcrumb.js.map +1 -1
  81. package/dist/components/pro/FileExplorer/CreateDialog.js.map +1 -1
  82. package/dist/components/pro/FileExplorer/FileExplorer.js.map +1 -1
  83. package/dist/components/pro/FileExplorer/FileIcon.js +22 -22
  84. package/dist/components/pro/FileExplorer/FileIcon.js.map +1 -1
  85. package/dist/components/pro/FileExplorer/GridView.js.map +1 -1
  86. package/dist/components/pro/FileExplorer/ListView.js.map +1 -1
  87. package/dist/components/pro/FileExplorer/Toolbar.js.map +1 -1
  88. package/dist/components/pro/Flow/Flow.js +496 -494
  89. package/dist/components/pro/Flow/Flow.js.map +1 -1
  90. package/dist/components/pro/Flow/FlowCanvas.js +916 -917
  91. package/dist/components/pro/Flow/FlowCanvas.js.map +1 -1
  92. package/dist/components/pro/Flow/context/FlowUIContext.js.map +1 -1
  93. package/dist/components/pro/Flow/edges/EdgeRenderer.js +59 -59
  94. package/dist/components/pro/Flow/edges/EdgeRenderer.js.map +1 -1
  95. package/dist/components/pro/Flow/hooks/useClipboard.js.map +1 -1
  96. package/dist/components/pro/Flow/hooks/useDeleteSelection.js.map +1 -1
  97. package/dist/components/pro/Flow/hooks/useEdgeMutations.js.map +1 -1
  98. package/dist/components/pro/Flow/hooks/useLayoutActions.js +9 -11
  99. package/dist/components/pro/Flow/hooks/useLayoutActions.js.map +1 -1
  100. package/dist/components/pro/Flow/hooks/useLineMutations.js.map +1 -1
  101. package/dist/components/pro/Flow/hooks/useMindMap.js.map +1 -1
  102. package/dist/components/pro/Flow/hooks/useNodeMutations.js.map +1 -1
  103. package/dist/components/pro/Flow/lines/FreehandTool.js +9 -9
  104. package/dist/components/pro/Flow/lines/FreehandTool.js.map +1 -1
  105. package/dist/components/pro/Flow/lines/LineRenderer.js +5 -5
  106. package/dist/components/pro/Flow/lines/LineRenderer.js.map +1 -1
  107. package/dist/components/pro/Flow/nodes/DataNodeView.js +113 -93
  108. package/dist/components/pro/Flow/nodes/DataNodeView.js.map +1 -1
  109. package/dist/components/pro/Flow/nodes/MediaContent.js.map +1 -1
  110. package/dist/components/pro/Flow/nodes/MediaOverlay.js.map +1 -1
  111. package/dist/components/pro/Flow/nodes/Model3DView.js +1 -1
  112. package/dist/components/pro/Flow/nodes/Model3DView.js.map +1 -1
  113. package/dist/components/pro/Flow/nodes/NodeRenderer.js +118 -118
  114. package/dist/components/pro/Flow/nodes/NodeRenderer.js.map +1 -1
  115. package/dist/components/pro/Flow/nodes/dataUtils.js.map +1 -1
  116. package/dist/components/pro/Flow/nodes/shapes.js +1 -3
  117. package/dist/components/pro/Flow/nodes/shapes.js.map +1 -1
  118. package/dist/components/pro/Flow/panels/AIPanel.js.map +1 -1
  119. package/dist/components/pro/Flow/panels/Breadcrumb.js.map +1 -1
  120. package/dist/components/pro/Flow/panels/ContextMenu.js.map +1 -1
  121. package/dist/components/pro/Flow/panels/DataInspectorSection.js.map +1 -1
  122. package/dist/components/pro/Flow/panels/ExpandableTextarea.js.map +1 -1
  123. package/dist/components/pro/Flow/panels/FlowPanelGroup.js.map +1 -1
  124. package/dist/components/pro/Flow/panels/FlowToolbar.js +97 -97
  125. package/dist/components/pro/Flow/panels/FlowToolbar.js.map +1 -1
  126. package/dist/components/pro/Flow/panels/InspectorPanel.js +57 -57
  127. package/dist/components/pro/Flow/panels/InspectorPanel.js.map +1 -1
  128. package/dist/components/pro/Flow/panels/OutlinePanel.js +26 -22
  129. package/dist/components/pro/Flow/panels/OutlinePanel.js.map +1 -1
  130. package/dist/components/pro/Flow/panels/PresentationMode.js +18 -16
  131. package/dist/components/pro/Flow/panels/PresentationMode.js.map +1 -1
  132. package/dist/components/pro/Flow/panels/ProjectTitle.js.map +1 -1
  133. package/dist/components/pro/Flow/panels/ShapePalette.js +109 -104
  134. package/dist/components/pro/Flow/panels/ShapePalette.js.map +1 -1
  135. package/dist/components/pro/Flow/panels/toolbarIcons.js.map +1 -1
  136. package/dist/components/pro/RichTextEditor/AIRewrite.js.map +1 -1
  137. package/dist/components/pro/RichTextEditor/BlockHandle.js.map +1 -1
  138. package/dist/components/pro/RichTextEditor/BubbleToolbar.js.map +1 -1
  139. package/dist/components/pro/RichTextEditor/CommentDialog.js.map +1 -1
  140. package/dist/components/pro/RichTextEditor/CommentPanel.js.map +1 -1
  141. package/dist/components/pro/RichTextEditor/CommentPopover.js.map +1 -1
  142. package/dist/components/pro/RichTextEditor/ContextMenu.js.map +1 -1
  143. package/dist/components/pro/RichTextEditor/RichTextEditor.js.map +1 -1
  144. package/dist/components/pro/RichTextEditor/SlashMenu.js.map +1 -1
  145. package/dist/components/pro/RichTextEditor/Toolbar/ColorPicker.js.map +1 -1
  146. package/dist/components/pro/RichTextEditor/Toolbar/FloatingDialogMenu.js.map +1 -1
  147. package/dist/components/pro/RichTextEditor/Toolbar/MarkdownTemplates.js.map +1 -1
  148. package/dist/components/pro/RichTextEditor/Toolbar/SelectDropdown.js.map +1 -1
  149. package/dist/components/pro/RichTextEditor/Toolbar/TableOpsMenu.js.map +1 -1
  150. package/dist/components/pro/RichTextEditor/Toolbar/Toolbar.js.map +1 -1
  151. package/dist/components/pro/RichTextEditor/extensions/CodeBlockView.js.map +1 -1
  152. package/dist/components/pro/RichTextEditor/extensions/FloatingDialog.js.map +1 -1
  153. package/dist/components/pro/RichTextEditor/extensions/MarkdownBlock.js.map +1 -1
  154. package/dist/contexts/AppContext.js.map +1 -1
  155. package/dist/dishui.css +1 -1
  156. package/dist/hooks/useTableColumns.js +7 -8
  157. package/dist/hooks/useTableColumns.js.map +1 -1
  158. package/dist/index.d.ts +2 -0
  159. package/dist/index.js +227 -221
  160. package/dist/layouts/MainLayout.js +22 -22
  161. package/dist/layouts/MainLayout.js.map +1 -1
  162. package/dist/layouts/Navbar.js.map +1 -1
  163. package/dist/layouts/Sidebar.js +94 -73
  164. package/dist/layouts/Sidebar.js.map +1 -1
  165. package/dist/layouts/headbar/Headbar.js.map +1 -1
  166. package/dist/layouts/headbar/HeadbarLangSwitcher.js.map +1 -1
  167. package/dist/layouts/headbar/HeadbarSearch.js.map +1 -1
  168. package/dist/layouts/headbar/HeadbarThemeSwitcher.js +11 -11
  169. package/dist/layouts/headbar/HeadbarThemeSwitcher.js.map +1 -1
  170. package/dist/layouts/headbar/HeadbarTitle.js.map +1 -1
  171. package/dist/utils/i18n.js +10 -10
  172. package/dist/utils/i18n.js.map +1 -1
  173. package/dist/utils/menu.js.map +1 -1
  174. package/dist/utils/routerBuilder.js +17 -15
  175. package/dist/utils/routerBuilder.js.map +1 -1
  176. package/dist/utils/themes.js.map +1 -1
  177. package/package.json +7 -7
@@ -27,25 +27,29 @@ function W({ node: n }) {
27
27
  }
28
28
  }) : null;
29
29
  }
30
- return n.type === "mediaNode" ? /* @__PURE__ */ u("span", {
31
- style: {
32
- width: 24,
33
- textAlign: "center",
34
- fontSize: 10,
35
- fontWeight: 700
36
- },
37
- children: n.data.mediaKind === "markdown" ? "M↓" : n.data.mediaKind === "html" ? "</>" : n.data.mediaKind === "mermaid" ? "⎇" : n.data.mediaKind === "math" ? "√x" : n.data.mediaKind === "image" ? "IMG" : n.data.mediaKind === "model3d" ? "3D" : n.data.mediaKind === "data" ? "⊞" : "AI"
38
- }) : /* @__PURE__ */ u(E, { type: n.type });
30
+ if (n.type === "mediaNode") {
31
+ const h = n.data.mediaKind === "markdown" ? "M↓" : n.data.mediaKind === "html" ? "</>" : n.data.mediaKind === "mermaid" ? "⎇" : n.data.mediaKind === "math" ? "√x" : n.data.mediaKind === "image" ? "IMG" : n.data.mediaKind === "model3d" ? "3D" : n.data.mediaKind === "data" ? "⊞" : "AI";
32
+ return /* @__PURE__ */ u("span", {
33
+ style: {
34
+ width: 24,
35
+ textAlign: "center",
36
+ fontSize: 10,
37
+ fontWeight: 700
38
+ },
39
+ children: h
40
+ });
41
+ }
42
+ return /* @__PURE__ */ u(E, { type: n.type });
39
43
  }
40
44
  function _(n, h, s) {
41
- const g = /* @__PURE__ */ new Map(), f = /* @__PURE__ */ new Map(), y = /* @__PURE__ */ new Set(), b = /* @__PURE__ */ new Set();
45
+ const g = /* @__PURE__ */ new Map(), f = /* @__PURE__ */ new Map(), y = /* @__PURE__ */ new Set(), x = /* @__PURE__ */ new Set();
42
46
  for (const e of n) if (e.parentId) {
43
47
  const c = g.get(e.parentId) ?? [];
44
48
  c.push(e), g.set(e.parentId, c), y.add(e.id);
45
49
  }
46
50
  for (const e of h) if (e.parentId) {
47
51
  const c = f.get(e.parentId) ?? [];
48
- c.push(e), f.set(e.parentId, c), b.add(e.id);
52
+ c.push(e), f.set(e.parentId, c), x.add(e.id);
49
53
  }
50
54
  const v = n.filter((e) => e.type === "geometryGroup");
51
55
  for (const e of v) {
@@ -56,23 +60,23 @@ function _(n, h, s) {
56
60
  o.push(t), g.set(e.id, o), y.add(t.id);
57
61
  }
58
62
  for (const t of h)
59
- if (!b.has(t.id) && t.points.length > 0 && t.points.every((o) => o.x >= c && o.x <= c + i && o.y >= r && o.y <= r + l)) {
63
+ if (!x.has(t.id) && t.points.length > 0 && t.points.every((o) => o.x >= c && o.x <= c + i && o.y >= r && o.y <= r + l)) {
60
64
  const o = f.get(e.id) ?? [];
61
- o.push(t), f.set(e.id, o), b.add(t.id);
65
+ o.push(t), f.set(e.id, o), x.add(t.id);
62
66
  }
63
67
  }
64
68
  const m = n.filter((e) => !y.has(e.id)), C = (e) => ({
65
69
  id: e.id,
66
70
  label: `${e.type} line`,
67
71
  icon: "〰"
68
- }), x = (e) => {
72
+ }), b = (e) => {
69
73
  const c = !!e.data.childCanvasId, r = /* @__PURE__ */ u(W, { node: e }), i = g.get(e.id), l = f.get(e.id), t = {
70
74
  id: e.id,
71
75
  label: e.data.label || e.type,
72
76
  icon: r,
73
77
  meta: c ? { childCanvasId: e.data.childCanvasId } : void 0
74
78
  }, o = [];
75
- if (i && i.length > 0 && o.push(...i.map(x)), l && l.length > 0 && o.push(...l.map(C)), c) {
79
+ if (i && i.length > 0 && o.push(...i.map(b)), l && l.length > 0 && o.push(...l.map(C)), c) {
76
80
  const d = s.canvases[e.data.childCanvasId];
77
81
  if (d) {
78
82
  const a = X(d, s, e.data.childCanvasId);
@@ -82,8 +86,8 @@ function _(n, h, s) {
82
86
  return o.length > 0 && (t.children = o), t;
83
87
  };
84
88
  return {
85
- nodeTree: m.map(x),
86
- assignedLineIds: b
89
+ nodeTree: m.map(b),
90
+ assignedLineIds: x
87
91
  };
88
92
  }
89
93
  function X(n, h, s) {
@@ -133,7 +137,7 @@ function te() {
133
137
  }) : null;
134
138
  }
135
139
  function Y() {
136
- const { focusOnRect: n } = k(), { doc: h, currentCanvas: s, currentCanvasId: g, selection: f, setSelection: y, pushCanvas: b } = L(), v = M(() => {
140
+ const { focusOnRect: n } = k(), { doc: h, currentCanvas: s, currentCanvasId: g, selection: f, setSelection: y, pushCanvas: x } = L(), v = M(() => {
137
141
  const { nodeTree: r, assignedLineIds: i } = _(s.nodes, s.lines, h), l = s.edges.map((a) => {
138
142
  const p = s.nodes.find((N) => N.id === a.source), I = s.nodes.find((N) => N.id === a.target), w = p?.data.label || a.source, S = I?.data.label || a.target;
139
143
  return {
@@ -186,7 +190,7 @@ function Y() {
186
190
  s.nodes,
187
191
  s.lines,
188
192
  m
189
- ]), x = T((r) => {
193
+ ]), b = T((r) => {
190
194
  const i = String(r.id);
191
195
  if (i.startsWith("_")) return;
192
196
  const l = s.nodes.find((d) => d.id === i), t = s.edges.find((d) => d.id === i), o = s.lines.find((d) => d.id === i);
@@ -215,8 +219,8 @@ function Y() {
215
219
  const i = String(r.id);
216
220
  if (i.startsWith("_")) return;
217
221
  const l = s.nodes.find((t) => t.id === i);
218
- l?.data.childCanvasId && b(l.data.childCanvasId);
219
- }, [s.nodes, b]), c = R(null);
222
+ l?.data.childCanvasId && x(l.data.childCanvasId);
223
+ }, [s.nodes, x]), c = R(null);
220
224
  return G(() => {
221
225
  if (!m || !c.current) return;
222
226
  const r = setTimeout(() => {
@@ -231,7 +235,7 @@ function Y() {
231
235
  ref: c,
232
236
  children: /* @__PURE__ */ u(z, {
233
237
  data: v,
234
- onNodeClick: x,
238
+ onNodeClick: b,
235
239
  onNodeDoubleClick: e,
236
240
  activeNodeId: m,
237
241
  defaultExpandedIds: C,
@@ -1 +1 @@
1
- {"version":3,"file":"OutlinePanel.js","names":[],"sources":["../../../../../src/components/pro/Flow/panels/OutlinePanel.tsx"],"sourcesContent":["import React, { useMemo, useCallback, useRef, useEffect } from 'react';\nimport { Tree, type TreeNode } from '../../../Tree';\nimport { useFlowUI } from '../context/FlowUIContext';\nimport { useFlowContext } from '../context/FlowContext';\nimport { useDraggablePanel } from '../hooks/useDraggablePanel';\nimport { useResizablePanel } from '../hooks/useResizablePanel';\nimport { PaletteThumbnail } from './ShapePalette';\nimport { buildSvgMarkup } from '../nodes/svgIcons';\nimport { resolveThemeColor } from '../utils/themeColor';\nimport type { FlowNode, FlowLine, FlowDocument, FlowCanvasData } from '../types';\n\nconst SUB_CANVAS_ICON = '⧉';\n\nfunction OutlineNodeIcon({ node }: { node: FlowNode }) {\n if (node.data.childCanvasId) return <span style={{ fontSize: 15 }}>{SUB_CANVAS_ICON}</span>;\n if (node.type === 'shapeSvg' && node.data.svgId) {\n const markup = buildSvgMarkup(node.data.svgId, resolveThemeColor(node.data.color, '#475569') || '#475569');\n return markup ? (\n <img\n src={`data:image/svg+xml;utf8,${encodeURIComponent(markup)}`}\n width={24}\n height={20}\n alt=\"\"\n style={{ display: 'block', objectFit: 'contain' }}\n />\n ) : null;\n }\n if (node.type === 'mediaNode') {\n const text = node.data.mediaKind === 'markdown' ? 'M↓'\n : node.data.mediaKind === 'html' ? '</>'\n : node.data.mediaKind === 'mermaid' ? '⎇'\n : node.data.mediaKind === 'math' ? '√x'\n : node.data.mediaKind === 'image' ? 'IMG'\n : node.data.mediaKind === 'model3d' ? '3D'\n : node.data.mediaKind === 'data' ? '⊞'\n : 'AI';\n return <span style={{ width: 24, textAlign: 'center', fontSize: 10, fontWeight: 700 }}>{text}</span>;\n }\n return <PaletteThumbnail type={node.type} />;\n}\n\nfunction buildNodeTree(nodes: FlowNode[], lines: FlowLine[], doc: FlowDocument): { nodeTree: TreeNode[]; assignedLineIds: Set<string> } {\n const childNodesOf = new Map<string, FlowNode[]>();\n const childLinesOf = new Map<string, FlowLine[]>();\n const assignedNodes = new Set<string>();\n const assignedLineIds = new Set<string>();\n\n for (const n of nodes) {\n if (n.parentId) {\n const list = childNodesOf.get(n.parentId) ?? [];\n list.push(n);\n childNodesOf.set(n.parentId, list);\n assignedNodes.add(n.id);\n }\n }\n for (const l of lines) {\n if (l.parentId) {\n const list = childLinesOf.get(l.parentId) ?? [];\n list.push(l);\n childLinesOf.set(l.parentId, list);\n assignedLineIds.add(l.id);\n }\n }\n\n // Spatial containment only for geometryGroup\n const geoGroups = nodes.filter(n => n.type === 'geometryGroup');\n for (const g of geoGroups) {\n const gx = g.position.x, gy = g.position.y;\n const gw = g.width, gh = g.height;\n for (const n of nodes) {\n if (n.id === g.id || assignedNodes.has(n.id)) continue;\n if (n.position.x >= gx && n.position.y >= gy\n && n.position.x + n.width <= gx + gw\n && n.position.y + n.height <= gy + gh) {\n const list = childNodesOf.get(g.id) ?? [];\n list.push(n);\n childNodesOf.set(g.id, list);\n assignedNodes.add(n.id);\n }\n }\n for (const l of lines) {\n if (assignedLineIds.has(l.id)) continue;\n if (l.points.length > 0 && l.points.every(p =>\n p.x >= gx && p.x <= gx + gw && p.y >= gy && p.y <= gy + gh\n )) {\n const list = childLinesOf.get(g.id) ?? [];\n list.push(l);\n childLinesOf.set(g.id, list);\n assignedLineIds.add(l.id);\n }\n }\n }\n\n const roots = nodes.filter(n => !assignedNodes.has(n.id));\n\n const lineToTree = (l: FlowLine): TreeNode => ({\n id: l.id,\n label: `${l.type} line`,\n icon: '〰',\n });\n\n const toTreeNode = (n: FlowNode): TreeNode => {\n const hasSubCanvas = !!n.data.childCanvasId;\n const icon = <OutlineNodeIcon node={n} />;\n const kidNodes = childNodesOf.get(n.id);\n const kidLines = childLinesOf.get(n.id);\n const item: TreeNode = {\n id: n.id,\n label: n.data.label || n.type,\n icon,\n meta: hasSubCanvas ? { childCanvasId: n.data.childCanvasId } : undefined,\n };\n\n const children: TreeNode[] = [];\n if (kidNodes && kidNodes.length > 0) {\n children.push(...kidNodes.map(toTreeNode));\n }\n if (kidLines && kidLines.length > 0) {\n children.push(...kidLines.map(lineToTree));\n }\n if (hasSubCanvas) {\n const subCanvas = doc.canvases[n.data.childCanvasId!];\n if (subCanvas) {\n const subTree = buildCanvasSubtree(subCanvas, doc, n.data.childCanvasId!);\n if (subTree.length > 0) {\n children.push(...subTree);\n }\n }\n }\n if (children.length > 0) {\n item.children = children;\n }\n return item;\n };\n\n return { nodeTree: roots.map(toTreeNode), assignedLineIds };\n}\n\nfunction buildCanvasSubtree(canvas: FlowCanvasData, doc: FlowDocument, canvasId: string): TreeNode[] {\n if (canvas.nodes.length === 0 && canvas.edges.length === 0 && canvas.lines.length === 0) {\n return [{ id: `_empty_${canvasId}`, label: '(empty sub-canvas)', icon: '○' }];\n }\n return buildNodeTree(canvas.nodes, canvas.lines, doc).nodeTree;\n}\n\n/**\n * Standalone panel (legacy). Prefer using OutlinePanelContent inside a FlowPanelGroup.\n */\nexport default function OutlinePanel() {\n const { showOutline } = useFlowUI();\n const { panelStyle, handleProps } = useDraggablePanel();\n const { panelWidth, resizeHandleProps } = useResizablePanel('left', 180);\n\n if (!showOutline) return null;\n\n return (\n <div className=\"flow-palette\" data-flow-panel style={{ ...(panelStyle ?? { top: 56, left: 'auto', right: 248 + 16 }), width: panelWidth }}>\n <div className=\"flow-panel-resize-handle flow-panel-resize-handle--left\" {...resizeHandleProps} />\n <div\n className=\"flow-panel-drag-handle\"\n {...handleProps}\n style={{ fontSize: 11, fontWeight: 600, marginBottom: 6, color: 'color-mix(in oklch, var(--color-base-content) 50%, transparent)', textTransform: 'uppercase', letterSpacing: '0.05em', cursor: 'grab' }}\n >\n Outline\n </div>\n <div className=\"flow-palette-content\">\n <OutlinePanelContent />\n </div>\n </div>\n );\n}\n\n/** Reusable content for embedding inside FlowPanelGroup tabs. */\nexport function OutlinePanelContent() {\n const { focusOnRect } = useFlowUI();\n const { doc, currentCanvas, currentCanvasId, selection, setSelection, pushCanvas } = useFlowContext();\n\n const treeData = useMemo<TreeNode[]>(() => {\n const { nodeTree, assignedLineIds } = buildNodeTree(currentCanvas.nodes, currentCanvas.lines, doc);\n const edgeItems: TreeNode[] = currentCanvas.edges.map(e => {\n const sn = currentCanvas.nodes.find(n => n.id === e.source);\n const tn = currentCanvas.nodes.find(n => n.id === e.target);\n const srcLabel = sn?.data.label || e.source;\n const tgtLabel = tn?.data.label || e.target;\n return { id: e.id, label: `${srcLabel} → ${tgtLabel}`, icon: '→' };\n });\n const unassignedLines = currentCanvas.lines.filter(l => !assignedLineIds.has(l.id));\n const lineItems: TreeNode[] = unassignedLines.map(l => ({\n id: l.id,\n label: `${l.type} line`,\n icon: '〰',\n }));\n\n const tree: TreeNode[] = [];\n if (nodeTree.length > 0) tree.push({ id: '_nodes', label: `Nodes (${currentCanvas.nodes.length})`, children: nodeTree });\n if (edgeItems.length > 0) tree.push({ id: '_edges', label: `Edges (${edgeItems.length})`, children: edgeItems });\n if (lineItems.length > 0) tree.push({ id: '_lines', label: `Lines (${unassignedLines.length})`, children: lineItems });\n return tree;\n }, [currentCanvas, doc]);\n\n const activeId = useMemo(() => {\n if (selection.nodeIds.size === 1) return [...selection.nodeIds][0];\n if (selection.edgeIds.size === 1) return [...selection.edgeIds][0];\n if (selection.lineIds.size === 1) return [...selection.lineIds][0];\n return undefined;\n }, [selection]);\n\n const defaultExpanded = useMemo(() => {\n const ids: (string | number)[] = ['_nodes', '_edges', '_lines'];\n for (const n of currentCanvas.nodes) {\n if (n.type === 'flowGroup' || n.type === 'geometryGroup' || n.data.isGroup) ids.push(n.id);\n if (n.data.childCanvasId) ids.push(n.id);\n }\n if (activeId) {\n const node = currentCanvas.nodes.find(n => n.id === activeId);\n if (node?.parentId) {\n let pid: string | undefined = node.parentId;\n while (pid) {\n ids.push(pid);\n const parent = currentCanvas.nodes.find(n => n.id === pid);\n pid = parent?.parentId;\n }\n }\n const line = currentCanvas.lines.find(l => l.id === activeId);\n if (line?.parentId) ids.push(line.parentId);\n }\n return ids;\n }, [currentCanvas.nodes, currentCanvas.lines, activeId]);\n\n const handleNodeClick = useCallback((node: TreeNode) => {\n const id = String(node.id);\n if (id.startsWith('_')) return;\n\n const flowNode = currentCanvas.nodes.find(n => n.id === id);\n const flowEdge = currentCanvas.edges.find(e => e.id === id);\n const flowLine = currentCanvas.lines.find(l => l.id === id);\n\n setSelection({\n nodeIds: flowNode ? new Set([id]) : new Set(),\n edgeIds: flowEdge ? new Set([id]) : new Set(),\n lineIds: flowLine ? new Set([id]) : new Set(),\n });\n\n if (flowNode) {\n focusOnRect(flowNode.position.x, flowNode.position.y, flowNode.width, flowNode.height);\n } else if (flowEdge) {\n const sn = currentCanvas.nodes.find(n => n.id === flowEdge.source);\n const tn = currentCanvas.nodes.find(n => n.id === flowEdge.target);\n if (sn && tn) {\n const minX = Math.min(sn.position.x, tn.position.x);\n const minY = Math.min(sn.position.y, tn.position.y);\n const maxX = Math.max(sn.position.x + sn.width, tn.position.x + tn.width);\n const maxY = Math.max(sn.position.y + sn.height, tn.position.y + tn.height);\n focusOnRect(minX, minY, maxX - minX, maxY - minY);\n }\n } else if (flowLine && flowLine.points.length > 0) {\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n for (const p of flowLine.points) {\n minX = Math.min(minX, p.x); minY = Math.min(minY, p.y);\n maxX = Math.max(maxX, p.x); maxY = Math.max(maxY, p.y);\n }\n focusOnRect(minX - 20, minY - 20, maxX - minX + 40, maxY - minY + 40);\n }\n }, [currentCanvas, setSelection, focusOnRect]);\n\n const handleNodeDoubleClick = useCallback((node: TreeNode) => {\n const id = String(node.id);\n if (id.startsWith('_')) return;\n const flowNode = currentCanvas.nodes.find(n => n.id === id);\n if (flowNode?.data.childCanvasId) {\n pushCanvas(flowNode.data.childCanvasId);\n }\n }, [currentCanvas.nodes, pushCanvas]);\n\n const containerRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (!activeId || !containerRef.current) return;\n const timer = setTimeout(() => {\n const el = containerRef.current?.querySelector(`[data-node-id=\"${activeId}\"]`);\n if (el) el.scrollIntoView({ block: 'nearest', behavior: 'smooth' });\n }, 60);\n return () => clearTimeout(timer);\n }, [activeId]);\n\n return (\n <div ref={containerRef}>\n <Tree\n data={treeData}\n onNodeClick={handleNodeClick}\n onNodeDoubleClick={handleNodeDoubleClick}\n activeNodeId={activeId}\n defaultExpandedIds={defaultExpanded}\n showSearch={false}\n showExpandAll={false}\n showIcon\n showLine\n indent={16}\n />\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"OutlinePanel.js","names":[],"sources":["../../../../../src/components/pro/Flow/panels/OutlinePanel.tsx"],"sourcesContent":["import React, { useMemo, useCallback, useRef, useEffect } from 'react';\nimport { Tree, type TreeNode } from '../../../Tree';\nimport { useFlowUI } from '../context/FlowUIContext';\nimport { useFlowContext } from '../context/FlowContext';\nimport { useDraggablePanel } from '../hooks/useDraggablePanel';\nimport { useResizablePanel } from '../hooks/useResizablePanel';\nimport { PaletteThumbnail } from './ShapePalette';\nimport { buildSvgMarkup } from '../nodes/svgIcons';\nimport { resolveThemeColor } from '../utils/themeColor';\nimport type { FlowNode, FlowLine, FlowDocument, FlowCanvasData } from '../types';\n\nconst SUB_CANVAS_ICON = '⧉';\n\nfunction OutlineNodeIcon({ node }: { node: FlowNode }) {\n if (node.data.childCanvasId) return <span style={{ fontSize: 15 }}>{SUB_CANVAS_ICON}</span>;\n if (node.type === 'shapeSvg' && node.data.svgId) {\n const markup = buildSvgMarkup(node.data.svgId, resolveThemeColor(node.data.color, '#475569') || '#475569');\n return markup ? (\n <img\n src={`data:image/svg+xml;utf8,${encodeURIComponent(markup)}`}\n width={24}\n height={20}\n alt=\"\"\n style={{ display: 'block', objectFit: 'contain' }}\n />\n ) : null;\n }\n if (node.type === 'mediaNode') {\n const text = node.data.mediaKind === 'markdown' ? 'M↓'\n : node.data.mediaKind === 'html' ? '</>'\n : node.data.mediaKind === 'mermaid' ? '⎇'\n : node.data.mediaKind === 'math' ? '√x'\n : node.data.mediaKind === 'image' ? 'IMG'\n : node.data.mediaKind === 'model3d' ? '3D'\n : node.data.mediaKind === 'data' ? '⊞'\n : 'AI';\n return <span style={{ width: 24, textAlign: 'center', fontSize: 10, fontWeight: 700 }}>{text}</span>;\n }\n return <PaletteThumbnail type={node.type} />;\n}\n\nfunction buildNodeTree(nodes: FlowNode[], lines: FlowLine[], doc: FlowDocument): { nodeTree: TreeNode[]; assignedLineIds: Set<string> } {\n const childNodesOf = new Map<string, FlowNode[]>();\n const childLinesOf = new Map<string, FlowLine[]>();\n const assignedNodes = new Set<string>();\n const assignedLineIds = new Set<string>();\n\n for (const n of nodes) {\n if (n.parentId) {\n const list = childNodesOf.get(n.parentId) ?? [];\n list.push(n);\n childNodesOf.set(n.parentId, list);\n assignedNodes.add(n.id);\n }\n }\n for (const l of lines) {\n if (l.parentId) {\n const list = childLinesOf.get(l.parentId) ?? [];\n list.push(l);\n childLinesOf.set(l.parentId, list);\n assignedLineIds.add(l.id);\n }\n }\n\n // Spatial containment only for geometryGroup\n const geoGroups = nodes.filter(n => n.type === 'geometryGroup');\n for (const g of geoGroups) {\n const gx = g.position.x, gy = g.position.y;\n const gw = g.width, gh = g.height;\n for (const n of nodes) {\n if (n.id === g.id || assignedNodes.has(n.id)) continue;\n if (n.position.x >= gx && n.position.y >= gy\n && n.position.x + n.width <= gx + gw\n && n.position.y + n.height <= gy + gh) {\n const list = childNodesOf.get(g.id) ?? [];\n list.push(n);\n childNodesOf.set(g.id, list);\n assignedNodes.add(n.id);\n }\n }\n for (const l of lines) {\n if (assignedLineIds.has(l.id)) continue;\n if (l.points.length > 0 && l.points.every(p =>\n p.x >= gx && p.x <= gx + gw && p.y >= gy && p.y <= gy + gh\n )) {\n const list = childLinesOf.get(g.id) ?? [];\n list.push(l);\n childLinesOf.set(g.id, list);\n assignedLineIds.add(l.id);\n }\n }\n }\n\n const roots = nodes.filter(n => !assignedNodes.has(n.id));\n\n const lineToTree = (l: FlowLine): TreeNode => ({\n id: l.id,\n label: `${l.type} line`,\n icon: '〰',\n });\n\n const toTreeNode = (n: FlowNode): TreeNode => {\n const hasSubCanvas = !!n.data.childCanvasId;\n const icon = <OutlineNodeIcon node={n} />;\n const kidNodes = childNodesOf.get(n.id);\n const kidLines = childLinesOf.get(n.id);\n const item: TreeNode = {\n id: n.id,\n label: n.data.label || n.type,\n icon,\n meta: hasSubCanvas ? { childCanvasId: n.data.childCanvasId } : undefined,\n };\n\n const children: TreeNode[] = [];\n if (kidNodes && kidNodes.length > 0) {\n children.push(...kidNodes.map(toTreeNode));\n }\n if (kidLines && kidLines.length > 0) {\n children.push(...kidLines.map(lineToTree));\n }\n if (hasSubCanvas) {\n const subCanvas = doc.canvases[n.data.childCanvasId!];\n if (subCanvas) {\n const subTree = buildCanvasSubtree(subCanvas, doc, n.data.childCanvasId!);\n if (subTree.length > 0) {\n children.push(...subTree);\n }\n }\n }\n if (children.length > 0) {\n item.children = children;\n }\n return item;\n };\n\n return { nodeTree: roots.map(toTreeNode), assignedLineIds };\n}\n\nfunction buildCanvasSubtree(canvas: FlowCanvasData, doc: FlowDocument, canvasId: string): TreeNode[] {\n if (canvas.nodes.length === 0 && canvas.edges.length === 0 && canvas.lines.length === 0) {\n return [{ id: `_empty_${canvasId}`, label: '(empty sub-canvas)', icon: '○' }];\n }\n return buildNodeTree(canvas.nodes, canvas.lines, doc).nodeTree;\n}\n\n/**\n * Standalone panel (legacy). Prefer using OutlinePanelContent inside a FlowPanelGroup.\n */\nexport default function OutlinePanel() {\n const { showOutline } = useFlowUI();\n const { panelStyle, handleProps } = useDraggablePanel();\n const { panelWidth, resizeHandleProps } = useResizablePanel('left', 180);\n\n if (!showOutline) return null;\n\n return (\n <div className=\"flow-palette\" data-flow-panel style={{ ...(panelStyle ?? { top: 56, left: 'auto', right: 248 + 16 }), width: panelWidth }}>\n <div className=\"flow-panel-resize-handle flow-panel-resize-handle--left\" {...resizeHandleProps} />\n <div\n className=\"flow-panel-drag-handle\"\n {...handleProps}\n style={{ fontSize: 11, fontWeight: 600, marginBottom: 6, color: 'color-mix(in oklch, var(--color-base-content) 50%, transparent)', textTransform: 'uppercase', letterSpacing: '0.05em', cursor: 'grab' }}\n >\n Outline\n </div>\n <div className=\"flow-palette-content\">\n <OutlinePanelContent />\n </div>\n </div>\n );\n}\n\n/** Reusable content for embedding inside FlowPanelGroup tabs. */\nexport function OutlinePanelContent() {\n const { focusOnRect } = useFlowUI();\n const { doc, currentCanvas, currentCanvasId, selection, setSelection, pushCanvas } = useFlowContext();\n\n const treeData = useMemo<TreeNode[]>(() => {\n const { nodeTree, assignedLineIds } = buildNodeTree(currentCanvas.nodes, currentCanvas.lines, doc);\n const edgeItems: TreeNode[] = currentCanvas.edges.map(e => {\n const sn = currentCanvas.nodes.find(n => n.id === e.source);\n const tn = currentCanvas.nodes.find(n => n.id === e.target);\n const srcLabel = sn?.data.label || e.source;\n const tgtLabel = tn?.data.label || e.target;\n return { id: e.id, label: `${srcLabel} → ${tgtLabel}`, icon: '→' };\n });\n const unassignedLines = currentCanvas.lines.filter(l => !assignedLineIds.has(l.id));\n const lineItems: TreeNode[] = unassignedLines.map(l => ({\n id: l.id,\n label: `${l.type} line`,\n icon: '〰',\n }));\n\n const tree: TreeNode[] = [];\n if (nodeTree.length > 0) tree.push({ id: '_nodes', label: `Nodes (${currentCanvas.nodes.length})`, children: nodeTree });\n if (edgeItems.length > 0) tree.push({ id: '_edges', label: `Edges (${edgeItems.length})`, children: edgeItems });\n if (lineItems.length > 0) tree.push({ id: '_lines', label: `Lines (${unassignedLines.length})`, children: lineItems });\n return tree;\n }, [currentCanvas, doc]);\n\n const activeId = useMemo(() => {\n if (selection.nodeIds.size === 1) return [...selection.nodeIds][0];\n if (selection.edgeIds.size === 1) return [...selection.edgeIds][0];\n if (selection.lineIds.size === 1) return [...selection.lineIds][0];\n return undefined;\n }, [selection]);\n\n const defaultExpanded = useMemo(() => {\n const ids: (string | number)[] = ['_nodes', '_edges', '_lines'];\n for (const n of currentCanvas.nodes) {\n if (n.type === 'flowGroup' || n.type === 'geometryGroup' || n.data.isGroup) ids.push(n.id);\n if (n.data.childCanvasId) ids.push(n.id);\n }\n if (activeId) {\n const node = currentCanvas.nodes.find(n => n.id === activeId);\n if (node?.parentId) {\n let pid: string | undefined = node.parentId;\n while (pid) {\n ids.push(pid);\n const parent = currentCanvas.nodes.find(n => n.id === pid);\n pid = parent?.parentId;\n }\n }\n const line = currentCanvas.lines.find(l => l.id === activeId);\n if (line?.parentId) ids.push(line.parentId);\n }\n return ids;\n }, [currentCanvas.nodes, currentCanvas.lines, activeId]);\n\n const handleNodeClick = useCallback((node: TreeNode) => {\n const id = String(node.id);\n if (id.startsWith('_')) return;\n\n const flowNode = currentCanvas.nodes.find(n => n.id === id);\n const flowEdge = currentCanvas.edges.find(e => e.id === id);\n const flowLine = currentCanvas.lines.find(l => l.id === id);\n\n setSelection({\n nodeIds: flowNode ? new Set([id]) : new Set(),\n edgeIds: flowEdge ? new Set([id]) : new Set(),\n lineIds: flowLine ? new Set([id]) : new Set(),\n });\n\n if (flowNode) {\n focusOnRect(flowNode.position.x, flowNode.position.y, flowNode.width, flowNode.height);\n } else if (flowEdge) {\n const sn = currentCanvas.nodes.find(n => n.id === flowEdge.source);\n const tn = currentCanvas.nodes.find(n => n.id === flowEdge.target);\n if (sn && tn) {\n const minX = Math.min(sn.position.x, tn.position.x);\n const minY = Math.min(sn.position.y, tn.position.y);\n const maxX = Math.max(sn.position.x + sn.width, tn.position.x + tn.width);\n const maxY = Math.max(sn.position.y + sn.height, tn.position.y + tn.height);\n focusOnRect(minX, minY, maxX - minX, maxY - minY);\n }\n } else if (flowLine && flowLine.points.length > 0) {\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n for (const p of flowLine.points) {\n minX = Math.min(minX, p.x); minY = Math.min(minY, p.y);\n maxX = Math.max(maxX, p.x); maxY = Math.max(maxY, p.y);\n }\n focusOnRect(minX - 20, minY - 20, maxX - minX + 40, maxY - minY + 40);\n }\n }, [currentCanvas, setSelection, focusOnRect]);\n\n const handleNodeDoubleClick = useCallback((node: TreeNode) => {\n const id = String(node.id);\n if (id.startsWith('_')) return;\n const flowNode = currentCanvas.nodes.find(n => n.id === id);\n if (flowNode?.data.childCanvasId) {\n pushCanvas(flowNode.data.childCanvasId);\n }\n }, [currentCanvas.nodes, pushCanvas]);\n\n const containerRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (!activeId || !containerRef.current) return;\n const timer = setTimeout(() => {\n const el = containerRef.current?.querySelector(`[data-node-id=\"${activeId}\"]`);\n if (el) el.scrollIntoView({ block: 'nearest', behavior: 'smooth' });\n }, 60);\n return () => clearTimeout(timer);\n }, [activeId]);\n\n return (\n <div ref={containerRef}>\n <Tree\n data={treeData}\n onNodeClick={handleNodeClick}\n onNodeDoubleClick={handleNodeDoubleClick}\n activeNodeId={activeId}\n defaultExpandedIds={defaultExpanded}\n showSearch={false}\n showExpandAll={false}\n showIcon\n showLine\n indent={16}\n />\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;AAWA,IAAM,IAAkB;AAExB,SAAS,EAAgB,EAAE,MAAA,EAAA,GAA4B;AACrD,MAAI,EAAK,KAAK,cAAe,QAAO,gBAAA,EAAC,QAAD;AAAA,IAAM,OAAO,EAAE,UAAU,GAAG;AAAA,IAAI,UAAA;AAAA,EAAsB,CAAA;AAC1F,MAAI,EAAK,SAAS,cAAc,EAAK,KAAK,OAAO;AAC/C,UAAM,IAAS,EAAe,EAAK,KAAK,OAAO,EAAkB,EAAK,KAAK,OAAO,SAAS,KAAK,SAAS;AACzG,WAAO,IACL,gBAAA,EAAC,OAAD;AAAA,MACE,KAAK,2BAA2B,mBAAmB,CAAM,CAAA;AAAA,MACzD,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,KAAI;AAAA,MACJ,OAAO;AAAA,QAAE,SAAS;AAAA,QAAS,WAAW;AAAA,MAAU;AAAA,IACjD,CAAA,IACC;AAAA,EACN;AACA,MAAI,EAAK,SAAS,aAAa;AAC7B,UAAM,IAAO,EAAK,KAAK,cAAc,aAAa,OAC9C,EAAK,KAAK,cAAc,SAAS,QAC/B,EAAK,KAAK,cAAc,YAAY,MAClC,EAAK,KAAK,cAAc,SAAS,OAC/B,EAAK,KAAK,cAAc,UAAU,QAChC,EAAK,KAAK,cAAc,YAAY,OAClC,EAAK,KAAK,cAAc,SAAS,MAC/B;AAChB,WAAO,gBAAA,EAAC,QAAD;AAAA,MAAM,OAAO;AAAA,QAAE,OAAO;AAAA,QAAI,WAAW;AAAA,QAAU,UAAU;AAAA,QAAI,YAAY;AAAA,MAAI;AAAA,MAAI,UAAA;AAAA,IAAW,CAAA;AAAA,EACrG;AACA,SAAO,gBAAA,EAAC,GAAD,EAAkB,MAAM,EAAK,KAAO,CAAA;AAC7C;AAEA,SAAS,EAAc,GAAmB,GAAmB,GAA2E;AACtI,QAAM,IAAe,oBAAI,IAAwB,GAC3C,IAAe,oBAAI,IAAwB,GAC3C,IAAgB,oBAAI,IAAY,GAChC,IAAkB,oBAAI,IAAY;AAExC,aAAW,KAAK,EACd,KAAI,EAAE,UAAU;AACd,UAAM,IAAO,EAAa,IAAI,EAAE,QAAQ,KAAK,CAAC;AAC9C,IAAA,EAAK,KAAK,CAAC,GACX,EAAa,IAAI,EAAE,UAAU,CAAI,GACjC,EAAc,IAAI,EAAE,EAAE;AAAA,EACxB;AAEF,aAAW,KAAK,EACd,KAAI,EAAE,UAAU;AACd,UAAM,IAAO,EAAa,IAAI,EAAE,QAAQ,KAAK,CAAC;AAC9C,IAAA,EAAK,KAAK,CAAC,GACX,EAAa,IAAI,EAAE,UAAU,CAAI,GACjC,EAAgB,IAAI,EAAE,EAAE;AAAA,EAC1B;AAIF,QAAM,IAAY,EAAM,OAAA,CAAO,MAAK,EAAE,SAAS,eAAe;AAC9D,aAAW,KAAK,GAAW;AACzB,UAAM,IAAK,EAAE,SAAS,GAAG,IAAK,EAAE,SAAS,GACnC,IAAK,EAAE,OAAO,IAAK,EAAE;AAC3B,eAAW,KAAK;AACd,UAAI,EAAA,EAAE,OAAO,EAAE,MAAM,EAAc,IAAI,EAAE,EAAE,MACvC,EAAE,SAAS,KAAK,KAAM,EAAE,SAAS,KAAK,KACrC,EAAE,SAAS,IAAI,EAAE,SAAS,IAAK,KAC/B,EAAE,SAAS,IAAI,EAAE,UAAU,IAAK,GAAI;AACvC,cAAM,IAAO,EAAa,IAAI,EAAE,EAAE,KAAK,CAAC;AACxC,QAAA,EAAK,KAAK,CAAC,GACX,EAAa,IAAI,EAAE,IAAI,CAAI,GAC3B,EAAc,IAAI,EAAE,EAAE;AAAA,MACxB;AAEF,eAAW,KAAK;AACd,UAAI,CAAA,EAAgB,IAAI,EAAE,EAAE,KACxB,EAAE,OAAO,SAAS,KAAK,EAAE,OAAO,MAAA,CAAM,MACxC,EAAE,KAAK,KAAM,EAAE,KAAK,IAAK,KAAM,EAAE,KAAK,KAAM,EAAE,KAAK,IAAK,CAC1D,GAAG;AACD,cAAM,IAAO,EAAa,IAAI,EAAE,EAAE,KAAK,CAAC;AACxC,QAAA,EAAK,KAAK,CAAC,GACX,EAAa,IAAI,EAAE,IAAI,CAAI,GAC3B,EAAgB,IAAI,EAAE,EAAE;AAAA,MAC1B;AAAA,EAEJ;AAEA,QAAM,IAAQ,EAAM,OAAA,CAAO,MAAK,CAAC,EAAc,IAAI,EAAE,EAAE,CAAC,GAElD,IAAA,CAAc,OAA2B;AAAA,IAC7C,IAAI,EAAE;AAAA,IACN,OAAO,GAAG,EAAE,IAAA;AAAA,IACZ,MAAM;AAAA,EACR,IAEM,IAAA,CAAc,MAA0B;AAC5C,UAAM,IAAe,CAAC,CAAC,EAAE,KAAK,eACxB,IAAO,gBAAA,EAAC,GAAD,EAAiB,MAAM,EAAI,CAAA,GAClC,IAAW,EAAa,IAAI,EAAE,EAAE,GAChC,IAAW,EAAa,IAAI,EAAE,EAAE,GAChC,IAAiB;AAAA,MACrB,IAAI,EAAE;AAAA,MACN,OAAO,EAAE,KAAK,SAAS,EAAE;AAAA,MACzB,MAAA;AAAA,MACA,MAAM,IAAe,EAAE,eAAe,EAAE,KAAK,cAAc,IAAI;AAAA,IACjE,GAEM,IAAuB,CAAC;AAO9B,QANI,KAAY,EAAS,SAAS,KAChC,EAAS,KAAK,GAAG,EAAS,IAAI,CAAU,CAAC,GAEvC,KAAY,EAAS,SAAS,KAChC,EAAS,KAAK,GAAG,EAAS,IAAI,CAAU,CAAC,GAEvC,GAAc;AAChB,YAAM,IAAY,EAAI,SAAS,EAAE,KAAK,aAAA;AACtC,UAAI,GAAW;AACb,cAAM,IAAU,EAAmB,GAAW,GAAK,EAAE,KAAK,aAAc;AACxE,QAAI,EAAQ,SAAS,KACnB,EAAS,KAAK,GAAG,CAAO;AAAA,MAE5B;AAAA,IACF;AACA,WAAI,EAAS,SAAS,MACpB,EAAK,WAAW,IAEX;AAAA,EACT;AAEA,SAAO;AAAA,IAAE,UAAU,EAAM,IAAI,CAAU;AAAA,IAAG,iBAAA;AAAA,EAAgB;AAC5D;AAEA,SAAS,EAAmB,GAAwB,GAAmB,GAA8B;AACnG,SAAI,EAAO,MAAM,WAAW,KAAK,EAAO,MAAM,WAAW,KAAK,EAAO,MAAM,WAAW,IAC7E,CAAC;AAAA,IAAE,IAAI,UAAU,CAAA;AAAA,IAAY,OAAO;AAAA,IAAsB,MAAM;AAAA,EAAI,CAAC,IAEvE,EAAc,EAAO,OAAO,EAAO,OAAO,CAAG,EAAE;AACxD;AAKA,SAAwB,KAAe;AACrC,QAAM,EAAE,aAAA,EAAA,IAAgB,EAAU,GAC5B,EAAE,YAAA,GAAY,aAAA,EAAA,IAAgB,EAAkB,GAChD,EAAE,YAAA,GAAY,mBAAA,EAAA,IAAsB,EAAkB,QAAQ,GAAG;AAEvE,SAAK,IAGH,gBAAA,EAAC,OAAD;AAAA,IAAK,WAAU;AAAA,IAAe,mBAAA;AAAA,IAAgB,OAAO;AAAA,MAAE,GAAI,KAAc;AAAA,QAAE,KAAK;AAAA,QAAI,MAAM;AAAA,QAAQ,OAAO;AAAA,MAAS;AAAA,MAAI,OAAO;AAAA,IAAW;AAAA,IAAxI,UAAA;AAAA,MACE,gBAAA,EAAC,OAAD;AAAA,QAAK,WAAU;AAAA,QAA0D,GAAI;AAAA,MAAoB,CAAA;AAAA,MACjG,gBAAA,EAAC,OAAD;AAAA,QACE,WAAU;AAAA,QACV,GAAI;AAAA,QACJ,OAAO;AAAA,UAAE,UAAU;AAAA,UAAI,YAAY;AAAA,UAAK,cAAc;AAAA,UAAG,OAAO;AAAA,UAAmE,eAAe;AAAA,UAAa,eAAe;AAAA,UAAU,QAAQ;AAAA,QAAO;AAAA,QACxM,UAAA;AAAA,MAEI,CAAA;AAAA,MACL,gBAAA,EAAC,OAAD;AAAA,QAAK,WAAU;AAAA,QACb,UAAA,gBAAA,EAAC,GAAD,CAAsB,CAAA;AAAA,MACnB,CAAA;AAAA,IACF;AAAA,OAfkB;AAiB3B;AAGA,SAAgB,IAAsB;AACpC,QAAM,EAAE,aAAA,EAAA,IAAgB,EAAU,GAC5B,EAAE,KAAA,GAAK,eAAA,GAAe,iBAAA,GAAiB,WAAA,GAAW,cAAA,GAAc,YAAA,EAAA,IAAe,EAAe,GAE9F,IAAW,EAAA,MAA0B;AACzC,UAAM,EAAE,UAAA,GAAU,iBAAA,EAAA,IAAoB,EAAc,EAAc,OAAO,EAAc,OAAO,CAAG,GAC3F,IAAwB,EAAc,MAAM,IAAA,CAAI,MAAK;AACzD,YAAM,IAAK,EAAc,MAAM,KAAA,CAAK,MAAK,EAAE,OAAO,EAAE,MAAM,GACpD,IAAK,EAAc,MAAM,KAAA,CAAK,MAAK,EAAE,OAAO,EAAE,MAAM,GACpD,IAAW,GAAI,KAAK,SAAS,EAAE,QAC/B,IAAW,GAAI,KAAK,SAAS,EAAE;AACrC,aAAO;AAAA,QAAE,IAAI,EAAE;AAAA,QAAI,OAAO,GAAG,CAAA,MAAc,CAAA;AAAA,QAAY,MAAM;AAAA,MAAI;AAAA,IACnE,CAAC,GACK,IAAkB,EAAc,MAAM,OAAA,CAAO,MAAK,CAAC,EAAgB,IAAI,EAAE,EAAE,CAAC,GAC5E,IAAwB,EAAgB,IAAA,CAAI,OAAM;AAAA,MACtD,IAAI,EAAE;AAAA,MACN,OAAO,GAAG,EAAE,IAAA;AAAA,MACZ,MAAM;AAAA,IACR,EAAE,GAEI,IAAmB,CAAC;AAC1B,WAAI,EAAS,SAAS,KAAG,EAAK,KAAK;AAAA,MAAE,IAAI;AAAA,MAAU,OAAO,UAAU,EAAc,MAAM,MAAA;AAAA,MAAW,UAAU;AAAA,IAAS,CAAC,GACnH,EAAU,SAAS,KAAG,EAAK,KAAK;AAAA,MAAE,IAAI;AAAA,MAAU,OAAO,UAAU,EAAU,MAAA;AAAA,MAAW,UAAU;AAAA,IAAU,CAAC,GAC3G,EAAU,SAAS,KAAG,EAAK,KAAK;AAAA,MAAE,IAAI;AAAA,MAAU,OAAO,UAAU,EAAgB,MAAA;AAAA,MAAW,UAAU;AAAA,IAAU,CAAC,GAC9G;AAAA,EACT,GAAG,CAAC,GAAe,CAAG,CAAC,GAEjB,IAAW,EAAA,MAAc;AAC7B,QAAI,EAAU,QAAQ,SAAS,EAAG,QAAO,CAAC,GAAG,EAAU,OAAO,EAAE,CAAA;AAChE,QAAI,EAAU,QAAQ,SAAS,EAAG,QAAO,CAAC,GAAG,EAAU,OAAO,EAAE,CAAA;AAChE,QAAI,EAAU,QAAQ,SAAS,EAAG,QAAO,CAAC,GAAG,EAAU,OAAO,EAAE,CAAA;AAAA,EAElE,GAAG,CAAC,CAAS,CAAC,GAER,IAAkB,EAAA,MAAc;AACpC,UAAM,IAA2B;AAAA,MAAC;AAAA,MAAU;AAAA,MAAU;AAAA,IAAQ;AAC9D,eAAW,KAAK,EAAc;AAC5B,OAAI,EAAE,SAAS,eAAe,EAAE,SAAS,mBAAmB,EAAE,KAAK,YAAS,EAAI,KAAK,EAAE,EAAE,GACrF,EAAE,KAAK,iBAAe,EAAI,KAAK,EAAE,EAAE;AAEzC,QAAI,GAAU;AACZ,YAAM,IAAO,EAAc,MAAM,KAAA,CAAK,MAAK,EAAE,OAAO,CAAQ;AAC5D,UAAI,GAAM,UAAU;AAClB,YAAI,IAA0B,EAAK;AACnC,eAAO;AACL,UAAA,EAAI,KAAK,CAAG,GAEZ,IADe,EAAc,MAAM,KAAA,CAAK,MAAK,EAAE,OAAO,CAChD,GAAQ;AAAA,MAElB;AACA,YAAM,IAAO,EAAc,MAAM,KAAA,CAAK,MAAK,EAAE,OAAO,CAAQ;AAC5D,MAAI,GAAM,YAAU,EAAI,KAAK,EAAK,QAAQ;AAAA,IAC5C;AACA,WAAO;AAAA,EACT,GAAG;AAAA,IAAC,EAAc;AAAA,IAAO,EAAc;AAAA,IAAO;AAAA,EAAQ,CAAC,GAEjD,IAAkB,EAAA,CAAa,MAAmB;AACtD,UAAM,IAAK,OAAO,EAAK,EAAE;AACzB,QAAI,EAAG,WAAW,GAAG,EAAG;AAExB,UAAM,IAAW,EAAc,MAAM,KAAA,CAAK,MAAK,EAAE,OAAO,CAAE,GACpD,IAAW,EAAc,MAAM,KAAA,CAAK,MAAK,EAAE,OAAO,CAAE,GACpD,IAAW,EAAc,MAAM,KAAA,CAAK,MAAK,EAAE,OAAO,CAAE;AAQ1D,QANA,EAAa;AAAA,MACX,SAAS,IAAW,oBAAI,IAAI,CAAC,CAAE,CAAC,IAAI,oBAAI,IAAI;AAAA,MAC5C,SAAS,IAAW,oBAAI,IAAI,CAAC,CAAE,CAAC,IAAI,oBAAI,IAAI;AAAA,MAC5C,SAAS,IAAW,oBAAI,IAAI,CAAC,CAAE,CAAC,IAAI,oBAAI,IAAI;AAAA,IAC9C,CAAC,GAEG,EACF,CAAA,EAAY,EAAS,SAAS,GAAG,EAAS,SAAS,GAAG,EAAS,OAAO,EAAS,MAAM;AAAA,aAC5E,GAAU;AACnB,YAAM,IAAK,EAAc,MAAM,KAAA,CAAK,MAAK,EAAE,OAAO,EAAS,MAAM,GAC3D,IAAK,EAAc,MAAM,KAAA,CAAK,MAAK,EAAE,OAAO,EAAS,MAAM;AACjE,UAAI,KAAM,GAAI;AACZ,cAAM,IAAO,KAAK,IAAI,EAAG,SAAS,GAAG,EAAG,SAAS,CAAC,GAC5C,IAAO,KAAK,IAAI,EAAG,SAAS,GAAG,EAAG,SAAS,CAAC,GAC5C,IAAO,KAAK,IAAI,EAAG,SAAS,IAAI,EAAG,OAAO,EAAG,SAAS,IAAI,EAAG,KAAK,GAClE,IAAO,KAAK,IAAI,EAAG,SAAS,IAAI,EAAG,QAAQ,EAAG,SAAS,IAAI,EAAG,MAAM;AAC1E,QAAA,EAAY,GAAM,GAAM,IAAO,GAAM,IAAO,CAAI;AAAA,MAClD;AAAA,IACF,WAAW,KAAY,EAAS,OAAO,SAAS,GAAG;AACjD,UAAI,IAAO,OAAU,IAAO,OAAU,IAAO,QAAW,IAAO;AAC/D,iBAAW,KAAK,EAAS;AACvB,QAAA,IAAO,KAAK,IAAI,GAAM,EAAE,CAAC,GAAG,IAAO,KAAK,IAAI,GAAM,EAAE,CAAC,GACrD,IAAO,KAAK,IAAI,GAAM,EAAE,CAAC,GAAG,IAAO,KAAK,IAAI,GAAM,EAAE,CAAC;AAEvD,MAAA,EAAY,IAAO,IAAI,IAAO,IAAI,IAAO,IAAO,IAAI,IAAO,IAAO,EAAE;AAAA,IACtE;AAAA,EACF,GAAG;AAAA,IAAC;AAAA,IAAe;AAAA,IAAc;AAAA,EAAW,CAAC,GAEvC,IAAwB,EAAA,CAAa,MAAmB;AAC5D,UAAM,IAAK,OAAO,EAAK,EAAE;AACzB,QAAI,EAAG,WAAW,GAAG,EAAG;AACxB,UAAM,IAAW,EAAc,MAAM,KAAA,CAAK,MAAK,EAAE,OAAO,CAAE;AAC1D,IAAI,GAAU,KAAK,iBACjB,EAAW,EAAS,KAAK,aAAa;AAAA,EAE1C,GAAG,CAAC,EAAc,OAAO,CAAU,CAAC,GAE9B,IAAe,EAAuB,IAAI;AAEhD,SAAA,EAAA,MAAgB;AACd,QAAI,CAAC,KAAY,CAAC,EAAa,QAAS;AACxC,UAAM,IAAQ,WAAA,MAAiB;AAC7B,YAAM,IAAK,EAAa,SAAS,cAAc,kBAAkB,CAAA,IAAY;AAC7E,MAAI,KAAI,EAAG,eAAe;AAAA,QAAE,OAAO;AAAA,QAAW,UAAU;AAAA,MAAS,CAAC;AAAA,IACpE,GAAG,EAAE;AACL,WAAA,MAAa,aAAa,CAAK;AAAA,EACjC,GAAG,CAAC,CAAQ,CAAC,GAGX,gBAAA,EAAC,OAAD;AAAA,IAAK,KAAK;AAAA,IACR,UAAA,gBAAA,EAAC,GAAD;AAAA,MACE,MAAM;AAAA,MACN,aAAa;AAAA,MACb,mBAAmB;AAAA,MACnB,cAAc;AAAA,MACd,oBAAoB;AAAA,MACpB,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,UAAA;AAAA,MACA,UAAA;AAAA,MACA,QAAQ;AAAA,IACT,CAAA;AAAA,EACE,CAAA;AAET"}
@@ -1,10 +1,10 @@
1
- import { useFlowContext as P } from "../context/FlowContext.js";
2
- import { useFlowUI as I } from "../context/FlowUIContext.js";
3
- import { anchorFocusRect as M, canvasStackTo as L, getDocumentSlides as S } from "../nodes/animAnchors.js";
4
- import { useCallback as v, useEffect as D, useMemo as U, useRef as N, useState as j } from "react";
1
+ import { useFlowContext as I } from "../context/FlowContext.js";
2
+ import { useFlowUI as M } from "../context/FlowUIContext.js";
3
+ import { anchorFocusRect as L, canvasStackTo as S, getDocumentSlides as U } from "../nodes/animAnchors.js";
4
+ import { useCallback as v, useEffect as D, useMemo as j, useRef as N, useState as K } from "react";
5
5
  import { jsx as i, jsxs as m } from "react/jsx-runtime";
6
- function B() {
7
- const { doc: u, setDoc: k, currentCanvasId: y } = P(), { presentation: r, setPresentation: l, focusOnRect: b } = I(), x = N(null), p = U(() => S(u), [u]), s = p.length, a = r !== null, e = r?.current ?? 0, [C, g] = j(null), A = N(u);
6
+ function G() {
7
+ const { doc: u, setDoc: k, currentCanvasId: y } = I(), { presentation: r, setPresentation: l, focusOnRect: b } = M(), x = N(null), p = j(() => U(u), [u]), s = p.length, a = r !== null, e = r?.current ?? 0, [C, g] = K(null), A = N(u);
8
8
  A.current = u;
9
9
  const d = v(() => {
10
10
  l(null), document.fullscreenElement && document.exitFullscreen().catch(() => {
@@ -22,15 +22,15 @@ function B() {
22
22
  });
23
23
  const c = p[t];
24
24
  if (!c) return;
25
- const f = A.current, h = L(f, c.canvasId), E = c.canvasId === y;
25
+ const f = A.current, h = S(f, c.canvasId), E = c.canvasId === y;
26
26
  if (!E && h) {
27
- const T = h.length > f.stack.length;
28
- g(T ? "in" : "out"), k((F) => ({
29
- ...F,
27
+ const F = h.length > f.stack.length;
28
+ g(F ? "in" : "out"), k((P) => ({
29
+ ...P,
30
30
  stack: h
31
31
  })), window.setTimeout(() => g(null), 480);
32
32
  }
33
- const w = M(c.node);
33
+ const w = L(c.node);
34
34
  window.setTimeout(() => b(w.x, w.y, w.w, w.h, {
35
35
  padding: 8,
36
36
  maxZoom: 4,
@@ -45,7 +45,7 @@ function B() {
45
45
  y,
46
46
  k
47
47
  ]);
48
- return D(() => {
48
+ if (D(() => {
49
49
  if (a && (R(), s > 0)) {
50
50
  o(e);
51
51
  const n = window.setTimeout(() => o(e), 180);
@@ -76,9 +76,11 @@ function B() {
76
76
  e,
77
77
  o,
78
78
  d
79
- ]), a ? /* @__PURE__ */ m("div", {
79
+ ]), !a) return null;
80
+ const T = C ? `flow-presentation--${C}` : "";
81
+ return /* @__PURE__ */ m("div", {
80
82
  ref: x,
81
- className: `flow-presentation ${C ? `flow-presentation--${C}` : ""}`,
83
+ className: `flow-presentation ${T}`,
82
84
  onClick: d,
83
85
  children: [/* @__PURE__ */ i("div", {
84
86
  className: "flow-presentation-slide-fx",
@@ -132,10 +134,10 @@ function B() {
132
134
  ]
133
135
  })]
134
136
  })]
135
- }) : null;
137
+ });
136
138
  }
137
139
  export {
138
- B as PresentationMode
140
+ G as PresentationMode
139
141
  };
140
142
 
141
143
  //# sourceMappingURL=PresentationMode.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PresentationMode.js","names":[],"sources":["../../../../../src/components/pro/Flow/panels/PresentationMode.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useFlowContext } from '../context/FlowContext';\nimport { useFlowUI } from '../context/FlowUIContext';\nimport { getDocumentSlides, anchorFocusRect, canvasStackTo } from '../nodes/animAnchors';\n\n/**\n * PPT-style presentation mode.\n *\n * While active the editor is read-only (all panels/toolbars are hidden) and the\n * viewport animates between animation anchors (slides). Anchors across the whole\n * document — including nested sub-canvases — share a single sequence, ordered by\n * stable creation index. Navigating to a slide on another canvas drills into or\n * out of that canvas before focusing the slide.\n *\n * Keys: →/↓/Space/PageDown = next, ←/↑/Shift+Space/PageUp = previous, Esc = exit.\n */\nexport function PresentationMode() {\n const { doc, setDoc, currentCanvasId } = useFlowContext();\n const { presentation, setPresentation, focusOnRect } = useFlowUI();\n const overlayRef = useRef<HTMLDivElement>(null);\n\n const slides = useMemo(() => getDocumentSlides(doc), [doc]);\n const count = slides.length;\n const active = presentation !== null;\n const current = presentation?.current ?? 0;\n const [transition, setTransition] = useState<'in' | 'out' | null>(null);\n\n const docRef = useRef(doc);\n docRef.current = doc;\n\n const exit = useCallback(() => {\n setPresentation(null);\n if (document.fullscreenElement) void document.exitFullscreen().catch(() => {});\n }, [setPresentation]);\n\n const enterFullscreen = useCallback(() => {\n const root = overlayRef.current?.closest('.flow-container') as HTMLElement | null;\n if (root && !document.fullscreenElement) {\n void root.requestFullscreen().catch(() => {});\n }\n }, []);\n\n const goTo = useCallback(\n (index: number) => {\n if (count === 0) return;\n const clamped = Math.max(0, Math.min(count - 1, index));\n setPresentation({\n current: clamped,\n showAnchor: presentation?.showAnchor ?? false,\n });\n const slide = slides[clamped];\n if (!slide) return;\n\n const d = docRef.current;\n const stack = canvasStackTo(d, slide.canvasId);\n\n // Decide drill direction by comparing with the current stack top.\n const onCurrentCanvas = slide.canvasId === currentCanvasId;\n if (!onCurrentCanvas && stack) {\n const deeper = stack.length > d.stack.length;\n setTransition(deeper ? 'in' : 'out');\n // Navigate the canvas stack to the slide's canvas.\n setDoc((prev) => ({ ...prev, stack }));\n // Clear the transition marker shortly after it starts.\n window.setTimeout(() => setTransition(null), 480);\n }\n\n const r = anchorFocusRect(slide.node);\n // Presentation uses the exact anchor frame with only a small screen-space\n // inset. The zoom is recomputed for every slide and viewport size.\n window.setTimeout(\n () => focusOnRect(r.x, r.y, r.w, r.h, { padding: 8, maxZoom: 4, duration: 350 }),\n onCurrentCanvas ? 0 : 30,\n );\n },\n [slides, count, presentation?.showAnchor, setPresentation, focusOnRect, currentCanvasId, setDoc],\n );\n\n // Entering: use the full display area and snap to the first slide. Refit once\n // fullscreen settles because the canvas dimensions change asynchronously.\n useEffect(() => {\n if (!active) return;\n enterFullscreen();\n if (count > 0) {\n goTo(current);\n const timer = window.setTimeout(() => goTo(current), 180);\n return () => window.clearTimeout(timer);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [active]);\n\n\n\n // Keyboard navigation (capture phase so arrows work over the canvas).\n useEffect(() => {\n if (!active) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n exit();\n return;\n }\n const next = ['ArrowRight', 'ArrowDown', 'PageDown', ' '];\n const prev = ['ArrowLeft', 'ArrowUp', 'PageUp'];\n if (next.includes(e.key)) {\n e.preventDefault();\n if (e.key === ' ' && e.shiftKey) goTo(current - 1);\n else goTo(current + 1);\n } else if (prev.includes(e.key)) {\n e.preventDefault();\n goTo(current - 1);\n }\n };\n window.addEventListener('keydown', onKey, true);\n return () => window.removeEventListener('keydown', onKey, true);\n }, [active, current, goTo, exit]);\n\n if (!active) return null;\n\n const cls = transition ? `flow-presentation--${transition}` : '';\n return (\n <div ref={overlayRef} className={`flow-presentation ${cls}`} onClick={exit}>\n <div className=\"flow-presentation-slide-fx\" style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }} />\n {count === 0 ? (\n <div className=\"flow-presentation-empty\">画布中没有动画锚点,点击退出</div>\n ) : (\n <div className=\"flow-presentation-hud\" onClick={(e) => e.stopPropagation()}>\n <span className=\"flow-presentation-counter\">\n {current + 1} / {count}\n </span>\n <div className=\"flow-presentation-nav\">\n <button type=\"button\" onClick={() => goTo(current - 1)} disabled={current <= 0}>‹ 上一张</button>\n <button type=\"button\" onClick={() => goTo(current + 1)} disabled={current >= count - 1}>下一张 ›</button>\n <button\n type=\"button\"\n onClick={() => setPresentation({\n current,\n showAnchor: !(presentation?.showAnchor ?? false),\n })}\n >\n {presentation?.showAnchor ? '隐藏锚点' : '显示锚点'}\n </button>\n <button type=\"button\" className=\"flow-presentation-exit\" onClick={exit}>退出 Esc</button>\n </div>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"PresentationMode.js","names":[],"sources":["../../../../../src/components/pro/Flow/panels/PresentationMode.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useFlowContext } from '../context/FlowContext';\nimport { useFlowUI } from '../context/FlowUIContext';\nimport { getDocumentSlides, anchorFocusRect, canvasStackTo } from '../nodes/animAnchors';\n\n/**\n * PPT-style presentation mode.\n *\n * While active the editor is read-only (all panels/toolbars are hidden) and the\n * viewport animates between animation anchors (slides). Anchors across the whole\n * document — including nested sub-canvases — share a single sequence, ordered by\n * stable creation index. Navigating to a slide on another canvas drills into or\n * out of that canvas before focusing the slide.\n *\n * Keys: →/↓/Space/PageDown = next, ←/↑/Shift+Space/PageUp = previous, Esc = exit.\n */\nexport function PresentationMode() {\n const { doc, setDoc, currentCanvasId } = useFlowContext();\n const { presentation, setPresentation, focusOnRect } = useFlowUI();\n const overlayRef = useRef<HTMLDivElement>(null);\n\n const slides = useMemo(() => getDocumentSlides(doc), [doc]);\n const count = slides.length;\n const active = presentation !== null;\n const current = presentation?.current ?? 0;\n const [transition, setTransition] = useState<'in' | 'out' | null>(null);\n\n const docRef = useRef(doc);\n docRef.current = doc;\n\n const exit = useCallback(() => {\n setPresentation(null);\n if (document.fullscreenElement) void document.exitFullscreen().catch(() => {});\n }, [setPresentation]);\n\n const enterFullscreen = useCallback(() => {\n const root = overlayRef.current?.closest('.flow-container') as HTMLElement | null;\n if (root && !document.fullscreenElement) {\n void root.requestFullscreen().catch(() => {});\n }\n }, []);\n\n const goTo = useCallback(\n (index: number) => {\n if (count === 0) return;\n const clamped = Math.max(0, Math.min(count - 1, index));\n setPresentation({\n current: clamped,\n showAnchor: presentation?.showAnchor ?? false,\n });\n const slide = slides[clamped];\n if (!slide) return;\n\n const d = docRef.current;\n const stack = canvasStackTo(d, slide.canvasId);\n\n // Decide drill direction by comparing with the current stack top.\n const onCurrentCanvas = slide.canvasId === currentCanvasId;\n if (!onCurrentCanvas && stack) {\n const deeper = stack.length > d.stack.length;\n setTransition(deeper ? 'in' : 'out');\n // Navigate the canvas stack to the slide's canvas.\n setDoc((prev) => ({ ...prev, stack }));\n // Clear the transition marker shortly after it starts.\n window.setTimeout(() => setTransition(null), 480);\n }\n\n const r = anchorFocusRect(slide.node);\n // Presentation uses the exact anchor frame with only a small screen-space\n // inset. The zoom is recomputed for every slide and viewport size.\n window.setTimeout(\n () => focusOnRect(r.x, r.y, r.w, r.h, { padding: 8, maxZoom: 4, duration: 350 }),\n onCurrentCanvas ? 0 : 30,\n );\n },\n [slides, count, presentation?.showAnchor, setPresentation, focusOnRect, currentCanvasId, setDoc],\n );\n\n // Entering: use the full display area and snap to the first slide. Refit once\n // fullscreen settles because the canvas dimensions change asynchronously.\n useEffect(() => {\n if (!active) return;\n enterFullscreen();\n if (count > 0) {\n goTo(current);\n const timer = window.setTimeout(() => goTo(current), 180);\n return () => window.clearTimeout(timer);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [active]);\n\n\n\n // Keyboard navigation (capture phase so arrows work over the canvas).\n useEffect(() => {\n if (!active) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n exit();\n return;\n }\n const next = ['ArrowRight', 'ArrowDown', 'PageDown', ' '];\n const prev = ['ArrowLeft', 'ArrowUp', 'PageUp'];\n if (next.includes(e.key)) {\n e.preventDefault();\n if (e.key === ' ' && e.shiftKey) goTo(current - 1);\n else goTo(current + 1);\n } else if (prev.includes(e.key)) {\n e.preventDefault();\n goTo(current - 1);\n }\n };\n window.addEventListener('keydown', onKey, true);\n return () => window.removeEventListener('keydown', onKey, true);\n }, [active, current, goTo, exit]);\n\n if (!active) return null;\n\n const cls = transition ? `flow-presentation--${transition}` : '';\n return (\n <div ref={overlayRef} className={`flow-presentation ${cls}`} onClick={exit}>\n <div className=\"flow-presentation-slide-fx\" style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }} />\n {count === 0 ? (\n <div className=\"flow-presentation-empty\">画布中没有动画锚点,点击退出</div>\n ) : (\n <div className=\"flow-presentation-hud\" onClick={(e) => e.stopPropagation()}>\n <span className=\"flow-presentation-counter\">\n {current + 1} / {count}\n </span>\n <div className=\"flow-presentation-nav\">\n <button type=\"button\" onClick={() => goTo(current - 1)} disabled={current <= 0}>‹ 上一张</button>\n <button type=\"button\" onClick={() => goTo(current + 1)} disabled={current >= count - 1}>下一张 ›</button>\n <button\n type=\"button\"\n onClick={() => setPresentation({\n current,\n showAnchor: !(presentation?.showAnchor ?? false),\n })}\n >\n {presentation?.showAnchor ? '隐藏锚点' : '显示锚点'}\n </button>\n <button type=\"button\" className=\"flow-presentation-exit\" onClick={exit}>退出 Esc</button>\n </div>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ProjectTitle.js","names":[],"sources":["../../../../../src/components/pro/Flow/panels/ProjectTitle.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\nimport { useFlowContext } from '../context/FlowContext';\n\nconst DEFAULT_TITLE = '未命名流程图';\n\n/**\n * Editable project title shown in the top-left. Renders as plain-looking text\n * (a borderless input) and only becomes editable on double-click, committing on\n * blur or Enter and reverting on Escape. The title is stored on the document\n * and used as the base filename for all exports.\n */\nexport default function ProjectTitle() {\n const { doc, setDoc } = useFlowContext();\n const [editing, setEditing] = useState(false);\n const [draft, setDraft] = useState(doc.title ?? '');\n const inputRef = useRef<HTMLInputElement>(null);\n\n // Keep the draft in sync when the document title changes externally\n // (import / undo / new document) while not actively editing.\n useEffect(() => {\n if (!editing) setDraft(doc.title ?? '');\n }, [doc.title, editing]);\n\n useEffect(() => {\n if (editing) {\n const el = inputRef.current;\n el?.focus();\n el?.select();\n }\n }, [editing]);\n\n const commit = () => {\n const next = draft.trim();\n setEditing(false);\n setDoc((prev) => ({ ...prev, title: next || undefined }));\n };\n\n const cancel = () => {\n setDraft(doc.title ?? '');\n setEditing(false);\n };\n\n return (\n <div className=\"flow-project-title\" title=\"双击编辑标题\">\n <input\n ref={inputRef}\n className={`flow-project-title-input${editing ? ' flow-project-title-input--editing' : ''}`}\n value={editing ? draft : (doc.title ?? '')}\n placeholder={DEFAULT_TITLE}\n readOnly={!editing}\n onDoubleClick={() => setEditing(true)}\n onChange={(e) => setDraft(e.target.value)}\n onBlur={() => { if (editing) commit(); }}\n onKeyDown={(e) => {\n if (e.key === 'Enter') { e.preventDefault(); commit(); }\n else if (e.key === 'Escape') { e.preventDefault(); cancel(); }\n }}\n spellCheck={false}\n />\n </div>\n );\n}\n"],"mappings":";;;AAGA,IAAM,IAAgB;AAQtB,SAAwB,IAAe;AACrC,QAAM,EAAE,KAAA,GAAK,QAAA,EAAA,IAAW,EAAe,GACjC,CAAC,GAAS,CAAA,IAAc,EAAS,EAAK,GACtC,CAAC,GAAO,CAAA,IAAY,EAAS,EAAI,SAAS,EAAE,GAC5C,IAAW,EAAyB,IAAI;AAI9C,EAAA,EAAA,MAAgB;AACd,IAAK,KAAS,EAAS,EAAI,SAAS,EAAE;AAAA,EACxC,GAAG,CAAC,EAAI,OAAO,CAAO,CAAC,GAEvB,EAAA,MAAgB;AACd,QAAI,GAAS;AACX,YAAM,IAAK,EAAS;AACpB,MAAA,GAAI,MAAM,GACV,GAAI,OAAO;AAAA,IACb;AAAA,EACF,GAAG,CAAC,CAAO,CAAC;AAEZ,QAAM,IAAA,MAAe;AACnB,UAAM,IAAO,EAAM,KAAK;AACxB,IAAA,EAAW,EAAK,GAChB,EAAA,CAAQ,OAAU;AAAA,MAAE,GAAG;AAAA,MAAM,OAAO,KAAQ;AAAA,IAAU,EAAE;AAAA,EAC1D,GAEM,IAAA,MAAe;AACnB,IAAA,EAAS,EAAI,SAAS,EAAE,GACxB,EAAW,EAAK;AAAA,EAClB;AAEA,SACE,gBAAA,EAAC,OAAD;AAAA,IAAK,WAAU;AAAA,IAAqB,OAAM;AAAA,cACxC,gBAAA,EAAC,SAAD;AAAA,MACE,KAAK;AAAA,MACL,WAAW,2BAA2B,IAAU,uCAAuC,EAAA;AAAA,MACvF,OAAO,IAAU,IAAS,EAAI,SAAS;AAAA,MACvC,aAAa;AAAA,MACb,UAAU,CAAC;AAAA,MACX,eAAA,MAAqB,EAAW,EAAI;AAAA,MACpC,UAAA,CAAW,MAAM,EAAS,EAAE,OAAO,KAAK;AAAA,MACxC,QAAA,MAAc;AAAE,QAAI,KAAS,EAAO;AAAA,MAAG;AAAA,MACvC,WAAA,CAAY,MAAM;AAChB,QAAI,EAAE,QAAQ,WAAW,EAAE,eAAe,GAAG,EAAO,KAC3C,EAAE,QAAQ,aAAY,EAAE,eAAe,GAAG,EAAO;AAAA,MAC5D;AAAA,MACA,YAAY;AAAA,IACb,CAAA;AAAA,EACE,CAAA;AAET"}
1
+ {"version":3,"file":"ProjectTitle.js","names":[],"sources":["../../../../../src/components/pro/Flow/panels/ProjectTitle.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\nimport { useFlowContext } from '../context/FlowContext';\n\nconst DEFAULT_TITLE = '未命名流程图';\n\n/**\n * Editable project title shown in the top-left. Renders as plain-looking text\n * (a borderless input) and only becomes editable on double-click, committing on\n * blur or Enter and reverting on Escape. The title is stored on the document\n * and used as the base filename for all exports.\n */\nexport default function ProjectTitle() {\n const { doc, setDoc } = useFlowContext();\n const [editing, setEditing] = useState(false);\n const [draft, setDraft] = useState(doc.title ?? '');\n const inputRef = useRef<HTMLInputElement>(null);\n\n // Keep the draft in sync when the document title changes externally\n // (import / undo / new document) while not actively editing.\n useEffect(() => {\n if (!editing) setDraft(doc.title ?? '');\n }, [doc.title, editing]);\n\n useEffect(() => {\n if (editing) {\n const el = inputRef.current;\n el?.focus();\n el?.select();\n }\n }, [editing]);\n\n const commit = () => {\n const next = draft.trim();\n setEditing(false);\n setDoc((prev) => ({ ...prev, title: next || undefined }));\n };\n\n const cancel = () => {\n setDraft(doc.title ?? '');\n setEditing(false);\n };\n\n return (\n <div className=\"flow-project-title\" title=\"双击编辑标题\">\n <input\n ref={inputRef}\n className={`flow-project-title-input${editing ? ' flow-project-title-input--editing' : ''}`}\n value={editing ? draft : (doc.title ?? '')}\n placeholder={DEFAULT_TITLE}\n readOnly={!editing}\n onDoubleClick={() => setEditing(true)}\n onChange={(e) => setDraft(e.target.value)}\n onBlur={() => { if (editing) commit(); }}\n onKeyDown={(e) => {\n if (e.key === 'Enter') { e.preventDefault(); commit(); }\n else if (e.key === 'Escape') { e.preventDefault(); cancel(); }\n }}\n spellCheck={false}\n />\n </div>\n );\n}\n"],"mappings":";;;AAGA,IAAM,IAAgB;AAQtB,SAAwB,IAAe;AACrC,QAAM,EAAE,KAAA,GAAK,QAAA,EAAA,IAAW,EAAe,GACjC,CAAC,GAAS,CAAA,IAAc,EAAS,EAAK,GACtC,CAAC,GAAO,CAAA,IAAY,EAAS,EAAI,SAAS,EAAE,GAC5C,IAAW,EAAyB,IAAI;AAI9C,EAAA,EAAA,MAAgB;AACd,IAAK,KAAS,EAAS,EAAI,SAAS,EAAE;AAAA,EACxC,GAAG,CAAC,EAAI,OAAO,CAAO,CAAC,GAEvB,EAAA,MAAgB;AACd,QAAI,GAAS;AACX,YAAM,IAAK,EAAS;AACpB,MAAA,GAAI,MAAM,GACV,GAAI,OAAO;AAAA,IACb;AAAA,EACF,GAAG,CAAC,CAAO,CAAC;AAEZ,QAAM,IAAA,MAAe;AACnB,UAAM,IAAO,EAAM,KAAK;AACxB,IAAA,EAAW,EAAK,GAChB,EAAA,CAAQ,OAAU;AAAA,MAAE,GAAG;AAAA,MAAM,OAAO,KAAQ;AAAA,IAAU,EAAE;AAAA,EAC1D,GAEM,IAAA,MAAe;AACnB,IAAA,EAAS,EAAI,SAAS,EAAE,GACxB,EAAW,EAAK;AAAA,EAClB;AAEA,SACE,gBAAA,EAAC,OAAD;AAAA,IAAK,WAAU;AAAA,IAAqB,OAAM;AAAA,IACxC,UAAA,gBAAA,EAAC,SAAD;AAAA,MACE,KAAK;AAAA,MACL,WAAW,2BAA2B,IAAU,uCAAuC,EAAA;AAAA,MACvF,OAAO,IAAU,IAAS,EAAI,SAAS;AAAA,MACvC,aAAa;AAAA,MACb,UAAU,CAAC;AAAA,MACX,eAAA,MAAqB,EAAW,EAAI;AAAA,MACpC,UAAA,CAAW,MAAM,EAAS,EAAE,OAAO,KAAK;AAAA,MACxC,QAAA,MAAc;AAAE,QAAI,KAAS,EAAO;AAAA,MAAG;AAAA,MACvC,WAAA,CAAY,MAAM;AAChB,QAAI,EAAE,QAAQ,WAAW,EAAE,eAAe,GAAG,EAAO,KAC3C,EAAE,QAAQ,aAAY,EAAE,eAAe,GAAG,EAAO;AAAA,MAC5D;AAAA,MACA,YAAY;AAAA,IACb,CAAA;AAAA,EACE,CAAA;AAET"}