Skip to content

Commit d6ec28f

Browse files
committed
Feat: added support for external shapes
1 parent a8a9485 commit d6ec28f

File tree

6 files changed

+44
-7
lines changed

6 files changed

+44
-7
lines changed

src/components/controls/shapes/index.tsx

+9-5
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ import { memo, useCallback, useState } from "react";
22
import { RectangleHorizontal } from "lucide-react";
33
import { default as isEqual } from "lodash/isEqual";
44
import { twMerge } from "tailwind-merge";
5+
import { useShapes } from "@/hooks";
6+
import { getMergedShapes } from "@/hooks/shapes";
57
import { store } from "@/store";
68
import { setCursor } from "@/store/reducers/editor";
9+
import { ISTKProps } from "@/types";
710
import { fallible } from "@/utils";
811
import { resizableRectangle, shapeSize, shapeStrokeWidth } from "../../workspace/elements/shape";
9-
import { shapeList } from "./shape-list";
1012

1113
const CursorShape = (Shape) => {
1214
const icon = (props) => (
@@ -25,7 +27,7 @@ const CursorShape = (Shape) => {
2527
return icon;
2628
};
2729

28-
const Controls = () => {
30+
const Controls = ({ options }: Pick<ISTKProps, "options">) => {
2931
const [selectedIndex, setSelectedIndex] = useState(0);
3032

3133
const onShapeClick = useCallback((shape, i) => {
@@ -35,9 +37,11 @@ const Controls = () => {
3537
});
3638
}, []);
3739

40+
const shapes = useShapes({ options });
41+
3842
return (
3943
<div className="w-full grid grid-cols-5 gap-4">
40-
{shapeList.map((Shape, i) => (
44+
{shapes.map((Shape, i) => (
4145
<div
4246
key={i}
4347
className={twMerge(
@@ -53,9 +57,9 @@ const Controls = () => {
5357
);
5458
};
5559

56-
export const selectFirstShape = () =>
60+
export const selectFirstShape = ({ options }: Pick<ISTKProps, "options">) =>
5761
fallible(() => {
58-
store.dispatch(setCursor(CursorShape(shapeList[0])));
62+
store.dispatch(setCursor(CursorShape(getMergedShapes(options)[0])));
5963
});
6064

6165
const ShapeControls = memo(Controls, isEqual);

src/components/toolbar/index.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ const ToolBar: React.FC<ISTKProps> = (props) => {
6666
store.dispatch(selectTool(tool));
6767
if ([Tool.Image, Tool.Shape].includes(tool)) {
6868
store.dispatch(showControls());
69-
if (tool === Tool.Shape) selectFirstShape();
69+
if (tool === Tool.Shape) selectFirstShape({ options: props.options });
7070
}
7171
if (tool !== Tool.Pen && selectedPolylineId) {
7272
store.dispatch(setSelectedPolylineId(null));

src/components/workspace/elements/shape.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { forwardRef } from "react";
22
import { twMerge } from "tailwind-merge";
3-
import { shapes } from "@/components/controls/shapes/shape-list";
43
import { dataAttributes } from "@/constants";
4+
import { useShapeMap } from "@/hooks";
55
import { ISTKProps, IShape } from "@/types";
66

77
export const shapeSize = 50;
@@ -44,6 +44,7 @@ const Shape: React.FC<IShapeProps> = forwardRef(
4444
},
4545
ref: any
4646
) => {
47+
const shapes = useShapeMap({ options: consumer.options });
4748
if (name === "RectangleHorizontal") {
4849
width ??= resizableRectangle.width;
4950
height ??= resizableRectangle.height;

src/hooks/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ export { default as useSkipFirstRender } from "./skip-first-render";
55
export { default as useToast } from "./toast";
66

77
export * from "./events";
8+
export * from "./shapes";

src/hooks/shapes.ts

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { useMemo } from "react";
2+
import { shapeList } from "@/components/controls/shapes/shape-list";
3+
import { ISTKProps } from "@/types";
4+
5+
export const getMergedShapes = (options: ISTKProps["options"]) => {
6+
if (!options?.shapes) return shapeList;
7+
if (options?.shapes.icons.length === 0) return shapeList;
8+
if (options?.shapes.overrideDefaultIconset) return options.shapes.icons;
9+
return [...shapeList, ...options.shapes.icons];
10+
};
11+
12+
export const useShapes = ({ options }: Pick<ISTKProps, "options">) => {
13+
return useMemo(() => {
14+
return getMergedShapes(options);
15+
}, [options?.shapes]);
16+
};
17+
18+
export const useShapeMap = ({ options }: Pick<ISTKProps, "options">) => {
19+
return useMemo(
20+
() =>
21+
getMergedShapes(options).reduce((acc, shape) => {
22+
acc[shape.displayName] = shape;
23+
return acc;
24+
}, {}),
25+
[options?.shapes]
26+
);
27+
};

src/types/index.ts

+4
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ export interface ISTKProps {
8888
/** Disables category deletion if there are reserved seats falling under the category */
8989
disableCategoryDeleteIfReserved?: boolean;
9090
disableSectionDelete?: boolean;
91+
shapes?: {
92+
icons: React.FC<any>[];
93+
overrideDefaultIconset?: boolean;
94+
};
9195
};
9296
plugins?: IPlugins;
9397
}

0 commit comments

Comments
 (0)