diff --git a/src/App.tsx b/src/App.tsx index a260020..b303803 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,64 +1,20 @@ import Header from "./components/header"; import Workspace from "./components/workspace"; -import { useComponent } from "./hooks/useComponent"; -import { useScreen } from "./hooks/useScreen" -import { useTables } from "./hooks/useTables"; +import { ProjectContext, useProject } from "./hooks/useProject"; function App() { - const projectData = { - id: "", - title: "", - detail: "", - createdTime: "", - updatedTime: "", - screens: [ - { - id: "screen1", - components: [], - index: 0, - name: "screen1", - projectId: "" - } - ], - tables: [] - }; - - const { - screenState, - screenActions, - screenDispatch - } = useScreen(projectData); - - const { - componentState, - componentActions, - componentDispatch - } = useComponent(screenState.curScreenIndex, screenState.curScreen, screenDispatch.setScreens); - - const { - tableState, - tableActions, - tableDispatch - } = useTables(projectData); - + const { projectStates, projectActions } = useProject(); + return ( -
-
-
- + +
+
+
+ +
-
+ ) } diff --git a/src/components/editor/canvas.tsx b/src/components/editor/canvas.tsx index db6d646..d88bb5c 100644 --- a/src/components/editor/canvas.tsx +++ b/src/components/editor/canvas.tsx @@ -1,8 +1,9 @@ -import type { ComponentState } from "../../hooks/useComponent"; +import { CurrentScreenContext } from "../../hooks/useCurrentScreen"; import { useDragComponent } from "../../hooks/useDragComponent"; +import { ProjectContext } from "../../hooks/useProject"; import { ComponentType } from "../../types/component"; -import type { ButtonGeneralData, Component, TableGeneralData, TextFieldGeneralData, TextGeneralData, UIData } from "../../types/component"; -import { useEffect, useRef, useState } from "react"; +import type { ButtonGeneralData, Component, TableGeneralData, TextFieldGeneralData, TextGeneralData } from "../../types/component"; +import { useContext, useEffect, useRef, useState } from "react"; interface CanvasComponentProps { @@ -84,25 +85,21 @@ } interface CanvasProps { - componentState: ComponentState canvasWidth: number - moveComponent: (index: number, uiData: UIData) => void - selectComponent: (index: number) => void - resetSelectingComponent: () => void } export default function Canvas({ - componentState, canvasWidth, - moveComponent, - selectComponent: selectComponentGrobal, - resetSelectingComponent }: CanvasProps) { const outRef = useRef(null); const canvasRef = useRef(null); const [widgetScale] = useState(0.4); const [scale, setScale] = useState(1); + + const projectContext = useContext(ProjectContext); + const curScreenContext = useContext(CurrentScreenContext); + const { componentX, componentY, @@ -113,9 +110,8 @@ draggingSquare, onDragEnd } = useDragComponent( - componentState.selectingComponent, - componentState.selectingComponentIndex, - moveComponent, + curScreenContext!.curScreenStates.selectingComponent, + projectContext!.projectActions.moveComponent, scale, widgetScale ); @@ -136,6 +132,11 @@ return () => observer.disconnect(); }, [canvasWidth]); + + if (projectContext === null || curScreenContext === null) return
loading...
+ + const curScreenStates = curScreenContext.curScreenStates; + const componentStyle = (isSelecting: boolean, component: Component) => { if (isSelecting) return { position: "absolute" as const, @@ -231,12 +232,12 @@ const selectComopnent = (e: React.MouseEvent, index: number) => { e.stopPropagation(); - selectComponentGrobal(index); + curScreenContext.curScreenActions.selectComponent(index); } const resetSelectComponent = (e: React.MouseEvent) => { e.stopPropagation(); - resetSelectingComponent(); + curScreenContext.curScreenActions.resetSelectingComponent(); } return ( @@ -255,17 +256,17 @@ > {/* Canvas Content */}
- {componentState.curScreenComponents.map((component, index) => + {curScreenStates.curScreenComponents.map((component, index) =>
{ selectComopnent(e, index) }} draggable - onDragStart={(e) => { if (componentState.selectingComponentIndex === index) onDragStart(e) }} - onDrag={(e) => { if (componentState.selectingComponentIndex === index) draggingComponent(e) }} - onDragEnd={(e) => { if (componentState.selectingComponentIndex === index) onDragEnd(e) }} + onDragStart={(e) => { if (curScreenStates.selectingComponentIndex === index) onDragStart(e) }} + onDrag={(e) => { if (curScreenStates.selectingComponentIndex === index) draggingComponent(e) }} + onDragEnd={(e) => { if (curScreenStates.selectingComponentIndex === index) onDragEnd(e) }} > - {componentState.selectingComponentIndex === index ? + {curScreenStates.selectingComponentIndex === index ?
(null); const [width, setWidth] = useState(600); - + useEffect(() => { if (!editorRef.current) return; setWidth(editorRef.current.offsetWidth); }, [editorRef]) - + return (
); diff --git a/src/components/header.tsx b/src/components/header.tsx index e9e4cdb..82f7f88 100644 --- a/src/components/header.tsx +++ b/src/components/header.tsx @@ -1,62 +1,64 @@ import { CiImport } from 'react-icons/ci'; import { jsonExport } from '../lib/jsonExport'; -import type { Project } from '../types/project'; -import { useRef, useState, type Dispatch, type SetStateAction } from 'react'; +import { useContext, useRef, useState } from 'react'; import { FaFileExport } from 'react-icons/fa'; -import type { Table } from '../types/table'; -import type { Screen } from '../types/screen'; +import { ProjectContext } from '../hooks/useProject'; -export default function Header( - { projectData, setScreens, setTables } - : { projectData: Project, setScreens: Dispatch>, setTables: Dispatch> } -) { - +export default function Header() { + + const projectContext = useContext(ProjectContext); + const jsonInputRef = useRef(null); const [exportTypeOpen, setExportTypeOpen] = useState(false); const [importTypeOpen, setImportTypeOpen] = useState(false); + + if (projectContext === null) return
loading...
+ + const { updateProject } = projectContext.projectActions; + const { project } = projectContext.projectStates; + const exportJson = async () => { - jsonExport(projectData); + jsonExport(project); setExportTypeOpen(false); } - + const importJson = () => { jsonInputRef.current?.click(); } - + const handleJsonFileChange = async (event: React.ChangeEvent) => { const file = event.target.files?.[0]; if (!file) return; try { const text = await file.text(); const json = JSON.parse(text); - setScreens(json.screens) - setTables(json.tables) + updateProject(json) } catch (error) { console.log(error); alert("JSONファイルの読み込みに失敗しました"); } setImportTypeOpen(false); } - + return (
- {projectData.title} + {project.title}
{importTypeOpen && @@ -70,7 +72,7 @@ > JSONファイル - +
} diff --git a/src/components/property/buttonAction.tsx b/src/components/property/buttonAction.tsx index bd2943e..8409cf1 100644 --- a/src/components/property/buttonAction.tsx +++ b/src/components/property/buttonAction.tsx @@ -1,40 +1,39 @@ -import type{ SelectComponentListenerType } from "../../hooks/useComponent"; -import { ButtonActionTypeMap } from "../../types/action"; +import { CurrentScreenContext, type SelectComponentListenerType } from "../../hooks/useCurrentScreen"; +import { ProjectContext } from "../../hooks/useProject"; +import { ButtonActionTypeMap } from "../../types/action"; import type { ButtonActionType, ButtonAddDataAction, ButtonDeleteDataAction, ButtonNavigateAction, ButtonSearchDataAction, ButtonUpdateDataAction } from "../../types/action"; import type { ButtonComponent, Component } from "../../types/component"; import type { Screen } from "../../types/screen"; import type { Table } from "../../types/table"; -import { useEffect, useState } from "react" +import { useContext, useEffect, useState } from "react" import { MdEdit } from "react-icons/md"; -interface ButtonActionPropertiesProps { - component: ButtonComponent - screens: Screen[], - curScreenIndex: number, - tables: Table[], - updateComponent: (index: number, newComponent: Component) => void, - setSelectComponentListener: (listener: SelectComponentListenerType) => void - activateSelectMode: () => void -} -export function ButtonActionProperties({ - component, - screens, - curScreenIndex, - tables, - updateComponent, - setSelectComponentListener, - activateSelectMode -}: ButtonActionPropertiesProps) { +export function ButtonActionProperties({ selectingComponent }: { selectingComponent: ButtonComponent }) { - const buttonAction = component.action?.type ?? ""; - const [action, setAction] = useState(component.action?.type ?? ""); + const projectContext = useContext(ProjectContext); + const curScreenContext = useContext(CurrentScreenContext); + + const buttonAction = selectingComponent.action?.type ?? ""; + const [action, setAction] = useState((curScreenContext?.curScreenStates.selectingComponent as ButtonComponent).action?.type ?? ""); useEffect(() => { // eslint-disable-next-line react-hooks/set-state-in-effect setAction(buttonAction) }, [buttonAction]) + if (projectContext === null || curScreenContext === null) return
loading...
+ + const projectActions = projectContext.projectActions; + const projectStates = projectContext.projectStates; + const curScreenActions = curScreenContext.curScreenActions; + const curScreenStates = curScreenContext.curScreenStates; + + const { screens, tables } = projectStates; + const { curScreenIndex } = curScreenStates; + const { updateComponent } = projectActions; + const { activateSelectMode, setSelectComponentListener } = curScreenActions; + return (
@@ -53,13 +52,13 @@
{action === "navigate" && } {action === "addData" && } {action === "updateData" && } {action === "deleteData" && } {action === "searchData" && void + updateComponent: (component: Component) => void } function NavigateProperties({ @@ -130,7 +129,7 @@ nextScreenName: screenName } const newComponent: ButtonComponent = { ...component, action: { type: "navigate", action: navigateAction } } - updateComponent(-1, newComponent); + updateComponent(newComponent); } return ( @@ -172,7 +171,7 @@ component: ButtonComponent screens: Screen[] tables: Table[] - updateComponent: (index: number, newComponent: Component) => void, + updateComponent: (newComponent: Component) => void, setSelectComponentListener: (listener: SelectComponentListenerType) => void activateSelectMode: () => void } @@ -186,15 +185,15 @@ activateSelectMode }: AddDataPropertiesProps) { - const buttonAction = - (component.action?.type ?? "") === "addData" - ? component.action?.action as ButtonAddDataAction - : { - tableName: "", - newData: {}, - failScreenName: "", - successScreenName: "" - }; + const buttonAction = + (component.action?.type ?? "") === "addData" + ? component.action?.action as ButtonAddDataAction + : { + tableName: "", + newData: {}, + failScreenName: "", + successScreenName: "" + }; const [tableName, setTableName] = useState(buttonAction?.tableName ?? ""); const [data, setData] = useState<{ [key: string]: string }>(buttonAction?.newData ?? {}); @@ -257,7 +256,7 @@ failScreenName: failScreen } const newComponent: ButtonComponent = { ...component, action: { type: "addData", action: action } }; - updateComponent(-1, newComponent) + updateComponent(newComponent) } const changeCheck = () => { @@ -383,7 +382,7 @@ component: ButtonComponent screens: Screen[] tables: Table[] - updateComponent: (index: number, newComponent: Component) => void, + updateComponent: (newComponent: Component) => void, setSelectComponentListener: (listener: SelectComponentListenerType) => void activateSelectMode: () => void } @@ -397,15 +396,15 @@ activateSelectMode }: UpdateDataPropertiesProps) { - const buttonAction = - (component.action?.type ?? "") === "updateData" - ? component.action?.action as ButtonUpdateDataAction - : { - tableName: "", - newData: {}, - failScreenName: "", - successScreenName: "" - }; + const buttonAction = + (component.action?.type ?? "") === "updateData" + ? component.action?.action as ButtonUpdateDataAction + : { + tableName: "", + newData: {}, + failScreenName: "", + successScreenName: "" + }; const [tableName, setTableName] = useState(buttonAction?.tableName ?? ""); const [data, setData] = useState<{ [key: string]: string }>(buttonAction?.newData ?? {}); @@ -468,7 +467,7 @@ failScreenName: failScreen } const newComponent: ButtonComponent = { ...component, action: { type: "updateData", action: action } }; - updateComponent(-1, newComponent) + updateComponent(newComponent) } const changeCheck = () => { @@ -592,7 +591,7 @@ component: ButtonComponent screens: Screen[] tables: Table[] - updateComponent: (index: number, newComponent: Component) => void, + updateComponent: (newComponent: Component) => void, setSelectComponentListener: (listener: SelectComponentListenerType) => void activateSelectMode: () => void } @@ -606,15 +605,15 @@ activateSelectMode }: DeleteDataPropertiesProps) { - const buttonAction = - (component.action?.type ?? "") === "deleteData" - ? component.action?.action as ButtonDeleteDataAction - : { - tableName: "", - deleteData: {}, - failScreenName: "", - successScreenName: "" - }; + const buttonAction = + (component.action?.type ?? "") === "deleteData" + ? component.action?.action as ButtonDeleteDataAction + : { + tableName: "", + deleteData: {}, + failScreenName: "", + successScreenName: "" + }; const [tableName, setTableName] = useState(buttonAction?.tableName ?? ""); const [data, setData] = useState<{ [key: string]: string }>(buttonAction?.deleteData ?? {}); @@ -670,7 +669,7 @@ failScreenName: failScreen } const newComponent: ButtonComponent = { ...component, action: { type: "deleteData", action: action } }; - updateComponent(-1, newComponent) + updateComponent(newComponent) } const changeCheck = () => { @@ -794,7 +793,7 @@ interface SearchDataPropertiesProps { component: ButtonComponent tables: Table[] - updateComponent: (index: number, newComponent: Component) => void, + updateComponent: (newComponent: Component) => void, setSelectComponentListener: (listener: SelectComponentListenerType) => void activateSelectMode: () => void } @@ -807,14 +806,14 @@ activateSelectMode }: SearchDataPropertiesProps) { - const buttonAction = - (component.action?.type ?? "") === "searchData" - ? component.action?.action as ButtonSearchDataAction - : { - tableName: "", - searchData: {}, - targetComponentName: "" - } as ButtonSearchDataAction + const buttonAction = + (component.action?.type ?? "") === "searchData" + ? component.action?.action as ButtonSearchDataAction + : { + tableName: "", + searchData: {}, + targetComponentName: "" + } as ButtonSearchDataAction const [tableName, setTableName] = useState(buttonAction?.tableName ?? ""); const [selectableColumns, setSelectableColumns] = useState(Object.keys(buttonAction?.searchData ?? {})); @@ -912,7 +911,7 @@ targetComponentName: targetComponentId } const newComponent: ButtonComponent = { ...component, action: { type: "searchData", action: action } }; - updateComponent(-1, newComponent) + updateComponent(newComponent) } const changeCheck = () => { diff --git a/src/components/property/buttonGeneral.tsx b/src/components/property/buttonGeneral.tsx index 3ddd3c5..b6929e9 100644 --- a/src/components/property/buttonGeneral.tsx +++ b/src/components/property/buttonGeneral.tsx @@ -1,20 +1,17 @@ -import type { ButtonGeneralData, Component } from "../../types/component"; -import { useEffect, useState } from "react"; +import { CurrentScreenContext } from "../../hooks/useCurrentScreen"; +import { ProjectContext } from "../../hooks/useProject"; +import type { ButtonComponent, ButtonGeneralData } from "../../types/component"; +import { useContext, useEffect, useState } from "react"; -interface ButtonGeneralPropertiesProps { - component: Component - index: number - updateComponent: (index: number, component: Component) => void -} -export function ButtonGeneralProperties({ - component, - index, - updateComponent, -}: ButtonGeneralPropertiesProps) { +export function ButtonGeneralProperties({ selectingComponent }: { selectingComponent: ButtonComponent }) { - const generalData = component.generalData as ButtonGeneralData; + const projectContext = useContext(ProjectContext); + const curScreenContext = useContext(CurrentScreenContext); + + + const generalData = selectingComponent.generalData as ButtonGeneralData; const [text, setText] = useState(generalData.text); useEffect(() => { @@ -22,10 +19,13 @@ setText(generalData.text); }, [generalData]) + if (projectContext === null || curScreenContext === null) return
loading...
+ + const projectActions = projectContext.projectActions; const handleChange = (e: React.ChangeEvent) => { setText(e.target.value); - updateComponent(index, { ...component, type: "button", generalData: { ...component.generalData, text: e.target.value } }) + projectActions.updateComponent({ ...selectingComponent, type: "button", generalData: { ...selectingComponent.generalData, text: e.target.value } }) } return ( diff --git a/src/components/property/buttonProperties.tsx b/src/components/property/buttonProperties.tsx index 8fed4a9..736e2b4 100644 --- a/src/components/property/buttonProperties.tsx +++ b/src/components/property/buttonProperties.tsx @@ -1,38 +1,21 @@ import { ActiveTab } from "../../constants/activeTab" -import type { ButtonComponent } from "../../types/component" import { ButtonGeneralProperties } from "./buttonGeneral" import { ButtonActionProperties } from "./buttonAction" -import type { Screen } from "../../types/screen" -import type { Table } from "../../types/table" -import type { ComponentActions } from "../../hooks/useComponent" - - +import type { ButtonComponent } from "../../types/component" interface ButtonPropertyProps { - component: ButtonComponent - index: number activeTab: number - screens: Screen[] - curScreenIndex: number, - tables: Table[], - componentActions: ComponentActions + selectingComponent: ButtonComponent } export function ButtonProperty({ - component, - index, activeTab, - screens, - curScreenIndex, - tables, - componentActions + selectingComponent }: ButtonPropertyProps) { if (activeTab === ActiveTab.GENERAL) return if (activeTab === ActiveTab.STYLE) @@ -40,13 +23,7 @@ if (activeTab === ActiveTab.ACTION) return } \ No newline at end of file diff --git a/src/components/property/property.tsx b/src/components/property/property.tsx index 1c26f53..71fa958 100644 --- a/src/components/property/property.tsx +++ b/src/components/property/property.tsx @@ -1,65 +1,38 @@ -import type { ComponentActions, ComponentState } from "../../hooks/useComponent"; -import { ComponentType } from "../../types/component"; -import type { Component } from "../../types/component"; -import { useEffect, useState } from "react"; +import { ComponentType, type Component } from "../../types/component"; +import { useContext, useEffect, useState } from "react"; import { TextProperty } from "./textProperties"; import { ButtonProperty } from "./buttonProperties"; -import type { Table } from "../../types/table"; import { TableProperty } from "./tableProperties"; -import type { Screen } from "../../types/screen"; import { ActiveTab } from "../../constants/activeTab"; - -interface PropertyProps { - componentState: ComponentState, - tables: Table[] - screens: Screen[], - curScreenIndex: number, - componentActions: ComponentActions, -} +import { ProjectContext } from "../../hooks/useProject"; +import { CurrentScreenContext } from "../../hooks/useCurrentScreen"; -export default function Property({ - componentState, - tables, - screens, - curScreenIndex, - componentActions -}: PropertyProps) { +export default function Property() { - const { selectingComponent, selectingComponentIndex } = componentState - if (selectingComponent === null) + const projectContext = useContext(ProjectContext); + const curScreenContext = useContext(CurrentScreenContext); + + if (projectContext === null || curScreenContext === null) return
loading...
+ + const curScreenStates = curScreenContext.curScreenStates; + + + if (curScreenStates.selectingComponent === null) return
return ; } -interface ComponentPropertyAreaProps { - component: Component - index: number - tables: Table[] - screens: Screen[] - curScreenIndex: number - componentActions: ComponentActions, -} +function ComponentPropertyArea({ selectingComponent }: { selectingComponent: Component }) { -function ComponentPropertyArea({ - component, - index, - tables, - screens, - curScreenIndex, - componentActions -}: ComponentPropertyAreaProps) { - - const componentName = component.name; + const projectContext = useContext(ProjectContext); + const curScreenContext = useContext(CurrentScreenContext); + + const componentName = selectingComponent.name; const [name, setName] = useState(componentName); const [activeTab, setActiveTab] = useState(ActiveTab.GENERAL); @@ -68,6 +41,11 @@ setName(componentName); }, [componentName]) + if (projectContext === null || curScreenContext === null) return
loading...
+ + const projectActions = projectContext.projectActions; + + const handleNameChange = (e: React.ChangeEvent) => { setName(e.target.value); } @@ -79,10 +57,10 @@ const handleNameConfirm = (e: React.FocusEvent) => { if (!nameValidate()) { - setName(component.name); + setName(selectingComponent.name); return; } - componentActions.updateComponent(index, { ...component, name: e.target.value }) + projectActions.updateComponent({ ...selectingComponent, name: e.target.value }) // componentActions.updateConfirm({ ...component, name: e.target.value }); } @@ -127,33 +105,22 @@ className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none transition-colors" />
} - {component.type === ComponentType.Text && + {selectingComponent.type === ComponentType.Text && } - {component.type === ComponentType.Button && + {selectingComponent.type === ComponentType.Button && } - {component.type === ComponentType.Table && + {selectingComponent.type === ComponentType.Table && }
diff --git a/src/components/property/tableProperties.tsx b/src/components/property/tableProperties.tsx index 86de231..da26323 100644 --- a/src/components/property/tableProperties.tsx +++ b/src/components/property/tableProperties.tsx @@ -1,29 +1,19 @@ -import { useEffect, useState } from "react" +import { useContext, useEffect, useState } from "react" import { ActiveTab } from "../../constants/activeTab" -import type { Component, TableComponent, TableGeneralData } from "../../types/component" -import type { Table } from "../../types/table" +import type { TableComponent, TableGeneralData } from "../../types/component" +import { ProjectContext } from "../../hooks/useProject"; +import { CurrentScreenContext } from "../../hooks/useCurrentScreen"; -interface TablePropertyProps { - component: TableComponent - index: number - activeTab: number - tables: Table[] - updateComponent: (index: number, component: Component) => void -} +export function TableProperty({ selectingComponent, activeTab }: { selectingComponent: TableComponent, activeTab: ActiveTab }) { -export function TableProperty({ - component, - index, - activeTab, - tables, - updateComponent, -}: TablePropertyProps) { + const projectContext = useContext(ProjectContext); + const curScreenContext = useContext(CurrentScreenContext); - const generalData = component.generalData as TableGeneralData; + const generalData = selectingComponent.generalData as TableGeneralData; const [reference, setReference] = useState(generalData.referenceTableName); - const selectableColumns = tables.find(table => table.name === reference)?.columns ?? []; + const selectableColumns = projectContext!.projectStates.tables.find(table => table.name === reference)?.columns ?? []; const [columns, setColumns] = useState(generalData.columns); useEffect(() => { @@ -32,19 +22,28 @@ setColumns(generalData.columns); }, [generalData]) + + if (projectContext === null || curScreenContext === null) return
loading...
+ + const projectActions = projectContext.projectActions; + const projectStates = projectContext.projectStates; + + const { updateComponent } = projectActions; + const { tables } = projectStates; + const onReferenceChange = (e: React.ChangeEvent) => { setReference(e.target.value); setColumns([]); - updateComponent(index, { ...component, generalData: { ...generalData, referenceTableName: e.target.value, columns: [] } }) + updateComponent({ ...selectingComponent, generalData: { ...generalData, referenceTableName: e.target.value, columns: [] } }) } const onColumnSelect = (name: string) => { if (columns.includes(name)) { setColumns(prev => prev.filter(col => col !== name)); - updateComponent(index, { ...component, generalData: { ...generalData, columns: columns.filter(col => col !== name) } }) + updateComponent({ ...selectingComponent, generalData: { ...generalData, columns: columns.filter(col => col !== name) } }) } else { setColumns(prev => [...prev, name]); - updateComponent(index, { ...component, generalData: { ...generalData, columns: [...columns, name] } }) + updateComponent({ ...selectingComponent, generalData: { ...generalData, columns: [...columns, name] } }) } } diff --git a/src/components/property/textProperties.tsx b/src/components/property/textProperties.tsx index 8167507..abad78e 100644 --- a/src/components/property/textProperties.tsx +++ b/src/components/property/textProperties.tsx @@ -1,26 +1,24 @@ -import { useEffect, useState } from "react" +import { useContext, useEffect, useState } from "react" import { ActiveTab } from "../../constants/activeTab" -import type { Component, TextComponent, TextGeneralData } from "../../types/component" +import type { TextComponent, TextGeneralData } from "../../types/component" import { MdEdit } from "react-icons/md" -import type { ComponentActions } from "../../hooks/useComponent" +import { ProjectContext } from "../../hooks/useProject" +import { CurrentScreenContext } from "../../hooks/useCurrentScreen" interface TextPropertyProps { - component: TextComponent - index: number activeTab: ActiveTab - componentActions: ComponentActions - updateComponent: (index: number, component: Component) => void + selectingComponent: TextComponent } export function TextProperty({ - component, - index, - activeTab, - componentActions, - updateComponent, + selectingComponent, + activeTab }: TextPropertyProps) { - const generalData = component.generalData as TextGeneralData; + const projectContext = useContext(ProjectContext); + const curScreenContext = useContext(CurrentScreenContext); + + const generalData = selectingComponent.generalData as TextGeneralData; const [text, setText] = useState(generalData.text); const [selectMode, setSelectMode] = useState(false); @@ -30,27 +28,32 @@ }, [generalData]) + if (projectContext === null || curScreenContext === null) return
loading...
+ + const projectActions = projectContext.projectActions; + const curScreenActions = curScreenContext.curScreenActions; + if (activeTab !== ActiveTab.GENERAL) return
const handleChange = (e: React.ChangeEvent) => { setText(e.target.value); - const newData: TextGeneralData = { ...component.generalData, text: e.target.value } - const newComponent: TextComponent = { ...component, generalData: newData } - updateComponent(index, newComponent) + const newData: TextGeneralData = { ...selectingComponent.generalData, text: e.target.value } + const newComponent: TextComponent = { ...selectingComponent as TextComponent, generalData: newData } + projectActions.updateComponent(newComponent) } const handleSelectMode = () => { - componentActions.setSelectComponentListener((comp) => { + curScreenActions.setSelectComponentListener((comp) => { if (comp !== null) { setText("${" + comp.name + "}"); - const newData: TextGeneralData = { ...component.generalData, text: "${" + comp.name + "}" } - const newComponent: TextComponent = { ...component, generalData: newData } - updateComponent(index, newComponent) + const newData: TextGeneralData = { ...selectingComponent.generalData, text: "${" + comp.name + "}" } + const newComponent: TextComponent = { ...selectingComponent as TextComponent, generalData: newData } + projectActions.updateComponent(newComponent) } setSelectMode(false); }) setSelectMode(true); - componentActions.activateSelectMode(); + curScreenActions.activateSelectMode(); } return ( diff --git a/src/components/sidebar/addComponentMenu.tsx b/src/components/sidebar/addComponentMenu.tsx index 54ad4e4..eb3270c 100644 --- a/src/components/sidebar/addComponentMenu.tsx +++ b/src/components/sidebar/addComponentMenu.tsx @@ -1,11 +1,23 @@ +import { useContext } from "react"; import { ComponentType } from "../../types/component"; import { FiEdit3, FiGrid, FiSquare, FiType } from "react-icons/fi"; +import { ProjectContext } from "../../hooks/useProject"; +import { CurrentScreenContext } from "../../hooks/useCurrentScreen"; -interface AddComponentMenuProps { - addComponent: (type: ComponentType) => void -} +export function AddComponentMenu() { -export function AddComponentMenu({addComponent}: AddComponentMenuProps) { + const projectContext = useContext(ProjectContext); + const curScreenContext = useContext(CurrentScreenContext); + + if (projectContext === null || curScreenContext === null) return
loading...
+ + const projectActions = projectContext.projectActions; + const curScreenStates = curScreenContext.curScreenStates; + + const addComponent = (type: ComponentType) => { + projectActions.addComponent(curScreenStates.curScreen.id, type) + } + return (
@@ -15,7 +27,7 @@
{type === "add" && }
@@ -359,20 +350,26 @@ } interface AddTemplateProps { - tableState: TablesState, - componenetActions: ComponentActions, - screenState: ScreenState, - screenActions: ScreenActions screenName: string close: () => void } -function AddTemplate({ tableState, componenetActions, screenName, screenActions, screenState, close }: AddTemplateProps) { +function AddTemplate({ screenName, close }: AddTemplateProps) { - const tables = tableState.tables; + const projectContext = useContext(ProjectContext); + const curScreenContext = useContext(CurrentScreenContext); + const [selectedTableId, setSelectedTableId] = useState(""); const [successScreen, setSuccessScreen] = useState(""); + if (projectContext === null || curScreenContext === null) return
loading...
+ + const tables = projectContext.projectStates.tables; + const projectActions = projectContext.projectActions; + const projectStates = projectContext.projectStates; + const curScreenActions = curScreenContext.curScreenActions; + + const confirm = async () => { const MARGIN_X = 50; const COLUMN_MARGIN_Y = 20; @@ -382,8 +379,8 @@ const INPUT_WIDTH = 650; const INPUT_HEIGHT = 40; - const screenId = await screenActions.addScreen(screenName); - componenetActions.selectComponent(-1); + const screenId = projectActions.addScreen(screenName); + curScreenActions.selectComponent(-1); const table = tables.find((table) => table.id === selectedTableId); const actionData: { [key: string]: string } = {}; const components: Component[] = []; @@ -485,7 +482,7 @@ } components.push(confirmButton); components.push(backButton) - componenetActions.addComponents(components, screenId); + projectActions.addComponents(screenId, components); close(); } @@ -515,7 +512,7 @@ > - {screenState.screens.map((screen, idx) => ( + {projectStates.screens.map((screen, idx) => ( diff --git a/src/components/sidebar/sidebar.tsx b/src/components/sidebar/sidebar.tsx index 2a835e1..5ebaa66 100644 --- a/src/components/sidebar/sidebar.tsx +++ b/src/components/sidebar/sidebar.tsx @@ -7,28 +7,13 @@ import type { Dispatch, SetStateAction } from "react"; import { ComponentList } from "./componentList"; import { TableList } from "./tableList"; -import type { ScreenActions, ScreenState } from "../../hooks/useScreen"; -import type { ComponentActions, ComponentState } from "../../hooks/useComponent"; -import type { TablesActions, TablesState } from "../../hooks/useTables"; interface SidebarProps { activeTabId: string - screenState: ScreenState - screenActions: ScreenActions - componentState: ComponentState - componentActions: ComponentActions - tableState: TablesState - tableActions: TablesActions } export function Sidebar({ activeTabId, - screenState, - screenActions, - componentState, - componentActions, - tableState, - tableActions, }: SidebarProps) { return ( @@ -38,33 +23,16 @@ >
{activeTabId === "screens" && - + } {activeTabId === "layer" && - + } {activeTabId === "components" && - + } {activeTabId === "tables" && - + }
diff --git a/src/components/sidebar/tableList.tsx b/src/components/sidebar/tableList.tsx index 0256100..7b1b256 100644 --- a/src/components/sidebar/tableList.tsx +++ b/src/components/sidebar/tableList.tsx @@ -1,27 +1,31 @@ -import type { TablesActions, TablesState } from "../../hooks/useTables"; -import { DataType, translateDataType } from "../../types/table"; +import { DataType, translateDataType } from "../../types/table"; import type { Column, Table } from "../../types/table"; -import { useState } from "react" +import { useContext, useState } from "react" import { FiX } from "react-icons/fi"; import { MdDeleteOutline, MdOutlineDelete, MdOutlineEdit } from "react-icons/md"; +import { ProjectContext } from "../../hooks/useProject"; +import { CurrentScreenContext } from "../../hooks/useCurrentScreen"; -interface TalbeListProps { - tableState: TablesState, - tableActions: TablesActions -} - -export function TableList({ tableState, tableActions }: TalbeListProps) { +export function TableList() { const [showAddModal, setShowAddModal] = useState(false); const [editTableIndex, setEditTableIndex] = useState(-1); + const projectContext = useContext(ProjectContext); + const curScreenContext = useContext(CurrentScreenContext); + + if (projectContext === null || curScreenContext === null) return
loading...
+ + const projectActions = projectContext.projectActions; + const projectStates = projectContext.projectStates; + const handleAddTable = () => { setShowAddModal(true); } const handleDeleteTable = (e: React.MouseEvent, id: string) => { e.stopPropagation(); - tableActions.deleteTable(id) + projectActions.deleteTable(id) } return ( @@ -31,7 +35,7 @@
- {tableState.tables.map((table, idx) => + {projectStates.tables.map((table, idx) =>
{ setEditTableIndex(idx); setShowAddModal(true) }} @@ -65,10 +69,10 @@
{showAddModal && { setEditTableIndex(-1); setShowAddModal(false) }} - tables={tableState.tables} - editTable={editTableIndex === -1 ? null : tableState.tables[editTableIndex]} - addTable={tableActions.addTable} - updateTable={tableActions.updateTable} + tables={projectStates.tables} + editTable={editTableIndex === -1 ? null : projectStates.tables[editTableIndex]} + addTable={projectActions.addTable} + updateTable={projectActions.updateTable} />}
) diff --git a/src/components/workspace.tsx b/src/components/workspace.tsx index 55bf51d..446daf1 100644 --- a/src/components/workspace.tsx +++ b/src/components/workspace.tsx @@ -1,56 +1,36 @@ import { Sidebar, SidebarIcons } from "./sidebar/sidebar"; import Editor from "./editor/editor"; import Property from "./property/property"; -import type { ScreenStateAndActions } from "../hooks/useScreen"; -import type { ComponentStateAndActions } from "../hooks/useComponent"; -import { useState } from "react"; -import type { TableStateAndActions } from "../hooks/useTables"; +import { useContext, useState } from "react"; +import { CurrentScreenContext, useCurrentScreen } from "../hooks/useCurrentScreen"; +import { ProjectContext } from "../hooks/useProject"; -export default function Workspace({ - screenStateAndActions, - componentStateAndActions, - tableStateAndActions - }: { - screenStateAndActions: ScreenStateAndActions, - componentStateAndActions: ComponentStateAndActions, - tableStateAndActions: TableStateAndActions - }) { +export default function Workspace() { + const projectContext = useContext(ProjectContext); + const { curScreenStates, curScreenActions } = useCurrentScreen(projectContext!.projectStates.screens); const [activeTabId, setActiveTabId] = useState(""); return ( -
- -
- +
+ -
- + -
-
- +
+ +
+
+ +
-
+ ); } \ No newline at end of file diff --git a/src/hooks/useComponent.ts b/src/hooks/useComponent.ts deleted file mode 100644 index caf143e..0000000 --- a/src/hooks/useComponent.ts +++ /dev/null @@ -1,230 +0,0 @@ -import type { ButtonGeneralData, Component, GeneralData, TableGeneralData, TextFieldGeneralData, TextGeneralData, UIData } from "../types/component"; -import { ComponentType } from "../types/component"; -import type { Screen } from "../types/screen"; -import { useCallback, useRef, useState } from "react"; -import type { Dispatch, SetStateAction } from "react"; - -export interface ComponentState { - selectingComponent: Component | null, - selectingComponentIndex: number, - curScreenComponents: Component[] -} - -export type SelectComponentListenerType = (selected: Component | null) => void - -export interface ComponentActions { - addComponent: (type: ComponentType) => void, - addComponents: (components: Component[], screenId: string) => void - moveComponent: (index: number, uiData: UIData) => void, - updateComponent: (index: number, newComponent: Component) => void, - deleteComponent: (index: number, id: string) => void, - setSelectComponentListener: (listner: SelectComponentListenerType) => void - selectComponent: (index: number) => void, - resetSelectingComponent: () => void, - activateSelectMode: () => void -} - -export interface ComponentDispatch { - setSelectingComponentIndex: Dispatch>, -} - -export interface ComponentStateAndActions { - componentState: ComponentState, - componentActions: ComponentActions, - componentDispatch: ComponentDispatch -} - -export function useComponent( - curScreenIndex: number, - curScreen: Screen, - setScreens: Dispatch> -): ComponentStateAndActions { - - const [selectingComponentIndex, setSelectingComponentIndex] = useState(-1); - const [selectMode, setSelectMode] = useState(false); - const selectComponentCallbackRef = useRef(null); - - const curScreenComponents: Component[] = curScreen.components; - const selectingComponent = selectingComponentIndex === -1 ? null : curScreenComponents[selectingComponentIndex]; - - function getInitialGeneralData(type: ComponentType): GeneralData { - switch (type) { - case ComponentType.Text: - return { text: "text" } - case ComponentType.Button: - return { text: "button" } - case ComponentType.TextField: - return { text: "text field" } - case ComponentType.Table: - return { referenceTableName: "", columns: [] } - } - } - - - const addComponent = async (type: ComponentType) => { - let nextIndex = 0; - if (curScreenComponents.length > 0) { - nextIndex = curScreenComponents[curScreenComponents.length - 1].index + 1; - } - - const uiData: UIData = { - posX: 100, - posY: 100, - width: 75, - height: 25 - } - const newId = "w" + self.crypto.randomUUID().replace(/-/g, "") - - let newComponent: Component; - - switch (type) { - case ComponentType.Button: - newComponent = { - id: newId, - name: newId, - type: type, - index: nextIndex, - screenId: curScreen.id, - generalData: getInitialGeneralData(type) as ButtonGeneralData, - style: {}, - uiData: uiData, - } - break; - case ComponentType.Text: - newComponent = { - id: newId, - name: newId, - type: type, - index: nextIndex, - screenId: curScreen.id, - generalData: getInitialGeneralData(type) as TextGeneralData, - style: {}, - uiData: uiData, - } - break; - case ComponentType.TextField: - newComponent = { - id: newId, - name: newId, - type: type, - index: nextIndex, - screenId: curScreen.id, - generalData: getInitialGeneralData(type) as TextFieldGeneralData, - style: {}, - uiData: uiData, - } - break; - case ComponentType.Table: - newComponent = { - id: newId, - name: newId, - type: type, - index: nextIndex, - screenId: curScreen.id, - generalData: getInitialGeneralData(type) as TableGeneralData, - style: {}, - uiData: uiData, - } - break; - } - - setScreens(screens => screens.map((screen, i) => - i === curScreenIndex ? { - ...screen, - components: [...screen.components, newComponent] - } : screen - )); - - } - - const addComponents = async (components: Component[], screenId: string) => { - setScreens(screens => screens.map((screen) => - screen.id === screenId ? { - ...screen, - components: [...screen.components, ...components] - } : screen - )); - } - - const moveComponent = async (index: number, uiData: UIData) => { - if (!selectingComponent) return; - setScreens(screens => screens.map((screen, i) => - i === curScreenIndex ? { - ...screen, - components: screens[i].components.map((comp, j) => j === index ? { ...comp, uiData: uiData } : comp) - } : screen - )); - } - - const deleteComponent = async (index: number) => { - setScreens((prev) => (prev.map((screen, scrIdx) => scrIdx === curScreenIndex ? { - ...screen, - components: screen.components.filter((_, compIdx) => compIdx !== index) - } : screen))); - } - - const updateComponent = (index: number, newComponent: Component) => { - if (index == -1) { //-1の時は現在選択中のコンポーネント - index = selectingComponentIndex - } - console.log(newComponent); - setScreens(screens => screens.map((screen, i) => - i === curScreenIndex ? { - ...screen, - components: screens[i].components.map((comp, j) => j === index ? newComponent : comp) - } : screen - )); - } - - const setSelectComponentListener = useCallback((listener: SelectComponentListenerType) => { - selectComponentCallbackRef.current = listener; - }, []) - - const selectComponent = (index: number) => { - if (selectMode) { - selectComponentCallbackRef.current?.(curScreenComponents[index]); - selectComponentCallbackRef.current = null; - setSelectMode(false); - } else { - setSelectingComponentIndex(index); - } - } - - - const resetSelectingComponent = () => { - if (selectMode) { - selectComponentCallbackRef.current?.(null); - selectComponentCallbackRef.current = null; - setSelectMode(false); - } else { - setSelectingComponentIndex(-1); - } - } - - const activateSelectMode = () => { - setSelectMode(true); - } - - return { - componentState: { - selectingComponent, - selectingComponentIndex, - curScreenComponents - }, - componentActions: { - addComponent, - addComponents, - deleteComponent, - moveComponent, - updateComponent, - setSelectComponentListener, - selectComponent, - resetSelectingComponent, - activateSelectMode - }, - componentDispatch: { - setSelectingComponentIndex - } - } - -} \ No newline at end of file diff --git a/src/hooks/useCurrentScreen.ts b/src/hooks/useCurrentScreen.ts new file mode 100644 index 0000000..ad9c314 --- /dev/null +++ b/src/hooks/useCurrentScreen.ts @@ -0,0 +1,90 @@ +import { createContext, useCallback, useRef, useState } from "react"; +import type { Screen } from "../types/screen"; +import type { Component } from "../types/component"; + +export interface CurrentScreenStates { + curScreen: Screen, + curScreenIndex: number + curScreenComponents: Component[] + selectingComponent: Component | null + selectingComponentIndex: number +} + +export interface CurrentScreenActions { + changeCurScreen: (index: number) => void + selectComponent: (index: number) => void + setSelectComponentListener: (listener: SelectComponentListenerType) => void + resetSelectingComponent: () => void + activateSelectMode: () => void +} + +export interface CurrentScreenStatesAndActions { + curScreenStates: CurrentScreenStates + curScreenActions: CurrentScreenActions +} + +export type SelectComponentListenerType = (selected: Component | null) => void + +export function useCurrentScreen(screens: Screen[]): CurrentScreenStatesAndActions { + + const [curScreenIndex, setCurScreenIndex] = useState(0); + const [selectingComponentIndex, setSelectingComponentIndex] = useState(-1); + const [selectMode, setSelectMode] = useState(false); + const selectComponentCallbackRef = useRef(null); + + const curScreen = screens[curScreenIndex]; + const components = screens[curScreenIndex].components; + const selectingComponent = selectingComponentIndex !== -1 ? screens[curScreenIndex].components[selectingComponentIndex] : null; + + const changeCurScreen = (index: number) => { + if (index >= screens.length) return; + setCurScreenIndex(index); + } + + const selectComponent = (index: number) => { + if (components.length <= index) return; + if (selectMode) { + selectComponentCallbackRef.current?.(components[index]); + selectComponentCallbackRef.current = null; + setSelectMode(false); + } else { + setSelectingComponentIndex(index); + } + } + + const setSelectComponentListener = useCallback((listener: SelectComponentListenerType) => { + selectComponentCallbackRef.current = listener; + }, []) + + const resetSelectingComponent = () => { + if (selectMode) { + setSelectMode(false); + } else { + setSelectingComponentIndex(-1); + } + } + + const activateSelectMode = () => { + setSelectMode(true); + } + + return { + curScreenStates: { + curScreen, + curScreenIndex, + curScreenComponents: components, + selectingComponent, + selectingComponentIndex, + }, + curScreenActions: { + changeCurScreen, + selectComponent, + setSelectComponentListener, + resetSelectingComponent, + activateSelectMode + } + } + +} + +export const CurrentScreenContext = createContext(null) \ No newline at end of file diff --git a/src/hooks/useDragComponent.ts b/src/hooks/useDragComponent.ts index b1f9735..3af6f9d 100644 --- a/src/hooks/useDragComponent.ts +++ b/src/hooks/useDragComponent.ts @@ -3,8 +3,7 @@ export function useDragComponent( selectingComponent: Component | null, - selectingComponentIndex: number, - moveComponent: (index: number, uiData: UIData) => void, + moveComponent: (screenId: string, componentId: string, uiData: UIData) => void, scale: number, widgetScale: number ) { @@ -117,7 +116,7 @@ width: componentW, height: componentH } - moveComponent(selectingComponentIndex, nextUiData); + moveComponent(selectingComponent.screenId, selectingComponent.id, nextUiData); } return { diff --git a/src/hooks/useProject.ts b/src/hooks/useProject.ts new file mode 100644 index 0000000..6adf91d --- /dev/null +++ b/src/hooks/useProject.ts @@ -0,0 +1,264 @@ +import { createContext, useState } from "react"; +import type { Project } from "../types/project"; +import type { Screen } from "../types/screen"; +import type { UIData, Component, GeneralData, ButtonGeneralData, TextGeneralData, TextFieldGeneralData, TableGeneralData } from "../types/component"; +import { ComponentType } from "../types/component"; +import type { Table } from "../types/table"; + +function getInitialGeneralData(type: ComponentType): GeneralData { + switch (type) { + case ComponentType.Text: + return { text: "text" } + case ComponentType.Button: + return { text: "button" } + case ComponentType.TextField: + return { text: "text field" } + case ComponentType.Table: + return { referenceTableName: "", columns: [] } + } +} + +export interface ProjectStates { + project: Project, + screens: Screen[], + tables: Table[] +} + +export interface ProjectActions { + updateProject: (project: Project) => void + addScreen: (name: string) => string + updateScreen: (screen: Screen) => void + deleteScreen: (screenId: string) => void + addComponent: (screenId: string, type: ComponentType) => void + addComponents: (screenId: string, components: Component[]) => void + updateComponent: (component: Component) => void + moveComponent: (screenId: string, componentId: string, uiData: UIData) => void + deleteComponent: (screenId: string, componentId: string) => void + addTable: (table: Table) => void + updateTable: (table: Table) => void + deleteTable: (tableId: string) => void +} + +export interface ProjectStatesAndActions { + projectStates: ProjectStates + projectActions: ProjectActions +} + +export function useProject(initProject: Project = { + id: "", + title: "", + detail: "", + createdTime: "", + updatedTime: "", + screens: [ + { + id: "screen1", + components: [], + index: 0, + name: "screen1", + projectId: "" + } + ], + tables: [] +}): ProjectStatesAndActions { + + const [project, setProject] = useState(initProject); + const screens = project.screens; + const tables = project.tables; + + const updateProject = (project: Project) => { + setProject(project); + } + + const addScreen = (name: string) => { + const nextIndex = screens[screens.length - 1].index + 1; + const newScreenId = "screen" + nextIndex; + const newScreen: Screen = { + id: newScreenId, + components: [], + index: nextIndex, + name: name, + projectId: project.id + } + setProject(prev => ({ ...prev, screens: [...prev.screens, newScreen] })); + return newScreenId; + } + + const deleteScreen = (screenId: string) => { + setProject(prev => ({ ...prev, screens: prev.screens.filter(s => s.id !== screenId) })); + } + + const updateScreen = (screen: Screen) => { + setProject(prev => ({ ...prev, screens: prev.screens.map(s => s.id === screen.id ? screen : s) })); + } + + const addComponent = (screenId: string, type: ComponentType) => { + const screen = screens.find(s => s.id === screenId); + if (!screen) { + return; + } + const nextIndex = screen.components.length > 0 ? screen.components[screen.components.length - 1].index + 1 : 0; + const uiData: UIData = { + posX: 100, + posY: 100, + width: 75, + height: 25 + }; + const newId = screen.id + "Widget" + nextIndex; + let newComponent: Component; + switch (type) { + case ComponentType.Button: + newComponent = { + id: newId, + name: newId, + type: type, + index: nextIndex, + screenId: screen.id, + generalData: getInitialGeneralData(type) as ButtonGeneralData, + style: {}, + uiData: uiData, + } + break; + case ComponentType.Text: + newComponent = { + id: newId, + name: newId, + type: type, + index: nextIndex, + screenId: screen.id, + generalData: getInitialGeneralData(type) as TextGeneralData, + style: {}, + uiData: uiData, + } + break; + case ComponentType.TextField: + newComponent = { + id: newId, + name: newId, + type: type, + index: nextIndex, + screenId: screen.id, + generalData: getInitialGeneralData(type) as TextFieldGeneralData, + style: {}, + uiData: uiData, + } + break; + case ComponentType.Table: + newComponent = { + id: newId, + name: newId, + type: type, + index: nextIndex, + screenId: screen.id, + generalData: getInitialGeneralData(type) as TableGeneralData, + style: {}, + uiData: uiData, + } + break; + } + setProject(prev => ( + { + ...prev, + screens: prev.screens.map((s, i) => s.id === screenId ? { + ...prev.screens[i], + components: [...prev.screens[i].components, newComponent] + } : s) + } + )) + } + + const addComponents = (screenId: string, components: Component[]) => { + setProject(prev => ( + { + ...prev, + screens: prev.screens.map((s, i) => s.id === screenId ? { + ...prev.screens[i], + components: [...prev.screens[i].components, ...components] + } : s) + } + )) + } + + const moveComponent = (screenId: string, componentId: string, uiData: UIData) => { + setProject(prev => ( + { + ...prev, + screens: prev.screens.map((s, i) => s.id === screenId ? { + ...prev.screens[i], + components: prev.screens[i].components.map((c, j) => c.id === componentId ? { + ...prev.screens[i].components[j], + uiData: uiData + } : c) + } : s) + } + )) + } + + const updateComponent = (component: Component) => { + setProject(prev => ( + { + ...prev, + screens: prev.screens.map((s, i) => s.id === component.screenId ? { + ...prev.screens[i], + components: prev.screens[i].components.map(c => c.id === component.id ? component : c) + } : s) + } + )) + } + + const deleteComponent = (screenId: string, componentId: string) => { + setProject(prev => ( + { + ...prev, + screens: prev.screens.map((s, i) => s.id === screenId ? { + ...prev.screens[i], + components: prev.screens[i].components.filter(c => c.id !== componentId) + } : s) + } + )) + } + + const addTable = (table: Table) => { + setProject(prev => ({ + ...prev, + tables: [...prev.tables, table] + })) + } + + const updateTable = (table: Table) => { + setProject(prev => ({ + ...prev, + tables: prev.tables.map(t => t.id === table.id ? table : t) + })); + } + + const deleteTable = (tableId: string) => { + setProject(prev => ({ + ...prev, + tables: prev.tables.filter(table => table.id !== tableId) + })) + } + + return { + projectStates: { project, screens, tables }, + projectActions: { + updateProject, + addScreen, + updateScreen, + deleteScreen, + addComponent, + addComponents, + updateComponent, + moveComponent, + deleteComponent, + addTable, + updateTable, + deleteTable + } + } + + +} + + +export const ProjectContext = createContext(null); diff --git a/src/hooks/useScreen.ts b/src/hooks/useScreen.ts deleted file mode 100644 index 733f161..0000000 --- a/src/hooks/useScreen.ts +++ /dev/null @@ -1,77 +0,0 @@ -import type { Project } from "../types/project"; -import type { Screen } from "../types/screen"; -import { useState } from "react"; -import type { Dispatch, SetStateAction } from "react"; - -export interface ScreenState { - screens: Screen[], - curScreenIndex: number, - curScreen: Screen -} - -export interface ScreenActions { - setCurScreenIndex: (index: number) => void - addScreen: (name: string) => Promise, - deleteScreen: (index: number) => void, - updateScreen: (index: number, name: string) => void -} - -export interface ScreenStateAndActions { - screenState: ScreenState, - screenActions: ScreenActions, - screenDispatch: { - setScreens: Dispatch> - } -} - -export function useScreen(project: Project): ScreenStateAndActions { - - const [screens, setScreens] = useState(project.screens); - const [curScreenIndex, setCurScreenIndex] = useState(0); - - const curScreen: Screen = screens[curScreenIndex]; - - const addScreen = async (name: string): Promise => { - const nextIndex = screens[screens.length - 1].index + 1; - const newScreenId = "s" + self.crypto.randomUUID().replace(/-/g, ""); - const newScreen: Screen = { - id: newScreenId, - components: [], - index: nextIndex, - name: name, - projectId: project.id - } - - setScreens((curScreens) => [...curScreens, newScreen]); - setCurScreenIndex(screens.length - 1); - - return newScreenId; - }; - - const deleteScreen = async (index: number) => { - setCurScreenIndex(0); - setScreens((prev) => prev.filter((_, i) => i !== index)); - } - - const updateScreen = async (index: number, name: string) => { - setScreens((prev) => prev.map((item, i) => i === index ? { ...item, name: name } : item)); - } - - return { - screenState: { - screens, - curScreenIndex, - curScreen - }, - screenActions: { - setCurScreenIndex, - addScreen, - updateScreen, - deleteScreen - }, - screenDispatch: { - setScreens - } - } - -} \ No newline at end of file diff --git a/src/hooks/useTables.ts b/src/hooks/useTables.ts deleted file mode 100644 index 20d623b..0000000 --- a/src/hooks/useTables.ts +++ /dev/null @@ -1,47 +0,0 @@ -import type { Project } from "../types/project"; -import type { Table } from "../types/table"; -import { useState, type Dispatch, type SetStateAction } from "react"; - -export interface TablesState { - tables: Table[] -} - -export interface TablesActions { - addTable: (table: Table) => void, - deleteTable: (id: string) => void, - updateTable: (updatedTable: Table) => void -} - -export interface TableStateAndActions { - tableState: TablesState, - tableActions: TablesActions, - tableDispatch: {setTables: Dispatch>} -} - -export function useTables(project: Project): TableStateAndActions { - - const [tables, setTables] = useState(project.tables); - - const addTable = async (table: Table) => { - setTables(cur => [...cur, table]) - } - - const deleteTable = async (id: string) => { - setTables(cur => cur.filter((cur) => cur.id !== id)) - } - - const updateTable = async (updatedTable: Table) => { - setTables(cur => cur.map((table) => table.id === updatedTable.id ? updatedTable : table)); - } - - return { - tableState: { tables }, - tableActions: { - addTable, - updateTable, - deleteTable - }, - tableDispatch: { setTables } - } - -} \ No newline at end of file