react-state-flow 0.0.3 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,22 @@
1
+ /**
2
+ * react-state-flow/runtime
3
+ *
4
+ * Import này TRƯỚC khi React mount để hook vào React DevTools global hook.
5
+ * Sends render events via WebSocket to the RSF CLI server.
6
+ *
7
+ * Usage:
8
+ * import 'react-state-flow/runtime' // top of main.tsx / index.tsx
9
+ */
10
+ export interface RenderEvent {
11
+ type: 'render';
12
+ componentName: string;
13
+ renderCount: number;
14
+ timestamp: number;
15
+ }
16
+ declare global {
17
+ interface Window {
18
+ __REACT_DEVTOOLS_GLOBAL_HOOK__: any;
19
+ __RSF_WS__: WebSocket | null;
20
+ }
21
+ }
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,QAAQ,CAAA;IACd,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,8BAA8B,EAAE,GAAG,CAAA;QACnC,UAAU,EAAE,SAAS,GAAG,IAAI,CAAA;KAC7B;CACF"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * react-state-flow/runtime
3
+ *
4
+ * Import này TRƯỚC khi React mount để hook vào React DevTools global hook.
5
+ * Sends render events via WebSocket to the RSF CLI server.
6
+ *
7
+ * Usage:
8
+ * import 'react-state-flow/runtime' // top of main.tsx / index.tsx
9
+ */
10
+ const RSF_PORT = window.__RSF_PORT__ ?? 7272;
11
+ const WS_URL = `ws://localhost:${RSF_PORT}/runtime`;
12
+ // B2: Render counter per component with max-size cap to prevent memory leak
13
+ const renderCounts = new Map();
14
+ const MAX_RENDER_COUNT_ENTRIES = 500;
15
+ function incrementRenderCount(name) {
16
+ if (!renderCounts.has(name) && renderCounts.size >= MAX_RENDER_COUNT_ENTRIES) {
17
+ // Evict oldest entry (insertion order)
18
+ const firstKey = renderCounts.keys().next().value;
19
+ if (firstKey !== undefined)
20
+ renderCounts.delete(firstKey);
21
+ }
22
+ const count = (renderCounts.get(name) ?? 0) + 1;
23
+ renderCounts.set(name, count);
24
+ return count;
25
+ }
26
+ function send(event) {
27
+ if (!window.__RSF_WS__ || window.__RSF_WS__.readyState !== WebSocket.OPEN)
28
+ return;
29
+ window.__RSF_WS__.send(JSON.stringify(event));
30
+ }
31
+ // B3: Exponential backoff reconnect
32
+ let reconnectDelay = 2000;
33
+ function connect() {
34
+ const ws = new WebSocket(WS_URL);
35
+ window.__RSF_WS__ = ws;
36
+ ws.addEventListener('open', () => {
37
+ reconnectDelay = 2000; // reset on successful connection
38
+ renderCounts.clear(); // B2: sync counts with server on reconnect
39
+ console.debug('[RSF] Runtime connected');
40
+ });
41
+ ws.addEventListener('close', () => {
42
+ console.debug(`[RSF] Runtime disconnected, retrying in ${reconnectDelay / 1000}s...`);
43
+ setTimeout(connect, reconnectDelay);
44
+ reconnectDelay = Math.min(reconnectDelay * 2, 30000);
45
+ });
46
+ ws.addEventListener('error', () => {
47
+ // suppress — will retry on close
48
+ });
49
+ }
50
+ function hookIntoReact() {
51
+ // React checks for this global hook on load and calls it during reconciliation
52
+ const existing = window.__REACT_DEVTOOLS_GLOBAL_HOOK__ ?? {};
53
+ const originalOnCommitFiberRoot = existing.onCommitFiberRoot?.bind(existing) ?? (() => { });
54
+ window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = {
55
+ ...existing,
56
+ isDisabled: false,
57
+ supportsFiber: true,
58
+ onCommitFiberRoot(rendererID, root, priorityLevel) {
59
+ // Call through so React DevTools still works
60
+ originalOnCommitFiberRoot(rendererID, root, priorityLevel);
61
+ // B1: Pass per-commit Set to avoid counting sibling instances multiple times
62
+ try {
63
+ walkFiber(root.current, new Set());
64
+ }
65
+ catch {
66
+ // Never break the app
67
+ }
68
+ },
69
+ };
70
+ }
71
+ function getFiberName(fiber) {
72
+ const type = fiber?.type;
73
+ if (!type)
74
+ return null;
75
+ if (typeof type === 'string')
76
+ return null; // DOM element
77
+ if (typeof type === 'function')
78
+ return type.displayName ?? type.name ?? null;
79
+ if (typeof type === 'object' && type !== null) {
80
+ // forwardRef, memo, etc.
81
+ return (type.displayName ??
82
+ type.render?.displayName ??
83
+ type.render?.name ??
84
+ null);
85
+ }
86
+ return null;
87
+ }
88
+ // B1: seenInCommit prevents counting sibling instances multiple times per commit
89
+ function walkFiber(fiber, seenInCommit) {
90
+ if (!fiber)
91
+ return;
92
+ const name = getFiberName(fiber);
93
+ if (name && /^[A-Z]/.test(name) && !seenInCommit.has(name)) {
94
+ seenInCommit.add(name);
95
+ const count = incrementRenderCount(name);
96
+ send({ type: 'render', componentName: name, renderCount: count, timestamp: Date.now() });
97
+ }
98
+ walkFiber(fiber.child, seenInCommit);
99
+ walkFiber(fiber.sibling, seenInCommit);
100
+ }
101
+ // Bootstrap — only in development
102
+ const isDev = typeof process !== 'undefined'
103
+ ? process.env.NODE_ENV !== 'production'
104
+ : import.meta.env?.MODE !== 'production';
105
+ if (typeof window !== 'undefined' && isDev) {
106
+ hookIntoReact();
107
+ connect();
108
+ }
109
+ export {};
package/package.json CHANGED
@@ -1,34 +1,60 @@
1
1
  {
2
2
  "name": "react-state-flow",
3
- "version": "0.0.3",
3
+ "version": "0.1.0",
4
4
  "description": "Visualize React component hierarchy, state flow, and real-time render events",
5
5
  "type": "module",
6
+ "license": "MIT",
6
7
  "bin": {
7
8
  "react-state-flow": "./dist/index.js"
8
9
  },
10
+ "exports": {
11
+ ".": {
12
+ "import": "./dist/index.js",
13
+ "types": "./dist/index.d.ts"
14
+ },
15
+ "./runtime": {
16
+ "import": "./dist/runtime/index.js",
17
+ "types": "./dist/runtime/index.d.ts"
18
+ }
19
+ },
9
20
  "files": [
10
- "dist"
21
+ "dist",
22
+ "!dist/parser"
11
23
  ],
12
24
  "engines": {
13
25
  "node": ">=18"
14
26
  },
15
27
  "scripts": {
16
- "start": "tsx src/index.ts",
17
- "build": "pnpm --filter @rsf/ui build && node build.mjs"
28
+ "build": "npm run build:ts && npm run build:ui",
29
+ "build:ts": "tsc -p tsconfig.json",
30
+ "build:ui": "vite build --config ui/vite.config.ts",
31
+ "dev": "tsx src/index.ts",
32
+ "ui:dev": "vite --config ui/vite.config.ts",
33
+ "prepublishOnly": "npm run build"
18
34
  },
19
35
  "dependencies": {
36
+ "@babel/parser": "^7.24.0",
37
+ "@babel/traverse": "^7.24.0",
38
+ "@babel/types": "^7.24.0",
20
39
  "chokidar": "^3.6.0",
21
40
  "express": "^4.19.0",
22
- "ws": "^8.17.0",
23
41
  "open": "^10.1.0",
24
- "picocolors": "^1.0.1"
42
+ "picocolors": "^1.0.1",
43
+ "ws": "^8.17.0"
25
44
  },
26
45
  "devDependencies": {
27
- "@rsf/parser": "workspace:*",
46
+ "@dagrejs/dagre": "^1.0.0",
47
+ "@types/babel__traverse": "^7.20.6",
28
48
  "@types/express": "^4.17.21",
49
+ "@types/react": "^18.3.0",
50
+ "@types/react-dom": "^18.3.0",
29
51
  "@types/ws": "^8.5.10",
30
- "esbuild": "^0.21.0",
52
+ "@vitejs/plugin-react": "^4.3.0",
53
+ "@xyflow/react": "^12.0.0",
54
+ "react": "^18.3.0",
55
+ "react-dom": "^18.3.0",
31
56
  "tsx": "^4.15.0",
32
- "typescript": "^5.4.0"
57
+ "typescript": "^5.4.0",
58
+ "vite": "^5.3.0"
33
59
  }
34
60
  }
@@ -1 +0,0 @@
1
- .react-flow{direction:ltr;--xy-edge-stroke-default: #b1b1b7;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #555;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(255, 255, 255, .5);--xy-minimap-background-color-default: #fff;--xy-minimap-mask-background-color-default: rgba(240, 240, 240, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #e2e2e2;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: transparent;--xy-background-pattern-dots-color-default: #91919a;--xy-background-pattern-lines-color-default: #eee;--xy-background-pattern-cross-color-default: #e2e2e2;background-color:var(--xy-background-color, var(--xy-background-color-default));--xy-node-color-default: inherit;--xy-node-border-default: 1px solid #1a192b;--xy-node-background-color-default: #fff;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(0, 0, 0, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #1a192b;--xy-node-border-radius-default: 3px;--xy-handle-background-color-default: #1a192b;--xy-handle-border-color-default: #fff;--xy-selection-background-color-default: rgba(0, 89, 220, .08);--xy-selection-border-default: 1px dotted rgba(0, 89, 220, .8);--xy-controls-button-background-color-default: #fefefe;--xy-controls-button-background-color-hover-default: #f4f4f4;--xy-controls-button-color-default: inherit;--xy-controls-button-color-hover-default: inherit;--xy-controls-button-border-color-default: #eee;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #ffffff;--xy-edge-label-color-default: inherit;--xy-resize-background-color-default: #3367d9}.react-flow.dark{--xy-edge-stroke-default: #3e3e3e;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #727272;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(150, 150, 150, .25);--xy-minimap-background-color-default: #141414;--xy-minimap-mask-background-color-default: rgba(60, 60, 60, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #2b2b2b;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: #141414;--xy-background-pattern-dots-color-default: #777;--xy-background-pattern-lines-color-default: #777;--xy-background-pattern-cross-color-default: #777;--xy-node-color-default: #f8f8f8;--xy-node-border-default: 1px solid #3c3c3c;--xy-node-background-color-default: #1e1e1e;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(255, 255, 255, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #999;--xy-handle-background-color-default: #bebebe;--xy-handle-border-color-default: #1e1e1e;--xy-selection-background-color-default: rgba(200, 200, 220, .08);--xy-selection-border-default: 1px dotted rgba(200, 200, 220, .8);--xy-controls-button-background-color-default: #2b2b2b;--xy-controls-button-background-color-hover-default: #3e3e3e;--xy-controls-button-color-default: #f8f8f8;--xy-controls-button-color-hover-default: #fff;--xy-controls-button-border-color-default: #5b5b5b;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #141414;--xy-edge-label-color-default: #f8f8f8}.react-flow__background{background-color:var(--xy-background-color-props, var(--xy-background-color, var(--xy-background-color-default)));pointer-events:none;z-index:-1}.react-flow__container{position:absolute;width:100%;height:100%;top:0;left:0}.react-flow__pane{z-index:1}.react-flow__pane.draggable{cursor:grab}.react-flow__pane.dragging{cursor:grabbing}.react-flow__pane.selection{cursor:pointer}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow__edge-path{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default));stroke-width:var(--xy-edge-stroke-width, var(--xy-edge-stroke-width-default));fill:none}.react-flow__connection-path{stroke:var(--xy-connectionline-stroke, var(--xy-connectionline-stroke-default));stroke-width:var(--xy-connectionline-stroke-width, var(--xy-connectionline-stroke-width-default));fill:none}.react-flow .react-flow__edges{position:absolute}.react-flow .react-flow__edges svg{overflow:visible;position:absolute;pointer-events:none}.react-flow__edge{pointer-events:visibleStroke}.react-flow__edge.selectable{cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge.selectable:focus .react-flow__edge-path,.react-flow__edge.selectable:focus-visible .react-flow__edge-path{stroke:var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default))}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__arrowhead polyline{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__arrowhead polyline.arrowclosed{fill:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;animation:dashdraw .5s linear infinite}svg.react-flow__connectionline{z-index:1001;overflow:visible;position:absolute}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:default}.react-flow__node.selectable{cursor:pointer}.react-flow__node.draggable{cursor:grab;pointer-events:all}.react-flow__node.draggable.dragging{cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.react-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:grab}.react-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px;width:6px;height:6px;background-color:var(--xy-handle-background-color, var(--xy-handle-background-color-default));border:1px solid var(--xy-handle-border-color, var(--xy-handle-border-color-default));border-radius:100%}.react-flow__handle.connectingfrom{pointer-events:all}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;left:50%;bottom:0;transform:translate(-50%,50%)}.react-flow__handle-top{top:0;left:50%;transform:translate(-50%,-50%)}.react-flow__handle-left{top:50%;left:0;transform:translate(-50%,-50%)}.react-flow__handle-right{top:50%;right:0;transform:translate(50%,-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__pane.selection .react-flow__panel{pointer-events:none}.react-flow__panel{position:absolute;z-index:5;margin:15px}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.top.center,.react-flow__panel.bottom.center{left:50%;transform:translate(-15px) translate(-50%)}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.left.center,.react-flow__panel.right.center{top:50%;transform:translateY(-15px) translateY(-50%)}.react-flow__attribution{font-size:10px;background:var(--xy-attribution-background-color, var(--xy-attribution-background-color-default));padding:2px 3px;margin:0}.react-flow__attribution a{text-decoration:none;color:#999}@keyframes dashdraw{0%{stroke-dashoffset:10}}.react-flow__edgelabel-renderer{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;left:0;top:0}.react-flow__viewport-portal{position:absolute;width:100%;height:100%;left:0;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__minimap{background:var( --xy-minimap-background-color-props, var(--xy-minimap-background-color, var(--xy-minimap-background-color-default)) )}.react-flow__minimap-svg{display:block}.react-flow__minimap-mask{fill:var( --xy-minimap-mask-background-color-props, var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default)) );stroke:var( --xy-minimap-mask-stroke-color-props, var(--xy-minimap-mask-stroke-color, var(--xy-minimap-mask-stroke-color-default)) );stroke-width:var( --xy-minimap-mask-stroke-width-props, var(--xy-minimap-mask-stroke-width, var(--xy-minimap-mask-stroke-width-default)) )}.react-flow__minimap-node{fill:var( --xy-minimap-node-background-color-props, var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default)) );stroke:var( --xy-minimap-node-stroke-color-props, var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default)) );stroke-width:var( --xy-minimap-node-stroke-width-props, var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default)) )}.react-flow__background-pattern.dots{fill:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-dots-color-default)) )}.react-flow__background-pattern.lines{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-lines-color-default)) )}.react-flow__background-pattern.cross{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-cross-color-default)) )}.react-flow__controls{display:flex;flex-direction:column;box-shadow:var(--xy-controls-box-shadow, var(--xy-controls-box-shadow-default))}.react-flow__controls.horizontal{flex-direction:row}.react-flow__controls-button{display:flex;justify-content:center;align-items:center;height:26px;width:26px;padding:4px;border:none;background:var(--xy-controls-button-background-color, var(--xy-controls-button-background-color-default));border-bottom:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) );color:var( --xy-controls-button-color-props, var(--xy-controls-button-color, var(--xy-controls-button-color-default)) );cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__controls-button svg{width:100%;max-width:12px;max-height:12px;fill:currentColor}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-text{font-size:10px}.react-flow__node.selectable:focus,.react-flow__node.selectable:focus-visible{outline:none}.react-flow__node-input,.react-flow__node-default,.react-flow__node-output,.react-flow__node-group{padding:10px;border-radius:var(--xy-node-border-radius, var(--xy-node-border-radius-default));width:150px;font-size:12px;color:var(--xy-node-color, var(--xy-node-color-default));text-align:center;border:var(--xy-node-border, var(--xy-node-border-default));background-color:var(--xy-node-background-color, var(--xy-node-background-color-default))}.react-flow__node-input.selectable:hover,.react-flow__node-default.selectable:hover,.react-flow__node-output.selectable:hover,.react-flow__node-group.selectable:hover{box-shadow:var(--xy-node-boxshadow-hover, var(--xy-node-boxshadow-hover-default))}.react-flow__node-input.selectable.selected,.react-flow__node-input.selectable:focus,.react-flow__node-input.selectable:focus-visible,.react-flow__node-default.selectable.selected,.react-flow__node-default.selectable:focus,.react-flow__node-default.selectable:focus-visible,.react-flow__node-output.selectable.selected,.react-flow__node-output.selectable:focus,.react-flow__node-output.selectable:focus-visible,.react-flow__node-group.selectable.selected,.react-flow__node-group.selectable:focus,.react-flow__node-group.selectable:focus-visible{box-shadow:var(--xy-node-boxshadow-selected, var(--xy-node-boxshadow-selected-default))}.react-flow__node-group{background-color:var(--xy-node-group-background-color, var(--xy-node-group-background-color-default))}.react-flow__nodesselection-rect,.react-flow__selection{background:var(--xy-selection-background-color, var(--xy-selection-background-color-default));border:var(--xy-selection-border, var(--xy-selection-border-default))}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible,.react-flow__selection:focus,.react-flow__selection:focus-visible{outline:none}.react-flow__controls-button:hover{background:var( --xy-controls-button-background-color-hover-props, var(--xy-controls-button-background-color-hover, var(--xy-controls-button-background-color-hover-default)) );color:var( --xy-controls-button-color-hover-props, var(--xy-controls-button-color-hover, var(--xy-controls-button-color-hover-default)) )}.react-flow__controls-button:disabled{pointer-events:none}.react-flow__controls-button:disabled svg{fill-opacity:.4}.react-flow__controls-button:last-child{border-bottom:none}.react-flow__controls.horizontal .react-flow__controls-button{border-bottom:none;border-right:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) )}.react-flow__controls.horizontal .react-flow__controls-button:last-child{border-right:none}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{width:5px;height:5px;border:1px solid #fff;border-radius:1px;background-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));translate:-50% -50%}.react-flow__resize-control.handle.left{left:0;top:50%}.react-flow__resize-control.handle.right{left:100%;top:50%}.react-flow__resize-control.handle.top{left:50%;top:0}.react-flow__resize-control.handle.bottom{left:50%;top:100%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));border-width:0;border-style:solid}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;transform:translate(-50%);top:0;height:100%}.react-flow__resize-control.line.left{left:0;border-left-width:1px}.react-flow__resize-control.line.right{left:100%;border-right-width:1px}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{height:1px;transform:translateY(-50%);left:0;width:100%}.react-flow__resize-control.line.top{top:0;border-top-width:1px}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%}.react-flow__edge-textbg{fill:var(--xy-edge-label-background-color, var(--xy-edge-label-background-color-default))}.react-flow__edge-text{fill:var(--xy-edge-label-color, var(--xy-edge-label-color-default))}