Skip to content

Commit

Permalink
feature/#440-Create-a-rich-text-paragraph-component
Browse files Browse the repository at this point in the history
  • Loading branch information
El-Mito-de-Giralda committed Dec 4, 2024
1 parent 2cb8737 commit dfcd849
Show file tree
Hide file tree
Showing 12 changed files with 244 additions and 3 deletions.
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions public/text/richtextparagraph.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from './normaltext-shape';
export * from './smalltext-shape';
export * from './paragraph-text-shape';
export * from './link-text-shape';
export * from './rich-text-paragraph';
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
/*import { forwardRef} from "react";
import { Text, Group } from "react-konva";
import { ShapeType } from "@/core/model";
import { ShapeSizeRestrictions } from "@/core/model";
import { BASIC_SHAPE } from '../front-components/shape.const';
import { ShapeProps } from "../shape.model";
import { fitSizeToShapeSizeRestrictions } from "@/common/utils/shapes";
import { useShapeProps } from "../../shapes/use-shape-props.hook";
import { useGroupShapeProps } from "../mock-components.utils";
interface LineSegment {
text: string;
bold: boolean;
italic: boolean;
}
export const richTextParagraphSizeRestrictions: ShapeSizeRestrictions = {
minWidth: 200,
minHeight: 70,
maxWidth: -1,
maxHeight: -1,
defaultWidth: 420,
defaultHeight: 260,
};
export const getRichTextParagraphSizeRestrictions = (): ShapeSizeRestrictions=>
richTextParagraphSizeRestrictions;
const shapeType: ShapeType = 'richTextParagraph';
export const RichTextParagraphShape = forwardRef<any,ShapeProps>(( props, ref ) => {
const {
x,
y,
width,
height,
id,
onSelected,
text,
otherProps,
...shapeProps
} = props;
const extractBoldSegments = (text: string): LineSegment[] => {
const segments: LineSegment[] = [];
let bold = false;
let italic = false;
let buffer = "";
for (let i = 0; i < text.length; i++) {
const word = text[i];
if (word === "*") {
bold= true;
if (bold) {
segments.push({ text: buffer, bold: true, italic: false });
buffer = "";
bold = false;
} else {
if (buffer) segments.push({ text: buffer, bold: false, italic: false });
buffer = "";
bold = true;
}
} else if (text[i] === "_") {
italic= true;
if (italic) {
segments.push({ text: buffer, bold: false, italic: true });
buffer = "";
italic = false;
} else {
if (buffer) segments.push({ text: buffer, bold: false, italic: false });
buffer = "";
italic = true;
}
} else {
buffer += text[i];
}
}
if (buffer) {
segments.push({ text: buffer, bold, italic });
}
return segments;
};
// Agrupar texto sin cortar palabras
const wrapTextWithSegments = (
segments: LineSegment[],
maxWidth: number,
font: string
): LineSegment[][] => {
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");
if (!context) return [];
context.font = font;
let currentLine: LineSegment[] = [];
const result: LineSegment[][] = [];
let lineWidth = 0;
segments.forEach(segment => {
const { text, bold, italic } = segment;
// Adjust font style for bold or italic
if (bold && italic) context.font = `italic bold ${font}`;
else if (bold) context.font = `bold ${font}`;
else if (italic) context.font = `italic ${font}`;
else context.font = font;
text.split(" ").forEach(word => {
const wordWidth = context.measureText(word + " ").width;
if (lineWidth + wordWidth > maxWidth) {
// Push current line to result and start a new line
result.push(currentLine);
currentLine = [];
lineWidth = 0;
}
// Add word to current line
currentLine.push({ text: word, bold, italic });
lineWidth += wordWidth;
});
});
if (currentLine.length > 0) {
result.push(currentLine);
}
return result;
};
const restrictedSize = fitSizeToShapeSizeRestrictions(
richTextParagraphSizeRestrictions,
width,
height
);
const { width: restrictedWidth, height: restrictedHeight } = restrictedSize;
const { textColor } = useShapeProps(otherProps, BASIC_SHAPE);
const commonGroupProps = useGroupShapeProps(
props,
restrictedSize,
shapeType,
ref
);
const lines = extractBoldSegments(text);
const wrappedLines = wrapTextWithSegments(lines, restrictedWidth, "16 px Arial" );
return (
<Group {...commonGroupProps} {...shapeProps}>
{lines.map((lineObj, lineIndex) => {
let currentX = 0; // Coordenada horizontal inicial para cada línea
const currentY = y + lineIndex * lineHeight; // Coordenada vertical de la línea
return (
<Group key={lineIndex}>
{lineObj.line.map((segment, segmentIndex) => {
const fontWeight = segment.bold ? "bold" : "normal";
const fontStyle = segment.italic ? "italic" : "normal";
const wordWidth = context.measureText(segment.text).width;
currentX += wordWidth;
return (
<Text
key={`${lineIndex}-${segmentIndex}`}
x={x + currentX} // Posición horizontal acumulada
y={currentY} // Posición vertical para la línea actual
text={segment.text}
fontFamily={BASIC_SHAPE.DEFAULT_FONT_FAMILY}
fontSize={14}
fill={textColor}
fontWeight={fontWeight}
fontStyle={fontStyle}
align="left"
verticalAlign="top"
wrap="none"
/>
);
})}
</Group>
);
})}
</Group>
);
}); */
2 changes: 2 additions & 0 deletions src/core/model/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export type ShapeType =
| 'normaltext'
| 'smalltext'
| 'paragraph'
| 'richTextParagraph'
| 'largeArrow'
| 'bar'
| 'triangle'
Expand Down Expand Up @@ -108,6 +109,7 @@ export const ShapeDisplayName: Record<ShapeType, string> = {
normaltext: 'Normal text',
smalltext: 'Small text',
paragraph: 'Paragraph',
richTextParagraph: 'Rich Text Paragraph',
link: 'Link',
triangle: 'Triangle',
'horizontal-menu': 'Horizontal Menu',
Expand Down
3 changes: 3 additions & 0 deletions src/pods/canvas/model/inline-editable.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const inlineEditableShapes = new Set<ShapeType>([
'normaltext',
'smalltext',
'paragraph',
'richTextParagraph',
'listbox',
'image',
'table',
Expand Down Expand Up @@ -63,6 +64,7 @@ const shapeTypesWithDefaultText = new Set<ShapeType>([
'normaltext',
'smalltext',
'paragraph',
'richTextParagraph',
'table',
'modal',
'appBar',
Expand Down Expand Up @@ -96,6 +98,7 @@ const defaultTextValueMap: Partial<Record<ShapeType, string>> = {
normaltext: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
smalltext: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
paragraph: `Lorem ipsum dolor sit amet, consectetur adipiscing elit.\nSed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\nUt enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\nDuis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\nExcepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.`,
richTextParagraph: `*This is a bold text* that is quite long to demonstrate word wrapping.\n_And this is italic text that is also quite long to demonstrate wrapping across multiple lines._\nNormal text can also be multiline.`,
table:
'Name ^, Age ^v, Country v\nJohn Doe, 30, USA\nJane Smith, 25, UK\nLuis Gomez, 35, Argentina\n{*L,20R,30C}',
modal:
Expand Down
1 change: 1 addition & 0 deletions src/pods/canvas/model/shape-other-props.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ export const generateDefaultOtherProps = (
textDecoration: `${INPUT_SHAPE.DEFAULT_TEXT_DECORATION}`,
};
case 'paragraph':
case 'richTextParagraph':
case 'label':
return {
textColor: '#000000',
Expand Down
2 changes: 2 additions & 0 deletions src/pods/canvas/model/shape-size.mapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import {
getLinkSizeRestrictions,
getNormaltextSizeRestrictions,
getParagraphSizeRestrictions,
getRichTextParagraphSizeRestrictions,
getSmalltextSizeRestrictions,
// other imports
} from '@/common/components/mock-components/front-text-components';
Expand Down Expand Up @@ -119,6 +120,7 @@ const shapeSizeMap: Record<ShapeType, () => ShapeSizeRestrictions> = {
normaltext: getNormaltextSizeRestrictions,
smalltext: getSmalltextSizeRestrictions,
paragraph: getParagraphSizeRestrictions,
richTextParagraph: getRichTextParagraphSizeRestrictions,
link: getLinkSizeRestrictions,
largeArrow: getLargeArrowShapeSizeRestrictions,
radiobutton: getRadioButtonShapeSizeRestrictions,
Expand Down
3 changes: 3 additions & 0 deletions src/pods/canvas/shape-renderer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import {
renderHeading3,
renderLink,
renderNormaltext,
renderRichTextParagraph,
} from './simple-text-components';
import { renderSmalltext } from './simple-text-components/smalltext.renderer';
import { renderParagraph } from './simple-text-components/paragraph.renderer';
Expand Down Expand Up @@ -152,6 +153,8 @@ export const renderShapeComponent = (
return renderSmalltext(shape, shapeRenderedProps);
case 'paragraph':
return renderParagraph(shape, shapeRenderedProps);
case 'richTextParagraph':
return renderRichTextParagraph(shape, shapeRenderedProps);
case 'link':
return renderLink(shape, shapeRenderedProps);
case 'largeArrow':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from './heading2.renderer';
export * from './heading3.renderer';
export * from './normaltext.renderer';
export * from './link.renderer';
export * from './richtextparagraph.renderer';
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*import { ShapeRendererProps } from '../model';
import { ShapeModel } from '@/core/model';
import { RichTextParagraphShape } from '@/common/components/mock-components/front-text-components';
import { Stage, Layer } from 'react-konva';
export const renderRichTextParagraph = (
shape: ShapeModel,
shapeRenderedProps: ShapeRendererProps
) => {
const { handleSelected, shapeRefs, handleDragEnd, handleTransform} =
shapeRenderedProps;
return (
<RichTextParagraphShape
id={shape.id}
key={shape.id}
ref={shapeRefs.current[shape.id]}
x={shape.x}
y={shape.y}
name="shape"
width={shape.width}
height={shape.height}
draggable
onSelected={handleSelected}
onDragEnd={handleDragEnd(shape.id)}
onTransform={handleTransform}
onTransformEnd={handleTransform}
editType={shape.editType}
isEditable={shape.allowsInlineEdition}
text={shape.text}
otherProps={shape.otherProps}
/>
);
};
*/
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ export const mockTextCollection: ItemInfo[] = [
{ thumbnailSrc: '/text/normaltext.svg', type: 'normaltext' },
{ thumbnailSrc: '/text/smalltext.svg', type: 'smalltext' },
{ thumbnailSrc: '/text/paragraph.svg', type: 'paragraph' },
{ thumbnailSrc: '/text/richtextparagraph.svg', type: 'richTextParagraph' },
];

0 comments on commit dfcd849

Please sign in to comment.