@yh-ui/flow 0.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +234 -0
- package/dist/Flow.d.vue.ts +306 -0
- package/dist/Flow.vue +959 -0
- package/dist/Flow.vue.d.ts +306 -0
- package/dist/__tests__/ai-workflow.ssr.test.cjs +352 -0
- package/dist/__tests__/ai-workflow.ssr.test.d.ts +1 -0
- package/dist/__tests__/ai-workflow.ssr.test.mjs +283 -0
- package/dist/__tests__/ai-workflow.test.cjs +109 -0
- package/dist/__tests__/ai-workflow.test.d.ts +1 -0
- package/dist/__tests__/ai-workflow.test.mjs +112 -0
- package/dist/__tests__/bpmn.ssr.test.cjs +278 -0
- package/dist/__tests__/bpmn.ssr.test.d.ts +1 -0
- package/dist/__tests__/bpmn.ssr.test.mjs +237 -0
- package/dist/__tests__/bpmn.test.cjs +103 -0
- package/dist/__tests__/bpmn.test.d.ts +1 -0
- package/dist/__tests__/bpmn.test.mjs +106 -0
- package/dist/__tests__/custom-types.test.cjs +300 -0
- package/dist/__tests__/custom-types.test.d.ts +1 -0
- package/dist/__tests__/custom-types.test.mjs +248 -0
- package/dist/__tests__/edge.test.cjs +56 -0
- package/dist/__tests__/edge.test.d.ts +1 -0
- package/dist/__tests__/edge.test.mjs +69 -0
- package/dist/__tests__/event-bus.test.cjs +80 -0
- package/dist/__tests__/event-bus.test.d.ts +1 -0
- package/dist/__tests__/event-bus.test.mjs +51 -0
- package/dist/__tests__/flow.ssr.test.cjs +156 -0
- package/dist/__tests__/flow.ssr.test.d.ts +1 -0
- package/dist/__tests__/flow.ssr.test.mjs +112 -0
- package/dist/__tests__/geometry.test.cjs +191 -0
- package/dist/__tests__/geometry.test.d.ts +1 -0
- package/dist/__tests__/geometry.test.mjs +105 -0
- package/dist/__tests__/graph.test.cjs +115 -0
- package/dist/__tests__/graph.test.d.ts +1 -0
- package/dist/__tests__/graph.test.mjs +85 -0
- package/dist/__tests__/history-plugin.test.cjs +191 -0
- package/dist/__tests__/history-plugin.test.d.ts +1 -0
- package/dist/__tests__/history-plugin.test.mjs +161 -0
- package/dist/__tests__/history.test.cjs +81 -0
- package/dist/__tests__/history.test.d.ts +1 -0
- package/dist/__tests__/history.test.mjs +43 -0
- package/dist/__tests__/layout.test.cjs +213 -0
- package/dist/__tests__/layout.test.d.ts +1 -0
- package/dist/__tests__/layout.test.mjs +170 -0
- package/dist/__tests__/node-edit-panel.ssr.test.cjs +168 -0
- package/dist/__tests__/node-edit-panel.ssr.test.d.ts +1 -0
- package/dist/__tests__/node-edit-panel.ssr.test.mjs +118 -0
- package/dist/__tests__/node-group-plugin.test.cjs +235 -0
- package/dist/__tests__/node-group-plugin.test.d.ts +1 -0
- package/dist/__tests__/node-group-plugin.test.mjs +187 -0
- package/dist/__tests__/node-handles.test.cjs +340 -0
- package/dist/__tests__/node-handles.test.d.ts +1 -0
- package/dist/__tests__/node-handles.test.mjs +230 -0
- package/dist/__tests__/plugin.test.cjs +151 -0
- package/dist/__tests__/plugin.test.d.ts +1 -0
- package/dist/__tests__/plugin.test.mjs +116 -0
- package/dist/__tests__/transform.test.cjs +58 -0
- package/dist/__tests__/transform.test.d.ts +1 -0
- package/dist/__tests__/transform.test.mjs +38 -0
- package/dist/__tests__/useAlignment.test.cjs +91 -0
- package/dist/__tests__/useAlignment.test.d.ts +1 -0
- package/dist/__tests__/useAlignment.test.mjs +52 -0
- package/dist/__tests__/useEdges.test.cjs +117 -0
- package/dist/__tests__/useEdges.test.d.ts +1 -0
- package/dist/__tests__/useEdges.test.mjs +80 -0
- package/dist/__tests__/useKeyboard.test.cjs +88 -0
- package/dist/__tests__/useKeyboard.test.d.ts +1 -0
- package/dist/__tests__/useKeyboard.test.mjs +56 -0
- package/dist/__tests__/useNodes.test.cjs +150 -0
- package/dist/__tests__/useNodes.test.d.ts +1 -0
- package/dist/__tests__/useNodes.test.mjs +80 -0
- package/dist/__tests__/useSelection.test.cjs +112 -0
- package/dist/__tests__/useSelection.test.d.ts +1 -0
- package/dist/__tests__/useSelection.test.mjs +76 -0
- package/dist/__tests__/useViewport.test.cjs +171 -0
- package/dist/__tests__/useViewport.test.d.ts +1 -0
- package/dist/__tests__/useViewport.test.mjs +82 -0
- package/dist/__tests__/utils/ssr.cjs +124 -0
- package/dist/__tests__/utils/ssr.d.ts +33 -0
- package/dist/__tests__/utils/ssr.mjs +129 -0
- package/dist/__tests__/validation.test.cjs +95 -0
- package/dist/__tests__/validation.test.d.ts +1 -0
- package/dist/__tests__/validation.test.mjs +36 -0
- package/dist/components/AiNodeEditPanel.d.vue.ts +13 -0
- package/dist/components/AiNodeEditPanel.vue +413 -0
- package/dist/components/AiNodeEditPanel.vue.d.ts +13 -0
- package/dist/components/EdgeEditPanel.d.vue.ts +14 -0
- package/dist/components/EdgeEditPanel.vue +205 -0
- package/dist/components/EdgeEditPanel.vue.d.ts +14 -0
- package/dist/components/NodeEditPanel.d.vue.ts +13 -0
- package/dist/components/NodeEditPanel.vue +214 -0
- package/dist/components/NodeEditPanel.vue.d.ts +13 -0
- package/dist/components/edges/BaseEdge.d.vue.ts +23 -0
- package/dist/components/edges/BaseEdge.vue +55 -0
- package/dist/components/edges/BaseEdge.vue.d.ts +23 -0
- package/dist/components/edges/BezierEdge.d.vue.ts +22 -0
- package/dist/components/edges/BezierEdge.vue +57 -0
- package/dist/components/edges/BezierEdge.vue.d.ts +22 -0
- package/dist/components/edges/DataFlowEdge.d.vue.ts +41 -0
- package/dist/components/edges/DataFlowEdge.vue +211 -0
- package/dist/components/edges/DataFlowEdge.vue.d.ts +41 -0
- package/dist/components/edges/SmoothEdge.d.vue.ts +22 -0
- package/dist/components/edges/SmoothEdge.vue +53 -0
- package/dist/components/edges/SmoothEdge.vue.d.ts +22 -0
- package/dist/components/edges/StepEdge.d.vue.ts +22 -0
- package/dist/components/edges/StepEdge.vue +42 -0
- package/dist/components/edges/StepEdge.vue.d.ts +22 -0
- package/dist/components/edges/index.cjs +41 -0
- package/dist/components/edges/index.d.ts +5 -0
- package/dist/components/edges/index.mjs +5 -0
- package/dist/components/nodes/BaseNode.d.vue.ts +25 -0
- package/dist/components/nodes/BaseNode.vue +93 -0
- package/dist/components/nodes/BaseNode.vue.d.ts +25 -0
- package/dist/components/nodes/CustomNode.d.vue.ts +36 -0
- package/dist/components/nodes/CustomNode.vue +44 -0
- package/dist/components/nodes/CustomNode.vue.d.ts +36 -0
- package/dist/components/nodes/DatabaseNode.d.vue.ts +19 -0
- package/dist/components/nodes/DatabaseNode.vue +62 -0
- package/dist/components/nodes/DatabaseNode.vue.d.ts +19 -0
- package/dist/components/nodes/DiamondNode.d.vue.ts +19 -0
- package/dist/components/nodes/DiamondNode.vue +62 -0
- package/dist/components/nodes/DiamondNode.vue.d.ts +19 -0
- package/dist/components/nodes/GroupNode.d.vue.ts +31 -0
- package/dist/components/nodes/GroupNode.vue +48 -0
- package/dist/components/nodes/GroupNode.vue.d.ts +31 -0
- package/dist/components/nodes/InputNode.d.vue.ts +23 -0
- package/dist/components/nodes/InputNode.vue +63 -0
- package/dist/components/nodes/InputNode.vue.d.ts +23 -0
- package/dist/components/nodes/NodeResizer.d.vue.ts +27 -0
- package/dist/components/nodes/NodeResizer.vue +89 -0
- package/dist/components/nodes/NodeResizer.vue.d.ts +27 -0
- package/dist/components/nodes/NodeToolbar.d.vue.ts +32 -0
- package/dist/components/nodes/NodeToolbar.vue +101 -0
- package/dist/components/nodes/NodeToolbar.vue.d.ts +32 -0
- package/dist/components/nodes/OutputNode.d.vue.ts +21 -0
- package/dist/components/nodes/OutputNode.vue +53 -0
- package/dist/components/nodes/OutputNode.vue.d.ts +21 -0
- package/dist/components/nodes/ai-workflow/AiAgentNode.d.vue.ts +20 -0
- package/dist/components/nodes/ai-workflow/AiAgentNode.vue +59 -0
- package/dist/components/nodes/ai-workflow/AiAgentNode.vue.d.ts +20 -0
- package/dist/components/nodes/ai-workflow/AiConditionNode.d.vue.ts +19 -0
- package/dist/components/nodes/ai-workflow/AiConditionNode.vue +65 -0
- package/dist/components/nodes/ai-workflow/AiConditionNode.vue.d.ts +19 -0
- package/dist/components/nodes/ai-workflow/AiEndNode.d.vue.ts +19 -0
- package/dist/components/nodes/ai-workflow/AiEndNode.vue +47 -0
- package/dist/components/nodes/ai-workflow/AiEndNode.vue.d.ts +19 -0
- package/dist/components/nodes/ai-workflow/AiLlmNode.d.vue.ts +19 -0
- package/dist/components/nodes/ai-workflow/AiLlmNode.vue +64 -0
- package/dist/components/nodes/ai-workflow/AiLlmNode.vue.d.ts +19 -0
- package/dist/components/nodes/ai-workflow/AiMemoryNode.d.vue.ts +19 -0
- package/dist/components/nodes/ai-workflow/AiMemoryNode.vue +59 -0
- package/dist/components/nodes/ai-workflow/AiMemoryNode.vue.d.ts +19 -0
- package/dist/components/nodes/ai-workflow/AiPromptNode.d.vue.ts +19 -0
- package/dist/components/nodes/ai-workflow/AiPromptNode.vue +61 -0
- package/dist/components/nodes/ai-workflow/AiPromptNode.vue.d.ts +19 -0
- package/dist/components/nodes/ai-workflow/AiStartNode.d.vue.ts +19 -0
- package/dist/components/nodes/ai-workflow/AiStartNode.vue +47 -0
- package/dist/components/nodes/ai-workflow/AiStartNode.vue.d.ts +19 -0
- package/dist/components/nodes/ai-workflow/AiToolNode.d.vue.ts +19 -0
- package/dist/components/nodes/ai-workflow/AiToolNode.vue +59 -0
- package/dist/components/nodes/ai-workflow/AiToolNode.vue.d.ts +19 -0
- package/dist/components/nodes/ai-workflow/index.cjs +109 -0
- package/dist/components/nodes/ai-workflow/index.d.ts +23 -0
- package/dist/components/nodes/ai-workflow/index.mjs +37 -0
- package/dist/components/nodes/bpmn/BpmnEndEvent.d.vue.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnEndEvent.vue +50 -0
- package/dist/components/nodes/bpmn/BpmnEndEvent.vue.d.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnExclusiveGateway.d.vue.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnExclusiveGateway.vue +60 -0
- package/dist/components/nodes/bpmn/BpmnExclusiveGateway.vue.d.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnInclusiveGateway.d.vue.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnInclusiveGateway.vue +60 -0
- package/dist/components/nodes/bpmn/BpmnInclusiveGateway.vue.d.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnParallelGateway.d.vue.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnParallelGateway.vue +60 -0
- package/dist/components/nodes/bpmn/BpmnParallelGateway.vue.d.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnServiceTask.d.vue.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnServiceTask.vue +55 -0
- package/dist/components/nodes/bpmn/BpmnServiceTask.vue.d.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnStartEvent.d.vue.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnStartEvent.vue +50 -0
- package/dist/components/nodes/bpmn/BpmnStartEvent.vue.d.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnTask.d.vue.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnTask.vue +54 -0
- package/dist/components/nodes/bpmn/BpmnTask.vue.d.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnUserTask.d.vue.ts +19 -0
- package/dist/components/nodes/bpmn/BpmnUserTask.vue +55 -0
- package/dist/components/nodes/bpmn/BpmnUserTask.vue.d.ts +19 -0
- package/dist/components/nodes/bpmn/index.cjs +109 -0
- package/dist/components/nodes/bpmn/index.d.ts +23 -0
- package/dist/components/nodes/bpmn/index.mjs +37 -0
- package/dist/components/nodes/index.cjs +246 -0
- package/dist/components/nodes/index.d.ts +13 -0
- package/dist/components/nodes/index.mjs +44 -0
- package/dist/core/FlowContext.cjs +21 -0
- package/dist/core/FlowContext.d.ts +10 -0
- package/dist/core/FlowContext.mjs +13 -0
- package/dist/core/index.cjs +104 -0
- package/dist/core/index.d.ts +9 -0
- package/dist/core/index.mjs +9 -0
- package/dist/core/useAlignment.cjs +81 -0
- package/dist/core/useAlignment.d.ts +33 -0
- package/dist/core/useAlignment.mjs +71 -0
- package/dist/core/useEdges.cjs +132 -0
- package/dist/core/useEdges.d.ts +29 -0
- package/dist/core/useEdges.mjs +89 -0
- package/dist/core/useFlow.cjs +40 -0
- package/dist/core/useFlow.d.ts +31 -0
- package/dist/core/useFlow.mjs +32 -0
- package/dist/core/useHistory.cjs +63 -0
- package/dist/core/useHistory.d.ts +15 -0
- package/dist/core/useHistory.mjs +54 -0
- package/dist/core/useKeyboard.cjs +54 -0
- package/dist/core/useKeyboard.d.ts +18 -0
- package/dist/core/useKeyboard.mjs +45 -0
- package/dist/core/useNodeDistribution.cjs +171 -0
- package/dist/core/useNodeDistribution.d.ts +12 -0
- package/dist/core/useNodeDistribution.mjs +145 -0
- package/dist/core/useNodes.cjs +146 -0
- package/dist/core/useNodes.d.ts +26 -0
- package/dist/core/useNodes.mjs +101 -0
- package/dist/core/useSelection.cjs +83 -0
- package/dist/core/useSelection.d.ts +18 -0
- package/dist/core/useSelection.mjs +53 -0
- package/dist/core/useViewport.cjs +157 -0
- package/dist/core/useViewport.d.ts +65 -0
- package/dist/core/useViewport.mjs +125 -0
- package/dist/flow.cjs +240 -0
- package/dist/flow.d.ts +276 -0
- package/dist/flow.mjs +230 -0
- package/dist/index.cjs +378 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.mjs +50 -0
- package/dist/plugins/index.cjs +96 -0
- package/dist/plugins/index.d.ts +34 -0
- package/dist/plugins/index.mjs +47 -0
- package/dist/plugins/plugin.cjs +117 -0
- package/dist/plugins/plugin.d.ts +72 -0
- package/dist/plugins/plugin.mjs +110 -0
- package/dist/plugins/plugins/controls.cjs +38 -0
- package/dist/plugins/plugins/controls.d.ts +12 -0
- package/dist/plugins/plugins/controls.mjs +28 -0
- package/dist/plugins/plugins/export.cjs +102 -0
- package/dist/plugins/plugins/export.d.ts +12 -0
- package/dist/plugins/plugins/export.mjs +89 -0
- package/dist/plugins/plugins/grid.cjs +36 -0
- package/dist/plugins/plugins/grid.d.ts +11 -0
- package/dist/plugins/plugins/grid.mjs +26 -0
- package/dist/plugins/plugins/history.cjs +140 -0
- package/dist/plugins/plugins/history.d.ts +53 -0
- package/dist/plugins/plugins/history.mjs +132 -0
- package/dist/plugins/plugins/index.cjs +104 -0
- package/dist/plugins/plugins/index.d.ts +9 -0
- package/dist/plugins/plugins/index.mjs +9 -0
- package/dist/plugins/plugins/keyboard.cjs +27 -0
- package/dist/plugins/plugins/keyboard.d.ts +10 -0
- package/dist/plugins/plugins/keyboard.mjs +18 -0
- package/dist/plugins/plugins/layout.cjs +275 -0
- package/dist/plugins/plugins/layout.d.ts +34 -0
- package/dist/plugins/plugins/layout.mjs +246 -0
- package/dist/plugins/plugins/minimap.cjs +60 -0
- package/dist/plugins/plugins/minimap.d.ts +25 -0
- package/dist/plugins/plugins/minimap.mjs +50 -0
- package/dist/plugins/plugins/node-group.cjs +209 -0
- package/dist/plugins/plugins/node-group.d.ts +26 -0
- package/dist/plugins/plugins/node-group.mjs +178 -0
- package/dist/plugins/plugins/snap.cjs +36 -0
- package/dist/plugins/plugins/snap.d.ts +12 -0
- package/dist/plugins/plugins/snap.mjs +26 -0
- package/dist/renderer/AlignmentLines.d.vue.ts +5 -0
- package/dist/renderer/AlignmentLines.vue +113 -0
- package/dist/renderer/AlignmentLines.vue.d.ts +5 -0
- package/dist/renderer/Background.d.vue.ts +7 -0
- package/dist/renderer/Background.vue +86 -0
- package/dist/renderer/Background.vue.d.ts +7 -0
- package/dist/renderer/Controls.d.vue.ts +13 -0
- package/dist/renderer/Controls.vue +82 -0
- package/dist/renderer/Controls.vue.d.ts +13 -0
- package/dist/renderer/EdgeHandlesRenderer.d.vue.ts +11 -0
- package/dist/renderer/EdgeHandlesRenderer.vue +75 -0
- package/dist/renderer/EdgeHandlesRenderer.vue.d.ts +11 -0
- package/dist/renderer/EdgeRenderer.d.vue.ts +39 -0
- package/dist/renderer/EdgeRenderer.vue +204 -0
- package/dist/renderer/EdgeRenderer.vue.d.ts +39 -0
- package/dist/renderer/FlowBackground.d.vue.ts +11 -0
- package/dist/renderer/FlowBackground.vue +82 -0
- package/dist/renderer/FlowBackground.vue.d.ts +11 -0
- package/dist/renderer/Minimap.d.vue.ts +30 -0
- package/dist/renderer/Minimap.vue +290 -0
- package/dist/renderer/Minimap.vue.d.ts +30 -0
- package/dist/renderer/NodeRenderer.d.vue.ts +56 -0
- package/dist/renderer/NodeRenderer.vue +328 -0
- package/dist/renderer/NodeRenderer.vue.d.ts +56 -0
- package/dist/renderer/SelectionBox.d.vue.ts +11 -0
- package/dist/renderer/SelectionBox.vue +28 -0
- package/dist/renderer/SelectionBox.vue.d.ts +11 -0
- package/dist/types/edge.cjs +13 -0
- package/dist/types/edge.d.ts +65 -0
- package/dist/types/edge.mjs +6 -0
- package/dist/types/events.cjs +1 -0
- package/dist/types/events.d.ts +115 -0
- package/dist/types/events.mjs +0 -0
- package/dist/types/index.cjs +1 -0
- package/dist/types/index.d.ts +366 -0
- package/dist/types/index.mjs +0 -0
- package/dist/types/node.cjs +9 -0
- package/dist/types/node.d.ts +90 -0
- package/dist/types/node.mjs +3 -0
- package/dist/types/viewport.cjs +42 -0
- package/dist/types/viewport.d.ts +62 -0
- package/dist/types/viewport.mjs +36 -0
- package/dist/utils/bpmn-engine.cjs +390 -0
- package/dist/utils/bpmn-engine.d.ts +164 -0
- package/dist/utils/bpmn-engine.mjs +378 -0
- package/dist/utils/bpmn.cjs +492 -0
- package/dist/utils/bpmn.d.ts +53 -0
- package/dist/utils/bpmn.mjs +430 -0
- package/dist/utils/collaboration.cjs +537 -0
- package/dist/utils/collaboration.d.ts +189 -0
- package/dist/utils/collaboration.mjs +521 -0
- package/dist/utils/custom-types.cjs +138 -0
- package/dist/utils/custom-types.d.ts +78 -0
- package/dist/utils/custom-types.mjs +108 -0
- package/dist/utils/edge.cjs +235 -0
- package/dist/utils/edge.d.ts +79 -0
- package/dist/utils/edge.mjs +172 -0
- package/dist/utils/event-bus.cjs +91 -0
- package/dist/utils/event-bus.d.ts +39 -0
- package/dist/utils/event-bus.mjs +82 -0
- package/dist/utils/geometry.cjs +178 -0
- package/dist/utils/geometry.d.ts +186 -0
- package/dist/utils/geometry.mjs +144 -0
- package/dist/utils/graph.cjs +158 -0
- package/dist/utils/graph.d.ts +40 -0
- package/dist/utils/graph.mjs +147 -0
- package/dist/utils/index.cjs +137 -0
- package/dist/utils/index.d.ts +12 -0
- package/dist/utils/index.mjs +12 -0
- package/dist/utils/performance.cjs +94 -0
- package/dist/utils/performance.d.ts +18 -0
- package/dist/utils/performance.mjs +82 -0
- package/dist/utils/screenshot.cjs +87 -0
- package/dist/utils/screenshot.d.ts +22 -0
- package/dist/utils/screenshot.mjs +66 -0
- package/dist/utils/theme.cjs +228 -0
- package/dist/utils/theme.d.ts +92 -0
- package/dist/utils/theme.mjs +217 -0
- package/dist/utils/transform.cjs +76 -0
- package/dist/utils/transform.d.ts +45 -0
- package/dist/utils/transform.mjs +57 -0
- package/dist/utils/validation.cjs +107 -0
- package/dist/utils/validation.d.ts +29 -0
- package/dist/utils/validation.mjs +85 -0
- package/package.json +61 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _vitest = require("vitest");
|
|
4
|
+
var _vue = require("vue");
|
|
5
|
+
var _useViewport = require("../core/useViewport.cjs");
|
|
6
|
+
(0, _vitest.describe)("flow/core/useViewport", () => {
|
|
7
|
+
(0, _vitest.it)("should set viewport and clamp zoom to min/max", () => {
|
|
8
|
+
const transform = (0, _vue.ref)({
|
|
9
|
+
x: 0,
|
|
10
|
+
y: 0,
|
|
11
|
+
zoom: 1
|
|
12
|
+
});
|
|
13
|
+
const v = (0, _useViewport.useViewport)(transform, {
|
|
14
|
+
minZoom: 0.2,
|
|
15
|
+
maxZoom: 4
|
|
16
|
+
});
|
|
17
|
+
v.setViewport(10, 20, 2);
|
|
18
|
+
(0, _vitest.expect)(transform.value).toEqual({
|
|
19
|
+
x: 10,
|
|
20
|
+
y: 20,
|
|
21
|
+
zoom: 2
|
|
22
|
+
});
|
|
23
|
+
v.setViewport(0, 0, 0.1);
|
|
24
|
+
(0, _vitest.expect)(transform.value.zoom).toBe(0.2);
|
|
25
|
+
v.setViewport(0, 0, 10);
|
|
26
|
+
(0, _vitest.expect)(transform.value.zoom).toBe(4);
|
|
27
|
+
});
|
|
28
|
+
(0, _vitest.it)("should zoom in and out", () => {
|
|
29
|
+
const transform = (0, _vue.ref)({
|
|
30
|
+
x: 0,
|
|
31
|
+
y: 0,
|
|
32
|
+
zoom: 1
|
|
33
|
+
});
|
|
34
|
+
const v = (0, _useViewport.useViewport)(transform, {
|
|
35
|
+
minZoom: 0.1,
|
|
36
|
+
maxZoom: 5
|
|
37
|
+
});
|
|
38
|
+
v.zoomIn(2);
|
|
39
|
+
(0, _vitest.expect)(transform.value.zoom).toBe(2);
|
|
40
|
+
v.zoomOut(2);
|
|
41
|
+
(0, _vitest.expect)(transform.value.zoom).toBe(1);
|
|
42
|
+
});
|
|
43
|
+
(0, _vitest.it)("should pan", () => {
|
|
44
|
+
const transform = (0, _vue.ref)({
|
|
45
|
+
x: 0,
|
|
46
|
+
y: 0,
|
|
47
|
+
zoom: 1
|
|
48
|
+
});
|
|
49
|
+
const v = (0, _useViewport.useViewport)(transform);
|
|
50
|
+
v.pan(50, 30);
|
|
51
|
+
(0, _vitest.expect)(transform.value.x).toBe(50);
|
|
52
|
+
(0, _vitest.expect)(transform.value.y).toBe(30);
|
|
53
|
+
});
|
|
54
|
+
(0, _vitest.it)("should panTo", () => {
|
|
55
|
+
const transform = (0, _vue.ref)({
|
|
56
|
+
x: 0,
|
|
57
|
+
y: 0,
|
|
58
|
+
zoom: 1
|
|
59
|
+
});
|
|
60
|
+
const v = (0, _useViewport.useViewport)(transform);
|
|
61
|
+
v.panTo(100, 200);
|
|
62
|
+
(0, _vitest.expect)(transform.value.x).toBe(100);
|
|
63
|
+
(0, _vitest.expect)(transform.value.y).toBe(200);
|
|
64
|
+
});
|
|
65
|
+
(0, _vitest.it)("should fitView to contain nodes", () => {
|
|
66
|
+
const transform = (0, _vue.ref)({
|
|
67
|
+
x: 0,
|
|
68
|
+
y: 0,
|
|
69
|
+
zoom: 1
|
|
70
|
+
});
|
|
71
|
+
const v = (0, _useViewport.useViewport)(transform, {
|
|
72
|
+
minZoom: 0.1,
|
|
73
|
+
maxZoom: 5
|
|
74
|
+
});
|
|
75
|
+
const nodes = [{
|
|
76
|
+
position: {
|
|
77
|
+
x: 0,
|
|
78
|
+
y: 0
|
|
79
|
+
},
|
|
80
|
+
width: 100,
|
|
81
|
+
height: 50
|
|
82
|
+
}, {
|
|
83
|
+
position: {
|
|
84
|
+
x: 200,
|
|
85
|
+
y: 100
|
|
86
|
+
},
|
|
87
|
+
width: 100,
|
|
88
|
+
height: 50
|
|
89
|
+
}];
|
|
90
|
+
v.fitView({
|
|
91
|
+
width: 400,
|
|
92
|
+
height: 300
|
|
93
|
+
}, nodes, {
|
|
94
|
+
padding: 20
|
|
95
|
+
});
|
|
96
|
+
(0, _vitest.expect)(transform.value.zoom).toBeLessThanOrEqual(1);
|
|
97
|
+
(0, _vitest.expect)(typeof transform.value.x).toBe("number");
|
|
98
|
+
(0, _vitest.expect)(typeof transform.value.y).toBe("number");
|
|
99
|
+
});
|
|
100
|
+
(0, _vitest.it)("should not fitView when nodes empty", () => {
|
|
101
|
+
const transform = (0, _vue.ref)({
|
|
102
|
+
x: 50,
|
|
103
|
+
y: 50,
|
|
104
|
+
zoom: 1
|
|
105
|
+
});
|
|
106
|
+
const v = (0, _useViewport.useViewport)(transform);
|
|
107
|
+
v.fitView({
|
|
108
|
+
width: 400,
|
|
109
|
+
height: 300
|
|
110
|
+
}, [], {
|
|
111
|
+
padding: 20
|
|
112
|
+
});
|
|
113
|
+
(0, _vitest.expect)(transform.value).toEqual({
|
|
114
|
+
x: 50,
|
|
115
|
+
y: 50,
|
|
116
|
+
zoom: 1
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
(0, _vitest.it)("screenToCanvas and canvasToScreen should be inverse", () => {
|
|
120
|
+
const transform = (0, _vue.ref)({
|
|
121
|
+
x: 100,
|
|
122
|
+
y: 50,
|
|
123
|
+
zoom: 2
|
|
124
|
+
});
|
|
125
|
+
const v = (0, _useViewport.useViewport)(transform);
|
|
126
|
+
const screen = {
|
|
127
|
+
x: 300,
|
|
128
|
+
y: 250
|
|
129
|
+
};
|
|
130
|
+
const canvas = v.screenToCanvas(screen.x, screen.y);
|
|
131
|
+
const back = v.canvasToScreen(canvas.x, canvas.y);
|
|
132
|
+
(0, _vitest.expect)(back.x).toBe(screen.x);
|
|
133
|
+
(0, _vitest.expect)(back.y).toBe(screen.y);
|
|
134
|
+
});
|
|
135
|
+
(0, _vitest.it)("isNodeVisible should return true when node in view", () => {
|
|
136
|
+
const transform = (0, _vue.ref)({
|
|
137
|
+
x: 0,
|
|
138
|
+
y: 0,
|
|
139
|
+
zoom: 1
|
|
140
|
+
});
|
|
141
|
+
const v = (0, _useViewport.useViewport)(transform);
|
|
142
|
+
const visible = v.isNodeVisible({
|
|
143
|
+
x: 50,
|
|
144
|
+
y: 50,
|
|
145
|
+
width: 100,
|
|
146
|
+
height: 50
|
|
147
|
+
}, {
|
|
148
|
+
width: 800,
|
|
149
|
+
height: 600
|
|
150
|
+
});
|
|
151
|
+
(0, _vitest.expect)(visible).toBe(true);
|
|
152
|
+
});
|
|
153
|
+
(0, _vitest.it)("isNodeVisible should return false when node outside view", () => {
|
|
154
|
+
const transform = (0, _vue.ref)({
|
|
155
|
+
x: -2e3,
|
|
156
|
+
y: 0,
|
|
157
|
+
zoom: 1
|
|
158
|
+
});
|
|
159
|
+
const v = (0, _useViewport.useViewport)(transform);
|
|
160
|
+
const visible = v.isNodeVisible({
|
|
161
|
+
x: 50,
|
|
162
|
+
y: 50,
|
|
163
|
+
width: 100,
|
|
164
|
+
height: 50
|
|
165
|
+
}, {
|
|
166
|
+
width: 800,
|
|
167
|
+
height: 600
|
|
168
|
+
});
|
|
169
|
+
(0, _vitest.expect)(visible).toBe(false);
|
|
170
|
+
});
|
|
171
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { ref } from "vue";
|
|
3
|
+
import { useViewport } from "../core/useViewport.mjs";
|
|
4
|
+
describe("flow/core/useViewport", () => {
|
|
5
|
+
it("should set viewport and clamp zoom to min/max", () => {
|
|
6
|
+
const transform = ref({ x: 0, y: 0, zoom: 1 });
|
|
7
|
+
const v = useViewport(transform, { minZoom: 0.2, maxZoom: 4 });
|
|
8
|
+
v.setViewport(10, 20, 2);
|
|
9
|
+
expect(transform.value).toEqual({ x: 10, y: 20, zoom: 2 });
|
|
10
|
+
v.setViewport(0, 0, 0.1);
|
|
11
|
+
expect(transform.value.zoom).toBe(0.2);
|
|
12
|
+
v.setViewport(0, 0, 10);
|
|
13
|
+
expect(transform.value.zoom).toBe(4);
|
|
14
|
+
});
|
|
15
|
+
it("should zoom in and out", () => {
|
|
16
|
+
const transform = ref({ x: 0, y: 0, zoom: 1 });
|
|
17
|
+
const v = useViewport(transform, { minZoom: 0.1, maxZoom: 5 });
|
|
18
|
+
v.zoomIn(2);
|
|
19
|
+
expect(transform.value.zoom).toBe(2);
|
|
20
|
+
v.zoomOut(2);
|
|
21
|
+
expect(transform.value.zoom).toBe(1);
|
|
22
|
+
});
|
|
23
|
+
it("should pan", () => {
|
|
24
|
+
const transform = ref({ x: 0, y: 0, zoom: 1 });
|
|
25
|
+
const v = useViewport(transform);
|
|
26
|
+
v.pan(50, 30);
|
|
27
|
+
expect(transform.value.x).toBe(50);
|
|
28
|
+
expect(transform.value.y).toBe(30);
|
|
29
|
+
});
|
|
30
|
+
it("should panTo", () => {
|
|
31
|
+
const transform = ref({ x: 0, y: 0, zoom: 1 });
|
|
32
|
+
const v = useViewport(transform);
|
|
33
|
+
v.panTo(100, 200);
|
|
34
|
+
expect(transform.value.x).toBe(100);
|
|
35
|
+
expect(transform.value.y).toBe(200);
|
|
36
|
+
});
|
|
37
|
+
it("should fitView to contain nodes", () => {
|
|
38
|
+
const transform = ref({ x: 0, y: 0, zoom: 1 });
|
|
39
|
+
const v = useViewport(transform, { minZoom: 0.1, maxZoom: 5 });
|
|
40
|
+
const nodes = [
|
|
41
|
+
{ position: { x: 0, y: 0 }, width: 100, height: 50 },
|
|
42
|
+
{ position: { x: 200, y: 100 }, width: 100, height: 50 }
|
|
43
|
+
];
|
|
44
|
+
v.fitView({ width: 400, height: 300 }, nodes, { padding: 20 });
|
|
45
|
+
expect(transform.value.zoom).toBeLessThanOrEqual(1);
|
|
46
|
+
expect(typeof transform.value.x).toBe("number");
|
|
47
|
+
expect(typeof transform.value.y).toBe("number");
|
|
48
|
+
});
|
|
49
|
+
it("should not fitView when nodes empty", () => {
|
|
50
|
+
const transform = ref({ x: 50, y: 50, zoom: 1 });
|
|
51
|
+
const v = useViewport(transform);
|
|
52
|
+
v.fitView({ width: 400, height: 300 }, [], { padding: 20 });
|
|
53
|
+
expect(transform.value).toEqual({ x: 50, y: 50, zoom: 1 });
|
|
54
|
+
});
|
|
55
|
+
it("screenToCanvas and canvasToScreen should be inverse", () => {
|
|
56
|
+
const transform = ref({ x: 100, y: 50, zoom: 2 });
|
|
57
|
+
const v = useViewport(transform);
|
|
58
|
+
const screen = { x: 300, y: 250 };
|
|
59
|
+
const canvas = v.screenToCanvas(screen.x, screen.y);
|
|
60
|
+
const back = v.canvasToScreen(canvas.x, canvas.y);
|
|
61
|
+
expect(back.x).toBe(screen.x);
|
|
62
|
+
expect(back.y).toBe(screen.y);
|
|
63
|
+
});
|
|
64
|
+
it("isNodeVisible should return true when node in view", () => {
|
|
65
|
+
const transform = ref({ x: 0, y: 0, zoom: 1 });
|
|
66
|
+
const v = useViewport(transform);
|
|
67
|
+
const visible = v.isNodeVisible(
|
|
68
|
+
{ x: 50, y: 50, width: 100, height: 50 },
|
|
69
|
+
{ width: 800, height: 600 }
|
|
70
|
+
);
|
|
71
|
+
expect(visible).toBe(true);
|
|
72
|
+
});
|
|
73
|
+
it("isNodeVisible should return false when node outside view", () => {
|
|
74
|
+
const transform = ref({ x: -2e3, y: 0, zoom: 1 });
|
|
75
|
+
const v = useViewport(transform);
|
|
76
|
+
const visible = v.isNodeVisible(
|
|
77
|
+
{ x: 50, y: 50, width: 100, height: 50 },
|
|
78
|
+
{ width: 800, height: 600 }
|
|
79
|
+
);
|
|
80
|
+
expect(visible).toBe(false);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.expectSSRContains = expectSSRContains;
|
|
7
|
+
exports.expectSSRHasClass = expectSSRHasClass;
|
|
8
|
+
exports.mockSSREnvironment = mockSSREnvironment;
|
|
9
|
+
exports.normalizeHtml = normalizeHtml;
|
|
10
|
+
exports.renderSSR = renderSSR;
|
|
11
|
+
exports.testHydration = testHydration;
|
|
12
|
+
var _vue = require("vue");
|
|
13
|
+
var _serverRenderer = require("vue/server-renderer");
|
|
14
|
+
async function renderSSR(component, props = {}, slots = {}) {
|
|
15
|
+
const app = (0, _vue.createSSRApp)({
|
|
16
|
+
render() {
|
|
17
|
+
return (0, _vue.h)(component, props, slots);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
return await (0, _serverRenderer.renderToString)(app);
|
|
21
|
+
}
|
|
22
|
+
function expectSSRContains(html, text) {
|
|
23
|
+
if (!html.includes(text)) {
|
|
24
|
+
throw new Error(`Expected SSR output to contain "${text}", but got:
|
|
25
|
+
${html}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function expectSSRHasClass(html, className) {
|
|
29
|
+
const classRegex = new RegExp(`class="[^"]*${className}[^"]*"`);
|
|
30
|
+
if (!classRegex.test(html)) {
|
|
31
|
+
throw new Error(`Expected SSR output to have class "${className}", but got:
|
|
32
|
+
${html}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function mockSSREnvironment() {
|
|
36
|
+
const originalWindow = global.window;
|
|
37
|
+
const originalDocument = global.document;
|
|
38
|
+
delete global.window;
|
|
39
|
+
delete global.document;
|
|
40
|
+
return () => {
|
|
41
|
+
;
|
|
42
|
+
global.window = originalWindow;
|
|
43
|
+
global.document = originalDocument;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function normalizeHtml(html) {
|
|
47
|
+
return html.replace(/<!--[\s\S]*?-->/g, "").replace(/\s+/g, " ").replace(/>\s+</g, "><").replace(/<(\/?)([a-z0-9-]+)([^>]*?)(\/?)>/gi, (match, close, tag, attrs, selfClosing) => {
|
|
48
|
+
tag = tag.toLowerCase();
|
|
49
|
+
if (close) {
|
|
50
|
+
return `</${tag}>`;
|
|
51
|
+
}
|
|
52
|
+
const attrRegex = /([^\s>=/]+)(?:="([^"]*)")?/gi;
|
|
53
|
+
const foundAttrs = [];
|
|
54
|
+
let m;
|
|
55
|
+
while ((m = attrRegex.exec(attrs)) !== null) {
|
|
56
|
+
const name = m[1].toLowerCase();
|
|
57
|
+
let value = m[2] || "";
|
|
58
|
+
if (name.startsWith("data-v-")) continue;
|
|
59
|
+
value = value.replace(/\s+/g, " ").trim();
|
|
60
|
+
if (value === "" || value === "false") continue;
|
|
61
|
+
if (name === "style") {
|
|
62
|
+
value = value.split(";").map(s => s.trim()).filter(Boolean).map(s => {
|
|
63
|
+
const parts = s.split(":");
|
|
64
|
+
if (parts.length < 2) return null;
|
|
65
|
+
const prop = parts[0].trim().toLowerCase();
|
|
66
|
+
let val = parts.slice(1).join(":").trim();
|
|
67
|
+
val = val.replace(/^0(?:px|em|rem|%)$/, "0");
|
|
68
|
+
if (val === "rgba(0,0,0,0)" || val === "rgba(0, 0, 0, 0)") val = "transparent";
|
|
69
|
+
if (prop.startsWith("-webkit-") || prop.startsWith("-ms-") || prop.startsWith("-moz-") || prop.startsWith("webkit-") || prop.startsWith("ms-") || prop.startsWith("moz-") || prop === "mstransform") {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
return `${prop}:${val}`;
|
|
73
|
+
}).filter(Boolean).sort().join(";");
|
|
74
|
+
}
|
|
75
|
+
if (name === "class") {
|
|
76
|
+
value = value.split(" ").filter(c => !/-(enter|leave)-(from|active|to)$/.test(c)).sort().join(" ");
|
|
77
|
+
if (!value) continue;
|
|
78
|
+
}
|
|
79
|
+
if (tag === "path" && name === "d") {
|
|
80
|
+
value = value.replace(/([A-Z])/gi, " $1 ").replace(/,/g, " ").replace(/\s+/g, " ").trim();
|
|
81
|
+
}
|
|
82
|
+
const isAriaValue = ["aria-valuenow", "aria-valuemin", "aria-valuemax"].includes(name);
|
|
83
|
+
if (name === "id" || name === "for" || name.startsWith("aria-") && !isAriaValue) {
|
|
84
|
+
value = "__ID__";
|
|
85
|
+
}
|
|
86
|
+
if (name === "xmlns" || name.startsWith("xmlns:")) continue;
|
|
87
|
+
if (value === "true") {
|
|
88
|
+
value = "";
|
|
89
|
+
}
|
|
90
|
+
foundAttrs.push(`${name}${value ? `="${value}"` : ""}`);
|
|
91
|
+
}
|
|
92
|
+
foundAttrs.sort();
|
|
93
|
+
const sortedAttrs = foundAttrs.join(" ");
|
|
94
|
+
const voidElements = ["area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr"];
|
|
95
|
+
const isVoid = voidElements.includes(tag);
|
|
96
|
+
const normalizedTag = `<${tag}${sortedAttrs ? " " + sortedAttrs : ""}>`;
|
|
97
|
+
return isVoid ? normalizedTag : selfClosing ? `${normalizedTag}</${tag}>` : normalizedTag;
|
|
98
|
+
}).replace(/<textarea([^>]*)>[\s\S]*?<\/textarea>/gi, "<textarea$1>__TEXTAREA_CONTENT__</textarea>").trim();
|
|
99
|
+
}
|
|
100
|
+
async function testHydration(component, props = {}, slots = {}) {
|
|
101
|
+
const ssrHtml = await renderSSR(component, props, slots);
|
|
102
|
+
const {
|
|
103
|
+
mount
|
|
104
|
+
} = await Promise.resolve().then(() => require("@vue/test-utils"));
|
|
105
|
+
const wrapper = mount(component, {
|
|
106
|
+
props,
|
|
107
|
+
slots,
|
|
108
|
+
global: {
|
|
109
|
+
stubs: {
|
|
110
|
+
transition: false,
|
|
111
|
+
"transition-group": false
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
const csrHtml = wrapper.html();
|
|
116
|
+
const ssrNormalized = normalizeHtml(ssrHtml);
|
|
117
|
+
const csrNormalized = normalizeHtml(csrHtml);
|
|
118
|
+
const isMatch = ssrNormalized === csrNormalized;
|
|
119
|
+
return {
|
|
120
|
+
ssrHtml: ssrNormalized,
|
|
121
|
+
csrHtml: csrNormalized,
|
|
122
|
+
isMatch
|
|
123
|
+
};
|
|
124
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flow Package SSR 测试工具函数
|
|
3
|
+
* @description 用于测试 Flow 组件在 SSR 环境下的行为
|
|
4
|
+
*/
|
|
5
|
+
import { type Component } from 'vue';
|
|
6
|
+
/**
|
|
7
|
+
* 渲染组件为 HTML 字符串(服务端)
|
|
8
|
+
*/
|
|
9
|
+
export declare function renderSSR(component: Component, props?: Record<string, unknown>, slots?: Record<string, unknown>): Promise<string>;
|
|
10
|
+
/**
|
|
11
|
+
* 检查 SSR 渲染结果中是否包含特定文本
|
|
12
|
+
*/
|
|
13
|
+
export declare function expectSSRContains(html: string, text: string): void;
|
|
14
|
+
/**
|
|
15
|
+
* 检查 SSR 渲染结果是否包含特定 class
|
|
16
|
+
*/
|
|
17
|
+
export declare function expectSSRHasClass(html: string, className: string): void;
|
|
18
|
+
/**
|
|
19
|
+
* 模拟 SSR 环境
|
|
20
|
+
*/
|
|
21
|
+
export declare function mockSSREnvironment(): () => void;
|
|
22
|
+
/**
|
|
23
|
+
* HTML 标准化,用于比较 SSR 和 CSR 结果
|
|
24
|
+
*/
|
|
25
|
+
export declare function normalizeHtml(html: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Hydration 测试辅助函数
|
|
28
|
+
*/
|
|
29
|
+
export declare function testHydration(component: Component, props?: Record<string, unknown>, slots?: Record<string, unknown>): Promise<{
|
|
30
|
+
ssrHtml: string;
|
|
31
|
+
csrHtml: string;
|
|
32
|
+
isMatch: boolean;
|
|
33
|
+
}>;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { createSSRApp, h } from "vue";
|
|
2
|
+
import { renderToString } from "vue/server-renderer";
|
|
3
|
+
export async function renderSSR(component, props = {}, slots = {}) {
|
|
4
|
+
const app = createSSRApp({
|
|
5
|
+
render() {
|
|
6
|
+
return h(component, props, slots);
|
|
7
|
+
}
|
|
8
|
+
});
|
|
9
|
+
return await renderToString(app);
|
|
10
|
+
}
|
|
11
|
+
export function expectSSRContains(html, text) {
|
|
12
|
+
if (!html.includes(text)) {
|
|
13
|
+
throw new Error(`Expected SSR output to contain "${text}", but got:
|
|
14
|
+
${html}`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function expectSSRHasClass(html, className) {
|
|
18
|
+
const classRegex = new RegExp(`class="[^"]*${className}[^"]*"`);
|
|
19
|
+
if (!classRegex.test(html)) {
|
|
20
|
+
throw new Error(`Expected SSR output to have class "${className}", but got:
|
|
21
|
+
${html}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export function mockSSREnvironment() {
|
|
25
|
+
const originalWindow = global.window;
|
|
26
|
+
const originalDocument = global.document;
|
|
27
|
+
delete global.window;
|
|
28
|
+
delete global.document;
|
|
29
|
+
return () => {
|
|
30
|
+
;
|
|
31
|
+
global.window = originalWindow;
|
|
32
|
+
global.document = originalDocument;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export function normalizeHtml(html) {
|
|
36
|
+
return html.replace(/<!--[\s\S]*?-->/g, "").replace(/\s+/g, " ").replace(/>\s+</g, "><").replace(/<(\/?)([a-z0-9-]+)([^>]*?)(\/?)>/gi, (match, close, tag, attrs, selfClosing) => {
|
|
37
|
+
tag = tag.toLowerCase();
|
|
38
|
+
if (close) {
|
|
39
|
+
return `</${tag}>`;
|
|
40
|
+
}
|
|
41
|
+
const attrRegex = /([^\s>=/]+)(?:="([^"]*)")?/gi;
|
|
42
|
+
const foundAttrs = [];
|
|
43
|
+
let m;
|
|
44
|
+
while ((m = attrRegex.exec(attrs)) !== null) {
|
|
45
|
+
const name = m[1].toLowerCase();
|
|
46
|
+
let value = m[2] || "";
|
|
47
|
+
if (name.startsWith("data-v-")) continue;
|
|
48
|
+
value = value.replace(/\s+/g, " ").trim();
|
|
49
|
+
if (value === "" || value === "false") continue;
|
|
50
|
+
if (name === "style") {
|
|
51
|
+
value = value.split(";").map((s) => s.trim()).filter(Boolean).map((s) => {
|
|
52
|
+
const parts = s.split(":");
|
|
53
|
+
if (parts.length < 2) return null;
|
|
54
|
+
const prop = parts[0].trim().toLowerCase();
|
|
55
|
+
let val = parts.slice(1).join(":").trim();
|
|
56
|
+
val = val.replace(/^0(?:px|em|rem|%)$/, "0");
|
|
57
|
+
if (val === "rgba(0,0,0,0)" || val === "rgba(0, 0, 0, 0)") val = "transparent";
|
|
58
|
+
if (prop.startsWith("-webkit-") || prop.startsWith("-ms-") || prop.startsWith("-moz-") || prop.startsWith("webkit-") || prop.startsWith("ms-") || prop.startsWith("moz-") || prop === "mstransform") {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
return `${prop}:${val}`;
|
|
62
|
+
}).filter(Boolean).sort().join(";");
|
|
63
|
+
}
|
|
64
|
+
if (name === "class") {
|
|
65
|
+
value = value.split(" ").filter((c) => !/-(enter|leave)-(from|active|to)$/.test(c)).sort().join(" ");
|
|
66
|
+
if (!value) continue;
|
|
67
|
+
}
|
|
68
|
+
if (tag === "path" && name === "d") {
|
|
69
|
+
value = value.replace(/([A-Z])/gi, " $1 ").replace(/,/g, " ").replace(/\s+/g, " ").trim();
|
|
70
|
+
}
|
|
71
|
+
const isAriaValue = ["aria-valuenow", "aria-valuemin", "aria-valuemax"].includes(name);
|
|
72
|
+
if (name === "id" || name === "for" || name.startsWith("aria-") && !isAriaValue) {
|
|
73
|
+
value = "__ID__";
|
|
74
|
+
}
|
|
75
|
+
if (name === "xmlns" || name.startsWith("xmlns:")) continue;
|
|
76
|
+
if (value === "true") {
|
|
77
|
+
value = "";
|
|
78
|
+
}
|
|
79
|
+
foundAttrs.push(`${name}${value ? `="${value}"` : ""}`);
|
|
80
|
+
}
|
|
81
|
+
foundAttrs.sort();
|
|
82
|
+
const sortedAttrs = foundAttrs.join(" ");
|
|
83
|
+
const voidElements = [
|
|
84
|
+
"area",
|
|
85
|
+
"base",
|
|
86
|
+
"br",
|
|
87
|
+
"col",
|
|
88
|
+
"embed",
|
|
89
|
+
"hr",
|
|
90
|
+
"img",
|
|
91
|
+
"input",
|
|
92
|
+
"link",
|
|
93
|
+
"meta",
|
|
94
|
+
"param",
|
|
95
|
+
"source",
|
|
96
|
+
"track",
|
|
97
|
+
"wbr"
|
|
98
|
+
];
|
|
99
|
+
const isVoid = voidElements.includes(tag);
|
|
100
|
+
const normalizedTag = `<${tag}${sortedAttrs ? " " + sortedAttrs : ""}>`;
|
|
101
|
+
return isVoid ? normalizedTag : selfClosing ? `${normalizedTag}</${tag}>` : normalizedTag;
|
|
102
|
+
}).replace(
|
|
103
|
+
/<textarea([^>]*)>[\s\S]*?<\/textarea>/gi,
|
|
104
|
+
"<textarea$1>__TEXTAREA_CONTENT__</textarea>"
|
|
105
|
+
).trim();
|
|
106
|
+
}
|
|
107
|
+
export async function testHydration(component, props = {}, slots = {}) {
|
|
108
|
+
const ssrHtml = await renderSSR(component, props, slots);
|
|
109
|
+
const { mount } = await import("@vue/test-utils");
|
|
110
|
+
const wrapper = mount(component, {
|
|
111
|
+
props,
|
|
112
|
+
slots,
|
|
113
|
+
global: {
|
|
114
|
+
stubs: {
|
|
115
|
+
transition: false,
|
|
116
|
+
"transition-group": false
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
const csrHtml = wrapper.html();
|
|
121
|
+
const ssrNormalized = normalizeHtml(ssrHtml);
|
|
122
|
+
const csrNormalized = normalizeHtml(csrHtml);
|
|
123
|
+
const isMatch = ssrNormalized === csrNormalized;
|
|
124
|
+
return {
|
|
125
|
+
ssrHtml: ssrNormalized,
|
|
126
|
+
csrHtml: csrNormalized,
|
|
127
|
+
isMatch
|
|
128
|
+
};
|
|
129
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _vitest = require("vitest");
|
|
4
|
+
var _validation = require("../utils/validation.cjs");
|
|
5
|
+
(0, _vitest.describe)("flow/utils/validation", () => {
|
|
6
|
+
const nodeA = {
|
|
7
|
+
id: "A",
|
|
8
|
+
type: "default",
|
|
9
|
+
position: {
|
|
10
|
+
x: 0,
|
|
11
|
+
y: 0
|
|
12
|
+
},
|
|
13
|
+
data: {}
|
|
14
|
+
};
|
|
15
|
+
const nodeB = {
|
|
16
|
+
id: "B",
|
|
17
|
+
type: "default",
|
|
18
|
+
position: {
|
|
19
|
+
x: 0,
|
|
20
|
+
y: 0
|
|
21
|
+
},
|
|
22
|
+
data: {}
|
|
23
|
+
};
|
|
24
|
+
(0, _vitest.it)("isValidConnection should fail when source/target missing", () => {
|
|
25
|
+
(0, _vitest.expect)((0, _validation.isValidConnection)(void 0, nodeB, {
|
|
26
|
+
source: "A",
|
|
27
|
+
target: "B"
|
|
28
|
+
}).isValid).toBe(false);
|
|
29
|
+
(0, _vitest.expect)((0, _validation.isValidConnection)(nodeA, void 0, {
|
|
30
|
+
source: "A",
|
|
31
|
+
target: "B"
|
|
32
|
+
}).isValid).toBe(false);
|
|
33
|
+
});
|
|
34
|
+
(0, _vitest.it)("isValidConnection should reject self connection", () => {
|
|
35
|
+
const r = (0, _validation.isValidConnection)(nodeA, nodeA, {
|
|
36
|
+
source: "A",
|
|
37
|
+
target: "A"
|
|
38
|
+
});
|
|
39
|
+
(0, _vitest.expect)(r.isValid).toBe(false);
|
|
40
|
+
});
|
|
41
|
+
(0, _vitest.it)("createConnectionValidator should allow when no rules", () => {
|
|
42
|
+
const v = (0, _validation.createConnectionValidator)();
|
|
43
|
+
(0, _vitest.expect)(v({
|
|
44
|
+
source: "a",
|
|
45
|
+
target: "b"
|
|
46
|
+
})).toBe(true);
|
|
47
|
+
});
|
|
48
|
+
(0, _vitest.it)("createConnectionValidator should match by exact id / wildcard", () => {
|
|
49
|
+
const v = (0, _validation.createConnectionValidator)([{
|
|
50
|
+
source: "A",
|
|
51
|
+
target: "*"
|
|
52
|
+
}]);
|
|
53
|
+
(0, _vitest.expect)(v({
|
|
54
|
+
source: "A",
|
|
55
|
+
target: "B"
|
|
56
|
+
})).toBe(true);
|
|
57
|
+
(0, _vitest.expect)(v({
|
|
58
|
+
source: "X",
|
|
59
|
+
target: "B"
|
|
60
|
+
})).toBe(false);
|
|
61
|
+
});
|
|
62
|
+
(0, _vitest.it)("createConnectionValidator should match by regex string", () => {
|
|
63
|
+
const v = (0, _validation.createConnectionValidator)([{
|
|
64
|
+
source: "^node-\\d+$",
|
|
65
|
+
target: "^node-\\d+$"
|
|
66
|
+
}]);
|
|
67
|
+
(0, _vitest.expect)(v({
|
|
68
|
+
source: "node-1",
|
|
69
|
+
target: "node-2"
|
|
70
|
+
})).toBe(true);
|
|
71
|
+
(0, _vitest.expect)(v({
|
|
72
|
+
source: "A",
|
|
73
|
+
target: "node-2"
|
|
74
|
+
})).toBe(false);
|
|
75
|
+
});
|
|
76
|
+
(0, _vitest.it)("detectCycles should detect cycles after adding edge", () => {
|
|
77
|
+
const edges = [{
|
|
78
|
+
id: "e1",
|
|
79
|
+
source: "A",
|
|
80
|
+
target: "B"
|
|
81
|
+
}, {
|
|
82
|
+
id: "e2",
|
|
83
|
+
source: "B",
|
|
84
|
+
target: "C"
|
|
85
|
+
}];
|
|
86
|
+
(0, _vitest.expect)((0, _validation.detectCycles)(edges, {
|
|
87
|
+
source: "C",
|
|
88
|
+
target: "A"
|
|
89
|
+
})).toBe(true);
|
|
90
|
+
(0, _vitest.expect)((0, _validation.detectCycles)(edges, {
|
|
91
|
+
source: "C",
|
|
92
|
+
target: "D"
|
|
93
|
+
})).toBe(false);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { createConnectionValidator, detectCycles, isValidConnection } from "../utils/validation.mjs";
|
|
3
|
+
describe("flow/utils/validation", () => {
|
|
4
|
+
const nodeA = { id: "A", type: "default", position: { x: 0, y: 0 }, data: {} };
|
|
5
|
+
const nodeB = { id: "B", type: "default", position: { x: 0, y: 0 }, data: {} };
|
|
6
|
+
it("isValidConnection should fail when source/target missing", () => {
|
|
7
|
+
expect(isValidConnection(void 0, nodeB, { source: "A", target: "B" }).isValid).toBe(false);
|
|
8
|
+
expect(isValidConnection(nodeA, void 0, { source: "A", target: "B" }).isValid).toBe(false);
|
|
9
|
+
});
|
|
10
|
+
it("isValidConnection should reject self connection", () => {
|
|
11
|
+
const r = isValidConnection(nodeA, nodeA, { source: "A", target: "A" });
|
|
12
|
+
expect(r.isValid).toBe(false);
|
|
13
|
+
});
|
|
14
|
+
it("createConnectionValidator should allow when no rules", () => {
|
|
15
|
+
const v = createConnectionValidator();
|
|
16
|
+
expect(v({ source: "a", target: "b" })).toBe(true);
|
|
17
|
+
});
|
|
18
|
+
it("createConnectionValidator should match by exact id / wildcard", () => {
|
|
19
|
+
const v = createConnectionValidator([{ source: "A", target: "*" }]);
|
|
20
|
+
expect(v({ source: "A", target: "B" })).toBe(true);
|
|
21
|
+
expect(v({ source: "X", target: "B" })).toBe(false);
|
|
22
|
+
});
|
|
23
|
+
it("createConnectionValidator should match by regex string", () => {
|
|
24
|
+
const v = createConnectionValidator([{ source: "^node-\\d+$", target: "^node-\\d+$" }]);
|
|
25
|
+
expect(v({ source: "node-1", target: "node-2" })).toBe(true);
|
|
26
|
+
expect(v({ source: "A", target: "node-2" })).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
it("detectCycles should detect cycles after adding edge", () => {
|
|
29
|
+
const edges = [
|
|
30
|
+
{ id: "e1", source: "A", target: "B" },
|
|
31
|
+
{ id: "e2", source: "B", target: "C" }
|
|
32
|
+
];
|
|
33
|
+
expect(detectCycles(edges, { source: "C", target: "A" })).toBe(true);
|
|
34
|
+
expect(detectCycles(edges, { source: "C", target: "D" })).toBe(false);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Node, NodeData } from '../types';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
node: Node | null;
|
|
4
|
+
visible: boolean;
|
|
5
|
+
};
|
|
6
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
7
|
+
close: () => any;
|
|
8
|
+
update: (node: Partial<Node<NodeData>>) => any;
|
|
9
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
10
|
+
onClose?: (() => any) | undefined;
|
|
11
|
+
onUpdate?: ((node: Partial<Node<NodeData>>) => any) | undefined;
|
|
12
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
13
|
+
export default _default;
|