Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add action to deselect node #31

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions src/main/endpoints/deselectNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { createEndpoint } from "../utils/createEndpoint";

export type DeselectNodeProps = {
id: string;
};

export const deselectNodeEndpoint = createEndpoint(
"DESELECT_NODE",
async ({ id }: DeselectNodeProps) => {
const currentSelection = figma.currentPage.selection;

if (currentSelection.length === 0) {
return;
}

// Check if all selected nodes are text nodes removed from the selection
if (currentSelection.every((node) => node.type === "TEXT")) {
figma.currentPage.selection = currentSelection.filter(
(node) => node.id !== id
);

return;
}

// Expand selection to include all text nodes
const expandedSelection = currentSelection.reduce((acc, node) => {
if (node.type === "TEXT") {
acc.push(node);
} else if (node.type === "FRAME" || node.type === "COMPONENT") {
acc.push(
...node.findAllWithCriteria({
types: ["TEXT"],
})
);
}

return acc;
}, [] as TextNode[]);

figma.currentPage.selection = expandedSelection.filter(
(node) => node.id !== id
);
}
);
2 changes: 2 additions & 0 deletions src/main/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
} from "./utils/settingsTools";
import { DEFAULT_SIZE } from "@/ui/hooks/useWindowSize";
import { highlightNodeEndpoint } from "./endpoints/highlightNode";
import { deselectNodeEndpoint } from "./endpoints/deselectNode";

const getAllPages = () => {
const document = figma.root;
Expand Down Expand Up @@ -93,6 +94,7 @@ export default async function () {
updateNodesEndpoint.register();
setNodesDataEndpoint.register();
highlightNodeEndpoint.register();
deselectNodeEndpoint.register();

const config = await getPluginData();

Expand Down
9 changes: 9 additions & 0 deletions src/ui/components/DeselectNodeButton/DeselectNodeButton.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.deselectButton {
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
width: 20px;
height: 20px;
color: var(--figma-color-text-secondary);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
declare const styles: {
readonly "deselectButton": string;
};
export = styles;

29 changes: 29 additions & 0 deletions src/ui/components/DeselectNodeButton/DeselectNodeButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { h } from "preact";

import styles from "./DeselectNodeButton.css";
import { RemoveFromList } from "@/ui/icons/SvgIcons";
import { useDeselectNodeMutation } from "@/ui/hooks/useDeselectNodeMutation";

type Props = {
nodeId: string;
};

export const DeselectNodeButton = ({ nodeId }: Props) => {
const deselectMutation = useDeselectNodeMutation();

const handleDeselect = () => {
deselectMutation.mutate({ id: nodeId });
};

return (
<div
data-cy="index_deselect_button"
role="button"
title="Remove from selection"
onClick={handleDeselect}
className={styles.deselectButton}
>
<RemoveFromList width={16} height={16} />
</div>
);
};
12 changes: 12 additions & 0 deletions src/ui/hooks/useDeselectNodeMutation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {
DeselectNodeProps,
deselectNodeEndpoint,
} from "@/main/endpoints/deselectNode";
import { useMutation } from "react-query";

export const useDeselectNodeMutation = () => {
return useMutation<void, void, DeselectNodeProps>(
[deselectNodeEndpoint.name],
(data: DeselectNodeProps) => deselectNodeEndpoint.call(data)
);
};
11 changes: 11 additions & 0 deletions src/ui/icons/SvgIcons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,14 @@ export const MyLocation = (props: h.JSX.SVGAttributes<SVGSVGElement>) => {
</svg>
);
};

export const RemoveFromList = (props: h.JSX.SVGAttributes<SVGSVGElement>) => {
return (
<svg {...props} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
fill="currentColor"
d="M3 17v-2h2v2zm0-4v-2h2v2zm0-4V7h2v2zm4 12v-2h2v2zM7 5V3h2v2zm4 0V3h2v2zm1.5 16l-1.4-1.4l3.55-3.55l-3.55-3.55l1.4-1.4l3.55 3.55l3.55-3.55l1.4 1.4l-3.55 3.55L21 19.6L19.6 21l-3.55-3.55zM15 5V3h2v2zm4 4V7h2v2zM3 5V3h2v2zm18 0h-2V3h2zM3 21v-2h2v2z"
/>
</svg>
);
};
3 changes: 3 additions & 0 deletions src/ui/views/Index/Index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { TopBar } from "../../components/TopBar/TopBar";
import styles from "./Index.css";
import { KeyInput } from "./KeyInput";
import { useSetNodesDataMutation } from "@/ui/hooks/useSetNodesDataMutation";
import { DeselectNodeButton } from "@/ui/components/DeselectNodeButton/DeselectNodeButton";

export const Index = () => {
const selectionLoadable = useSelectedNodes();
Expand Down Expand Up @@ -271,6 +272,8 @@ export const Index = () => {
/>
)}
</div>

<DeselectNodeButton nodeId={node.id} />
</div>
);
}}
Expand Down