Skip to content

Commit

Permalink
feat: add more attributes that can be edited
Browse files Browse the repository at this point in the history
  • Loading branch information
maitrungduc1410 committed Jun 14, 2023
1 parent b934e4c commit f46fdda
Show file tree
Hide file tree
Showing 8 changed files with 413 additions and 108 deletions.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "konva-inspector",
"version": "0.0.9",
"version": "0.0.10",
"description": "Devtools for your Konva App",
"license": "MIT",
"repository": {
Expand All @@ -18,6 +18,7 @@
"type": "module",
"dependencies": {
"konva": "^9.0.2",
"lodash-es": "^4.17.21",
"react": "18.2.0",
"react-dom": "18.2.0"
},
Expand All @@ -26,6 +27,7 @@
"@testing-library/react": "^13.4.0",
"@types/chrome": "^0.0.224",
"@types/jest": "29.0.3",
"@types/lodash-es": "^4.17.7",
"@types/node": "18.15.11",
"@types/react": "18.0.21",
"@types/react-dom": "18.0.11",
Expand Down
128 changes: 128 additions & 0 deletions src/pages/panel/components/Attributes.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import React from "react";
import { bridge } from "..";
import CopyToClipboard from "./CopyToClipboard";
import { IAttr } from "./constants";

interface IProps {
title: string;
nodeAttrs: Record<string, any>;
attrs: IAttr[];
custom?: boolean;
updateAttr: (attrName: string, val: any) => Promise<void>;
}

export default function Attributes({
title,
nodeAttrs,
attrs,
custom,
updateAttr,
}: IProps) {
const copyToClipBoard = () => {
bridge(
`window.copy(window.__KONVA_DEVTOOLS_GLOBAL_HOOK__ && window.__KONVA_DEVTOOLS_GLOBAL_HOOK__.selection.selected().attrs)`
);
};

return (
<div className="attributes">
<div className="header-row">
<div className="header">{title}</div>
<button
className="button"
title="Copy Attributes to Clipboard"
onClick={() => copyToClipBoard()}
>
<span className="button-content" tabIndex={-1}>
<CopyToClipboard />
</span>
</button>
</div>
<div className="attr-list">
{attrs.map((item) => {
let input;

switch (item.type) {
case "boolean": {
input = (
<input
type="checkbox"
checked={
nodeAttrs[item.name] === undefined
? item.defaultValue !== undefined
? item.defaultValue
: true
: nodeAttrs[item.name]
}
onChange={(e) => updateAttr(item.name, e.target.checked)}
/>
);
break;
}
case "number": {
input = (
<input
value={
nodeAttrs[item.name] !== undefined
? nodeAttrs[item.name]
: ""
}
type="number"
placeholder="<default>"
onChange={(e) =>
updateAttr(
item.name,
isNaN(e.target.valueAsNumber)
? null // JSON.stringify will not preserve undefined, so we have to use null here
: e.target.valueAsNumber
)
}
min={item.min}
/>
);
break;
}
case "json": {
input = (
<textarea
value={
nodeAttrs[item.name] !== undefined
? JSON.stringify(nodeAttrs[item.name])
: ""
}
placeholder="<default>"
onChange={(e) =>
updateAttr(item.name, JSON.parse(e.target.value))
}
/>
);
break;
}
default: {
input = (
<input
value={
nodeAttrs[item.name] !== undefined
? nodeAttrs[item.name]
: ""
}
type="text"
placeholder="<default>"
onChange={(e) => updateAttr(item.name, e.target.value)}
/>
);
}
}
return (
<div className="attr-item" key={item.name}>
<span className={`item-name ${custom ? "key-name" : ""}`}>
{item.name}:
</span>
{input}
</div>
);
})}
</div>
</div>
);
}
111 changes: 19 additions & 92 deletions src/pages/panel/components/InspectedElement.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useEffect, useState } from "react";
import { bridge } from "..";
import { OutlineNode } from "../types";
import CopyToClipboard from "./CopyToClipboard";
import { ATTRS, SHAPE_ATTRS } from "./constants";
import { ATTRS, SHAPE_ATTRS, SHAPE_CUSTOM_ATTRS } from "./constants";
import Attributes from "./Attributes";

interface IProps {
selectedNode: OutlineNode | null;
Expand All @@ -20,9 +20,6 @@ export default function InspectedElement({ selectedNode }: IProps) {
});
}
}, [selectedNode]);
// if (!selectedNode) {
// return null;
// }

const updateAttr = async (attrName: string, val: any) => {
await bridge(
Expand All @@ -40,12 +37,6 @@ export default function InspectedElement({ selectedNode }: IProps) {

const attrs = selectedNode?.isShape ? SHAPE_ATTRS : ATTRS;

const copyToClipBoard = () => {
bridge(
`window.copy(window.__KONVA_DEVTOOLS_GLOBAL_HOOK__ && window.__KONVA_DEVTOOLS_GLOBAL_HOOK__.selection.selected().attrs)`
);
};

return (
<>
<div className="title-row">
Expand All @@ -59,88 +50,24 @@ export default function InspectedElement({ selectedNode }: IProps) {
</div>
<div className="inspected-element-data">
{selectedNode && (
<div className="attributes">
<div className="header-row">
<div className="header">Attributes</div>
<button
className="button"
title="Copy Attributes to Clipboard"
onClick={() => copyToClipBoard()}
>
<span className="button-content" tabIndex={-1}>
<CopyToClipboard />
</span>
</button>
</div>
<div className="attr-list">
{attrs.map((item) => {
let input;
<>
{SHAPE_CUSTOM_ATTRS[selectedNode.className] && (
<Attributes
title={`${selectedNode.className} Attributes`}
attrs={SHAPE_CUSTOM_ATTRS[selectedNode.className]}
nodeAttrs={nodeAttrs}
updateAttr={updateAttr}
custom
/>
)}

switch (item.type) {
case "boolean": {
input = (
<input
type="checkbox"
checked={
nodeAttrs[item.name] === undefined
? item.defaultValue !== undefined
? item.defaultValue
: true
: nodeAttrs[item.name]
}
onChange={(e) =>
updateAttr(item.name, e.target.checked)
}
/>
);
break;
}
case "number": {
input = (
<input
value={
nodeAttrs[item.name] !== undefined
? nodeAttrs[item.name]
: ""
}
type="number"
placeholder="<default>"
onChange={(e) =>
updateAttr(
item.name,
isNaN(e.target.valueAsNumber)
? null // JSON.stringify will not preserve undefined, so we have to use null here
: e.target.valueAsNumber
)
}
/>
);
break;
}
default: {
input = (
<input
value={
nodeAttrs[item.name] !== undefined
? nodeAttrs[item.name]
: ""
}
type="text"
placeholder="<default>"
onChange={(e) => updateAttr(item.name, e.target.value)}
/>
);
}
}
return (
<div className="attr-item" key={item.name}>
<span className="item-name">{item.name}:</span>
{input}
</div>
);
})}
</div>
</div>
<Attributes
title="Attributes"
attrs={attrs}
nodeAttrs={nodeAttrs}
updateAttr={updateAttr}
/>
</>
)}
</div>
</>
Expand Down
24 changes: 16 additions & 8 deletions src/pages/panel/components/Panel.scss
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ body {
font-family: var(--font-family-sans);
-webkit-font-smoothing: var(--font-smoothing);

.key-name {
color: var(--color-attribute-name);
}

.button {
border: none;
background: var(--color-button-background);
Expand Down Expand Up @@ -183,7 +187,9 @@ body {
}
.trees {
overflow-y: auto;
height: calc(100% - 42px - 3px); // add 3px as buffer for better scrollbar visibility
height: calc(
100% - 42px - 3px
); // add 3px as buffer for better scrollbar visibility
}
}
.inspected-element {
Expand Down Expand Up @@ -225,7 +231,9 @@ body {

.inspected-element-data {
overflow-y: auto;
height: calc(100% - 42px - 3px); // add 3px as buffer for better scrollbar visibility
height: calc(
100% - 42px - 3px
); // add 3px as buffer for better scrollbar visibility
.header-row {
display: flex;
align-items: center;
Expand All @@ -241,7 +249,7 @@ body {
padding: 0.25rem;
border-top: 1px solid var(--color-border);
}
.attributes {
.attributes:first-child {
border-top: none;
}
.attributes {
Expand All @@ -255,9 +263,10 @@ body {

.item-name {
margin-right: 0.5rem;
font-family: var(--font-family-monospace);
}

input {
input, textarea {
flex: 1 1;
background: none;
border: 1px solid transparent;
Expand All @@ -270,6 +279,9 @@ body {
outline: none;
}
}
textarea {
resize: vertical;
}
}
}
}
Expand Down Expand Up @@ -316,10 +328,6 @@ body {
}
}

.key-name {
color: var(--color-attribute-name);
}

.key-value {
color: var(--color-attribute-value);
user-select: text;
Expand Down
Loading

0 comments on commit f46fdda

Please sign in to comment.