diff --git a/public/rich-components/button-bar-group.svg b/public/rich-components/button-bar-group.svg new file mode 100644 index 00000000..ebb58963 --- /dev/null +++ b/public/rich-components/button-bar-group.svg @@ -0,0 +1,13 @@ + + + + Button 1 + + + + Button 2 + + + + Button 3 + \ No newline at end of file diff --git a/src/common/components/front-rich-components/buttonBar.tsx b/src/common/components/front-rich-components/buttonBar.tsx new file mode 100644 index 00000000..942a9f66 --- /dev/null +++ b/src/common/components/front-rich-components/buttonBar.tsx @@ -0,0 +1,100 @@ +import { ShapeSizeRestrictions } from '@/core/model'; +import { forwardRef, useMemo } from 'react'; +import { Group, Rect, Text } from 'react-konva'; +import { ShapeProps } from '../front-components/shape.model'; +import { fitSizeToShapeSizeRestrictions } from '@/common/utils/shapes/shape-restrictions'; + +const horizontalMenuShapeSizeRestrictions: ShapeSizeRestrictions = { + minWidth: 75, + minHeight: 25, + maxWidth: -1, + maxHeight: 100, + defaultWidth: 200, + defaultHeight: 50, +}; + +export const getButtonBarShapeSizeRestrictions = (): ShapeSizeRestrictions => + horizontalMenuShapeSizeRestrictions; + +export const ButtonBarShape = forwardRef( + ( + { x, y, width, height, id, onSelected, text, otherProps, ...shapeProps }, + ref + ) => { + const menuElements: string[] = text.split('\n'); + const numberOfItems = menuElements.length; + const minItemWidth = 100; + const itemSpacing = 20; + const totalWidth = Math.max( + minItemWidth * numberOfItems + itemSpacing * (numberOfItems + 1), + width + ); + const { width: restrictedWidth, height: restrictedHeight } = + fitSizeToShapeSizeRestrictions( + horizontalMenuShapeSizeRestrictions, + totalWidth, + height + ); + const totalMargins = restrictedWidth - itemSpacing * (numberOfItems + 1); + const itemWidth = totalMargins / numberOfItems; + + const textColor = useMemo( + () => otherProps?.textColor ?? 'black', + [otherProps?.textColor] + ); + const backgroundColor = useMemo( + () => otherProps?.backgroundColor ?? 'white', + [otherProps?.backgroundColor] + ); + const strokeColor = useMemo( + () => otherProps?.stroke ?? 'black', + [otherProps?.stroke] + ); + const strokeStyle = useMemo( + () => otherProps?.strokeStyle ?? [], + [otherProps?.strokeStyle] + ); + + return ( + onSelected(id, 'horizontal-menu')} + > + + + {menuElements.map((e: string, index: number) => ( + + + + ))} + + ); + } +); + +export default ButtonBarShape; diff --git a/src/common/components/front-rich-components/index.ts b/src/common/components/front-rich-components/index.ts index 9d2360dc..2982da60 100644 --- a/src/common/components/front-rich-components/index.ts +++ b/src/common/components/front-rich-components/index.ts @@ -11,3 +11,4 @@ export * from './calendar/calendar'; export * from './table/table'; export * from './modal/modal'; export * from './appBar'; +export * from './buttonBar'; diff --git a/src/core/model/index.ts b/src/core/model/index.ts index 278f6728..8d825876 100644 --- a/src/core/model/index.ts +++ b/src/core/model/index.ts @@ -58,7 +58,8 @@ export type ShapeType = | 'verticalScrollBar' | 'horizontalScrollBar' | 'modal' - | 'appBar'; + | 'appBar' + | 'buttonBar'; export const ShapeDisplayName: Record = { combobox: 'Combobox', @@ -108,6 +109,7 @@ export const ShapeDisplayName: Record = { verticalScrollBar: 'Vertical Scroll Bar', modal: 'Modal', appBar: 'AppBar', + buttonBar: 'Button Bar', }; export type EditType = 'input' | 'textarea' | 'imageupload'; diff --git a/src/pods/canvas/canvas.model.ts b/src/pods/canvas/canvas.model.ts index 272cb308..92bdde7f 100644 --- a/src/pods/canvas/canvas.model.ts +++ b/src/pods/canvas/canvas.model.ts @@ -57,6 +57,7 @@ import { getTableSizeRestrictions, getModalShapeSizeRestrictions, getAppBarShapeSizeRestrictions, + getButtonBarShapeSizeRestrictions, } from '@/common/components/front-rich-components'; import { getHeading1SizeRestrictions, @@ -169,6 +170,8 @@ export const getSizeRestrictionFromShape = ( return getModalShapeSizeRestrictions(); case 'appBar': return getAppBarShapeSizeRestrictions(); + case 'buttonBar': + return getButtonBarShapeSizeRestrictions(); default: console.warn( `** Shape ${shapeType} has not defined default size, check getDefaultSizeFromShape helper function` @@ -223,6 +226,7 @@ const doesShapeAllowInlineEdition = (shapeType: ShapeType): boolean => { case 'table': case 'modal': case 'appBar': + case 'buttonBar': return true; default: return false; @@ -252,6 +256,7 @@ const generateTypeOfTransformer = (shapeType: ShapeType): string[] => { case 'smalltext': case 'horizontalScrollBar': case 'appBar': + case 'buttonBar': return ['middle-left', 'middle-right']; case 'verticalScrollBar': return ['top-center', 'bottom-center']; @@ -317,6 +322,8 @@ const generateDefaultTextValue = (shapeType: ShapeType): string | undefined => { return 'Alert\nWarning: The action you are about to perform may affect existing data. Are you sure you want to proceed? Once confirmed, this action cannot be undone.\nConfirm,Cancel'; case 'appBar': return 'AppBar'; + case 'buttonBar': + return 'Button 1\nButton 2\nButton 3'; default: return undefined; } @@ -337,6 +344,7 @@ const getShapeEditInlineType = (shapeType: ShapeType): EditType | undefined => { case 'table': case 'modal': case 'appBar': + case 'buttonBar': return 'textarea'; break; case 'image': @@ -366,6 +374,7 @@ export const generateDefaultOtherProps = ( case 'datepickerinput': case 'timepickerinput': case 'modal': + case 'buttonBar': return { stroke: BASIC_SHAPE.DEFAULT_STROKE_COLOR, backgroundColor: BASIC_SHAPE.DEFAULT_FILL_BACKGROUND, diff --git a/src/pods/canvas/shape-renderer/index.tsx b/src/pods/canvas/shape-renderer/index.tsx index 605e1ed5..e400d239 100644 --- a/src/pods/canvas/shape-renderer/index.tsx +++ b/src/pods/canvas/shape-renderer/index.tsx @@ -36,6 +36,7 @@ import { renderVerticalMenuShape, renderTable, renderModal, + renderButtonBar, } from './simple-rich-components'; import { renderDiamond, @@ -158,6 +159,8 @@ export const renderShapeComponent = ( return renderModal(shape, shapeRenderedProps); case 'appBar': return renderAppBar(shape, shapeRenderedProps); + case 'buttonBar': + return renderButtonBar(shape, shapeRenderedProps); default: return renderNotFound(shape, shapeRenderedProps); } diff --git a/src/pods/canvas/shape-renderer/simple-rich-components/button-bar.renderer.tsx b/src/pods/canvas/shape-renderer/simple-rich-components/button-bar.renderer.tsx new file mode 100644 index 00000000..be08c6d9 --- /dev/null +++ b/src/pods/canvas/shape-renderer/simple-rich-components/button-bar.renderer.tsx @@ -0,0 +1,33 @@ +import { ButtonBarShape } from '@/common/components/front-rich-components/buttonBar'; +import { ShapeRendererProps } from '../model'; +import { ShapeModel } from '@/core/model'; + +export const renderButtonBar = ( + shape: ShapeModel, + shapeRenderedProps: ShapeRendererProps +) => { + const { handleSelected, shapeRefs, handleDragEnd, handleTransform } = + shapeRenderedProps; + + return ( + + ); +}; diff --git a/src/pods/canvas/shape-renderer/simple-rich-components/index.ts b/src/pods/canvas/shape-renderer/simple-rich-components/index.ts index f7d2b070..08bdae97 100644 --- a/src/pods/canvas/shape-renderer/simple-rich-components/index.ts +++ b/src/pods/canvas/shape-renderer/simple-rich-components/index.ts @@ -11,3 +11,4 @@ export * from './calendar.renderer'; export * from './table.renderer'; export * from './modal.renderer'; export * from './appBar.renderer'; +export * from './button-bar.renderer'; 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 846672d2..910a4079 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 @@ -20,4 +20,5 @@ export const mockRichComponentsCollection: ItemInfo[] = [ { thumbnailSrc: '/rich-components/table.svg', type: 'table' }, { thumbnailSrc: '/rich-components/modal.svg', type: 'modal' }, { thumbnailSrc: '/rich-components/appBar.svg', type: 'appBar' }, + { thumbnailSrc: '/rich-components/button-bar-group.svg', type: 'buttonBar' }, ];