diff --git a/public/shapes/line.svg b/public/shapes/line.svg
new file mode 100644
index 00000000..2c40684d
--- /dev/null
+++ b/public/shapes/line.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/src/common/components/front-basic-sapes/index.ts b/src/common/components/front-basic-sapes/index.ts
index 915b6d11..0d891240 100644
--- a/src/common/components/front-basic-sapes/index.ts
+++ b/src/common/components/front-basic-sapes/index.ts
@@ -1,2 +1,3 @@
export * from './rectangle-basic-shape';
export * from './diamond-shape';
+export * from './line-basic-shape';
diff --git a/src/common/components/front-basic-sapes/line-basic-shape.tsx b/src/common/components/front-basic-sapes/line-basic-shape.tsx
new file mode 100644
index 00000000..ba1e707f
--- /dev/null
+++ b/src/common/components/front-basic-sapes/line-basic-shape.tsx
@@ -0,0 +1,51 @@
+import { forwardRef } from 'react';
+import { Group, Line, Rect } from 'react-konva';
+import { ShapeSizeRestrictions } from '@/core/model';
+import { fitSizeToShapeSizeRestrictions } from '@/common/utils/shapes/shape-restrictions';
+import { ShapeProps } from '../front-components/shape.model';
+
+const lineShapeRestrictions: ShapeSizeRestrictions = {
+ minWidth: 50,
+ minHeight: 10,
+ maxWidth: -1,
+ maxHeight: 10,
+ defaultWidth: 200,
+ defaultHeight: 10,
+};
+
+export const getlineShapeRestrictions = (): ShapeSizeRestrictions =>
+ lineShapeRestrictions;
+
+export const LineShape = forwardRef(
+ ({ x, y, width, height, id, onSelected, text, ...shapeProps }, ref) => {
+ const { width: restrictedWidth, height: restrictedHeight } =
+ fitSizeToShapeSizeRestrictions(lineShapeRestrictions, width, height);
+
+ return (
+ onSelected(id, 'line')}
+ >
+ {/* Transparent rectangle for applying margin */}
+
+
+
+
+ );
+ }
+);
diff --git a/src/core/model/index.ts b/src/core/model/index.ts
index 7a07f20c..78e995c8 100644
--- a/src/core/model/index.ts
+++ b/src/core/model/index.ts
@@ -27,6 +27,7 @@ export type ShapeType =
| 'rectangle'
| 'videoPlayer'
| 'diamond'
+ | 'line';
| 'accordion';
/* | "text"| "button" | "radio" | "image"*/
@@ -54,6 +55,7 @@ export interface ShapeModel {
height: number;
type: ShapeType;
allowsInlineEdition: boolean;
+ hasLateralTransformer: boolean;
editType?: EditType;
text?: string;
}
diff --git a/src/pods/basic-shapes-gallery/basic-gallery-data/index.ts b/src/pods/basic-shapes-gallery/basic-gallery-data/index.ts
index b9e34aa7..b30f90ee 100644
--- a/src/pods/basic-shapes-gallery/basic-gallery-data/index.ts
+++ b/src/pods/basic-shapes-gallery/basic-gallery-data/index.ts
@@ -3,4 +3,5 @@ import { ItemInfo } from '@/common/components/gallery/components/model';
export const mockBasicShapesCollection: ItemInfo[] = [
{ thumbnailSrc: '/shapes/rectangle.svg', type: 'rectangle' },
{ thumbnailSrc: '/shapes/diamond.svg', type: 'diamond' },
+ { thumbnailSrc: '/shapes/line.svg', type: 'line' },
];
diff --git a/src/pods/canvas/canvas.model.ts b/src/pods/canvas/canvas.model.ts
index 30aa1f05..ccf95068 100644
--- a/src/pods/canvas/canvas.model.ts
+++ b/src/pods/canvas/canvas.model.ts
@@ -21,6 +21,7 @@ import { getLabelSizeRestrictions } from '@/common/components/front-components/l
import {
getDiamondShapeSizeRestrictions,
getRectangleShapeSizeRestrictions,
+ getlineShapeRestrictions,
} from '@/common/components/front-basic-sapes';
import {
getAccordionShapeSizeRestrictions,
@@ -110,6 +111,11 @@ export const getDefaultSizeFromShape = (shapeType: ShapeType): Size => {
width: getDiamondShapeSizeRestrictions().defaultWidth,
height: getDiamondShapeSizeRestrictions().defaultHeight,
};
+ case 'line':
+ return {
+ width: getlineShapeRestrictions().defaultWidth,
+ height: getlineShapeRestrictions().defaultHeight,
+ };
case 'accordion':
return {
width: getAccordionShapeSizeRestrictions().defaultWidth,
@@ -139,6 +145,15 @@ const doesShapeAllowInlineEdition = (shapeType: ShapeType): boolean => {
}
};
+const doesShapeHaveLateralTransformer = (shapeType: ShapeType): boolean => {
+ switch (shapeType) {
+ case 'line':
+ return true;
+ default:
+ return false;
+ }
+};
+
const generateDefaultTextValue = (shapeType: ShapeType): string | undefined => {
switch (shapeType) {
case 'input':
@@ -189,6 +204,7 @@ export const createShape = (coord: Coord, shapeType: ShapeType): ShapeModel => {
height,
type: shapeType,
allowsInlineEdition: doesShapeAllowInlineEdition(shapeType),
+ hasLateralTransformer: doesShapeHaveLateralTransformer(shapeType),
text: generateDefaultTextValue(shapeType),
editType: getShapeEditInlineType(shapeType),
};
diff --git a/src/pods/canvas/canvas.pod.tsx b/src/pods/canvas/canvas.pod.tsx
index ffc4c030..d686a462 100644
--- a/src/pods/canvas/canvas.pod.tsx
+++ b/src/pods/canvas/canvas.pod.tsx
@@ -72,12 +72,7 @@ export const CanvasPod = () => {
} = useSnapIn(transformerRef, selectedShapeKonvaId);
const { handleTransform, handleTransformerBoundBoxFunc } = useTransform(
- updateShapeSizeAndPosition,
- {
- selectedShapeRef,
- selectedShapeId,
- selectedShapeType,
- }
+ updateShapeSizeAndPosition
);
const handleDragEnd =
diff --git a/src/pods/canvas/shape-renderer/index.tsx b/src/pods/canvas/shape-renderer/index.tsx
index facedc6c..b1c00ece 100644
--- a/src/pods/canvas/shape-renderer/index.tsx
+++ b/src/pods/canvas/shape-renderer/index.tsx
@@ -20,11 +20,15 @@ import {
renderMobilePhoneContainer,
renderTablet,
} from './simple-container';
-import { renderRectangle } from './simple-basic-shapes/rectangle.rerender';
import { renderVideoPlayer } from './simple-rich-components';
-import { renderDiamond } from './simple-basic-shapes';
+import {
+ renderDiamond,
+ renderRectangle,
+ renderLine,
+} from './simple-basic-shapes';
import { renderAccordion } from './simple-rich-components/accordion.renderer';
+
export const renderShapeComponent = (
shape: ShapeModel,
shapeRenderedProps: ShapeRendererProps
@@ -66,6 +70,8 @@ export const renderShapeComponent = (
return renderVideoPlayer(shape, shapeRenderedProps);
case 'diamond':
return renderDiamond(shape, shapeRenderedProps);
+ case 'line':
+ return renderLine(shape, shapeRenderedProps);
case 'accordion':
return renderAccordion(shape, shapeRenderedProps);
default:
diff --git a/src/pods/canvas/shape-renderer/simple-basic-shapes/index.ts b/src/pods/canvas/shape-renderer/simple-basic-shapes/index.ts
index 10ef35f9..df9b02af 100644
--- a/src/pods/canvas/shape-renderer/simple-basic-shapes/index.ts
+++ b/src/pods/canvas/shape-renderer/simple-basic-shapes/index.ts
@@ -1,2 +1,3 @@
export * from './rectangle.rerender';
export * from './diamond.renderer';
+export * from './line.renderer';
diff --git a/src/pods/canvas/shape-renderer/simple-basic-shapes/line.renderer.tsx b/src/pods/canvas/shape-renderer/simple-basic-shapes/line.renderer.tsx
new file mode 100644
index 00000000..edb7f647
--- /dev/null
+++ b/src/pods/canvas/shape-renderer/simple-basic-shapes/line.renderer.tsx
@@ -0,0 +1,30 @@
+import { LineShape } from '@/common/components/front-basic-sapes';
+import { ShapeRendererProps } from '../model';
+import { ShapeModel } from '@/core/model';
+
+export const renderLine = (
+ shape: ShapeModel,
+ shapeRenderedProps: ShapeRendererProps
+) => {
+ const { handleSelected, shapeRefs, handleDragEnd, handleTransform } =
+ shapeRenderedProps;
+
+ return (
+
+ );
+};
diff --git a/src/pods/canvas/use-transform.hook.ts b/src/pods/canvas/use-transform.hook.ts
index 7a3fc66c..9682d974 100644
--- a/src/pods/canvas/use-transform.hook.ts
+++ b/src/pods/canvas/use-transform.hook.ts
@@ -1,18 +1,35 @@
-import { Node, NodeConfig } from 'konva/lib/Node';
import { Box } from 'konva/lib/shapes/Transformer';
-import { Coord, ShapeType, Size } from '@/core/model';
-
-interface TransFormSelectedInfo {
- selectedShapeRef: React.MutableRefObject | null>;
- selectedShapeId: string;
- selectedShapeType: ShapeType | null;
-}
+import { Coord, Size } from '@/core/model';
+import { useEffect } from 'react';
+import { useCanvasContext } from '@/core/providers';
export const useTransform = (
- updateShapeSizeAndPosition: (id: string, position: Coord, size: Size) => void,
- transformSelectedInfo: TransFormSelectedInfo
+ updateShapeSizeAndPosition: (id: string, position: Coord, size: Size) => void
) => {
- const { selectedShapeId, selectedShapeRef } = transformSelectedInfo;
+ const { selectedShapeId, selectedShapeRef, transformerRef } =
+ useCanvasContext().selectionInfo;
+
+ useEffect(() => {
+ const selectedShape = selectedShapeRef.current;
+ const transformer = transformerRef.current;
+ if (selectedShape && transformer) {
+ const hasLateralTransformer = selectedShape.attrs.hasLateralTransformer;
+ if (hasLateralTransformer) {
+ transformerRef.current.enabledAnchors(['middle-left', 'middle-right']);
+ } else {
+ transformerRef.current.enabledAnchors([
+ 'top-left',
+ 'top-center',
+ 'top-right',
+ 'middle-left',
+ 'middle-right',
+ 'bottom-left',
+ 'bottom-center',
+ 'bottom-right',
+ ]);
+ }
+ }
+ }, [selectedShapeId]);
const handleTransform = () => {
const node = selectedShapeRef.current;