From e13f3245bd2258b6e58989e28d5e93c8bf356a3f Mon Sep 17 00:00:00 2001
From: * <8>
Date: Thu, 31 Mar 2022 10:25:52 +0800
Subject: [PATCH] Match-id-7133f2734eacafd1263023fbe3921097f915d497
---
.../src/components/ComponentInfo.tsx | 6 +--
.../src/components/ComponentsInfo.less | 1 +
libs/extension/src/components/Search.less | 2 +-
libs/extension/src/components/Search.tsx | 4 +-
libs/extension/src/components/VTree.less | 9 ++--
libs/extension/src/components/VTree.tsx | 39 +++++++-------
libs/extension/src/components/assets.less | 6 +--
libs/extension/src/devtools/mock.ts | 47 +++++++++-------
libs/extension/src/panel/App.less | 17 +++---
libs/extension/src/panel/App.tsx | 16 +++---
libs/extension/src/panel/index.tsx | 4 +-
libs/extension/src/panel/panel.html | 53 +++++++++++--------
libs/extension/src/parser/parseAttr.ts | 19 ++++---
libs/extension/src/parser/parseVNode.ts | 9 ++--
libs/extension/src/svgs/Arrow.tsx | 8 +--
libs/extension/src/svgs/Copy.tsx | 4 +-
libs/extension/src/svgs/Debug.tsx | 2 +-
libs/extension/src/svgs/Eye.tsx | 6 +--
libs/extension/src/svgs/Select.tsx | 3 +-
libs/extension/src/utils.ts | 4 +-
libs/extension/webpack.dev.js | 18 +++----
21 files changed, 155 insertions(+), 122 deletions(-)
diff --git a/libs/extension/src/components/ComponentInfo.tsx b/libs/extension/src/components/ComponentInfo.tsx
index 7e13bb42..9c76b503 100644
--- a/libs/extension/src/components/ComponentInfo.tsx
+++ b/libs/extension/src/components/ComponentInfo.tsx
@@ -35,7 +35,7 @@ function ComponentAttr({ name, attr }: { name: string, attr: IAttr[] }) {
newSet.add(index);
}
setCollapsedNode(newSet);
- }
+ };
const showAttr = [];
let currentIndentation = null;
@@ -76,7 +76,7 @@ function ComponentAttr({ name, attr }: { name: string, attr: IAttr[] }) {
{showAttr}
- )
+ );
}
export default function ComponentInfo({ name, attrs }: IComponentInfo) {
@@ -104,5 +104,5 @@ export default function ComponentInfo({ name, attrs }: IComponentInfo) {
- )
+ );
}
\ No newline at end of file
diff --git a/libs/extension/src/components/ComponentsInfo.less b/libs/extension/src/components/ComponentsInfo.less
index 173bec22..3622363e 100644
--- a/libs/extension/src/components/ComponentsInfo.less
+++ b/libs/extension/src/components/ComponentsInfo.less
@@ -68,6 +68,7 @@
.attrDetail {
padding-bottom: 0.5rem;
+
.attrArrow {
color: @arrow-color;
width: 12px;
diff --git a/libs/extension/src/components/Search.less b/libs/extension/src/components/Search.less
index 617a9d26..003f8577 100644
--- a/libs/extension/src/components/Search.less
+++ b/libs/extension/src/components/Search.less
@@ -1,3 +1,3 @@
.search {
width: 100%;
-}
\ No newline at end of file
+}
diff --git a/libs/extension/src/components/Search.tsx b/libs/extension/src/components/Search.tsx
index 7418bc71..ce644325 100644
--- a/libs/extension/src/components/Search.tsx
+++ b/libs/extension/src/components/Search.tsx
@@ -8,12 +8,12 @@ export default function Search(props: SearchProps) {
const { onChange } = props;
const handleChange = (event) => {
onChange(event.target.value);
- }
+ };
return (
- )
+ );
}
\ No newline at end of file
diff --git a/libs/extension/src/components/VTree.less b/libs/extension/src/components/VTree.less
index e83125e3..1460ce0f 100644
--- a/libs/extension/src/components/VTree.less
+++ b/libs/extension/src/components/VTree.less
@@ -5,10 +5,12 @@
width: 100%;
height: 100%;
overflow-y: auto;
+
.treeItem {
width: 100%;
position: absolute;
line-height: 18px;
+
&:hover {
background-color: @select-color;
}
@@ -19,15 +21,15 @@
width: 12px;
padding-left: 0.5rem;
}
-
+
.componentName {
color: @component-name-color;
}
-
+
.componentKeyName {
color: @component-key-color;
}
-
+
.componentKeyValue {
color: @componentKeyValue-color;
}
@@ -37,4 +39,3 @@
background-color: rgb(141 199 248 / 60%);
}
}
-
diff --git a/libs/extension/src/components/VTree.tsx b/libs/extension/src/components/VTree.tsx
index 91a7c42e..86f1daf7 100644
--- a/libs/extension/src/components/VTree.tsx
+++ b/libs/extension/src/components/VTree.tsx
@@ -26,14 +26,14 @@ const lineHeight = 18;
const indentationLength = 20;
function Item(props: IItem) {
- const {
- name,
- style,
+ const {
+ name,
+ style,
userKey,
- hasChild,
- onCollapse,
- isCollapsed,
- id,
+ hasChild,
+ onCollapse,
+ isCollapsed,
+ id,
indentation,
onClick,
isSelect,
@@ -43,14 +43,14 @@ function Item(props: IItem) {
const showIcon = hasChild ? : '';
const handleClickCollapse = () => {
onCollapse(id);
- }
+ };
const handleClick = () => {
onClick(id);
- }
- const itemAttr: any = {style, className: styles.treeItem, onClick: handleClick};
+ };
+ const itemAttr: any = { style, className: styles.treeItem, onClick: handleClick };
if (isSelect) {
itemAttr.tabIndex = 0;
- itemAttr.className = styles.treeItem + ' ' + styles.select
+ itemAttr.className = styles.treeItem + ' ' + styles.select;
}
const reg = createRegExp(highlightValue);
const heightCharacters = name.match(reg);
@@ -60,7 +60,7 @@ function Item(props: IItem) {
showName = [];
// 高亮第一次匹配即可
const char = heightCharacters[0];
- let index = name.search(char);
+ const index = name.search(char);
const notHighlightStr = cutName.slice(0, index);
showName.push(notHighlightStr);
showName.push({char});
@@ -90,7 +90,7 @@ function Item(props: IItem) {
>
)}
- )
+ );
}
function VTree({ data, highlightValue }: { data: IData[], highlightValue: string }) {
@@ -128,10 +128,11 @@ function VTree({ data, highlightValue }: { data: IData[], highlightValue: string
currentCollapseIndentation = null;
}
}
- let id = item.id;
+ const id = item.id;
const isCollapsed = collapseNode.has(id);
if (totalHeight >= scrollTop && showList.length <= showNum) {
const nextItem = data[index + 1];
+ // 如果存在下一个节点,并且节点缩进比自己大,说明下个节点是子节点,节点本身需要显示展开收起图标
const hasChild = nextItem ? nextItem.indentation > item.indentation : false;
showList.push(
- )
+ );
}
totalHeight = totalHeight + lineHeight;
if (isCollapsed) {
@@ -155,19 +156,19 @@ function VTree({ data, highlightValue }: { data: IData[], highlightValue: string
}
});
- const scroll = (event: any) => {
+ const handleScroll = (event: any) => {
const scrollTop = event.target.scrollTop;
// 顶部留 100px 冗余高度
setScrollTop(Math.max(scrollTop - 100, 0));
- }
+ };
return (
-
+
{showList}
{/* 确保有足够的高度 */}
- )
+ );
}
export default VTree;
diff --git a/libs/extension/src/components/assets.less b/libs/extension/src/components/assets.less
index a00d8ade..7e74bacf 100644
--- a/libs/extension/src/components/assets.less
+++ b/libs/extension/src/components/assets.less
@@ -1,5 +1,5 @@
-@arrow-color:rgb(95, 99, 104);
-@divider-color:rgb(202, 205, 209);
+@arrow-color: rgb(95, 99, 104);
+@divider-color: rgb(202, 205, 209);
@attr-name-color: rgb(200, 0, 0);
@component-name-color: rgb(136, 18, 128);
@component-key-color: rgb(153, 69, 0);
@@ -11,4 +11,4 @@
@divider-width: 0.2px;
@common-font-size: 12px;
-@divider-style: @divider-color solid @divider-width;
\ No newline at end of file
+@divider-style: @divider-color solid @divider-width;
diff --git a/libs/extension/src/devtools/mock.ts b/libs/extension/src/devtools/mock.ts
index 0c40d06b..3a3eef88 100644
--- a/libs/extension/src/devtools/mock.ts
+++ b/libs/extension/src/devtools/mock.ts
@@ -1,3 +1,7 @@
+/**
+ * 用一个纯数据类型的对象 tree 去表示树的结构是非常清晰的,但是它不能准确的模拟 VNode 中存在的引用
+ * 关系,需要进行转换 getMockVNodeTree
+ */
import { parseAttr } from '../parser/parseAttr';
import parseTreeRoot from '../parser/parseVNode';
@@ -9,7 +13,7 @@ const mockComponentNames = ['Apple', 'Pear', 'Banana', 'Orange', 'Jenny', 'Kiwi'
function MockVNode(tag: string, props = {}, key = null, realNode = {}) {
const vNode = new VNode(tag, props, key, realNode);
const name = mockComponentNames.shift() || 'MockComponent';
- vNode.type = {name};
+ vNode.type = { name };
return vNode;
}
@@ -18,41 +22,49 @@ interface IMockTree {
children?: IMockTree[],
}
+// 模拟树
const tree: IMockTree = {
tag: ClassComponent,
children: [
- {tag: FunctionComponent},
- {tag: ClassComponent},
- {tag: FunctionComponent},
+ { tag: FunctionComponent },
+ { tag: ClassComponent },
+ { tag: FunctionComponent },
{
tag: FunctionComponent,
children: [
- {tag: ClassComponent}
+ { tag: ClassComponent }
]
}
]
-}
+};
function addOneThousandNode(node: IMockTree) {
const nodes = [];
- for(let i = 0; i < 1000; i++) {
- nodes.push({tag: FunctionComponent});
+ for (let i = 0; i < 1000; i++) {
+ nodes.push({ tag: FunctionComponent });
}
- node?.children.push({tag: ClassComponent,children: nodes});
-};
+ node?.children.push({ tag: ClassComponent, children: nodes });
+}
addOneThousandNode(tree);
-function getMockVNodeTree(tree: IMockTree, vNode: VNode) {
- const children = tree.children;
+/**
+ * 将mock数据转变为 VNode 树
+ *
+ * @param node 树节点
+ * @param vNode VNode节点
+ */
+function getMockVNodeTree(node: IMockTree, vNode: VNode) {
+ const children = node.children;
if (children && children.length !== 0) {
const childNode = children[0];
let childVNode = MockVNode(childNode.tag);
childVNode.key = '0';
getMockVNodeTree(childNode, childVNode);
+ // 需要建立双链
vNode.child = childVNode;
childVNode.parent = vNode;
- for(let i = 1; i < children.length; i++) {
+ for (let i = 1; i < children.length; i++) {
const nextNode = children[i];
const nextVNode = MockVNode(nextNode.tag);
nextVNode.key = String(i);
@@ -68,20 +80,19 @@ getMockVNodeTree(tree, rootVNode);
export const mockParsedVNodeData = parseTreeRoot(rootVNode);
-
const mockState = {
str: 'jenny',
num: 3,
boolean: true,
und: undefined,
- fun: () => {},
+ fun: () => ({}),
symbol: Symbol('sym'),
map: new Map([['a', 'a']]),
set: new Set(['a', 1, 2, Symbol('bambi')]),
- arr: [1,2,3,4],
+ arr: [1, 2, 3, 4],
obj: {
- niko: {jenny: 'jenny'}
+ niko: { jenny: 'jenny' }
}
};
-export const parsedMockState = parseAttr(mockState);
\ No newline at end of file
+export const parsedMockState = parseAttr(mockState);
diff --git a/libs/extension/src/panel/App.less b/libs/extension/src/panel/App.less
index 0186eec1..f48e225a 100644
--- a/libs/extension/src/panel/App.less
+++ b/libs/extension/src/panel/App.less
@@ -1,48 +1,53 @@
@import '../components/assets.less';
-.app{
+.app {
display: flex;
flex-direction: row;
height: 100%;
font-size: @common-font-size;
}
-.left{
+.left {
flex: 7;
display: flex;
flex-direction: column;
+
.left_top {
border-bottom: @divider-style;
flex: 0 0 @top-height;
display: flex;
align-items: center;
+
.select {
padding: 0 0.25rem 0 0.25rem;
flex: 0 0;
}
+
.divider {
flex: 0 0 1px;
margin: 0 0.25rem 0 0.25rem;
border-left: @divider-style;
height: calc(100% - 1rem);
}
+
.search {
flex: 1 1 0;
}
}
+
.left_bottom {
- flex: 1;
+ flex: 1;
height: 0;
}
}
-.right{
+.right {
flex: 3;
border-left: @divider-style;
}
-input{
+input {
outline: none;
border-width: 0;
padding: 0;
-}
\ No newline at end of file
+}
diff --git a/libs/extension/src/panel/App.tsx b/libs/extension/src/panel/App.tsx
index 871ad0ad..2b9ef6bc 100644
--- a/libs/extension/src/panel/App.tsx
+++ b/libs/extension/src/panel/App.tsx
@@ -1,4 +1,4 @@
-import {useState, useEffect} from 'horizon';
+import { useState, useEffect } from 'horizon';
import VTree, { IData } from '../components/VTree';
import Search from '../components/Search';
import ComponentInfo from '../components/ComponentInfo';
@@ -8,7 +8,7 @@ import { mockParsedVNodeData, parsedMockState } from '../devtools/mock';
function App() {
const [parsedVNodeData, setParsedVNodeData] = useState([]);
- const [componentInfo, setComponentInfo] = useState({name: null, attrs: {}});
+ const [componentInfo, setComponentInfo] = useState({ name: null, attrs: {} });
const [filterValue, setFilterValue] = useState('');
useEffect(() => {
if (isDev) {
@@ -19,7 +19,7 @@ function App() {
state: parsedMockState,
props: parsedMockState,
},
- })
+ });
}
}, []);
const idIndentationMap: {
@@ -27,7 +27,7 @@ function App() {
} = {};
const data: IData[] = [];
let i = 0;
- while(i < parsedVNodeData.length) {
+ while (i < parsedVNodeData.length) {
const id = parsedVNodeData[i] as string;
i++;
const name = parsedVNodeData[i] as string;
@@ -46,7 +46,7 @@ function App() {
const handleSearchChange = (str: string) => {
setFilterValue(str);
- }
+ };
return (
@@ -57,15 +57,15 @@ function App() {
-
+
-
+
-
+
);
diff --git a/libs/extension/src/panel/index.tsx b/libs/extension/src/panel/index.tsx
index 9e50ba58..a6174e37 100644
--- a/libs/extension/src/panel/index.tsx
+++ b/libs/extension/src/panel/index.tsx
@@ -1,7 +1,7 @@
-import {render} from 'horizon';
+import { render } from 'horizon';
import App from './App';
render(
- ,
+ ,
document.getElementById('root')
);
\ No newline at end of file
diff --git a/libs/extension/src/panel/panel.html b/libs/extension/src/panel/panel.html
index 70f60f3b..ae944454 100644
--- a/libs/extension/src/panel/panel.html
+++ b/libs/extension/src/panel/panel.html
@@ -1,27 +1,34 @@
-
-
-
-
-
-
-
-
+
+
+ Horizon
+
+
+
+
+
+
+
+
+
diff --git a/libs/extension/src/parser/parseAttr.ts b/libs/extension/src/parser/parseAttr.ts
index 0c5335d1..c52b1891 100644
--- a/libs/extension/src/parser/parseAttr.ts
+++ b/libs/extension/src/parser/parseAttr.ts
@@ -1,6 +1,13 @@
+
+// 将状态的值解析成固定格式
export function parseAttr(rootAttr: any) {
- const result = [];
- let indentation = 0;
+ const result: {
+ name: string,
+ type: string,
+ value: string,
+ indentation: number
+ }[] = [];
+ const indentation = 0;
const parseSubAttr = (attr: any, parentIndentation: number, attrName: string) => {
const stateType = typeof attr;
let value: any;
@@ -20,7 +27,7 @@ export function parseAttr(rootAttr: any) {
} else if (stateType === 'object') {
if (attr === null) {
showType = 'null';
- }else if (attr instanceof Map) {
+ } else if (attr instanceof Map) {
showType = 'map';
const size = attr.size;
value = `Map(${size})`;
@@ -28,7 +35,7 @@ export function parseAttr(rootAttr: any) {
attr.forEach((value, key) => {
parseSubAttr(value, parentIndentation + 2, key);
});
- }
+ };
} else if (attr instanceof Set) {
showType = 'set';
const size = attr.size;
@@ -46,8 +53,8 @@ export function parseAttr(rootAttr: any) {
addSubState = () => {
attr.forEach((value, index) => {
parseSubAttr(value, parentIndentation + 2, String(index));
- })
- }
+ });
+ };
} else {
showType = stateType;
value = '{...}';
diff --git a/libs/extension/src/parser/parseVNode.ts b/libs/extension/src/parser/parseVNode.ts
index bb8ad91d..91104058 100644
--- a/libs/extension/src/parser/parseVNode.ts
+++ b/libs/extension/src/parser/parseVNode.ts
@@ -1,7 +1,8 @@
-import { travelVNodeTree } from "../../../../libs/horizon/src/renderer/vnode/VNodeUtils";
-import { VNode } from "../../../../libs/horizon/src/renderer/Types";
-import { ClassComponent, FunctionComponent } from "../../../../libs/horizon/src/renderer/vnode/VNodeTags";
+import { travelVNodeTree } from '../../../../libs/horizon/src/renderer/vnode/VNodeUtils';
+import { VNode } from '../../../../libs/horizon/src/renderer/Types';
+import { ClassComponent, FunctionComponent } from '../../../../libs/horizon/src/renderer/vnode/VNodeTags';
+// 建立双向映射关系,当用户在修改属性值后,可以找到对应的 VNode
const VNodeToIdMap = new Map();
const IdToVNodeMap = new Map();
@@ -34,7 +35,7 @@ function parseTreeRoot(treeRoot: VNode) {
if (isUserComponent(tag)) {
const id = generateUid();
result.push(id);
- const name = (node.type as Function).name;
+ const name = node.type.name;
result.push(name);
const parent = getParentUserComponent(node);
if (parent) {
diff --git a/libs/extension/src/svgs/Arrow.tsx b/libs/extension/src/svgs/Arrow.tsx
index c315bf19..0cb49d0d 100644
--- a/libs/extension/src/svgs/Arrow.tsx
+++ b/libs/extension/src/svgs/Arrow.tsx
@@ -2,16 +2,16 @@ interface IArrow {
director: 'right' | 'down'
}
-export default function Arrow({director}: IArrow) {
+export default function Arrow({ director }: IArrow) {
let d: string;
if (director === 'right') {
- d = 'm2 0l12 8l-12 8 z'
+ d = 'm2 0l12 8l-12 8 z';
} else if (director === 'down') {
d = 'm0 2h16 l-8 12 z';
}
return (
- )
+ );
}
\ No newline at end of file
diff --git a/libs/extension/src/svgs/Copy.tsx b/libs/extension/src/svgs/Copy.tsx
index 865222fe..483d9ece 100644
--- a/libs/extension/src/svgs/Copy.tsx
+++ b/libs/extension/src/svgs/Copy.tsx
@@ -2,7 +2,7 @@
export default function Copy() {
return (
- )
+ );
}
diff --git a/libs/extension/src/svgs/Debug.tsx b/libs/extension/src/svgs/Debug.tsx
index 6ac25393..41e037fb 100644
--- a/libs/extension/src/svgs/Debug.tsx
+++ b/libs/extension/src/svgs/Debug.tsx
@@ -4,5 +4,5 @@ export default function Debug() {
- )
+ );
}
diff --git a/libs/extension/src/svgs/Eye.tsx b/libs/extension/src/svgs/Eye.tsx
index f17f1fd2..bd34c2ac 100644
--- a/libs/extension/src/svgs/Eye.tsx
+++ b/libs/extension/src/svgs/Eye.tsx
@@ -3,8 +3,8 @@ export default function Eye() {
return (
- )
+ );
}
diff --git a/libs/extension/src/svgs/Select.tsx b/libs/extension/src/svgs/Select.tsx
index 08aef9bb..463805e5 100644
--- a/libs/extension/src/svgs/Select.tsx
+++ b/libs/extension/src/svgs/Select.tsx
@@ -1,9 +1,8 @@
-
export default function Select() {
return (
- )
+ );
}
\ No newline at end of file
diff --git a/libs/extension/src/utils.ts b/libs/extension/src/utils.ts
index 727c672d..ae2ee2a0 100644
--- a/libs/extension/src/utils.ts
+++ b/libs/extension/src/utils.ts
@@ -1,5 +1,5 @@
-export function createRegExp(expression: string){
+export function createRegExp(expression: string) {
let str = expression;
if (str[0] === '/') {
str = str.slice(1);
@@ -9,7 +9,7 @@ export function createRegExp(expression: string){
}
try {
return new RegExp(str, 'i');
- }catch(err) {
+ } catch (err) {
return null;
}
}
\ No newline at end of file
diff --git a/libs/extension/webpack.dev.js b/libs/extension/webpack.dev.js
index 37cbf13c..1c468b0c 100644
--- a/libs/extension/webpack.dev.js
+++ b/libs/extension/webpack.dev.js
@@ -30,8 +30,8 @@ module.exports = {
'@babel/preset-typescript',
['@babel/preset-react', {
runtime: 'classic',
- "pragma": "Horizon.createElement",
- "pragmaFrag": "Horizon.Fragment",
+ 'pragma': 'Horizon.createElement',
+ 'pragmaFrag': 'Horizon.Fragment',
}]],
plugins: ['@babel/plugin-proposal-class-properties'],
}
@@ -41,14 +41,14 @@ module.exports = {
{
test: /\.less/i,
use: [
- "style-loader",
- {
- loader: "css-loader",
- options: {
+ 'style-loader',
+ {
+ loader: 'css-loader',
+ options: {
modules: true,
-
- }
- },
+
+ }
+ },
'less-loader'],
}]
},