From 32522a135ab0fc3c211b3332c0b1ff0694d64e60 Mon Sep 17 00:00:00 2001 From: LeticiadelaOsa Date: Sat, 10 Aug 2024 18:50:41 +0200 Subject: [PATCH 01/10] Updating buttons with new configuration and splitting buttons into actions --- .../icons/delete-icon.component.tsx | 4 +- .../components/about-button/about-button.tsx | 12 ++--- .../delete-button/delete-button.tsx | 3 +- .../export-button/export-button.tsx | 11 ++-- .../components/new-button/new-button.tsx | 14 ++--- .../components/open-button/open-button.tsx | 14 ++--- .../components/redo-button/redo-button.tsx | 14 ++--- .../components/save-button/save-button.tsx | 12 +++-- .../components/toolbar-button/index.ts | 1 + .../toolbar-button/toolbar-button.tsx | 7 +-- .../components/undo-button/undo-button.tsx | 14 ++--- .../zoom-in-button/zoom-in-button.tsx | 11 ++-- .../zoom-out-component/zoom-out-button.tsx | 11 ++-- src/pods/toolbar/shortcut/shortcut.hook.tsx | 4 +- src/pods/toolbar/toolbar.pod.module.css | 15 +++++- src/pods/toolbar/toolbar.pod.tsx | 52 ++++++++++++++----- 16 files changed, 112 insertions(+), 87 deletions(-) create mode 100644 src/pods/toolbar/components/toolbar-button/index.ts diff --git a/src/common/components/icons/delete-icon.component.tsx b/src/common/components/icons/delete-icon.component.tsx index f991af72..a1f387b0 100644 --- a/src/common/components/icons/delete-icon.component.tsx +++ b/src/common/components/icons/delete-icon.component.tsx @@ -2,8 +2,8 @@ export const DeleteIcon = () => { return ( { }; return ( - - - About Us - + } + label="About" + /> ); }; - -export default AboutButton; diff --git a/src/pods/toolbar/components/delete-button/delete-button.tsx b/src/pods/toolbar/components/delete-button/delete-button.tsx index 0d66e544..bebb53ba 100644 --- a/src/pods/toolbar/components/delete-button/delete-button.tsx +++ b/src/pods/toolbar/components/delete-button/delete-button.tsx @@ -1,5 +1,5 @@ import { DeleteIcon } from '@/common/components/icons/delete-icon.component'; -import { ToolbarButton } from '@/pods/toolbar/components/toolbar-button/toolbar-button'; +import { ToolbarButton } from '../toolbar-button'; import classes from '@/pods/toolbar/toolbar.pod.module.css'; import { useCanvasContext } from '@/core/providers'; import { SHORTCUTS } from '../../shortcut/shortcut.const'; @@ -21,7 +21,6 @@ export const DeleteButton = () => { className={classes.button} disabled={!selectionInfo.selectedShapeId} shortcutOptions={SHORTCUTS.delete} - children={<>} /> ); }; diff --git a/src/pods/toolbar/components/export-button/export-button.tsx b/src/pods/toolbar/components/export-button/export-button.tsx index 0ae6bcf1..668f9f34 100644 --- a/src/pods/toolbar/components/export-button/export-button.tsx +++ b/src/pods/toolbar/components/export-button/export-button.tsx @@ -1,9 +1,9 @@ import { ExportIcon } from '@/common/components/icons/export-icon.component'; import { useCanvasContext } from '@/core/providers'; -import ToolbarButton from '@/pods/toolbar/components/toolbar-button/toolbar-button'; import classes from '@/pods/toolbar/toolbar.pod.module.css'; import { Stage } from 'konva/lib/Stage'; import { calculateCanvasBounds } from './export-button.utils'; +import { ToolbarButton } from '../toolbar-button'; export const ExportButton = () => { const { stageRef, shapes } = useCanvasContext(); @@ -44,11 +44,8 @@ export const ExportButton = () => { onClick={handleExport} className={classes.button} disabled={shapes.length === 0} - > - - Export - + icon={} + label="Export" + /> ); }; - -export default ExportButton; diff --git a/src/pods/toolbar/components/new-button/new-button.tsx b/src/pods/toolbar/components/new-button/new-button.tsx index 87adb150..fa694298 100644 --- a/src/pods/toolbar/components/new-button/new-button.tsx +++ b/src/pods/toolbar/components/new-button/new-button.tsx @@ -1,7 +1,7 @@ import { NewIcon } from '@/common/components/icons/new-button.components'; -import ToolbarButton from '../toolbar-button/toolbar-button'; import classes from '@/pods/toolbar/toolbar.pod.module.css'; import { useCanvasContext } from '@/core/providers'; +import { ToolbarButton } from '../toolbar-button'; export const NewButton = () => { const { clearCanvas } = useCanvasContext(); @@ -11,11 +11,11 @@ export const NewButton = () => { }; return ( - - - New - + } + label="New" + /> ); }; - -export default NewButton; diff --git a/src/pods/toolbar/components/open-button/open-button.tsx b/src/pods/toolbar/components/open-button/open-button.tsx index 56ae929c..9984676c 100644 --- a/src/pods/toolbar/components/open-button/open-button.tsx +++ b/src/pods/toolbar/components/open-button/open-button.tsx @@ -1,5 +1,5 @@ import { OpenIcon } from '@/common/components/icons/open-icon.component'; -import ToolbarButton from '../toolbar-button/toolbar-button'; +import { ToolbarButton } from '../toolbar-button'; import classes from '@/pods/toolbar/toolbar.pod.module.css'; export const OpenButton = () => { @@ -8,11 +8,11 @@ export const OpenButton = () => { }; return ( - - - Open - + } + label="Open" + /> ); }; - -export default OpenButton; diff --git a/src/pods/toolbar/components/redo-button/redo-button.tsx b/src/pods/toolbar/components/redo-button/redo-button.tsx index b8ebcc19..f06e6436 100644 --- a/src/pods/toolbar/components/redo-button/redo-button.tsx +++ b/src/pods/toolbar/components/redo-button/redo-button.tsx @@ -1,6 +1,6 @@ import { RedoIcon } from '@/common/components/icons/redo-icon.component'; -import ToolbarButton from '../toolbar-button/toolbar-button'; import classes from '@/pods/toolbar/toolbar.pod.module.css'; +import { ToolbarButton } from '../toolbar-button'; export const RedoButton = () => { const handleClick = () => { @@ -8,11 +8,11 @@ export const RedoButton = () => { }; return ( - - - Redo - + } + label="Redo" + /> ); }; - -export default RedoButton; diff --git a/src/pods/toolbar/components/save-button/save-button.tsx b/src/pods/toolbar/components/save-button/save-button.tsx index b6abfb4b..46fa8042 100644 --- a/src/pods/toolbar/components/save-button/save-button.tsx +++ b/src/pods/toolbar/components/save-button/save-button.tsx @@ -1,6 +1,6 @@ import { SaveIcon } from '@/common/components/icons/save-icon.component'; -import ToolbarButton from '../toolbar-button/toolbar-button'; import classes from '@/pods/toolbar/toolbar.pod.module.css'; +import { ToolbarButton } from '../toolbar-button'; export const SaveButton = () => { const handleClick = () => { @@ -8,9 +8,11 @@ export const SaveButton = () => { }; return ( - - - Save - + } + label="Save" + /> ); }; diff --git a/src/pods/toolbar/components/toolbar-button/index.ts b/src/pods/toolbar/components/toolbar-button/index.ts new file mode 100644 index 00000000..0e445312 --- /dev/null +++ b/src/pods/toolbar/components/toolbar-button/index.ts @@ -0,0 +1 @@ +export * from './toolbar-button'; diff --git a/src/pods/toolbar/components/toolbar-button/toolbar-button.tsx b/src/pods/toolbar/components/toolbar-button/toolbar-button.tsx index 00cea662..b31ed027 100644 --- a/src/pods/toolbar/components/toolbar-button/toolbar-button.tsx +++ b/src/pods/toolbar/components/toolbar-button/toolbar-button.tsx @@ -1,9 +1,8 @@ -import useShortcut from '../../shortcut/shortcut.hook'; +import { useShortcut } from '../../shortcut/shortcut.hook'; /* import { isMacOS } from '@/common/helpers/platform.helpers'; */ import { ShortcutOptions } from '../../shortcut/shortcut.model'; interface Props { - children: React.ReactNode; onClick?: () => void; className?: string; disabled?: boolean; @@ -13,7 +12,6 @@ interface Props { } export const ToolbarButton: React.FC = props => { const { - children, onClick = () => {}, className, disabled, @@ -46,9 +44,6 @@ export const ToolbarButton: React.FC = props => { {tooltipText} )} */} - {children} ); }; - -export default ToolbarButton; diff --git a/src/pods/toolbar/components/undo-button/undo-button.tsx b/src/pods/toolbar/components/undo-button/undo-button.tsx index d695bdea..f73a4955 100644 --- a/src/pods/toolbar/components/undo-button/undo-button.tsx +++ b/src/pods/toolbar/components/undo-button/undo-button.tsx @@ -1,6 +1,6 @@ import { UndoIcon } from '@/common/components/icons/undo-icon.component'; -import ToolbarButton from '../toolbar-button/toolbar-button'; import classes from '@/pods/toolbar/toolbar.pod.module.css'; +import { ToolbarButton } from '../toolbar-button/toolbar-button'; export const UndoButton = () => { const handleClick = () => { @@ -8,11 +8,11 @@ export const UndoButton = () => { }; return ( - - - Undo - + } + label="Undo" + /> ); }; - -export default UndoButton; diff --git a/src/pods/toolbar/components/zoom-in-button/zoom-in-button.tsx b/src/pods/toolbar/components/zoom-in-button/zoom-in-button.tsx index de46ee0b..62eb96d1 100644 --- a/src/pods/toolbar/components/zoom-in-button/zoom-in-button.tsx +++ b/src/pods/toolbar/components/zoom-in-button/zoom-in-button.tsx @@ -1,7 +1,7 @@ -import ToolbarButton from '../toolbar-button/toolbar-button'; import classes from '@/pods/toolbar/toolbar.pod.module.css'; import { ZoomInIcon } from '@/common/components/icons/zoom-in.component'; import { useCanvasContext } from '@/core/providers'; +import { ToolbarButton } from '../toolbar-button'; export const ZoomInButton = () => { const { scale, setScale } = useCanvasContext(); @@ -17,11 +17,8 @@ export const ZoomInButton = () => { onClick={handleClick} className={classes.button} disabled={isDisabled} - > - - Zoom In - + icon={} + label="Zoom In" + /> ); }; - -export default ZoomInButton; diff --git a/src/pods/toolbar/components/zoom-out-component/zoom-out-button.tsx b/src/pods/toolbar/components/zoom-out-component/zoom-out-button.tsx index 22023cca..7047806f 100644 --- a/src/pods/toolbar/components/zoom-out-component/zoom-out-button.tsx +++ b/src/pods/toolbar/components/zoom-out-component/zoom-out-button.tsx @@ -1,7 +1,7 @@ import { ZoomOutIcon } from '@/common/components/icons/zoom-out.component'; -import ToolbarButton from '../toolbar-button/toolbar-button'; import classes from '@/pods/toolbar/toolbar.pod.module.css'; import { useCanvasContext } from '@/core/providers'; +import { ToolbarButton } from '../toolbar-button'; export const ZoomOutButton = () => { const { scale, setScale } = useCanvasContext(); @@ -17,11 +17,8 @@ export const ZoomOutButton = () => { onClick={handleClick} className={classes.button} disabled={isDisabled} - > - - Zoom Out - + icon={} + label="Zoom Out" + /> ); }; - -export default ZoomOutButton; diff --git a/src/pods/toolbar/shortcut/shortcut.hook.tsx b/src/pods/toolbar/shortcut/shortcut.hook.tsx index 0c10da62..f4d171ce 100644 --- a/src/pods/toolbar/shortcut/shortcut.hook.tsx +++ b/src/pods/toolbar/shortcut/shortcut.hook.tsx @@ -6,7 +6,7 @@ export interface ShortcutHookProps { callback: () => void; } -const useShortcut = ({ targetKey, callback }: ShortcutHookProps) => { +export const useShortcut = ({ targetKey, callback }: ShortcutHookProps) => { const handleKeyPress = (event: KeyboardEvent) => { const isAltKeyPressed = event.getModifierState('Alt'); const isCtrlKeyPressed = event.getModifierState('Control'); @@ -31,5 +31,3 @@ const useShortcut = ({ targetKey, callback }: ShortcutHookProps) => { }; }, [targetKey, callback]); }; - -export default useShortcut; diff --git a/src/pods/toolbar/toolbar.pod.module.css b/src/pods/toolbar/toolbar.pod.module.css index 6e986d0e..89c1d812 100644 --- a/src/pods/toolbar/toolbar.pod.module.css +++ b/src/pods/toolbar/toolbar.pod.module.css @@ -1,10 +1,21 @@ .container { grid-area: toolbar; display: flex; - justify-content: space-evenly; - padding: var(--space-s); + justify-content: space-between; + padding: var(--space-s) var(--space-md); background-color: var(--primary-100); border-bottom: 1px solid var(--primary-900); + ul { + padding: 0; + margin: 0; + list-style: none; + } +} + +.buttonGroup { + display: flex; + justify-content: space-between; + gap: var(--space-xl); } .button { diff --git a/src/pods/toolbar/toolbar.pod.tsx b/src/pods/toolbar/toolbar.pod.tsx index ec08b634..4b10d54c 100644 --- a/src/pods/toolbar/toolbar.pod.tsx +++ b/src/pods/toolbar/toolbar.pod.tsx @@ -14,17 +14,45 @@ import classes from './toolbar.pod.module.css'; export const ToolbarPod: React.FC = () => { return ( -
- - - - - - - - - - -
+
+
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
    +
  • + +
  • +
  • + +
  • +
+
    +
  • + +
  • +
+
); }; From 36959c5f9f03378d145646f3464b05cf67753268 Mon Sep 17 00:00:00 2001 From: Braulio Date: Sat, 10 Aug 2024 20:58:55 +0200 Subject: [PATCH 02/10] very basic svg and drop --- public/rich-components/accordion.svg | 17 +++ .../front-rich-components/accordion.tsx | 100 ++++++++++++++++++ .../components/front-rich-components/index.ts | 1 + src/core/model/index.ts | 3 +- src/pods/canvas/shape-renderer/index.tsx | 3 + .../accordion.renderer.tsx | 29 +++++ .../rich-components-gallery-data/index.ts | 1 + 7 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 public/rich-components/accordion.svg create mode 100644 src/common/components/front-rich-components/accordion.tsx create mode 100644 src/pods/canvas/shape-renderer/simple-rich-components/accordion.renderer.tsx diff --git a/public/rich-components/accordion.svg b/public/rich-components/accordion.svg new file mode 100644 index 00000000..3541a93e --- /dev/null +++ b/public/rich-components/accordion.svg @@ -0,0 +1,17 @@ + + + + + + Section 1 + + + + Content of section 1 + + + + + + Section 2 + \ No newline at end of file diff --git a/src/common/components/front-rich-components/accordion.tsx b/src/common/components/front-rich-components/accordion.tsx new file mode 100644 index 00000000..3d349514 --- /dev/null +++ b/src/common/components/front-rich-components/accordion.tsx @@ -0,0 +1,100 @@ +import { Group, Line, Path, Rect, Text } from 'react-konva'; +import { ShapeSizeRestrictions } from '@/core/model'; +import { forwardRef } from 'react'; +import { ShapeProps } from '../front-components/shape.model'; +import { fitSizeToShapeSizeRestrictions } from '@/common/utils/shapes/shape-restrictions'; + +const accordionShapeSizeRestrictions: ShapeSizeRestrictions = { + minWidth: 280, + minHeight: 200, + maxWidth: -1, + maxHeight: -1, + defaultWidth: 280, + defaultHeight: 200, +}; + +export const getAccordionShapeSizeRestrictions = (): ShapeSizeRestrictions => + accordionShapeSizeRestrictions; + +export const AccordionShape = forwardRef( + ({ x, y, width, height, id, onSelected, ...shapeProps }, ref) => { + const { width: restrictedWidth, height: restrictedHeight } = + fitSizeToShapeSizeRestrictions( + accordionShapeSizeRestrictions, + width, + height + ); + + return ( + onSelected(id, 'accordion')} + > + + {/* down arrow triangle */} + + + + {/* Contenido de la sección 1 */} + + + + {/* Sección 2: Colapsada */} + + {/* Right arrow triangle */} + + + + ); + } +); diff --git a/src/common/components/front-rich-components/index.ts b/src/common/components/front-rich-components/index.ts index f0ab1146..905e2136 100644 --- a/src/common/components/front-rich-components/index.ts +++ b/src/common/components/front-rich-components/index.ts @@ -1 +1,2 @@ export * from './video-player'; +export * from './accordion'; diff --git a/src/core/model/index.ts b/src/core/model/index.ts index dadd8f19..7a07f20c 100644 --- a/src/core/model/index.ts +++ b/src/core/model/index.ts @@ -26,7 +26,8 @@ export type ShapeType = | 'radiobutton' | 'rectangle' | 'videoPlayer' - | 'diamond'; + | 'diamond' + | 'accordion'; /* | "text"| "button" | "radio" | "image"*/ export type EditType = 'input' | 'textarea'; diff --git a/src/pods/canvas/shape-renderer/index.tsx b/src/pods/canvas/shape-renderer/index.tsx index 89a21433..facedc6c 100644 --- a/src/pods/canvas/shape-renderer/index.tsx +++ b/src/pods/canvas/shape-renderer/index.tsx @@ -23,6 +23,7 @@ import { import { renderRectangle } from './simple-basic-shapes/rectangle.rerender'; import { renderVideoPlayer } from './simple-rich-components'; import { renderDiamond } from './simple-basic-shapes'; +import { renderAccordion } from './simple-rich-components/accordion.renderer'; export const renderShapeComponent = ( shape: ShapeModel, @@ -65,6 +66,8 @@ export const renderShapeComponent = ( return renderVideoPlayer(shape, shapeRenderedProps); case 'diamond': return renderDiamond(shape, shapeRenderedProps); + case 'accordion': + return renderAccordion(shape, shapeRenderedProps); default: return renderNotFound(shape, shapeRenderedProps); } diff --git a/src/pods/canvas/shape-renderer/simple-rich-components/accordion.renderer.tsx b/src/pods/canvas/shape-renderer/simple-rich-components/accordion.renderer.tsx new file mode 100644 index 00000000..0855e5bf --- /dev/null +++ b/src/pods/canvas/shape-renderer/simple-rich-components/accordion.renderer.tsx @@ -0,0 +1,29 @@ +import { AccordionShape } from '@/common/components/front-rich-components'; +import { ShapeRendererProps } from '../model'; +import { ShapeModel } from '@/core/model'; + +export const renderAccordion = ( + shape: ShapeModel, + shapeRenderedProps: ShapeRendererProps +) => { + const { handleSelected, shapeRefs, handleDragEnd, handleTransform } = + shapeRenderedProps; + + return ( + + ); +}; diff --git a/src/pods/rich-components-gallery/rich-components-gallery-data/index.ts b/src/pods/rich-components-gallery/rich-components-gallery-data/index.ts index 19d3d76d..88cf4851 100644 --- a/src/pods/rich-components-gallery/rich-components-gallery-data/index.ts +++ b/src/pods/rich-components-gallery/rich-components-gallery-data/index.ts @@ -2,4 +2,5 @@ import { ItemInfo } from '@/common/components/gallery/components/model'; export const mockRichComponentsCollection: ItemInfo[] = [ { thumbnailSrc: '/rich-components/videoPlayer.svg', type: 'videoPlayer' }, + { thumbnailSrc: '/rich-components/accordion.svg', type: 'accordion' }, ]; From 25e937229f21de8595652fe55d942db2779a2a00 Mon Sep 17 00:00:00 2001 From: Braulio Date: Sun, 11 Aug 2024 09:59:56 +0200 Subject: [PATCH 03/10] body included at the end --- .../front-rich-components/accordion.tsx | 204 ++++++++++++------ .../components/accordion-body.component.tsx | 28 +++ src/pods/canvas/canvas.model.ts | 4 + .../simple-component/textarea.renderer.tsx | 2 +- .../accordion.renderer.tsx | 3 + 5 files changed, 175 insertions(+), 66 deletions(-) create mode 100644 src/common/components/front-rich-components/components/accordion-body.component.tsx diff --git a/src/common/components/front-rich-components/accordion.tsx b/src/common/components/front-rich-components/accordion.tsx index 3d349514..97e79e4c 100644 --- a/src/common/components/front-rich-components/accordion.tsx +++ b/src/common/components/front-rich-components/accordion.tsx @@ -1,30 +1,74 @@ -import { Group, Line, Path, Rect, Text } from 'react-konva'; +import { Group, Line, Rect, Text } from 'react-konva'; import { ShapeSizeRestrictions } from '@/core/model'; -import { forwardRef } from 'react'; +import { forwardRef, useEffect, useMemo, useState } from 'react'; import { ShapeProps } from '../front-components/shape.model'; import { fitSizeToShapeSizeRestrictions } from '@/common/utils/shapes/shape-restrictions'; +import { AccordionBody } from './components/accordion-body.component'; const accordionShapeSizeRestrictions: ShapeSizeRestrictions = { - minWidth: 280, - minHeight: 200, + minWidth: 315, + minHeight: 225, maxWidth: -1, maxHeight: -1, - defaultWidth: 280, - defaultHeight: 200, + defaultWidth: 315, + defaultHeight: 225, }; export const getAccordionShapeSizeRestrictions = (): ShapeSizeRestrictions => accordionShapeSizeRestrictions; +const singleHeaderHeight = 50; +const minimumAccordionBodyHeight = 50; + export const AccordionShape = forwardRef( - ({ x, y, width, height, id, onSelected, ...shapeProps }, ref) => { - const { width: restrictedWidth, height: restrictedHeight } = - fitSizeToShapeSizeRestrictions( + ({ x, y, width, height, id, onSelected, text, ...shapeProps }, ref) => { + const [sections, setSections] = useState([ + 'Sección A', + 'Sección B', + ]); + const [selectedSectionIndex, setSelectedSectionIndex] = useState(0); + + useEffect(() => { + if (text) { + const sections = text.split('\n'); + setSections(sections); + // right now let's set a default value, TODO enhance this + setSelectedSectionIndex(0); + } else { + setSections([]); + } + }, [text]); + + const accordionSelectedBodyHeight = useMemo(() => { + const accordionsHeadersHeight = singleHeaderHeight * sections.length; + let accordionSelectedBodyHeight = height - accordionsHeadersHeight; + + if (accordionSelectedBodyHeight < 0) { + accordionSelectedBodyHeight = minimumAccordionBodyHeight; + } + + return accordionSelectedBodyHeight; + }, [sections, height]); + + const calculateDynamicContentSizeRestriction = () => { + // Accordion section height: + const accordionsHeadersHeight = singleHeaderHeight * sections.length; + + const restrictedSize = fitSizeToShapeSizeRestrictions( accordionShapeSizeRestrictions, width, height ); + restrictedSize.height = + accordionsHeadersHeight + accordionSelectedBodyHeight; + + return restrictedSize; + }; + + const { width: restrictedWidth, height: restrictedHeight } = + calculateDynamicContentSizeRestriction(); + return ( ( height={restrictedHeight} {...shapeProps} onClick={() => onSelected(id, 'accordion')} + fill="black" > - - {/* down arrow triangle */} - - - - {/* Contenido de la sección 1 */} - ( + <> + + + + ))} + - - - {/* Sección 2: Colapsada */} - - {/* Right arrow triangle */} - - ); } ); + +// +// {/* down arrow triangle */} +// +// + +// {/* Contenido de la sección 1 */} +// +// + +// {/* Sección 2: Colapsada */} +// +// {/* Right arrow triangle */} +// +// diff --git a/src/common/components/front-rich-components/components/accordion-body.component.tsx b/src/common/components/front-rich-components/components/accordion-body.component.tsx new file mode 100644 index 00000000..233aa9d3 --- /dev/null +++ b/src/common/components/front-rich-components/components/accordion-body.component.tsx @@ -0,0 +1,28 @@ +import { forwardRef } from 'react'; +import { Group, Rect } from 'react-konva'; +import { ShapeProps } from '../../front-components/shape.model'; + +export const AccordionBody = forwardRef( + ({ x, y, width, height, ...shapeProps }, ref) => { + return ( + + + + ); + } +); diff --git a/src/pods/canvas/canvas.model.ts b/src/pods/canvas/canvas.model.ts index eb1bfa90..d7375755 100644 --- a/src/pods/canvas/canvas.model.ts +++ b/src/pods/canvas/canvas.model.ts @@ -119,6 +119,7 @@ const doesShapeAllowInlineEdition = (shapeType: ShapeType): boolean => { case 'combobox': case 'button': case 'textarea': + case 'accordion': return true; default: return false; @@ -137,6 +138,8 @@ const generateDefaultTextValue = (shapeType: ShapeType): string | undefined => { return 'Click Me!'; case 'textarea': return 'Your text here...'; + case 'accordion': + return 'Section A\nSection B'; default: return undefined; } @@ -147,6 +150,7 @@ const getShapeEditInlineType = (shapeType: ShapeType): EditType | undefined => { switch (shapeType) { case 'textarea': + case 'accordion': return 'textarea'; break; } diff --git a/src/pods/canvas/shape-renderer/simple-component/textarea.renderer.tsx b/src/pods/canvas/shape-renderer/simple-component/textarea.renderer.tsx index 3bc2ce5f..85d0aa9b 100644 --- a/src/pods/canvas/shape-renderer/simple-component/textarea.renderer.tsx +++ b/src/pods/canvas/shape-renderer/simple-component/textarea.renderer.tsx @@ -25,7 +25,7 @@ export const renderTextArea = ( onTransform={handleTransform} onTransformEnd={handleTransform} editType={shape.editType} - isEditable={shape.editType} + isEditable={true} text={shape.text} /> ); diff --git a/src/pods/canvas/shape-renderer/simple-rich-components/accordion.renderer.tsx b/src/pods/canvas/shape-renderer/simple-rich-components/accordion.renderer.tsx index 0855e5bf..a3024a24 100644 --- a/src/pods/canvas/shape-renderer/simple-rich-components/accordion.renderer.tsx +++ b/src/pods/canvas/shape-renderer/simple-rich-components/accordion.renderer.tsx @@ -24,6 +24,9 @@ export const renderAccordion = ( onDragEnd={handleDragEnd(shape.id)} onTransform={handleTransform} onTransformEnd={handleTransform} + editType={shape.editType} + isEditable={true} + text={shape.text} /> ); }; From bd1c3842b4c8f8d69fcac7baab598019ec312952 Mon Sep 17 00:00:00 2001 From: Braulio Date: Sun, 11 Aug 2024 12:28:30 +0200 Subject: [PATCH 04/10] basic refactor accordion --- .../accordion.business.ts | 36 +++++ .../front-rich-components/accordion.tsx | 125 +++--------------- .../accordion-all-parts.component.tsx | 50 +++++++ .../components/accordion-header.component.tsx | 36 +++++ .../front-rich-components/components/index.ts | 1 + 5 files changed, 140 insertions(+), 108 deletions(-) create mode 100644 src/common/components/front-rich-components/accordion.business.ts create mode 100644 src/common/components/front-rich-components/components/accordion-all-parts.component.tsx create mode 100644 src/common/components/front-rich-components/components/accordion-header.component.tsx create mode 100644 src/common/components/front-rich-components/components/index.ts diff --git a/src/common/components/front-rich-components/accordion.business.ts b/src/common/components/front-rich-components/accordion.business.ts new file mode 100644 index 00000000..5a4bd604 --- /dev/null +++ b/src/common/components/front-rich-components/accordion.business.ts @@ -0,0 +1,36 @@ +import { fitSizeToShapeSizeRestrictions } from '@/common/utils/shapes/shape-restrictions'; +import { ShapeSizeRestrictions } from '@/core/model'; + +interface SizeInfo { + width: number; + height: number; + singleHeaderHeight: number; + accordionShapeSizeRestrictions: ShapeSizeRestrictions; + accordionSelectedBodyHeight: number; +} + +export const calculateDynamicContentSizeRestriction = ( + sections: string[], + sizeInfo: SizeInfo +) => { + const { + width, + height, + singleHeaderHeight, + accordionShapeSizeRestrictions, + accordionSelectedBodyHeight, + } = sizeInfo; + + // Accordion section height: + const accordionsHeadersHeight = singleHeaderHeight * sections.length; + + const restrictedSize = fitSizeToShapeSizeRestrictions( + accordionShapeSizeRestrictions, + width, + height + ); + + restrictedSize.height = accordionsHeadersHeight + accordionSelectedBodyHeight; + + return restrictedSize; +}; diff --git a/src/common/components/front-rich-components/accordion.tsx b/src/common/components/front-rich-components/accordion.tsx index 97e79e4c..d2e895a9 100644 --- a/src/common/components/front-rich-components/accordion.tsx +++ b/src/common/components/front-rich-components/accordion.tsx @@ -1,9 +1,9 @@ -import { Group, Line, Rect, Text } from 'react-konva'; +import { Group } from 'react-konva'; import { ShapeSizeRestrictions } from '@/core/model'; import { forwardRef, useEffect, useMemo, useState } from 'react'; import { ShapeProps } from '../front-components/shape.model'; -import { fitSizeToShapeSizeRestrictions } from '@/common/utils/shapes/shape-restrictions'; -import { AccordionBody } from './components/accordion-body.component'; +import { AccordionAllParts } from './components'; +import { calculateDynamicContentSizeRestriction } from './accordion.business'; const accordionShapeSizeRestrictions: ShapeSizeRestrictions = { minWidth: 315, @@ -11,14 +11,14 @@ const accordionShapeSizeRestrictions: ShapeSizeRestrictions = { maxWidth: -1, maxHeight: -1, defaultWidth: 315, - defaultHeight: 225, + defaultHeight: 250, }; export const getAccordionShapeSizeRestrictions = (): ShapeSizeRestrictions => accordionShapeSizeRestrictions; const singleHeaderHeight = 50; -const minimumAccordionBodyHeight = 50; +const minimumAccordionBodyHeight = 60; export const AccordionShape = forwardRef( ({ x, y, width, height, id, onSelected, text, ...shapeProps }, ref) => { @@ -50,24 +50,14 @@ export const AccordionShape = forwardRef( return accordionSelectedBodyHeight; }, [sections, height]); - const calculateDynamicContentSizeRestriction = () => { - // Accordion section height: - const accordionsHeadersHeight = singleHeaderHeight * sections.length; - - const restrictedSize = fitSizeToShapeSizeRestrictions( - accordionShapeSizeRestrictions, - width, - height - ); - - restrictedSize.height = - accordionsHeadersHeight + accordionSelectedBodyHeight; - - return restrictedSize; - }; - const { width: restrictedWidth, height: restrictedHeight } = - calculateDynamicContentSizeRestriction(); + calculateDynamicContentSizeRestriction(sections, { + width, + height, + singleHeaderHeight, + accordionShapeSizeRestrictions, + accordionSelectedBodyHeight, + }); return ( ( onClick={() => onSelected(id, 'accordion')} fill="black" > - {sections.map((section, index) => ( - <> - - - - ))} - ); } ); - -// -// {/* down arrow triangle */} -// -// - -// {/* Contenido de la sección 1 */} -// -// - -// {/* Sección 2: Colapsada */} -// -// {/* Right arrow triangle */} -// -// diff --git a/src/common/components/front-rich-components/components/accordion-all-parts.component.tsx b/src/common/components/front-rich-components/components/accordion-all-parts.component.tsx new file mode 100644 index 00000000..62dcaeaf --- /dev/null +++ b/src/common/components/front-rich-components/components/accordion-all-parts.component.tsx @@ -0,0 +1,50 @@ +import { AccordionBody } from './accordion-body.component'; +import { AccordionHeader } from './accordion-header.component'; + +interface Props { + width: number; + singleHeaderHeight: number; + accordionSelectedBodyHeight: number; + sections: string[]; + selectedSectionIndex: number; +} + +export const AccordionAllParts: React.FC = props => { + const { + singleHeaderHeight, + accordionSelectedBodyHeight, + sections, + selectedSectionIndex, + width, + } = props; + + let accordionBodyAppliedOffset = 0; + + const renderAccordionBody = () => { + accordionBodyAppliedOffset = accordionSelectedBodyHeight; + return ( + + ); + }; + const renderAccordion = () => { + return sections.map((section, index) => ( + <> + + {selectedSectionIndex === index ? renderAccordionBody() : null} + + )); + }; + + return renderAccordion(); +}; diff --git a/src/common/components/front-rich-components/components/accordion-header.component.tsx b/src/common/components/front-rich-components/components/accordion-header.component.tsx new file mode 100644 index 00000000..f96051dd --- /dev/null +++ b/src/common/components/front-rich-components/components/accordion-header.component.tsx @@ -0,0 +1,36 @@ +import { forwardRef } from 'react'; +import { Group, Rect, Text } from 'react-konva'; +import { ShapeProps } from '../../front-components/shape.model'; + +export const AccordionHeader = forwardRef( + ({ x, y, width, height, text, ...shapeProps }, ref) => { + return ( + + + + + ); + } +); diff --git a/src/common/components/front-rich-components/components/index.ts b/src/common/components/front-rich-components/components/index.ts new file mode 100644 index 00000000..9a2b486d --- /dev/null +++ b/src/common/components/front-rich-components/components/index.ts @@ -0,0 +1 @@ +export * from './accordion-all-parts.component'; From 732a5e4dc9b9187488ddc96e5650ac45a0f96042 Mon Sep 17 00:00:00 2001 From: Braulio Date: Sun, 11 Aug 2024 12:44:05 +0200 Subject: [PATCH 05/10] selected working --- .../accordion.business.ts | 35 +++++++++++++++++++ .../front-rich-components/accordion.tsx | 9 +++-- .../accordion-all-parts.component.tsx | 6 ++-- .../components/triangle-lef.component.tsx | 16 +++++++++ 4 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 src/common/components/front-rich-components/components/triangle-lef.component.tsx diff --git a/src/common/components/front-rich-components/accordion.business.ts b/src/common/components/front-rich-components/accordion.business.ts index 5a4bd604..79a9409d 100644 --- a/src/common/components/front-rich-components/accordion.business.ts +++ b/src/common/components/front-rich-components/accordion.business.ts @@ -34,3 +34,38 @@ export const calculateDynamicContentSizeRestriction = ( return restrictedSize; }; + +interface SectionsInfo { + sections: string[]; + selectedSectionIndex: number; +} + +// TODO: Add Unit tests +// case 1 if text is empty just show default sections +// case 2 if text has 1 section, then show 1 section and selectedSectionIndex = 0 +// case 3 if text has 2 sections, and section to starts with [*] then show 2 sections and selectedSectionIndex = 1, and section with removed [*] +// case 4 if text has 2 sections, and no section to starts with [*] then show 2 sections and selectedSectionIndex = 0, and section with removed [*] +// ... +// If there are more than one section selected, pick the first one and remove the [*] from all of them +export const mapTextToSections = (text: string): SectionsInfo => { + if (!text) { + return { + sections: ['Section A', 'Section B'], + selectedSectionIndex: 0, + }; + } + + let sections: string[] = text.split('\n'); + + const selectedSectionIndex = sections.findIndex(section => + section.startsWith('[*]') + ); + + sections = sections.map(section => section.replace(/^\[\*\]/, '')); + + return { + sections, + selectedSectionIndex: + selectedSectionIndex === -1 ? 0 : selectedSectionIndex, + }; +}; diff --git a/src/common/components/front-rich-components/accordion.tsx b/src/common/components/front-rich-components/accordion.tsx index d2e895a9..81cbdcae 100644 --- a/src/common/components/front-rich-components/accordion.tsx +++ b/src/common/components/front-rich-components/accordion.tsx @@ -3,7 +3,10 @@ import { ShapeSizeRestrictions } from '@/core/model'; import { forwardRef, useEffect, useMemo, useState } from 'react'; import { ShapeProps } from '../front-components/shape.model'; import { AccordionAllParts } from './components'; -import { calculateDynamicContentSizeRestriction } from './accordion.business'; +import { + calculateDynamicContentSizeRestriction, + mapTextToSections, +} from './accordion.business'; const accordionShapeSizeRestrictions: ShapeSizeRestrictions = { minWidth: 315, @@ -30,10 +33,10 @@ export const AccordionShape = forwardRef( useEffect(() => { if (text) { - const sections = text.split('\n'); + const { sections, selectedSectionIndex } = mapTextToSections(text); setSections(sections); // right now let's set a default value, TODO enhance this - setSelectedSectionIndex(0); + setSelectedSectionIndex(selectedSectionIndex); } else { setSections([]); } diff --git a/src/common/components/front-rich-components/components/accordion-all-parts.component.tsx b/src/common/components/front-rich-components/components/accordion-all-parts.component.tsx index 62dcaeaf..c6d8bd40 100644 --- a/src/common/components/front-rich-components/components/accordion-all-parts.component.tsx +++ b/src/common/components/front-rich-components/components/accordion-all-parts.component.tsx @@ -20,12 +20,12 @@ export const AccordionAllParts: React.FC = props => { let accordionBodyAppliedOffset = 0; - const renderAccordionBody = () => { + const renderAccordionBody = (headerIndex: number) => { accordionBodyAppliedOffset = accordionSelectedBodyHeight; return ( @@ -41,7 +41,7 @@ export const AccordionAllParts: React.FC = props => { height={singleHeaderHeight} text={section} /> - {selectedSectionIndex === index ? renderAccordionBody() : null} + {selectedSectionIndex === index ? renderAccordionBody(index) : null} )); }; diff --git a/src/common/components/front-rich-components/components/triangle-lef.component.tsx b/src/common/components/front-rich-components/components/triangle-lef.component.tsx new file mode 100644 index 00000000..1e94aa38 --- /dev/null +++ b/src/common/components/front-rich-components/components/triangle-lef.component.tsx @@ -0,0 +1,16 @@ +import { Group, Line } from 'react-konva'; + +interface Props { + x: number; + y: number; +} + +export const TriangleLeft: React.FC = ({ x, y }) => { + const points = [x, y, x, y + 20, x + 20, y + 10]; + + return ( + + + + ); +}; From 9a81d2c7afd6e4e92b46c578d3846d2d679f738b Mon Sep 17 00:00:00 2001 From: Braulio Date: Sun, 11 Aug 2024 12:53:01 +0200 Subject: [PATCH 06/10] basics working --- .../accordion-all-parts.component.tsx | 1 + .../components/accordion-header.component.tsx | 12 +++++++--- .../components/triangle-down.component.tsx | 23 +++++++++++++++++++ .../triangle-selector.component.tsx | 18 +++++++++++++++ 4 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 src/common/components/front-rich-components/components/triangle-down.component.tsx create mode 100644 src/common/components/front-rich-components/components/triangle-selector.component.tsx diff --git a/src/common/components/front-rich-components/components/accordion-all-parts.component.tsx b/src/common/components/front-rich-components/components/accordion-all-parts.component.tsx index c6d8bd40..6b36c54e 100644 --- a/src/common/components/front-rich-components/components/accordion-all-parts.component.tsx +++ b/src/common/components/front-rich-components/components/accordion-all-parts.component.tsx @@ -40,6 +40,7 @@ export const AccordionAllParts: React.FC = props => { width={width} height={singleHeaderHeight} text={section} + isSelected={selectedSectionIndex === index} /> {selectedSectionIndex === index ? renderAccordionBody(index) : null} diff --git a/src/common/components/front-rich-components/components/accordion-header.component.tsx b/src/common/components/front-rich-components/components/accordion-header.component.tsx index f96051dd..2bc1a6e0 100644 --- a/src/common/components/front-rich-components/components/accordion-header.component.tsx +++ b/src/common/components/front-rich-components/components/accordion-header.component.tsx @@ -1,9 +1,14 @@ import { forwardRef } from 'react'; import { Group, Rect, Text } from 'react-konva'; import { ShapeProps } from '../../front-components/shape.model'; +import { TriangleSelector } from './triangle-selector.component'; -export const AccordionHeader = forwardRef( - ({ x, y, width, height, text, ...shapeProps }, ref) => { +interface Props extends ShapeProps { + isSelected: boolean; +} + +export const AccordionHeader = forwardRef( + ({ x, y, width, height, text, isSelected, ...shapeProps }, ref) => { return ( ( stroke="black" strokeWidth={2} /> + = props => { + const points = [ + props.x, + props.y, + props.x + 20, + props.y, + props.x + 10, + props.y + 20, + ]; + + return ( + + + + ); +}; diff --git a/src/common/components/front-rich-components/components/triangle-selector.component.tsx b/src/common/components/front-rich-components/components/triangle-selector.component.tsx new file mode 100644 index 00000000..ad01e132 --- /dev/null +++ b/src/common/components/front-rich-components/components/triangle-selector.component.tsx @@ -0,0 +1,18 @@ +import { TriangleDown } from './triangle-down.component'; +import { TriangleLeft } from './triangle-lef.component'; + +interface Props { + x: number; + y: number; + isSelected: boolean; +} + +export const TriangleSelector: React.FC = props => { + const { x, y, isSelected } = props; + + return isSelected ? ( + + ) : ( + + ); +}; From ed0c50ff265276909adb68eb5acc95cb97690365 Mon Sep 17 00:00:00 2001 From: Braulio Date: Sun, 11 Aug 2024 12:58:53 +0200 Subject: [PATCH 07/10] fixed default size accordion editing --- src/pods/canvas/canvas.model.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/pods/canvas/canvas.model.ts b/src/pods/canvas/canvas.model.ts index d7375755..ef7a0414 100644 --- a/src/pods/canvas/canvas.model.ts +++ b/src/pods/canvas/canvas.model.ts @@ -22,7 +22,10 @@ import { getDiamondShapeSizeRestrictions, getRectangleShapeSizeRestrictions, } from '@/common/components/front-basic-sapes'; -import { getVideoPlayerShapeSizeRestrictions } from '@/common/components/front-rich-components'; +import { + getAccordionShapeSizeRestrictions, + getVideoPlayerShapeSizeRestrictions, +} from '@/common/components/front-rich-components'; export const getDefaultSizeFromShape = (shapeType: ShapeType): Size => { switch (shapeType) { @@ -107,7 +110,15 @@ export const getDefaultSizeFromShape = (shapeType: ShapeType): Size => { width: getDiamondShapeSizeRestrictions().defaultWidth, height: getDiamondShapeSizeRestrictions().defaultHeight, }; + case 'accordion': + return { + width: getAccordionShapeSizeRestrictions().defaultWidth, + height: getAccordionShapeSizeRestrictions().defaultHeight, + }; default: + console.warn( + `** Shape ${shapeType} has not defined default size, check getDefaultSizeFromShape helper function` + ); return { width: 200, height: 50 }; } }; From f1c45a254baf49edd7d4ba00d9f82461011b2097 Mon Sep 17 00:00:00 2001 From: Braulio Date: Sun, 11 Aug 2024 13:01:10 +0200 Subject: [PATCH 08/10] basic version working --- .../components/accordion-all-parts.component.tsx | 7 ++++--- src/pods/canvas/canvas.model.ts | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/common/components/front-rich-components/components/accordion-all-parts.component.tsx b/src/common/components/front-rich-components/components/accordion-all-parts.component.tsx index 6b36c54e..37c34d0e 100644 --- a/src/common/components/front-rich-components/components/accordion-all-parts.component.tsx +++ b/src/common/components/front-rich-components/components/accordion-all-parts.component.tsx @@ -26,18 +26,19 @@ export const AccordionAllParts: React.FC = props => { ); }; const renderAccordion = () => { + const textMarginLeft = 10; return sections.map((section, index) => ( <> { case 'textarea': return 'Your text here...'; case 'accordion': - return 'Section A\nSection B'; + return '[*]Section A\nSection B'; default: return undefined; } From 3fbeb4207dc9e52663260b179e4a1d19ae00f646 Mon Sep 17 00:00:00 2001 From: Braulio Date: Sun, 11 Aug 2024 13:25:09 +0200 Subject: [PATCH 09/10] refactor --- .../accordion.business.ts | 23 +++++++++++++++++++ .../front-rich-components/accordion.tsx | 19 +++++++-------- .../accordion-all-parts.component.tsx | 5 ++-- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/src/common/components/front-rich-components/accordion.business.ts b/src/common/components/front-rich-components/accordion.business.ts index 79a9409d..f858a31c 100644 --- a/src/common/components/front-rich-components/accordion.business.ts +++ b/src/common/components/front-rich-components/accordion.business.ts @@ -69,3 +69,26 @@ export const mapTextToSections = (text: string): SectionsInfo => { selectedSectionIndex === -1 ? 0 : selectedSectionIndex, }; }; + +// TODO: Add unit tests +interface SelectedAccordionSizeInfo { + height: number; + minimumAccordionBodyHeight: number; + singleHeaderHeight: number; +} + +export const calculateSelectedAccordionHeight = ( + sections: string[], + sizeInfo: SelectedAccordionSizeInfo +) => { + const { height, minimumAccordionBodyHeight, singleHeaderHeight } = sizeInfo; + + const accordionsHeadersHeight = singleHeaderHeight * sections.length; + let accordionSelectedBodyHeight = height - accordionsHeadersHeight; + + if (accordionSelectedBodyHeight < 0) { + accordionSelectedBodyHeight = minimumAccordionBodyHeight; + } + + return accordionSelectedBodyHeight; +}; diff --git a/src/common/components/front-rich-components/accordion.tsx b/src/common/components/front-rich-components/accordion.tsx index 81cbdcae..dd7a0113 100644 --- a/src/common/components/front-rich-components/accordion.tsx +++ b/src/common/components/front-rich-components/accordion.tsx @@ -5,6 +5,7 @@ import { ShapeProps } from '../front-components/shape.model'; import { AccordionAllParts } from './components'; import { calculateDynamicContentSizeRestriction, + calculateSelectedAccordionHeight, mapTextToSections, } from './accordion.business'; @@ -26,8 +27,8 @@ const minimumAccordionBodyHeight = 60; export const AccordionShape = forwardRef( ({ x, y, width, height, id, onSelected, text, ...shapeProps }, ref) => { const [sections, setSections] = useState([ - 'Sección A', - 'Sección B', + '[*] Sectión A', + 'Sectión B', ]); const [selectedSectionIndex, setSelectedSectionIndex] = useState(0); @@ -35,7 +36,6 @@ export const AccordionShape = forwardRef( if (text) { const { sections, selectedSectionIndex } = mapTextToSections(text); setSections(sections); - // right now let's set a default value, TODO enhance this setSelectedSectionIndex(selectedSectionIndex); } else { setSections([]); @@ -43,14 +43,11 @@ export const AccordionShape = forwardRef( }, [text]); const accordionSelectedBodyHeight = useMemo(() => { - const accordionsHeadersHeight = singleHeaderHeight * sections.length; - let accordionSelectedBodyHeight = height - accordionsHeadersHeight; - - if (accordionSelectedBodyHeight < 0) { - accordionSelectedBodyHeight = minimumAccordionBodyHeight; - } - - return accordionSelectedBodyHeight; + return calculateSelectedAccordionHeight(sections, { + height, + minimumAccordionBodyHeight, + singleHeaderHeight, + }); }, [sections, height]); const { width: restrictedWidth, height: restrictedHeight } = diff --git a/src/common/components/front-rich-components/components/accordion-all-parts.component.tsx b/src/common/components/front-rich-components/components/accordion-all-parts.component.tsx index 37c34d0e..71e94b7e 100644 --- a/src/common/components/front-rich-components/components/accordion-all-parts.component.tsx +++ b/src/common/components/front-rich-components/components/accordion-all-parts.component.tsx @@ -22,11 +22,12 @@ export const AccordionAllParts: React.FC = props => { const renderAccordionBody = (headerIndex: number) => { accordionBodyAppliedOffset = accordionSelectedBodyHeight; + const marginLeft = 10; return ( ); From 08f9b53bdf236d6157caf3d8effd35cbd1853f93 Mon Sep 17 00:00:00 2001 From: Braulio Date: Sun, 11 Aug 2024 13:28:43 +0200 Subject: [PATCH 10/10] add unit tests issue --- public/rich-components/accordion.svg | 3 +-- .../components/front-rich-components/accordion.business.ts | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/public/rich-components/accordion.svg b/public/rich-components/accordion.svg index 3541a93e..1f1ec01e 100644 --- a/public/rich-components/accordion.svg +++ b/public/rich-components/accordion.svg @@ -7,8 +7,7 @@ - Content of section 1 - + diff --git a/src/common/components/front-rich-components/accordion.business.ts b/src/common/components/front-rich-components/accordion.business.ts index f858a31c..beacf84d 100644 --- a/src/common/components/front-rich-components/accordion.business.ts +++ b/src/common/components/front-rich-components/accordion.business.ts @@ -1,6 +1,8 @@ import { fitSizeToShapeSizeRestrictions } from '@/common/utils/shapes/shape-restrictions'; import { ShapeSizeRestrictions } from '@/core/model'; +// TODO: Add unit tests #169 + interface SizeInfo { width: number; height: number;