Skip to content

Commit 0cbf740

Browse files
authored
Merge pull request #763 from Lemoncode/feature/#754-create-scribble-paragraph-under-low-mock
Feature/#754 create scribble paragraph under low mock
2 parents 7b7d6b7 + beee89c commit 0cbf740

File tree

11 files changed

+179
-1
lines changed

11 files changed

+179
-1
lines changed
Lines changed: 27 additions & 0 deletions
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './paragraph-scribbled-shape';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { forwardRef, useMemo } from 'react';
2+
import { Group, Path, Rect } from 'react-konva';
3+
import { ShapeSizeRestrictions, ShapeType } from '@/core/model';
4+
import { ShapeProps } from '../../shape.model';
5+
import { useShapeProps } from '../../../shapes/use-shape-props.hook';
6+
import { BASIC_SHAPE } from '../../front-components/shape.const';
7+
import { useGroupShapeProps } from '../../mock-components.utils';
8+
import { fitSizeToShapeSizeRestrictions } from '@/common/utils/shapes';
9+
import { MIN_LINE_HEIGHT } from './paragraph-scribbled.const';
10+
import { calculateParagraphPaths } from './paragraph-scribbled.business';
11+
12+
const paragraphScribbledShapeRestrictions: ShapeSizeRestrictions = {
13+
minWidth: 100,
14+
minHeight: MIN_LINE_HEIGHT,
15+
maxWidth: -1,
16+
maxHeight: -1,
17+
defaultWidth: 300,
18+
defaultHeight: 150,
19+
};
20+
21+
export const getParagraphScribbledShapeRestrictions =
22+
(): ShapeSizeRestrictions => paragraphScribbledShapeRestrictions;
23+
24+
const shapeType: ShapeType = 'paragraphScribbled';
25+
26+
export const ParagraphScribbled = forwardRef<any, ShapeProps>((props, ref) => {
27+
const { width, height, id, otherProps, ...shapeProps } = props;
28+
29+
const { stroke } = useShapeProps(otherProps, BASIC_SHAPE);
30+
const commonGroupProps = useGroupShapeProps(
31+
props,
32+
{ width, height },
33+
shapeType,
34+
ref
35+
);
36+
37+
const restrictedSize = fitSizeToShapeSizeRestrictions(
38+
paragraphScribbledShapeRestrictions,
39+
width,
40+
height
41+
);
42+
43+
const { width: restrictedWidth, height: restrictedHeight } = restrictedSize;
44+
45+
const paths = useMemo(() => {
46+
return calculateParagraphPaths(restrictedWidth, restrictedHeight, id);
47+
}, [restrictedWidth, restrictedHeight, id]);
48+
49+
return (
50+
<Group {...commonGroupProps} {...shapeProps}>
51+
{paths.map((path, idx) => (
52+
<Path
53+
key={idx}
54+
data={path}
55+
stroke={stroke}
56+
strokeWidth={3}
57+
lineCap="round"
58+
lineJoin="round"
59+
/>
60+
))}
61+
<Rect
62+
width={restrictedSize.width}
63+
height={restrictedSize.height}
64+
stroke={stroke}
65+
strokeWidth={0}
66+
/>
67+
</Group>
68+
);
69+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { calculatePath } from '../text-scribbled-shape/text-scribbled.business';
2+
import { MIN_LINE_HEIGHT } from './paragraph-scribbled.const';
3+
4+
export const calculateParagraphPaths = (
5+
restrictedWidth: number,
6+
restrictedHeight: number,
7+
id: string
8+
): string[] => {
9+
// Calculate how many lines fit based on the height
10+
const numLines = Math.max(1, Math.trunc(restrictedHeight / MIN_LINE_HEIGHT));
11+
12+
return Array.from({ length: numLines }).map((_, i) => {
13+
const lineY = i * MIN_LINE_HEIGHT;
14+
const lineId = `${id}-${i}`;
15+
const rawPath = calculatePath(restrictedWidth, MIN_LINE_HEIGHT, lineId);
16+
17+
// Adjust the path to shift Y coordinate for each line
18+
// 🔍 Step by step:
19+
// The path assumes the text is vertically centered in a block of given height (e.g., 25px).
20+
// If you just drew this path multiple times, all lines would overlap.
21+
// To fix that, we shift the Y coordinate for each point in the path.
22+
//
23+
// Regular expression: /\d+,\d+/g
24+
// Finds all x,y coordinates in the path string (e.g., "10,12", "15,11").
25+
// We split each coordinate, convert y to number, add vertical offset (lineY),
26+
// then reassemble the coordinate string.
27+
const shiftedPath = rawPath.replace(/\d+,\d+/g, match => {
28+
const [xStr, yStr] = match.split(',');
29+
const x = parseFloat(xStr);
30+
const y = parseFloat(yStr) + lineY;
31+
return `${x},${y}`;
32+
});
33+
34+
return shiftedPath;
35+
});
36+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const MIN_LINE_HEIGHT = 25;

src/core/model/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ export type ShapeType =
8383
| 'ellipseLow'
8484
| 'rectangleLow'
8585
| 'circleLow'
86-
| 'textScribbled';
86+
| 'textScribbled'
87+
| 'paragraphScribbled';
8788

8889
export const ShapeDisplayName: Record<ShapeType, string> = {
8990
multiple: 'multiple',
@@ -156,6 +157,7 @@ export const ShapeDisplayName: Record<ShapeType, string> = {
156157
rectangleLow: 'Rectangle Placeholder',
157158
circleLow: 'Circle',
158159
textScribbled: 'Text Scribbled',
160+
paragraphScribbled: 'Paragraph Scribbled',
159161
};
160162

161163
export type EditType = 'input' | 'textarea' | 'imageupload';

src/pods/canvas/model/shape-size.mapper.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ import {
8787
getCircleLowShapeSizeRestrictions,
8888
getTextScribbledShapeRestrictions,
8989
} from '@/common/components/mock-components/front-low-wireframes-components';
90+
import { getParagraphScribbledShapeRestrictions } from '@/common/components/mock-components/front-low-wireframes-components/paragraph-scribbled-shape';
9091

9192
const getMultipleNodeSizeRestrictions = (): ShapeSizeRestrictions => ({
9293
minWidth: 0,
@@ -169,6 +170,7 @@ const shapeSizeMap: Record<ShapeType, () => ShapeSizeRestrictions> = {
169170
rectangleLow: getRectangleLowShapeRestrictions,
170171
circleLow: getCircleLowShapeSizeRestrictions,
171172
textScribbled: getTextScribbledShapeRestrictions,
173+
paragraphScribbled: getParagraphScribbledShapeRestrictions,
172174
};
173175

174176
export default shapeSizeMap;

src/pods/canvas/shape-renderer/index.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ import {
8181
renderEllipseLow,
8282
renderRectangleLow,
8383
renderTextScribbled,
84+
renderParagraphScribbled,
8485
} from './simple-low-wireframes-components';
8586

8687
export const renderShapeComponent = (
@@ -226,6 +227,8 @@ export const renderShapeComponent = (
226227
return renderCircleLow(shape, shapeRenderedProps);
227228
case 'textScribbled':
228229
return renderTextScribbled(shape, shapeRenderedProps);
230+
case 'paragraphScribbled':
231+
return renderParagraphScribbled(shape, shapeRenderedProps);
229232
default:
230233
return renderNotFound(shape, shapeRenderedProps);
231234
}

src/pods/canvas/shape-renderer/simple-low-wireframes-components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ export * from './low-vertical-line.renderer';
55
export * from './rectangle-low.renderer';
66
export * from './circle-low.renderer';
77
export * from './text-scribbled.renderer';
8+
export * from './paragraph-scribbled.renderer';
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { ShapeRendererProps } from '../model';
2+
import { ShapeModel } from '@/core/model';
3+
import { ParagraphScribbled } from '@/common/components/mock-components/front-low-wireframes-components/paragraph-scribbled-shape';
4+
5+
export const renderParagraphScribbled = (
6+
shape: ShapeModel,
7+
shapeRenderedProps: ShapeRendererProps
8+
) => {
9+
const { handleSelected, shapeRefs, handleDragEnd, handleTransform } =
10+
shapeRenderedProps;
11+
12+
return (
13+
<ParagraphScribbled
14+
id={shape.id}
15+
key={shape.id}
16+
ref={shapeRefs.current[shape.id]}
17+
x={shape.x}
18+
y={shape.y}
19+
name="shape"
20+
width={shape.width}
21+
height={shape.height}
22+
draggable
23+
typeOfTransformer={shape.typeOfTransformer}
24+
onSelected={handleSelected}
25+
onDragEnd={handleDragEnd(shape.id)}
26+
onTransform={handleTransform}
27+
onTransformEnd={handleTransform}
28+
text={shape.text || 'Scribbled Paragraph'}
29+
otherProps={shape.otherProps}
30+
/>
31+
);
32+
};

src/pods/galleries/low-wireframe-gallery/low-wireframe-gallery-data/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,8 @@ export const mockLowWireframeCollection: ItemInfo[] = [
2929
thumbnailSrc: '/low-wireframes/textScribbled.svg',
3030
type: 'textScribbled',
3131
},
32+
{
33+
thumbnailSrc: '/low-wireframes/paragraphScribbled.svg',
34+
type: 'paragraphScribbled',
35+
},
3236
];

0 commit comments

Comments
 (0)