@refinedev/devtools 1.2.6 → 1.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/devtools-selector.d.cts.map +1 -1
- package/dist/components/devtools-selector.d.ts.map +1 -1
- package/dist/components/selectable-elements.d.cts.map +1 -1
- package/dist/components/selectable-elements.d.ts.map +1 -1
- package/dist/index.cjs +21 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +21 -10
- package/dist/index.mjs.map +1 -1
- package/dist/panel.d.cts.map +1 -1
- package/dist/panel.d.ts.map +1 -1
- package/dist/provider.d.cts +11 -1
- package/dist/provider.d.cts.map +1 -1
- package/dist/provider.d.mts +11 -1
- package/dist/provider.d.mts.map +11 -1
- package/dist/provider.d.ts +11 -1
- package/dist/provider.d.ts.map +1 -1
- package/dist/utilities/get-devtools-url-from-env.d.cts +2 -0
- package/dist/utilities/get-devtools-url-from-env.d.cts.map +1 -0
- package/dist/utilities/get-devtools-url-from-env.d.mts +2 -0
- package/dist/utilities/get-devtools-url-from-env.d.mts.map +2 -0
- package/dist/utilities/get-devtools-url-from-env.d.ts +2 -0
- package/dist/utilities/get-devtools-url-from-env.d.ts.map +1 -0
- package/dist/utilities/selector-helpers.d.cts +8 -0
- package/dist/utilities/selector-helpers.d.cts.map +1 -0
- package/dist/utilities/selector-helpers.d.mts +8 -0
- package/dist/utilities/selector-helpers.d.mts.map +8 -0
- package/dist/utilities/selector-helpers.d.ts +8 -0
- package/dist/utilities/selector-helpers.d.ts.map +1 -0
- package/dist/utilities/use-selector.d.cts +1 -5
- package/dist/utilities/use-selector.d.cts.map +1 -1
- package/dist/utilities/use-selector.d.mts +1 -5
- package/dist/utilities/use-selector.d.mts.map +1 -5
- package/dist/utilities/use-selector.d.ts +1 -5
- package/dist/utilities/use-selector.d.ts.map +1 -1
- package/package.json +5 -4
- package/src/components/devtools-selector.tsx +1 -0
- package/src/components/selectable-elements.tsx +24 -17
- package/src/define.d.ts +8 -0
- package/src/panel.tsx +64 -15
- package/src/provider.tsx +18 -3
- package/src/utilities/get-devtools-url-from-env.ts +20 -0
- package/src/utilities/selector-helpers.ts +157 -0
- package/src/utilities/use-selector.tsx +13 -109
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type SelectableElement = {
|
|
2
|
+
element: HTMLElement;
|
|
3
|
+
name: string;
|
|
4
|
+
};
|
|
5
|
+
export declare const filterInvisibleNodes: (nodes: SelectableElement[]) => SelectableElement[];
|
|
6
|
+
export declare const getUniqueNodes: (nodes: SelectableElement[]) => SelectableElement[];
|
|
7
|
+
export declare const traverseDom: (node: HTMLElement | null, activeTraceItems: string[]) => SelectableElement[];
|
|
8
|
+
//# sourceMappingURL=selector-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selector-helpers.d.ts","sourceRoot":"","sources":["../../src/utilities/selector-helpers.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,WAAW,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AA0FF,eAAO,MAAM,oBAAoB,UAAW,iBAAiB,EAAE,wBAI9D,CAAC;AAEF,eAAO,MAAM,cAAc,UAAW,iBAAiB,EAAE,wBAaxD,CAAC;AAEF,eAAO,MAAM,WAAW,SAChB,WAAW,GAAG,IAAI,oBACN,MAAM,EAAE,KACzB,iBAAiB,EA4BnB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type SelectableElement = {
|
|
2
|
+
element: HTMLElement;
|
|
3
|
+
name: string;
|
|
4
|
+
};
|
|
5
|
+
export declare const filterInvisibleNodes: (nodes: SelectableElement[]) => SelectableElement[];
|
|
6
|
+
export declare const getUniqueNodes: (nodes: SelectableElement[]) => SelectableElement[];
|
|
7
|
+
export declare const traverseDom: (node: HTMLElement | null, activeTraceItems: string[]) => SelectableElement[];
|
|
8
|
+
//# sourceMappingURL=selector-helpers.d.ts.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type SelectableElement = {
|
|
2
|
+
element: HTMLElement;
|
|
3
|
+
name: string;
|
|
4
|
+
};
|
|
5
|
+
export declare const filterInvisibleNodes: (nodes: SelectableElement[]) => SelectableElement[];
|
|
6
|
+
export declare const getUniqueNodes: (nodes: SelectableElement[]) => SelectableElement[];
|
|
7
|
+
export declare const traverseDom: (node: HTMLElement | null, activeTraceItems: string[]) => SelectableElement[];
|
|
8
|
+
//# sourceMappingURL=selector-helpers.d.ts.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type SelectableElement = {
|
|
2
|
+
element: HTMLElement;
|
|
3
|
+
name: string;
|
|
4
|
+
};
|
|
5
|
+
export declare const filterInvisibleNodes: (nodes: SelectableElement[]) => SelectableElement[];
|
|
6
|
+
export declare const getUniqueNodes: (nodes: SelectableElement[]) => SelectableElement[];
|
|
7
|
+
export declare const traverseDom: (node: HTMLElement | null, activeTraceItems: string[]) => SelectableElement[];
|
|
8
|
+
//# sourceMappingURL=selector-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selector-helpers.d.ts","sourceRoot":"","sources":["../../src/utilities/selector-helpers.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,WAAW,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AA0FF,eAAO,MAAM,oBAAoB,UAAW,iBAAiB,EAAE,wBAI9D,CAAC;AAEF,eAAO,MAAM,cAAc,UAAW,iBAAiB,EAAE,wBAaxD,CAAC;AAEF,eAAO,MAAM,WAAW,SAChB,WAAW,GAAG,IAAI,oBACN,MAAM,EAAE,KACzB,iBAAiB,EA4BnB,CAAC"}
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
type SelectableElement
|
|
2
|
-
element: HTMLElement;
|
|
3
|
-
name: string;
|
|
4
|
-
};
|
|
1
|
+
import { type SelectableElement } from "./selector-helpers";
|
|
5
2
|
export declare const useSelector: (active: boolean) => {
|
|
6
3
|
selectableElements: SelectableElement[];
|
|
7
4
|
};
|
|
8
|
-
export {};
|
|
9
5
|
//# sourceMappingURL=use-selector.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-selector.d.ts","sourceRoot":"","sources":["../../src/utilities/use-selector.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"use-selector.d.ts","sourceRoot":"","sources":["../../src/utilities/use-selector.tsx"],"names":[],"mappings":"AAGA,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,oBAAoB,CAAC;AAE5B,eAAO,MAAM,WAAW,WAAY,OAAO;;CA+B1C,CAAC"}
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
type SelectableElement
|
|
2
|
-
element: HTMLElement;
|
|
3
|
-
name: string;
|
|
4
|
-
};
|
|
1
|
+
import { type SelectableElement } from "./selector-helpers";
|
|
5
2
|
export declare const useSelector: (active: boolean) => {
|
|
6
3
|
selectableElements: SelectableElement[];
|
|
7
4
|
};
|
|
8
|
-
export {};
|
|
9
5
|
//# sourceMappingURL=use-selector.d.ts.map
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
type SelectableElement
|
|
2
|
-
element: HTMLElement;
|
|
3
|
-
name: string;
|
|
4
|
-
};
|
|
1
|
+
import { type SelectableElement } from "./selector-helpers";
|
|
5
2
|
export declare const useSelector: (active: boolean) => {
|
|
6
3
|
selectableElements: SelectableElement[];
|
|
7
4
|
};
|
|
8
|
-
export {};
|
|
9
5
|
//# sourceMappingURL=use-selector.d.ts.map
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
type SelectableElement
|
|
2
|
-
element: HTMLElement;
|
|
3
|
-
name: string;
|
|
4
|
-
};
|
|
1
|
+
import { type SelectableElement } from "./selector-helpers";
|
|
5
2
|
export declare const useSelector: (active: boolean) => {
|
|
6
3
|
selectableElements: SelectableElement[];
|
|
7
4
|
};
|
|
8
|
-
export {};
|
|
9
5
|
//# sourceMappingURL=use-selector.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-selector.d.ts","sourceRoot":"","sources":["../../src/utilities/use-selector.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"use-selector.d.ts","sourceRoot":"","sources":["../../src/utilities/use-selector.tsx"],"names":[],"mappings":"AAGA,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,oBAAoB,CAAC;AAE5B,eAAO,MAAM,WAAW,WAAY,OAAO;;CA+B1C,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@refinedev/devtools",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.8",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "refine devtools offers a set of features from monitoring to quickly prototyping a UI.",
|
|
6
6
|
"repository": {
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
],
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@aliemir/dom-to-fiber-utils": "^0.4.0",
|
|
35
|
-
"@refinedev/devtools-shared": "1.1.
|
|
35
|
+
"@refinedev/devtools-shared": "1.1.12",
|
|
36
36
|
"error-stack-parser": "^2.1.4",
|
|
37
37
|
"lodash": "^4.17.21",
|
|
38
38
|
"lodash-es": "^4.17.21"
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"@types/jest": "^29.2.4",
|
|
44
44
|
"@types/lodash": "^4.14.171",
|
|
45
45
|
"@types/node": "^18.16.2",
|
|
46
|
+
"@types/react-reconciler": "^0.28.8",
|
|
46
47
|
"@types/testing-library__jest-dom": "^5.14.3",
|
|
47
48
|
"jest": "^29.3.1",
|
|
48
49
|
"jest-environment-jsdom": "^29.3.1",
|
|
@@ -53,9 +54,9 @@
|
|
|
53
54
|
"typescript": "^5.4.2"
|
|
54
55
|
},
|
|
55
56
|
"peerDependencies": {
|
|
56
|
-
"@refinedev/cli": "2.16.
|
|
57
|
+
"@refinedev/cli": "2.16.38",
|
|
57
58
|
"@refinedev/core": "^4.46.1",
|
|
58
|
-
"@refinedev/devtools-server": "1.1.
|
|
59
|
+
"@refinedev/devtools-server": "1.1.36",
|
|
59
60
|
"@types/react": "^17.0.0 || ^18.0.0",
|
|
60
61
|
"@types/react-dom": "^17.0.0 || ^18.0.0",
|
|
61
62
|
"react": "^17.0.0 || ^18.0.0",
|
|
@@ -4,6 +4,22 @@ import { createPortal } from "react-dom";
|
|
|
4
4
|
import { ApplyStyles } from "./apply-styles";
|
|
5
5
|
import { SelectorIcon } from "./icons/selector-button";
|
|
6
6
|
|
|
7
|
+
const MIN_SIZE = 22;
|
|
8
|
+
|
|
9
|
+
const getPosition = (element: HTMLElement, document: Document) => {
|
|
10
|
+
const { top, left, width, height } = element.getBoundingClientRect();
|
|
11
|
+
const { scrollLeft, scrollTop } = document.documentElement;
|
|
12
|
+
const positionLeft = left + scrollLeft - Math.max(0, MIN_SIZE - width) / 2;
|
|
13
|
+
const positionTop = top + scrollTop - Math.max(0, MIN_SIZE - height) / 2;
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
left: positionLeft,
|
|
17
|
+
top: positionTop,
|
|
18
|
+
width: Math.max(MIN_SIZE, width),
|
|
19
|
+
height: Math.max(MIN_SIZE, height),
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
|
|
7
23
|
const SelectableElement = ({
|
|
8
24
|
element,
|
|
9
25
|
name,
|
|
@@ -13,14 +29,7 @@ const SelectableElement = ({
|
|
|
13
29
|
name: string;
|
|
14
30
|
onSelect: (name: string) => void;
|
|
15
31
|
}) => {
|
|
16
|
-
const [position] = React.useState(() =>
|
|
17
|
-
const { top, left, width, height } = element.getBoundingClientRect();
|
|
18
|
-
const { scrollLeft, scrollTop } = document.documentElement;
|
|
19
|
-
const positionLeft = left + scrollLeft;
|
|
20
|
-
const positionTop = top + scrollTop;
|
|
21
|
-
|
|
22
|
-
return { left: positionLeft, top: positionTop, width, height };
|
|
23
|
-
});
|
|
32
|
+
const [position] = React.useState(() => getPosition(element, document));
|
|
24
33
|
|
|
25
34
|
const elementRef = React.useRef<HTMLButtonElement | null>(null);
|
|
26
35
|
|
|
@@ -28,15 +37,10 @@ const SelectableElement = ({
|
|
|
28
37
|
// use scroll event listener
|
|
29
38
|
const onScroll = debounce(
|
|
30
39
|
() => {
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
elementRef.current?.style.setProperty("left", `${positionLeft}px`);
|
|
37
|
-
elementRef.current?.style.setProperty("top", `${positionTop}px`);
|
|
38
|
-
elementRef.current?.style.setProperty("width", `${width}px`);
|
|
39
|
-
elementRef.current?.style.setProperty("height", `${height}px`);
|
|
40
|
+
const nextPos = getPosition(element, document);
|
|
41
|
+
(["left", "top", "width", "height"] as const).forEach((prop) => {
|
|
42
|
+
elementRef.current?.style.setProperty(prop, `${nextPos[prop]}px`);
|
|
43
|
+
});
|
|
40
44
|
elementRef.current?.style.setProperty("opacity", "1");
|
|
41
45
|
},
|
|
42
46
|
200,
|
|
@@ -247,6 +251,9 @@ export const SelectableElements = ({
|
|
|
247
251
|
max-width: 200px;
|
|
248
252
|
padding-right: 8px;
|
|
249
253
|
}
|
|
254
|
+
.selector-xray-box:hover .selector-xray-info-title {
|
|
255
|
+
z-index: 90;
|
|
256
|
+
}
|
|
250
257
|
`
|
|
251
258
|
}
|
|
252
259
|
</ApplyStyles>
|
package/src/define.d.ts
CHANGED
|
@@ -1 +1,9 @@
|
|
|
1
1
|
declare const __DEV_CONDITION__: string;
|
|
2
|
+
declare const __IMPORT_META_KEY__: any;
|
|
3
|
+
declare const __PROCESS_KEY__: any;
|
|
4
|
+
|
|
5
|
+
declare const __PROCESS_ENV_REFINE_DEVTOOLS_PORT_KEY__: any;
|
|
6
|
+
declare const __PROCESS_ENV_NEXT_PUBLIC_REFINE_DEVTOOLS_PORT_KEY__: any;
|
|
7
|
+
declare const __PROCESS_ENV_REACT_APP_REFINE_DEVTOOLS_PORT_KEY__: any;
|
|
8
|
+
declare const __IMPORT_META_ENV_REFINE_DEVTOOLS_PORT_KEY__: any;
|
|
9
|
+
declare const __IMPORT_META_ENV_VITE_REFINE_DEVTOOLS_PORT_KEY__: any;
|
package/src/panel.tsx
CHANGED
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
|
|
11
11
|
import type { Placement } from "./interfaces/placement";
|
|
12
12
|
|
|
13
|
+
const MAX_IFRAME_WAIT_TIME = 1500;
|
|
14
|
+
|
|
13
15
|
export const DevtoolsPanel =
|
|
14
16
|
__DEV_CONDITION__ !== "development"
|
|
15
17
|
? () => null
|
|
@@ -17,9 +19,12 @@ export const DevtoolsPanel =
|
|
|
17
19
|
const [browser, setBrowser] = React.useState<boolean>(false);
|
|
18
20
|
const [visible, setVisible] = React.useState(false);
|
|
19
21
|
const [placement] = React.useState<Placement>("bottom");
|
|
20
|
-
const {
|
|
22
|
+
const { httpUrl, ws } = React.useContext(DevToolsContext);
|
|
21
23
|
const [width, setWidth] = React.useState<number>(0);
|
|
22
24
|
const [selectorActive, setSelectorActive] = React.useState(false);
|
|
25
|
+
const [iframeStatus, setIframeStatus] = React.useState<
|
|
26
|
+
"loading" | "loaded" | "failed"
|
|
27
|
+
>("loading");
|
|
23
28
|
|
|
24
29
|
const onSelectorHighlight = React.useCallback(
|
|
25
30
|
(name: string) => {
|
|
@@ -33,10 +38,6 @@ export const DevtoolsPanel =
|
|
|
33
38
|
[ws],
|
|
34
39
|
);
|
|
35
40
|
|
|
36
|
-
const onSelectorOpen = React.useCallback(() => {
|
|
37
|
-
setVisible(false);
|
|
38
|
-
}, []);
|
|
39
|
-
|
|
40
41
|
React.useEffect(() => {
|
|
41
42
|
if (selectorActive) {
|
|
42
43
|
setVisible(false);
|
|
@@ -68,6 +69,41 @@ export const DevtoolsPanel =
|
|
|
68
69
|
return () => undefined;
|
|
69
70
|
}, [browser]);
|
|
70
71
|
|
|
72
|
+
React.useEffect(() => {
|
|
73
|
+
if (iframeStatus !== "loaded") {
|
|
74
|
+
const onMessage = (event: MessageEvent) => {
|
|
75
|
+
if (event.data.type === "refine-devtools-iframe-loaded") {
|
|
76
|
+
setIframeStatus("loaded");
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
window.addEventListener("message", onMessage);
|
|
81
|
+
|
|
82
|
+
return () => {
|
|
83
|
+
window.removeEventListener("message", onMessage);
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return () => 0;
|
|
88
|
+
}, []);
|
|
89
|
+
|
|
90
|
+
React.useEffect(() => {
|
|
91
|
+
let timeout: number;
|
|
92
|
+
if (iframeStatus === "loading") {
|
|
93
|
+
timeout = window.setTimeout(() => {
|
|
94
|
+
setIframeStatus("failed");
|
|
95
|
+
if (timeout) {
|
|
96
|
+
clearInterval(timeout);
|
|
97
|
+
}
|
|
98
|
+
}, MAX_IFRAME_WAIT_TIME);
|
|
99
|
+
}
|
|
100
|
+
return () => {
|
|
101
|
+
if (typeof timeout !== "undefined") {
|
|
102
|
+
clearInterval(timeout);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
}, [iframeStatus]);
|
|
106
|
+
|
|
71
107
|
if (!browser) {
|
|
72
108
|
return null;
|
|
73
109
|
}
|
|
@@ -95,17 +131,13 @@ export const DevtoolsPanel =
|
|
|
95
131
|
{({ resizing }) => (
|
|
96
132
|
<iframe
|
|
97
133
|
allow="clipboard-write;"
|
|
98
|
-
src={
|
|
134
|
+
src={httpUrl}
|
|
99
135
|
srcDoc={
|
|
100
|
-
|
|
101
|
-
?
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
<h1 style="font-family:ui-monospace,monospace;color:#CFD7E2;text-align:center;">Could not connect to the devtools server</h1>
|
|
106
|
-
</body>
|
|
107
|
-
</html>
|
|
108
|
-
`
|
|
136
|
+
httpUrl
|
|
137
|
+
? iframeStatus === "failed"
|
|
138
|
+
? failedConnectionContent
|
|
139
|
+
: undefined
|
|
140
|
+
: missingUrlContent
|
|
109
141
|
}
|
|
110
142
|
style={{
|
|
111
143
|
width: "100%",
|
|
@@ -121,3 +153,20 @@ export const DevtoolsPanel =
|
|
|
121
153
|
</div>
|
|
122
154
|
);
|
|
123
155
|
};
|
|
156
|
+
|
|
157
|
+
const missingUrlContent = `
|
|
158
|
+
<html style="height:100%;padding:0;margin:0;background:#14141F;">
|
|
159
|
+
<body style="background:#14141F;display:flex;justify-content:center;height:100%;padding:24px;margin:0;align-items:center;box-sizing:border-box;">
|
|
160
|
+
<h1 style="font-family:ui-monospace,monospace;font-weight:400;color:#CFD7E2;text-align:center;font-size:24px;">Could not connect to the devtools server.</h1>
|
|
161
|
+
</body>
|
|
162
|
+
</html>
|
|
163
|
+
`;
|
|
164
|
+
|
|
165
|
+
const failedConnectionContent = `
|
|
166
|
+
<html style="height:100%;padding:0;margin:0;background:#14141F;">
|
|
167
|
+
<body style="background:#14141F;display:flex;flex-direction:column;justify-content:center;height:100%;padding:24px;margin:0;align-items:center;box-sizing:border-box;">
|
|
168
|
+
<h1 style="max-width:480px;min-width:480px;font-family:ui-monospace,monospace;font-weight:400;color:#CFD7E2;text-align:left;font-size:24px;margin-bottom:12px;line-height:24px;">Devtools Server is unreachable.</h1>
|
|
169
|
+
<p style="max-width:480px;font-family:ui-monospace,monospace;font-weight:400;color:#6C7793;text-align:left;font-size:16px;line-height:32px;">Please make sure Refine Devtools is running and <code style="background:#303450;color:#A3ADC2;padding:3px 6px;border-radius:4px;"><DevtoolsProvider /></code> has valid <code style="background:#303450;color:#A3ADC2;padding:3px 6px;border-radius:4px;">url</code> prop. Environment variables may not always be available in browser depending on your project setup.</p>
|
|
170
|
+
</body>
|
|
171
|
+
</html>
|
|
172
|
+
`;
|
package/src/provider.tsx
CHANGED
|
@@ -1,9 +1,24 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { DevToolsContextProvider } from "@refinedev/devtools-shared";
|
|
3
|
+
import { getDevtoolsUrlFromEnv } from "./utilities/get-devtools-url-from-env";
|
|
4
|
+
|
|
5
|
+
type Props = React.PropsWithChildren<{
|
|
6
|
+
/**
|
|
7
|
+
* Devtools URL to connect to the server. This will also be used for the WebSocket connections and serving the Devtools UI.
|
|
8
|
+
* By default, it will use the `REFINE_DEVTOOLS_PORT` environment variable to construct to URL or use `5001` as the default port.
|
|
9
|
+
* If you're using `refine dev` command, it will try to automatically set the environment variable for you and use it.
|
|
10
|
+
* If environment variable is not working for you, you can manually set the URL as a string or a tuple of `[httpUrl: string, wsUrl: string]`.
|
|
11
|
+
*/
|
|
12
|
+
url?: string | [httpUrl: string, wsUrl: string];
|
|
13
|
+
}>;
|
|
3
14
|
|
|
4
15
|
export const DevtoolsProvider =
|
|
5
16
|
__DEV_CONDITION__ !== "development"
|
|
6
|
-
? ({ children }:
|
|
7
|
-
: ({ children }:
|
|
8
|
-
return
|
|
17
|
+
? ({ children }: Props) => children as any
|
|
18
|
+
: ({ children, url = getDevtoolsUrlFromEnv() }: Props) => {
|
|
19
|
+
return (
|
|
20
|
+
<DevToolsContextProvider url={url}>
|
|
21
|
+
{children}
|
|
22
|
+
</DevToolsContextProvider>
|
|
23
|
+
);
|
|
9
24
|
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const DEFAULT_DEVTOOLS_PORT = 5001;
|
|
2
|
+
|
|
3
|
+
export const getDevtoolsUrlFromEnv = () => {
|
|
4
|
+
const PORT_FROM_ENV =
|
|
5
|
+
typeof __PROCESS_KEY__ !== "undefined" && "env" in __PROCESS_KEY__
|
|
6
|
+
? __PROCESS_ENV_REFINE_DEVTOOLS_PORT_KEY__ ||
|
|
7
|
+
__PROCESS_ENV_NEXT_PUBLIC_REFINE_DEVTOOLS_PORT_KEY__ ||
|
|
8
|
+
__PROCESS_ENV_REACT_APP_REFINE_DEVTOOLS_PORT_KEY__
|
|
9
|
+
: typeof __IMPORT_META_KEY__ !== "undefined" && __IMPORT_META_KEY__.env
|
|
10
|
+
? __IMPORT_META_ENV_REFINE_DEVTOOLS_PORT_KEY__ ||
|
|
11
|
+
__IMPORT_META_ENV_VITE_REFINE_DEVTOOLS_PORT_KEY__
|
|
12
|
+
: null;
|
|
13
|
+
|
|
14
|
+
const port = PORT_FROM_ENV || DEFAULT_DEVTOOLS_PORT;
|
|
15
|
+
|
|
16
|
+
return [`http://localhost:${port}`, `ws://localhost:${port}`] as [
|
|
17
|
+
httpUrl: string,
|
|
18
|
+
wsUrl: string,
|
|
19
|
+
];
|
|
20
|
+
};
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getElementFromFiber,
|
|
3
|
+
getFiberFromElement,
|
|
4
|
+
getFirstFiberHasName,
|
|
5
|
+
getFirstStateNodeFiber,
|
|
6
|
+
getNameFromFiber,
|
|
7
|
+
getParentOfFiber,
|
|
8
|
+
} from "@aliemir/dom-to-fiber-utils";
|
|
9
|
+
|
|
10
|
+
type Fiber = Exclude<ReturnType<typeof getFiberFromElement>, null>;
|
|
11
|
+
|
|
12
|
+
export type SelectableElement = {
|
|
13
|
+
element: HTMLElement;
|
|
14
|
+
name: string;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const getChildOfFiber = (fiber: Fiber | null) => {
|
|
18
|
+
if (!fiber) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return fiber.child;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const getFirstHTMLElementFromFiberByChild = (fiber: Fiber | null) => {
|
|
26
|
+
let child = fiber;
|
|
27
|
+
|
|
28
|
+
while (child) {
|
|
29
|
+
const element = getElementFromFiber(child);
|
|
30
|
+
if (element && element instanceof HTMLElement) {
|
|
31
|
+
return element;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
child = getChildOfFiber(child) as Fiber;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return null;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const getFirstHTMLElementFromFiberByParent = (fiber: Fiber | null) => {
|
|
41
|
+
let parent = fiber;
|
|
42
|
+
|
|
43
|
+
while (parent) {
|
|
44
|
+
const element = getElementFromFiber(parent);
|
|
45
|
+
if (element && element instanceof HTMLElement) {
|
|
46
|
+
return element;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
parent = getParentOfFiber(parent) as Fiber;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return null;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const getFirstHTMLElementFromFiber = (
|
|
56
|
+
fiber: Fiber | null,
|
|
57
|
+
): [element: HTMLElement, "child" | "parent" | "body"] => {
|
|
58
|
+
let element = getFirstHTMLElementFromFiberByChild(fiber);
|
|
59
|
+
|
|
60
|
+
if (element) {
|
|
61
|
+
return [element, "child"];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
element = getFirstHTMLElementFromFiberByParent(fiber);
|
|
65
|
+
|
|
66
|
+
if (element) {
|
|
67
|
+
return [element, "parent"];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return [document.body, "body"];
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const selectFiber = (start: Fiber | null, activeTraceItems: string[]) => {
|
|
74
|
+
let fiber = start;
|
|
75
|
+
let firstParentOfNodeWithName: Fiber | null = null;
|
|
76
|
+
let fiberWithStateNode: Fiber | null = null;
|
|
77
|
+
|
|
78
|
+
let acceptedName = false;
|
|
79
|
+
|
|
80
|
+
while (!acceptedName && fiber) {
|
|
81
|
+
// Get the first fiber node that has a name (look up the tree)
|
|
82
|
+
firstParentOfNodeWithName = getFirstFiberHasName(fiber);
|
|
83
|
+
// Get the first fiber node that has a state node (look up the tree)
|
|
84
|
+
fiberWithStateNode = getFirstStateNodeFiber(firstParentOfNodeWithName);
|
|
85
|
+
acceptedName = activeTraceItems.includes(
|
|
86
|
+
getNameFromFiber(firstParentOfNodeWithName) ?? "",
|
|
87
|
+
);
|
|
88
|
+
if (!acceptedName) {
|
|
89
|
+
fiber = getParentOfFiber(fiber);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (fiberWithStateNode && firstParentOfNodeWithName) {
|
|
94
|
+
return {
|
|
95
|
+
stateNode: fiberWithStateNode,
|
|
96
|
+
nameFiber: firstParentOfNodeWithName,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
stateNode: null,
|
|
101
|
+
nameFiber: null,
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export const filterInvisibleNodes = (nodes: SelectableElement[]) => {
|
|
106
|
+
return nodes.filter(
|
|
107
|
+
(item) => item.element.offsetWidth > 0 && item.element.offsetHeight > 0,
|
|
108
|
+
);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
export const getUniqueNodes = (nodes: SelectableElement[]) => {
|
|
112
|
+
const uniques: SelectableElement[] = [];
|
|
113
|
+
|
|
114
|
+
nodes.forEach((node) => {
|
|
115
|
+
const isElementExist = uniques.find(
|
|
116
|
+
(item) => item.element === node.element && item.name === node.name,
|
|
117
|
+
);
|
|
118
|
+
if (!isElementExist) {
|
|
119
|
+
uniques.push(node);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
return uniques;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export const traverseDom = (
|
|
127
|
+
node: HTMLElement | null,
|
|
128
|
+
activeTraceItems: string[],
|
|
129
|
+
): SelectableElement[] => {
|
|
130
|
+
if (!node) {
|
|
131
|
+
return [];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const items: SelectableElement[] = [];
|
|
135
|
+
|
|
136
|
+
const fiber = getFiberFromElement(node);
|
|
137
|
+
const targetFiber = selectFiber(fiber, activeTraceItems);
|
|
138
|
+
|
|
139
|
+
if (targetFiber.nameFiber) {
|
|
140
|
+
const [element] = getFirstHTMLElementFromFiber(targetFiber.nameFiber);
|
|
141
|
+
const name = getNameFromFiber(targetFiber.nameFiber);
|
|
142
|
+
if (element && name) {
|
|
143
|
+
items.push({
|
|
144
|
+
element,
|
|
145
|
+
name,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
for (let i = 0; i < node?.children?.length ?? 0; i++) {
|
|
151
|
+
items.push(
|
|
152
|
+
...traverseDom(node.children[i] as HTMLElement, activeTraceItems),
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return items;
|
|
157
|
+
};
|