Add support for highlighting when hovering over a node.

This commit is contained in:
Tom Alexander 2024-01-27 18:39:54 -05:00
parent e89be0feff
commit 0e02e09018
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
4 changed files with 112 additions and 19 deletions

View File

@ -2,7 +2,7 @@ import React, { ReactNode, useState } from "react";
import "./Editor.css"; import "./Editor.css";
import { Highlight } from "./highlight"; import { Highlight } from "./highlight";
import { buildShadow } from "./shadow"; import { buildShadow } from "./shadow";
import OrgAst from "./OrgAst"; import OrgAst, { OrgNodeReference } from "./OrgAst";
import { parse_org } from "../../organic/target/wasm32-unknown-unknown/js/wasm"; import { parse_org } from "../../organic/target/wasm32-unknown-unknown/js/wasm";
const default_org_source: string = `Welcome to the Organic Wasm Demo! const default_org_source: string = `Welcome to the Organic Wasm Demo!
@ -31,8 +31,15 @@ function Editor({ defaultValue = default_org_source }) {
const [highlights, setHighlights] = useState<Array<Highlight>>([]); const [highlights, setHighlights] = useState<Array<Highlight>>([]);
function setHighlight(start: number, end: number) { function setHighlight(nodes: OrgNodeReference[]) {
let new_highlights = [new Highlight(start, end)]; let new_highlights = nodes.map((node: OrgNodeReference) => {
return new Highlight(node.start - 1, node.end - 1);
});
new_highlights.sort(function (a, b) {
if (a.start < b.start) return -1;
if (a.start > b.start) return 1;
return 0;
});
setHighlights(new_highlights); setHighlights(new_highlights);
} }

View File

@ -35,6 +35,12 @@
} }
} }
.OrgAstNode.hovered:not(.selected) {
> .OrgAstNodeType {
background: #70f8ba;
}
}
.OrgAstNodeType { .OrgAstNodeType {
font-size: 1.3rem; font-size: 1.3rem;
font-weight: 700; font-weight: 700;

View File

@ -3,5 +3,6 @@ export const OrgAstNode: string;
export const OrgAstNodeType: string; export const OrgAstNodeType: string;
export const OrgAstChildren: string; export const OrgAstChildren: string;
export const selected: string; export const selected: string;
export const hovered: string;
export const OrgAstProperties: string; export const OrgAstProperties: string;
export const OrgAstObjectTree: string; export const OrgAstObjectTree: string;

View File

@ -8,11 +8,28 @@ const OrgAst = (props: {
astTree: any; astTree: any;
value: string; value: string;
}) => { }) => {
const [selectedNode, setSelectedNode] = useState<string>(""); const [selectedNode, setSelectedNode] = useState<OrgNodeReference | null>(
null,
);
const [hoveredNode, setHoveredNode] = useState<OrgNodeReference | null>(null);
function selectNode(uid: string, start: number, end: number) { function selectNode(uid: string, start: number, end: number) {
props.setHighlight(start, end); const new_node: OrgNodeReference = { uid: uid, start: start, end: end };
setSelectedNode(uid); props.setHighlight([new_node, hoveredNode].filter((node) => node !== null));
setSelectedNode({ uid: uid, start: start, end: end });
}
function startHoverNode(uid: string, start: number, end: number) {
const new_node: OrgNodeReference = { uid: uid, start: start, end: end };
props.setHighlight(
[selectedNode, new_node].filter((node) => node !== null),
);
setHoveredNode({ uid: uid, start: start, end: end });
}
function endHoverNode(uid: string) {
props.setHighlight([selectedNode].filter((node) => node !== null));
setHoveredNode(null);
} }
if (props.astTree.status !== "success") { if (props.astTree.status !== "success") {
@ -24,6 +41,8 @@ const OrgAst = (props: {
key="^" key="^"
uid="^" uid="^"
selectNode={selectNode} selectNode={selectNode}
startHoverNode={startHoverNode}
endHoverNode={endHoverNode}
node={props.astTree.content} node={props.astTree.content}
selectedNode={selectedNode} selectedNode={selectedNode}
/> />
@ -32,34 +51,68 @@ const OrgAst = (props: {
} }
}; };
interface OrgNodeReference {
uid: string;
start: number;
end: number;
}
const OrgAstNode = (props: { const OrgAstNode = (props: {
selectNode: Function; selectNode: Function;
startHoverNode: Function;
endHoverNode: Function;
node: any; node: any;
uid: string; uid: string;
selectedNode: string; selectedNode: OrgNodeReference | null;
}) => { }) => {
const [isHovered, setIsHovered] = useState(false);
function selectNode() { function selectNode() {
props.selectNode( props.selectNode(
props.uid, props.uid,
props.node["standard-properties"]["begin"] - 1, props.node["standard-properties"]["begin"],
props.node["standard-properties"]["end"] - 1, props.node["standard-properties"]["end"],
); );
} }
const nodeClassName = function hoverNode() {
props.selectedNode === props.uid props.startHoverNode(
? styles.OrgAstNode + " " + styles.selected props.uid,
: styles.OrgAstNode; props.node["standard-properties"]["begin"],
props.node["standard-properties"]["end"],
);
setIsHovered(true);
}
function endHoverNode() {
props.endHoverNode(props.uid);
setIsHovered(false);
}
let nodeClassName = styles.OrgAstNode;
if (props.selectedNode?.uid === props.uid) {
nodeClassName = nodeClassName + " " + styles.selected;
}
if (isHovered) {
nodeClassName = nodeClassName + " " + styles.hovered;
}
return ( return (
<div className={nodeClassName}> <div className={nodeClassName}>
<div className={styles.OrgAstNodeType} onClick={selectNode}> <div
className={styles.OrgAstNodeType}
onClick={selectNode}
onMouseEnter={hoverNode}
onMouseLeave={endHoverNode}
>
{props.node["ast-node"]} {props.node["ast-node"]}
</div> </div>
<details> <details>
<summary>Standard Properties</summary> <summary>Standard Properties</summary>
<OrgPropertiesList <OrgPropertiesList
selectNode={props.selectNode} selectNode={props.selectNode}
startHoverNode={props.startHoverNode}
endHoverNode={props.endHoverNode}
parentUniqueId={props.uid} parentUniqueId={props.uid}
selectedNode={props.selectedNode} selectedNode={props.selectedNode}
properties={props.node["standard-properties"]} properties={props.node["standard-properties"]}
@ -71,6 +124,8 @@ const OrgAstNode = (props: {
<summary>Properties</summary> <summary>Properties</summary>
<OrgPropertiesList <OrgPropertiesList
selectNode={props.selectNode} selectNode={props.selectNode}
startHoverNode={props.startHoverNode}
endHoverNode={props.endHoverNode}
parentUniqueId={props.uid} parentUniqueId={props.uid}
selectedNode={props.selectedNode} selectedNode={props.selectedNode}
properties={props.node.properties} properties={props.node.properties}
@ -84,6 +139,8 @@ const OrgAstNode = (props: {
<div className={styles.OrgAstChildren}> <div className={styles.OrgAstChildren}>
<OrgAstNodeList <OrgAstNodeList
selectNode={props.selectNode} selectNode={props.selectNode}
startHoverNode={props.startHoverNode}
endHoverNode={props.endHoverNode}
parentUniqueId={props.uid} parentUniqueId={props.uid}
selectedNode={props.selectedNode} selectedNode={props.selectedNode}
node_list={props.node.children} node_list={props.node.children}
@ -97,8 +154,10 @@ const OrgAstNode = (props: {
const OrgAstNodeList = (props: { const OrgAstNodeList = (props: {
selectNode: Function; selectNode: Function;
startHoverNode: Function;
endHoverNode: Function;
parentUniqueId: string; parentUniqueId: string;
selectedNode: string; selectedNode: OrgNodeReference | null;
node_list: any[]; node_list: any[];
}): React.JSX.Element[] => { }): React.JSX.Element[] => {
return props.node_list.map((node) => { return props.node_list.map((node) => {
@ -116,6 +175,8 @@ const OrgAstNodeList = (props: {
key={uid} key={uid}
uid={uid} uid={uid}
selectNode={props.selectNode} selectNode={props.selectNode}
startHoverNode={props.startHoverNode}
endHoverNode={props.endHoverNode}
selectedNode={props.selectedNode} selectedNode={props.selectedNode}
node={node} node={node}
/> />
@ -125,8 +186,10 @@ const OrgAstNodeList = (props: {
const OrgPropertiesList = (props: { const OrgPropertiesList = (props: {
selectNode: Function; selectNode: Function;
startHoverNode: Function;
endHoverNode: Function;
parentUniqueId: string; parentUniqueId: string;
selectedNode: string; selectedNode: OrgNodeReference | null;
properties: Object; properties: Object;
}): React.JSX.Element => { }): React.JSX.Element => {
const entries = Object.entries(props.properties) const entries = Object.entries(props.properties)
@ -150,6 +213,8 @@ const OrgPropertiesList = (props: {
<td> <td>
<OrgPropertyValue <OrgPropertyValue
selectNode={props.selectNode} selectNode={props.selectNode}
startHoverNode={props.startHoverNode}
endHoverNode={props.endHoverNode}
parentUniqueId={props.parentUniqueId} parentUniqueId={props.parentUniqueId}
selectedNode={props.selectedNode} selectedNode={props.selectedNode}
value={value} value={value}
@ -168,8 +233,10 @@ const OrgPropertiesList = (props: {
const OrgPropertyValue = (props: { const OrgPropertyValue = (props: {
selectNode: Function; selectNode: Function;
startHoverNode: Function;
endHoverNode: Function;
parentUniqueId: string; parentUniqueId: string;
selectedNode: string; selectedNode: OrgNodeReference | null;
value: any; value: any;
}): React.ReactNode => { }): React.ReactNode => {
if ( if (
@ -183,6 +250,8 @@ const OrgPropertyValue = (props: {
<div className={styles.OrgAstChildren}> <div className={styles.OrgAstChildren}>
<OrgAstNodeList <OrgAstNodeList
selectNode={props.selectNode} selectNode={props.selectNode}
startHoverNode={props.startHoverNode}
endHoverNode={props.endHoverNode}
parentUniqueId={props.parentUniqueId} parentUniqueId={props.parentUniqueId}
selectedNode={props.selectedNode} selectedNode={props.selectedNode}
node_list={props.value} node_list={props.value}
@ -193,6 +262,8 @@ const OrgPropertyValue = (props: {
return ( return (
<OrgObjectTree <OrgObjectTree
selectNode={props.selectNode} selectNode={props.selectNode}
startHoverNode={props.startHoverNode}
endHoverNode={props.endHoverNode}
parentUniqueId={props.parentUniqueId} parentUniqueId={props.parentUniqueId}
selectedNode={props.selectedNode} selectedNode={props.selectedNode}
value={props.value} value={props.value}
@ -205,13 +276,17 @@ const OrgPropertyValue = (props: {
interface OrgObjectTreeProps { interface OrgObjectTreeProps {
selectNode: Function; selectNode: Function;
startHoverNode: Function;
endHoverNode: Function;
parentUniqueId: string; parentUniqueId: string;
selectedNode: string; selectedNode: OrgNodeReference | null;
value: any; value: any;
} }
function OrgObjectTree({ function OrgObjectTree({
selectNode, selectNode,
startHoverNode,
endHoverNode,
parentUniqueId, parentUniqueId,
selectedNode, selectedNode,
value, value,
@ -224,6 +299,8 @@ function OrgObjectTree({
<td> <td>
<OrgAstNodeList <OrgAstNodeList
selectNode={selectNode} selectNode={selectNode}
startHoverNode={startHoverNode}
endHoverNode={endHoverNode}
parentUniqueId={parentUniqueId} parentUniqueId={parentUniqueId}
selectedNode={selectedNode} selectedNode={selectedNode}
node_list={entry[0]} node_list={entry[0]}
@ -235,6 +312,8 @@ function OrgObjectTree({
<td> <td>
<OrgAstNodeList <OrgAstNodeList
selectNode={selectNode} selectNode={selectNode}
startHoverNode={startHoverNode}
endHoverNode={endHoverNode}
parentUniqueId={parentUniqueId} parentUniqueId={parentUniqueId}
selectedNode={selectedNode} selectedNode={selectedNode}
node_list={entry[1]} node_list={entry[1]}
@ -275,4 +354,4 @@ function is_object_tree(val: any): boolean {
return is_object(val) && val.hasOwnProperty("object-tree"); return is_object(val) && val.hasOwnProperty("object-tree");
} }
export default OrgAst; export { OrgAst as default, OrgNodeReference };