Skip to content

Commit 9d1c77e

Browse files
feat: implement fab button component
1 parent 2700928 commit 9d1c77e

2 files changed

Lines changed: 97 additions & 0 deletions

File tree

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import { BASE_ICONS_URL, ShapeSizeRestrictions, ShapeType } from '@/core/model';
2+
import { forwardRef, useEffect, useState } from 'react';
3+
import { Circle, Group, Image } from 'react-konva';
4+
import { ShapeProps } from '../../shape.model';
5+
import { fitSizeToShapeSizeRestrictions } from '@/common/utils/shapes';
6+
import { useShapeProps } from '@/common/components/shapes/use-shape-props.hook';
7+
import { useGroupShapeProps } from '../../mock-components.utils';
8+
import { BASIC_SHAPE } from '../../front-components/shape.const';
9+
import { loadSvgWithFill } from '../../front-components/icon/icon-shape.business';
10+
import { IconModal } from '@/pods/properties/components/icon-selector/modal';
11+
import { useModalDialogContext } from '@/core/providers/model-dialog-providers/model-dialog.provider';
12+
import { useCanvasContext } from '@/core/providers';
13+
14+
const fabButtonShapeRestrictions: ShapeSizeRestrictions = {
15+
minWidth: 25,
16+
minHeight: 25,
17+
maxWidth: -1,
18+
maxHeight: -1,
19+
defaultWidth: 85,
20+
defaultHeight: 85,
21+
};
22+
23+
const shapeType: ShapeType = 'fabButton';
24+
25+
export const getFabButtonShapeSizeRestrictions = (): ShapeSizeRestrictions =>
26+
fabButtonShapeRestrictions;
27+
28+
export const FabButtonShape = forwardRef<any, ShapeProps>((props, ref) => {
29+
const { x, y, width, height, id, onSelected, otherProps, ...shapeProps } =
30+
props;
31+
32+
const [iconImage, setIconImage] = useState<HTMLImageElement | null>(null);
33+
34+
const { openModal } = useModalDialogContext();
35+
const { selectionInfo } = useCanvasContext();
36+
const { updateOtherPropsOnSelected } = selectionInfo;
37+
38+
const restrictedSize = fitSizeToShapeSizeRestrictions(
39+
fabButtonShapeRestrictions,
40+
width,
41+
height
42+
);
43+
const { width: restrictedWidth, height: restrictedHeight } = restrictedSize;
44+
45+
const radius = Math.min(restrictedWidth, restrictedHeight) / 2;
46+
const center = radius;
47+
48+
const iconInfo = otherProps?.icon;
49+
const iconSize = radius * 1.2;
50+
const iconStroke = otherProps?.stroke || '#ffffff';
51+
52+
const { fill } = useShapeProps(otherProps, BASIC_SHAPE);
53+
const commonGroupProps = useGroupShapeProps(
54+
props,
55+
restrictedSize,
56+
shapeType,
57+
ref
58+
);
59+
60+
const handleDoubleClick = () => {
61+
if (iconInfo) {
62+
openModal(
63+
<IconModal
64+
actualIcon={iconInfo}
65+
onChange={icon => updateOtherPropsOnSelected('icon', icon)}
66+
/>,
67+
'Choose Icon'
68+
);
69+
}
70+
};
71+
72+
useEffect(() => {
73+
if (iconInfo?.filename) {
74+
loadSvgWithFill(`${BASE_ICONS_URL}${iconInfo.filename}`, iconStroke).then(
75+
img => setIconImage(img)
76+
);
77+
}
78+
}, [iconInfo?.filename, iconStroke]);
79+
80+
return (
81+
<Group {...commonGroupProps} {...shapeProps} onDblClick={handleDoubleClick}>
82+
{/* Background Circle */}
83+
<Circle x={center} y={center} radius={radius} fill={fill} />
84+
{/* Icon */}
85+
{iconImage && (
86+
<Image
87+
image={iconImage}
88+
x={center - iconSize / 2}
89+
y={center - iconSize / 2}
90+
width={iconSize}
91+
height={iconSize}
92+
/>
93+
)}
94+
</Group>
95+
);
96+
});

src/common/components/mock-components/front-rich-components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ export * from './loading-indicator';
1818
export * from './videoconference';
1919
export * from './togglelightdark-shape';
2020
export * from './gauge/gauge';
21+
export * from './fab-button/fab-button';

0 commit comments

Comments
 (0)