diff --git a/src/common/components/icons/delete-icon.component.tsx b/src/common/components/icons/delete-icon.component.tsx
new file mode 100644
index 00000000..f991af72
--- /dev/null
+++ b/src/common/components/icons/delete-icon.component.tsx
@@ -0,0 +1,15 @@
+export const DeleteIcon = () => {
+ return (
+
+ );
+};
diff --git a/src/core/providers/canvas/canvas.business.spec.ts b/src/core/providers/canvas/canvas.business.spec.ts
new file mode 100644
index 00000000..f252897e
--- /dev/null
+++ b/src/core/providers/canvas/canvas.business.spec.ts
@@ -0,0 +1,168 @@
+import { describe, it, expect } from 'vitest';
+import { removeShapeFromList } from './canvas.business';
+import { ShapeModel } from '@/core/model';
+
+describe('canvas.business', () => {
+ describe('removeShapeFromList', () => {
+ it('should return an empty array if shapeCollection is empty', () => {
+ // Arrange
+ const shapeId = '';
+ const shapeCollection: ShapeModel[] = [];
+
+ // Act
+ const result = removeShapeFromList(shapeId, shapeCollection);
+
+ // Assert
+ expect(result).toEqual([]);
+ });
+
+ it('should return the same array if shapeCollection has elements and shapeId is empty string', () => {
+ // Arrange
+ const shapeId = '';
+ const shapeCollection: ShapeModel[] = [
+ {
+ id: '1',
+ x: 0,
+ y: 0,
+ width: 10,
+ height: 10,
+ type: 'combobox',
+ allowsInlineEdition: false,
+ },
+ {
+ id: '2',
+ x: 1,
+ y: 1,
+ width: 20,
+ height: 20,
+ type: 'input',
+ allowsInlineEdition: true,
+ },
+ ];
+
+ // Act
+ const result = removeShapeFromList(shapeId, shapeCollection);
+
+ // Assert
+ expect(result).toHaveLength(2);
+ expect(result).toEqual(shapeCollection);
+ });
+
+ it('should remove the shape with the specified shapeId if it exists in a collection with multiple elements', () => {
+ // Arrange
+ const shapeId = '2';
+ const shapeCollection: ShapeModel[] = [
+ {
+ id: '1',
+ x: 0,
+ y: 0,
+ width: 10,
+ height: 10,
+ type: 'combobox',
+ allowsInlineEdition: false,
+ },
+ {
+ id: '2',
+ x: 1,
+ y: 1,
+ width: 20,
+ height: 20,
+ type: 'input',
+ allowsInlineEdition: true,
+ },
+ {
+ id: '3',
+ x: 2,
+ y: 2,
+ width: 30,
+ height: 30,
+ type: 'button',
+ allowsInlineEdition: false,
+ },
+ {
+ id: '4',
+ x: 3,
+ y: 3,
+ width: 40,
+ height: 40,
+ type: 'checkbox',
+ allowsInlineEdition: true,
+ },
+ ];
+
+ // Act
+ const result = removeShapeFromList(shapeId, shapeCollection);
+
+ // Assert
+ expect(result).toHaveLength(3);
+ expect(result).toEqual([
+ {
+ id: '1',
+ x: 0,
+ y: 0,
+ width: 10,
+ height: 10,
+ type: 'combobox',
+ allowsInlineEdition: false,
+ },
+ {
+ id: '3',
+ x: 2,
+ y: 2,
+ width: 30,
+ height: 30,
+ type: 'button',
+ allowsInlineEdition: false,
+ },
+ {
+ id: '4',
+ x: 3,
+ y: 3,
+ width: 40,
+ height: 40,
+ type: 'checkbox',
+ allowsInlineEdition: true,
+ },
+ ]);
+ });
+
+ it('should return an empty array if the shape with the specified shapeId exists in a collection with a single element', () => {
+ // Arrange
+ const shapeId = '1';
+ const shapeCollection: ShapeModel[] = [
+ {
+ id: '1',
+ x: 0,
+ y: 0,
+ width: 10,
+ height: 10,
+ type: 'combobox',
+ allowsInlineEdition: false,
+ },
+ ];
+
+ // Act
+ const result = removeShapeFromList(shapeId, shapeCollection);
+
+ // Assert
+ expect(result).toEqual([]);
+ });
+ });
+
+ it('shapeID contains a value and exists on the shape list (1 element)', () => {
+ const shapeId = '1';
+ const shapeCollection: ShapeModel[] = [
+ {
+ id: '1',
+ x: 0,
+ y: 0,
+ width: 10,
+ height: 10,
+ type: 'combobox',
+ allowsInlineEdition: false,
+ },
+ ];
+ const result = removeShapeFromList(shapeId, shapeCollection);
+ expect(result).toEqual([]);
+ });
+});
diff --git a/src/core/providers/canvas/canvas.business.ts b/src/core/providers/canvas/canvas.business.ts
new file mode 100644
index 00000000..30ef7a00
--- /dev/null
+++ b/src/core/providers/canvas/canvas.business.ts
@@ -0,0 +1,11 @@
+import { ShapeModel } from '@/core/model';
+
+export const removeShapeFromList = (
+ shapeId: string,
+ shapeCollection: ShapeModel[]
+): ShapeModel[] => {
+ if (shapeId === '') {
+ return shapeCollection;
+ }
+ return shapeCollection.filter(shape => shape.id !== shapeId);
+};
diff --git a/src/core/providers/canvas/canvas.model.ts b/src/core/providers/canvas/canvas.model.ts
index 9da5fd9c..1c7af256 100644
--- a/src/core/providers/canvas/canvas.model.ts
+++ b/src/core/providers/canvas/canvas.model.ts
@@ -30,4 +30,5 @@ export interface CanvasContextModel {
updateShapeSizeAndPosition: (id: string, position: Coord, size: Size) => void;
updateShapePosition: (id: string, position: Coord) => void;
selectionInfo: SelectionInfo;
+ deleteSelectedShape: () => void;
}
diff --git a/src/core/providers/canvas/canvas.provider.tsx b/src/core/providers/canvas/canvas.provider.tsx
index 1f10a97a..3981e7d9 100644
--- a/src/core/providers/canvas/canvas.provider.tsx
+++ b/src/core/providers/canvas/canvas.provider.tsx
@@ -4,6 +4,7 @@ import { CanvasContext } from './canvas.context';
import { useSelection } from './use-selection.hook';
import { createShape } from '@/pods/canvas/canvas.model';
import { v4 as uuidv4 } from 'uuid';
+import { removeShapeFromList } from './canvas.business';
interface Props {
children: React.ReactNode;
@@ -16,6 +17,12 @@ export const CanvasProvider: React.FC = props => {
const selectionInfo = useSelection(shapes, setShapes);
+ const deleteSelectedShape = () => {
+ setShapes(prevShapes =>
+ removeShapeFromList(selectionInfo.selectedShapeId, prevShapes)
+ );
+ };
+
const clearCanvas = () => {
setShapes([]);
};
@@ -62,6 +69,7 @@ export const CanvasProvider: React.FC = props => {
pasteShape,
updateShapeSizeAndPosition,
updateShapePosition,
+ deleteSelectedShape,
}}
>
{children}
diff --git a/src/pods/toolbar/components/delete-button/delete-button.tsx b/src/pods/toolbar/components/delete-button/delete-button.tsx
new file mode 100644
index 00000000..c4ce131a
--- /dev/null
+++ b/src/pods/toolbar/components/delete-button/delete-button.tsx
@@ -0,0 +1,18 @@
+import { DeleteIcon } from '@/common/components/icons/delete-icon.component';
+import { ToolbarButton } from '@/pods/toolbar/components/toolbar-button/toolbar-button';
+import classes from '@/pods/toolbar/toolbar.pod.module.css';
+import { useCanvasContext } from '@/core/providers';
+export const DeleteButton = () => {
+ const { deleteSelectedShape, selectionInfo } = useCanvasContext();
+
+ return (
+
+
+ Delete
+
+ );
+};
diff --git a/src/pods/toolbar/components/delete-button/index.ts b/src/pods/toolbar/components/delete-button/index.ts
new file mode 100644
index 00000000..b7ab2a9a
--- /dev/null
+++ b/src/pods/toolbar/components/delete-button/index.ts
@@ -0,0 +1 @@
+export * from './delete-button';
diff --git a/src/pods/toolbar/toolbar.pod.tsx b/src/pods/toolbar/toolbar.pod.tsx
index e15558ae..ec08b634 100644
--- a/src/pods/toolbar/toolbar.pod.tsx
+++ b/src/pods/toolbar/toolbar.pod.tsx
@@ -1,3 +1,4 @@
+import { DeleteButton } from './components/delete-button';
import {
ZoomInButton,
ZoomOutButton,
@@ -22,6 +23,7 @@ export const ToolbarPod: React.FC = () => {
+
);