diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index a4f4357..d48e721 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,7 +1,3 @@
-## Installation
-
-Run `bun i @mezh-hq/react-seat-toolkit` to incorporate into your project
-
## Getting started
- Run `bun install` to install all dependencies
diff --git a/README.md b/README.md
index 0d4f96f..0ac3084 100644
--- a/README.md
+++ b/README.md
@@ -29,8 +29,6 @@ React UI library to design and render seat layouts. The library is still under a
-
-
## Features
- **JSON based**: Define your seat layout using JSON data and retrieve it back as JSON after customization ✓
@@ -82,6 +80,71 @@ React UI library to design and render seat layouts. The library is still under a
- **Override styles**: Override the default styles to match your application's theme 🛠️
+## Installation
+
+Run `bun i @mezh-hq/react-seat-toolkit` to incorporate into your project
+
+## Usage
+
+### User mode
+
+```jsx
+import React from 'react';
+import SeatToolkit from '@mezh-hq/react-seat-toolkit';
+
+const App = () => {
+ const data = {
+ seats: [
+ {
+ id: '1',
+ x: 100,
+ y: 100,
+ label: 'A1',
+ color: 'blue',
+ },
+ ],
+ };
+ return (
+ {
+ console.log(seat);
+ },
+ onSectionClick: (section) => {
+ console.log(section);
+ },
+ }}
+ />
+ );
+};
+
+export default App;
+```
+
+### Designer mode
+
+```jsx
+import React from 'react';
+import SeatToolkit from '@mezh-hq/react-seat-toolkit';
+
+const App = () => {
+ return (
+ {
+ console.log(data);
+ },
+ }}
+ />
+ );
+};
+
+export default App;
+```
+
## Contributing
-Please read [CONTRIBUTING.md](https://github.com/mezh-hq/react-seat-toolkit/blob/main/CONTRIBUTING.md) for details on setting up your development environment and the process for submitting pull requests to us.
+Please read [CONTRIBUTING.md](https://github.com/mezh-hq/react-seat-toolkit/blob/main/CONTRIBUTING.md) for details on setting up your development environment and the process of submitting pull requests to us.
diff --git a/src/components/core/animated-switcher.jsx b/src/components/core/animated-switcher.tsx
similarity index 59%
rename from src/components/core/animated-switcher.jsx
rename to src/components/core/animated-switcher.tsx
index 9f17a7a..f0066b5 100644
--- a/src/components/core/animated-switcher.jsx
+++ b/src/components/core/animated-switcher.tsx
@@ -1,7 +1,23 @@
import { motion } from "framer-motion";
import { twMerge } from "tailwind-merge";
-const AnimatedSwitcher = ({ customKey, component, alternateComponent, show, className, duration }) => {
+interface AnimatedSwitcherProps {
+ customKey?: string;
+ component: React.ReactNode;
+ alternateComponent?: React.ReactNode;
+ show: boolean;
+ className?: string;
+ duration?: number;
+}
+
+const AnimatedSwitcher = ({
+ customKey,
+ component,
+ alternateComponent,
+ show,
+ className,
+ duration
+}: AnimatedSwitcherProps) => {
return (
{
- const selectedTool = useSelector((state) => state.toolbar.selectedTool);
+ const selectedTool = useSelector((state: any) => state.toolbar.selectedTool);
return (
React Seat Toolkit
@@ -12,6 +12,7 @@ const Footer = () => {
customKey={selectedTool}
className="absolute top-[0.4rem] left-5 text-xs"
component={{tools[selectedTool]?.description}}
+ alternateComponent={null}
duration={0.2}
/>
diff --git a/src/components/index.jsx b/src/components/index.jsx
deleted file mode 100644
index 87e6411..0000000
--- a/src/components/index.jsx
+++ /dev/null
@@ -1,6 +0,0 @@
-export * from "./core";
-export * from "./workspace";
-export { default as Controls } from "./controls";
-export { default as Footer } from "./footer";
-export { default as Operations } from "./operations";
-export { default as Toolbar } from "./toolbar";
diff --git a/src/components/index.tsx b/src/components/index.tsx
new file mode 100644
index 0000000..bd83353
--- /dev/null
+++ b/src/components/index.tsx
@@ -0,0 +1,46 @@
+import { STKMode } from "@/constants";
+import { useEvents, useInteractions } from "@/hooks";
+import type { ISTKProps } from "@/types";
+import { default as Controls } from "./controls";
+import { default as Footer } from "./footer";
+import { default as Operations } from "./operations";
+import { default as Toolbar } from "./toolbar";
+import { Cursor, default as Workspace } from "./workspace";
+
+export * from "./core";
+
+const Designer: React.FC = (props) => {
+ useEvents();
+ useInteractions();
+ return (
+ <>
+
+
+
+ >
+ );
+};
+
+const User: React.FC = (props) => {
+ return (
+
+
+
+ );
+};
+
+const Core = (props: ISTKProps) => {
+ if (props.mode === STKMode.Designer) {
+ return ;
+ }
+ return ;
+};
+
+export default Core;
diff --git a/src/components/workspace/crosshairs.jsx b/src/components/workspace/crosshairs.tsx
similarity index 97%
rename from src/components/workspace/crosshairs.jsx
rename to src/components/workspace/crosshairs.tsx
index 6587805..8143af2 100644
--- a/src/components/workspace/crosshairs.jsx
+++ b/src/components/workspace/crosshairs.tsx
@@ -7,7 +7,7 @@ export const Crosshairs = ({ render }) => {
const [y, setY] = useState(0);
const [enabled, setEnabled] = useState(false);
- const move = (e) => {
+ const move = (e: Event) => {
const pointer = d3.pointer(e);
setX(pointer[0]);
setY(pointer[1]);
diff --git a/src/components/workspace/grid.jsx b/src/components/workspace/grid.tsx
similarity index 74%
rename from src/components/workspace/grid.jsx
rename to src/components/workspace/grid.tsx
index 0297015..93ac3e5 100644
--- a/src/components/workspace/grid.jsx
+++ b/src/components/workspace/grid.tsx
@@ -1,15 +1,14 @@
-import GridLines from "react-gridlines";
+import { default as GridLines } from "react-gridlines";
import { useSelector } from "react-redux";
import { AnimatedSwitcher } from "../core";
const Grid = () => {
- const grid = useSelector((state) => state.editor.grid);
+ const grid = useSelector((state: any) => state.editor.grid);
if (!grid) return null;
return (
}
- alternateComponent={null}
className="absolute top-0 left-0 pointer-events-none"
/>
);
diff --git a/src/components/workspace/index.jsx b/src/components/workspace/index.tsx
similarity index 71%
rename from src/components/workspace/index.jsx
rename to src/components/workspace/index.tsx
index 5603e16..e991e52 100644
--- a/src/components/workspace/index.jsx
+++ b/src/components/workspace/index.tsx
@@ -2,7 +2,8 @@ import { useCallback, useLayoutEffect } from "react";
import { useSelector } from "react-redux";
import { ids } from "@/constants";
import { store } from "@/store";
-import { initializeElements } from "@/store/reducers/editor";
+import { initializeElements, sync } from "@/store/reducers/editor";
+import type { ISTKProps } from "@/types";
import { Tool, tools } from "../toolbar/data";
import { default as Crosshairs } from "./crosshairs";
import { default as Element, ElementType } from "./elements";
@@ -11,21 +12,25 @@ import { default as Zoom } from "./zoom";
export { default as Cursor } from "./cursor";
-export const Workspace = () => {
- const booths = useSelector((state) => state.editor.booths);
- const seats = useSelector((state) => state.editor.seats);
- const text = useSelector((state) => state.editor.text);
- const shapes = useSelector((state) => state.editor.shapes);
- const polylines = useSelector((state) => state.editor.polylines);
- const images = useSelector((state) => state.editor.images);
- const categories = useSelector((state) => state.editor.categories);
- const selectedElementIds = useSelector((state) => state.editor.selectedElementIds);
- const selectedPolylineId = useSelector((state) => state.editor.selectedPolylineId);
- const selectedTool = useSelector((state) => state.toolbar.selectedTool);
+export const Workspace: React.FC = (props) => {
+ const booths = useSelector((state: any) => state.editor.booths);
+ const seats = useSelector((state: any) => state.editor.seats);
+ const text = useSelector((state: any) => state.editor.text);
+ const shapes = useSelector((state: any) => state.editor.shapes);
+ const polylines = useSelector((state: any) => state.editor.polylines);
+ const images = useSelector((state: any) => state.editor.images);
+ const categories = useSelector((state: any) => state.editor.categories);
+ const selectedElementIds = useSelector((state: any) => state.editor.selectedElementIds);
+ const selectedPolylineId = useSelector((state: any) => state.editor.selectedPolylineId);
+ const selectedTool = useSelector((state: any) => state.toolbar.selectedTool);
useLayoutEffect(() => {
- store.dispatch(initializeElements());
- }, []);
+ if (props.data) {
+ store.dispatch(sync(props.data));
+ } else {
+ store.dispatch(initializeElements());
+ }
+ }, [props.data]);
const elementProps = useCallback(
(elem) => ({
diff --git a/src/constants/index.ts b/src/constants/index.ts
index 727f2bf..9634278 100644
--- a/src/constants/index.ts
+++ b/src/constants/index.ts
@@ -46,3 +46,8 @@ export const seatStatusColors = {
label: "#ffffff"
}
};
+
+export enum STKMode {
+ Designer = "designer",
+ User = "user"
+}
diff --git a/src/index.tsx b/src/index.tsx
index 010af74..ab66d23 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,34 +1,15 @@
import { Provider } from "react-redux";
-import { Controls, Cursor, Footer, Operations, Toolbar, TooltipProvider, Workspace } from "@/components";
-import { useEvents, useInteractions } from "@/hooks";
+import { default as Core, TooltipProvider } from "@/components";
import { store } from "@/store";
+import { type ISTKProps } from "./types";
-export const SeatToolkit = () => {
+export const SeatToolkit = (props: ISTKProps) => {
return (
-
-
- );
-};
-
-const Designer = () => {
- useEvents();
- useInteractions();
- return (
- <>
-
-
+
-
- >
+
);
};
diff --git a/src/store/reducers/editor/index.ts b/src/store/reducers/editor/index.ts
index 46b2591..fdcf0f2 100644
--- a/src/store/reducers/editor/index.ts
+++ b/src/store/reducers/editor/index.ts
@@ -1,5 +1,6 @@
import { createSlice } from "@reduxjs/toolkit";
import { v4 as uuidv4 } from "uuid";
+import type { ISTKData } from "@/types";
import booths from "./booths";
import seats from "./seats";
import shapes from "./shapes";
@@ -203,6 +204,13 @@ export const slice = createSlice({
},
setSelectedPolylineId: (state, action) => {
state.selectedPolylineId = action.payload;
+ },
+ sync: (state, action) => {
+ const { name, ...data } = action.payload as ISTKData;
+ state.location = name ?? state.location;
+ Object.keys(data).forEach((key) => {
+ state[key] = data[key] ?? state[key];
+ });
}
}
});
@@ -241,7 +249,8 @@ export const {
addSection,
updateSection,
deleteSection,
- setSelectedPolylineId
+ setSelectedPolylineId,
+ sync
} = slice.actions;
export default slice.reducer;
diff --git a/src/stories/designer.stories.jsx b/src/stories/designer.stories.tsx
similarity index 67%
rename from src/stories/designer.stories.jsx
rename to src/stories/designer.stories.tsx
index 6e5dc5f..81c9d02 100644
--- a/src/stories/designer.stories.jsx
+++ b/src/stories/designer.stories.tsx
@@ -1,3 +1,4 @@
+import { STKMode } from "@/constants";
import SeatToolkit from "@/index";
export default {
@@ -10,5 +11,5 @@ export default {
};
export const Default = {
- render: () =>
+ render: () =>
};
diff --git a/src/types/elements/booth.ts b/src/types/elements/booth.ts
new file mode 100644
index 0000000..6525e9e
--- /dev/null
+++ b/src/types/elements/booth.ts
@@ -0,0 +1,5 @@
+export interface IBooth {
+ id: string;
+ x: number;
+ y: number;
+}
diff --git a/src/types/elements/image.ts b/src/types/elements/image.ts
new file mode 100644
index 0000000..99fe52e
--- /dev/null
+++ b/src/types/elements/image.ts
@@ -0,0 +1,8 @@
+export interface IImage {
+ id: string;
+ x: number;
+ y: number;
+ href: string;
+ width?: number;
+ height?: number;
+}
diff --git a/src/types/elements/index.ts b/src/types/elements/index.ts
new file mode 100644
index 0000000..8a61a15
--- /dev/null
+++ b/src/types/elements/index.ts
@@ -0,0 +1,6 @@
+export * from "./image";
+export * from "./seat";
+export * from "./text";
+export * from "./shape";
+export * from "./booth";
+export * from "./polyline";
diff --git a/src/types/elements/polyline.ts b/src/types/elements/polyline.ts
new file mode 100644
index 0000000..e5506c4
--- /dev/null
+++ b/src/types/elements/polyline.ts
@@ -0,0 +1,20 @@
+export interface ISection {
+ id: string;
+ name: string;
+ color: string;
+ freeSeating: boolean;
+ capacity?: number;
+}
+
+export interface IPolylinepoint {
+ x: number;
+ y: number;
+}
+
+export interface IPolyline {
+ id: string;
+ points: IPolylinepoint[];
+ color?: string;
+ stroke?: string;
+ section?: string;
+}
diff --git a/src/types/elements/seat.ts b/src/types/elements/seat.ts
new file mode 100644
index 0000000..46a150b
--- /dev/null
+++ b/src/types/elements/seat.ts
@@ -0,0 +1,18 @@
+import { SeatStatus } from "@/constants";
+
+export interface ISeatCategory {
+ id: string;
+ name: string;
+ color: string;
+ textColor: string;
+ cost: number;
+}
+
+export interface ISeat {
+ id: string;
+ x: number;
+ y: number;
+ label?: string;
+ category?: string;
+ status?: SeatStatus;
+}
diff --git a/src/types/elements/shape.ts b/src/types/elements/shape.ts
new file mode 100644
index 0000000..9bdf575
--- /dev/null
+++ b/src/types/elements/shape.ts
@@ -0,0 +1,11 @@
+export interface IShape {
+ id: string;
+ x: number;
+ y: number;
+ name: string;
+ width?: number;
+ height?: number;
+ rx?: number;
+ stroke?: string;
+ color?: string;
+}
diff --git a/src/types/elements/text.ts b/src/types/elements/text.ts
new file mode 100644
index 0000000..d052bec
--- /dev/null
+++ b/src/types/elements/text.ts
@@ -0,0 +1,10 @@
+export interface IText {
+ id: string;
+ x: number;
+ y: number;
+ label?: string;
+ fontSize?: number;
+ fontWeight?: number;
+ letterSpacing?: number;
+ color?: string;
+}
diff --git a/src/types/index.ts b/src/types/index.ts
new file mode 100644
index 0000000..203f7ac
--- /dev/null
+++ b/src/types/index.ts
@@ -0,0 +1,26 @@
+import { STKMode } from "@/constants";
+import { IBooth, IImage, IPolyline, ISeat, ISeatCategory, ISection, IShape, IText } from "./elements";
+
+export interface IEvents {
+ onSeatClick: (seat: ISeat & { category?: ISeatCategory }) => void;
+ onSectionClick: (section: ISection) => void;
+ onExport: (data: ISTKData) => void;
+}
+
+export interface ISTKData {
+ name?: string;
+ categories?: ISeatCategory[];
+ sections?: ISection[];
+ seats?: ISeat[];
+ booths?: IBooth[];
+ text?: IText[];
+ shapes?: IShape[];
+ polylines?: IPolyline[];
+ images?: IImage[];
+}
+
+export interface ISTKProps {
+ mode: STKMode;
+ events?: IEvents;
+ data?: ISTKData;
+}
diff --git a/src/utils/workspace.ts b/src/utils/workspace.ts
index baa0172..6050aca 100644
--- a/src/utils/workspace.ts
+++ b/src/utils/workspace.ts
@@ -12,10 +12,10 @@ export const getWorkspaceHeight = () => {
export const getWorkspaceCenterX = () => {
const workspaceContainer = document.getElementById(ids.workspaceContainer);
- return window.innerWidth / 2 - workspaceContainer.offsetLeft - 8;
+ return window.innerWidth / 2 - (workspaceContainer?.offsetLeft ?? 0) - 8;
};
export const getWorkspaceCenterY = () => {
const workspaceContainer = document.getElementById(ids.workspaceContainer);
- return window.innerHeight / 2 - workspaceContainer.offsetTop;
+ return window.innerHeight / 2 - (workspaceContainer?.offsetTop ?? 0);
};
diff --git a/jsconfig.json b/tsconfig.json
similarity index 79%
rename from jsconfig.json
rename to tsconfig.json
index 4334062..e87e8ee 100644
--- a/jsconfig.json
+++ b/tsconfig.json
@@ -5,6 +5,6 @@
"@/*": ["*"]
},
"jsx": "react-jsx",
- "resolveJsonModule": true
+ "resolveJsonModule": true,
},
}