テスト用ボタンを削除する
今までのコードでは動作確認用にいくつかテスト用のボタンと確認用の処理を書いてきました。今回それらのボタンを削除して本番用のボタンなどを配置していきましょう。
確認用ボタンを取り除いたBuildPanel.tsxを示します。
import Stack from "@mui/material/Stack";
import { FC } from "react" ;
import { useItems } from "redux/items/hooks";
import { useFlows } from "redux/meta/hooks";
import FlowComp from "sym/flow/Flow";
export interface BuildPanelProps{
}
const BuildPanel :FC<BuildPanelProps> = ({})=>{
const {
flows:flowIds,
} = useFlows();
const flows = useItems(flowIds) ;
return (
<div>
<Stack spacing={2}>
{Object.entries(flows).map(([flowId,_item])=>{
return (
<FlowComp flowId={flowId}/>
) ;
})}
</Stack>
</div>
)
}
export default BuildPanel ;
機能を洗い出す
今回実装する機能は以下の通りです。
- 編集パネル上のボタンをクリックするとフローを追加する
- フローに対して記号を追加する
フローの追加
この機能を実装するためには、編集パネル上にボタンを配置し、それがクリックされたときにフローを追加する処理を記述する必要があります。
それぞれ実装します。
+ import Box from "@mui/material/Box";
+ import Button from "@mui/material/Button";
import Stack from "@mui/material/Stack";
import { FC } from "react" ;
import { useItems } from "redux/items/hooks";
import { useFlows } from "redux/meta/hooks";
import FlowComp from "sym/flow/Flow";
export interface BuildPanelProps{
}
const BuildPanel :FC<BuildPanelProps> = ({})=>{
const {
flows:flowIds,
} = useFlows();
const flows = useItems(flowIds) ;
//フローを追加する処理
+ const handleAddFlow = ()=>{
+ //フローオブジェクト作成
+ //フローのIDを決定
+ //idとオブジェクトを紐づける(setItem呼び出し)
+ //meta.flowsにフローのID追加する
+ } ;
return (
<div>
<Stack spacing={2}>
{Object.entries(flows).map(([flowId,_item])=>{
return (
<FlowComp flowId={flowId}/>
) ;
})}
+ <Box sx={{border:"dashed 1px black",p:2,width:"fit-content"}}>
+ <Button onClick={handleAddFlow}>フローを追加</Button>
+ </Box>
</Stack>
</div>
)
}
export default BuildPanel ;
ここでhandleAddFlow
関数内に記述すべき処理を考えます。フローを新規に作成し登録するためには、meta.flowsに追加する必要があります(そこに追加されることでBuildPanelコンポーネントで描画されます)。よってmeta.flowsに追加する処理がまず必要です。しかしこの時追加するのはフローオブジェクトではなくフローのIDです。IDをmeta.flowsに追加しただけだとuseItems
hookでそのフローのフローオブジェクトを取得した時に、フローオブジェクトが取得できないため、フローのIDを追加すると同時にフローオブジェクトも登録する必要があります。よってuseItemOperations
hookで取得できるsetItem
関数を使用してフローオブジェクトも登録します。ということはこの時必要になるフローオブジェクトとそのIDも準備する必要があるため、実行すべき処理は4つになるわけです。
- フローオブジェクトを準備
- そのIDを準備
- setItemでIDとフローオブジェクト登録
- meta.flowsにフローのIDを登録
これを実装しましょう。
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import Stack from "@mui/material/Stack";
import { FC } from "react" ;
import { useItems,useItemOperations } from "redux/items/hooks";
import { Flow } from "redux/items/types";
import { useFlows } from "redux/meta/hooks";
import FlowComp from "sym/flow/Flow";
export interface BuildPanelProps{
}
const BuildPanel :FC<BuildPanelProps> = ({})=>{
const {
flows:flowIds,
addFlow,
} = useFlows();
const flows = useItems(flowIds) ;
const { setItem } = useItemOperations() ;
//フローを追加する処理
const handleAddFlow = ()=>{
//フローオブジェクト作成
const flow :Flow = {
itemType:"flow",
childrenSyms:[],
} ;
//フローのIDを決定(ランダム)
const flowId = `id-flow-${Math.floor(Math.random()*10000000)}` ;
//idとオブジェクトを紐づける(setItem呼び出し)
setItem(flowId,flow);
//meta.flowsにフローのID追加する
addFlow(flowId);
} ;
return (
<div>
<Stack spacing={2}>
{Object.entries(flows).map(([flowId,_item])=>{
return (
<FlowComp flowId={flowId}/>
) ;
})}
<Box sx={{border:"dashed 1px black",p:2,width:"fit-content"}}>
<Button onClick={handleAddFlow}>フローを追加</Button>
</Box>
</Stack>
</div>
)
}
export default BuildPanel ;
おそらくこれでフローが追加できたはずですが今のままではフローの子アイテムがないときに何も表示されていないので、フローがないのかフローはあるが子要素がないのかが分かりにくいです(下の画像参照)。
もし子アイテムが1つもないときは「要素がありません」のような表示をしてほしいです。なのでFlow.tsxを編集します。
import Stack from "@mui/material/Stack";
import { FC } from "react";
import { useItem } from "redux/items/hooks";
import { ItemId,Flow } from "redux/items/types";
import RectSym from "sym/rect/RectSym";
import Arrow from "./Arrow";
export interface FlowProps {
flowId:ItemId,
}
const FlowComp: FC<FlowProps> = ({flowId}) => {
const flow = useItem(flowId) as Flow;
return (
<Stack direction="column">
{flow.childrenSyms.map((symId, idx) => (
<>
{idx === 0 ? null : <Arrow />}
<RectSym itemId={symId} />
</>
))}
+ {/* 子要素がない */}
+ {flow.childrenSyms.length === 0 ?
+ <>
+ 子要素がありません
+ </>
+ : ""}
</Stack>
);
};
export default FlowComp;
これで親切に表示してくれます。
これでフローを追加することができるようになりました。
記号の追加
記号の追加をするためにユーザはどのような操作をすればいいでしょうか?様々な方法が考えられますが、今回は記号を追加ボタンをクリックするまたは記号前後の追加ボタンをクリックすると記号が追加できるようにしてみます。
[[ここに完成イメージ入れたい]]
一番最初の子要素の追加
まず1つも記号がない場合には「子要素がありません」と表示するだけでなく記号を追加するボタンを配置してそれがクリックされたときに子要素を追加するようにします。
import Stack from "@mui/material/Stack";
+ import Button from "components/util/Button";
import { FC } from "react";
import { useItem } from "redux/items/hooks";
import { ItemId,Flow } from "redux/items/types";
import RectSym from "sym/rect/RectSym";
import Arrow from "./Arrow";
export interface FlowProps {
flowId:ItemId,
}
const FlowComp: FC<FlowProps> = ({flowId}) => {
const flow = useItem(flowId) as Flow;
const handleAddSym = ()=>{
//記号を追加する処理
} ;
return (
<Stack direction="column">
{flow.childrenSyms.map((symId, idx) => (
<>
{idx === 0 ? null : <Arrow />}
<RectSym itemId={symId} />
</>
))}
{/* 子要素がない */}
{flow.childrenSyms.length === 0 ?
<>
子要素がありません
+ <Button onClick={handleAddSym}>
+ 記号を追加する
+ </Button>
</>
: ""}
</Stack>
);
};
export default FlowComp;
handleAddSym
にはどのような処理を書けばいいでしょうか?まずは記号をsetItemで登録しておきます(この時IDと記号オブジェクトを用意しておく必要があります)。その後flowのchildrenSymsに新しく作成した記号のIDを登録する必要があります。
import Stack from "@mui/material/Stack";
import Button from "components/util/Button";
import { FC } from "react";
+ import { useItem,useItemOperations } from "redux/items/hooks";
+ import { ItemId,Flow,Sym } from "redux/items/types";
import RectSym from "sym/rect/RectSym";
import Arrow from "./Arrow";
export interface FlowProps {
flowId:ItemId,
}
const FlowComp: FC<FlowProps> = ({flowId}) => {
const flow = useItem(flowId) as Flow;
+ const { setItem } = useItemOperations() ;
const handleAddSym = ()=>{
+ //記号を登録する処理
+ const sym :Sym = {
+ itemType:"rect",
+ options:[],
+ } ;
+ const symId = `rect-id-${Math.floor(Math.random()*100000)}` ;
+ setItem(symId,sym) ;
+ //フローに追加する処理
+ const newFlow = {
+ ...flow,
+ childrenSyms:[ symId ],
+ } ;
+ setItem(flowId,newFlow);
} ;
return (
<Stack direction="column">
{flow.childrenSyms.map((symId, idx) => (
<>
{idx === 0 ? null : <Arrow />}
<RectSym itemId={symId} />
</>
))}
{/* 子要素がない */}
{flow.childrenSyms.length === 0 ?
<>
子要素がありません
<Button onClick={handleAddSym}>
記号を追加する
</Button>
</>
: ""}
</Stack>
);
};
export default FlowComp;
これで一番最初の記号が追加できるようになりました。
2番目以降の子要素の追加
2番目以降の子要素はすでにある要素の前後にボタンを出現させ、それをクリックすることで追加できるようにします。各子要素の前後に追加ボタンを配置します。
+ import Box from "@mui/material/Box";
import Stack from "@mui/material/Stack";
import Button from "components/util/Button";
import { FC } from "react";
import { useItem, useItemOperations } from "redux/items/hooks";
import { ItemId,Flow, Sym } from "redux/items/types";
import RectSym from "sym/rect/RectSym";
import Arrow from "./Arrow";
export interface FlowProps {
flowId:ItemId,
}
const FlowComp: FC<FlowProps> = ({flowId}) => {
const flow = useItem(flowId) as Flow;
const { setItem } = useItemOperations() ;
//一番初めに追加するときの処理
const handleAddSym = ()=>{
//記号を登録する処理
const sym :Sym = {
itemType:"rect",
options:[],
} ;
const symId = `rect-id-${Math.floor(Math.random()*100000)}` ;
setItem(symId,sym) ;
//フローに追加する処理
const newFlow = {
...flow,
childrenSyms:[ symId ],
} ;
setItem(flowId,newFlow);
} ;
+ //2つめ以降の子要素の追加処理
+ const handleAddSymSec = ()=>{
+ //子要素の追加処理
+ } ;
return (
<Stack direction="column">
{flow.childrenSyms.map((symId, idx) => (
<>
{idx === 0 ? null : <Arrow />}
+ <Box sx={{display:"flex",justifyContent:"center",width:baseSetting.size.width}}>
+ <Button onClick={handleAddSymSec} sx={{width:"fit-content"}}>追加</Button>
+ </Box>
<RectSym itemId={symId} />
+ <Box sx={{display:"flex",justifyContent:"center",width:baseSetting.size.width}}>
+ <Button onClick={handleAddSymSec} sx={{width:"fit-content"}}>追加</Button>
+ </Box>
</>
))}
{/* 子要素がない */}
{flow.childrenSyms.length === 0 ?
<>
子要素がありません
<Button onClick={handleAddSym}>
記号を追加する
</Button>
</>
: ""}
</Stack>
);
};
export default FlowComp;
handleAddSymSec
を実装しましょう。
ここで問題が一つ、ですが1つ目の追加処理とは違い、2つ目以降はどこに追加するのかという情報も必要です。なので
なのでhandleAddSymSecにはどこに追加するのかという情報を引数で渡す必要があります。定義時と呼び出し時に引数を追加しましょう。
import Box from "@mui/material/Box";
import Stack from "@mui/material/Stack";
import Button from "components/util/Button";
import { FC } from "react";
import { useItem, useItemOperations } from "redux/items/hooks";
import { ItemId,Flow, Sym } from "redux/items/types";
import { baseSetting } from "sym/base/SymBase";
import RectSym from "sym/rect/RectSym";
import Arrow from "./Arrow";
export interface FlowProps {
flowId:ItemId,
}
const FlowComp: FC<FlowProps> = ({flowId}) => {
const flow = useItem(flowId) as Flow;
const { setItem } = useItemOperations() ;
//一番初めに追加するときの処理
const handleAddSym = ()=>{
//記号を登録する処理
const sym :Sym = {
itemType:"rect",
options:[],
} ;
const symId = `rect-id-${Math.floor(Math.random()*100000)}` ;
setItem(symId,sym) ;
//フローに追加する処理
const newFlow = {
...flow,
childrenSyms:[ symId ],
} ;
setItem(flowId,newFlow);
} ;
//2つめ以降の子要素の追加処理
+ const handleAddSymSec = (idx:number)=>{
//子要素の追加処理
//idxで指定した位置に追加する
} ;
return (
<Stack direction="column">
{flow.childrenSyms.map((symId, idx) => (
<>
{idx === 0 ? null : <Arrow />}
<Box sx={{display:"flex",justifyContent:"center",width:baseSetting.size.width}}>
+ <Button onClick={()=>handleAddSymSec(idx)} sx={{width:"fit-content"}}>追加</Button>
</Box>
<RectSym itemId={symId} />
<Box sx={{display:"flex",justifyContent:"center",width:baseSetting.size.width}}>
+ <Button onClick={()=>handleAddSymSec(idx+1)} sx={{width:"fit-content"}}>追加</Button>
</Box>
</>
))}
{/* 子要素がない */}
{flow.childrenSyms.length === 0 ?
<>
子要素がありません
<Button onClick={handleAddSym}>
記号を追加する
</Button>
</>
: ""}
</Stack>
);
};
export default FlowComp;
いよいよ追加する処理を考えていきます。前と同じように①追加する記号のオブジェクトを用意し、②記号をsetItemし、③フローに追加して、④フローをsetItemする4手順で実装します。
import Box from "@mui/material/Box";
import Stack from "@mui/material/Stack";
import Button from "components/util/Button";
import { FC } from "react";
import { useItem, useItemOperations } from "redux/items/hooks";
import { ItemId,Flow, Sym } from "redux/items/types";
import { baseSetting } from "sym/base/SymBase";
import RectSym from "sym/rect/RectSym";
import Arrow from "./Arrow";
export interface FlowProps {
flowId:ItemId,
}
const FlowComp: FC<FlowProps> = ({flowId}) => {
const flow = useItem(flowId) as Flow;
const { setItem } = useItemOperations() ;
//一番初めに追加するときの処理
const handleAddSym = ()=>{
//記号を登録する処理
const sym :Sym = {
itemType:"rect",
options:[],
} ;
const symId = `rect-id-${Math.floor(Math.random()*100000)}` ;
setItem(symId,sym) ;
//フローに追加する処理
const newFlow = {
...flow,
childrenSyms:[ symId ],
} ;
setItem(flowId,newFlow);
} ;
//2つめ以降の子要素の追加処理
const handleAddSymSec = (idx:number)=>{
//子要素の追加処理
//idxで指定した位置に追加する
+ const sym :Sym = {
+ itemType:"rect",
+ options:[],
+ } ;
+ const symId = `rect-id-${Math.floor(Math.random()*100000)}` ;
+ setItem(symId,sym);
+ const newChildrenSyms = [...flow.childrenSyms] ;
+ newChildrenSyms.splice(idx,0,symId) ;
+ const newFlow = {
+ ...flow,
+ childrenSyms:newChildrenSyms,
+ } ;
+ setItem(flowId,newFlow)
} ;
return (
<Stack direction="column">
{flow.childrenSyms.map((symId, idx) => (
<>
{idx === 0 ? null : <Arrow />}
<Box sx={{display:"flex",justifyContent:"center",width:baseSetting.size.width}}>
<Button onClick={()=>handleAddSymSec(idx)} sx={{width:"fit-content"}}>追加</Button>
</Box>
<RectSym itemId={symId} />
<Box sx={{display:"flex",justifyContent:"center",width:baseSetting.size.width}}>
<Button onClick={()=>handleAddSymSec(idx+1)} sx={{width:"fit-content"}}>追加</Button>
</Box>
</>
))}
{/* 子要素がない */}
{flow.childrenSyms.length === 0 ?
<>
子要素がありません
<Button onClick={handleAddSym}>
記号を追加する
</Button>
</>
: ""}
</Stack>
);
};
export default FlowComp;
これで子要素の追加もできるようになりました。
リファクタリング
ここでちょっとしたリファクタリングを行います。具体的には共通部分の関数化などを行っていきます。
hadleAddSymの統一
1つ目の子要素の追加処理handleAddSym()
は2つ目の子要素の追加処理handleAddSymSec(0)
と同等です。よっていままでhandleAddSym
を呼び出していたところはhandleAddSymSec(0)
に置き換えることができます。これで無駄な関数定義を排除してコードを見やすくします。またこれで雇用を追加する関数はhandleAddSymSec
のみになったのでhandleAddSym
に名前を変えておきましょう。
import Box from "@mui/material/Box";
import Stack from "@mui/material/Stack";
import Button from "components/util/Button";
import { FC } from "react";
import { useItem, useItemOperations } from "redux/items/hooks";
import { ItemId,Flow, Sym } from "redux/items/types";
import { baseSetting } from "sym/base/SymBase";
import RectSym from "sym/rect/RectSym";
import Arrow from "./Arrow";
export interface FlowProps {
flowId:ItemId,
}
const FlowComp: FC<FlowProps> = ({flowId}) => {
const flow = useItem(flowId) as Flow;
const { setItem } = useItemOperations() ;
//追加処理
+ const handleAddSym = (idx:number)=>{
//子要素の追加処理
//idxで指定した位置に追加する
const sym :Sym = {
itemType:"rect",
options:[],
} ;
const symId = `rect-id-${Math.floor(Math.random()*100000)}` ;
setItem(symId,sym);
const newChildrenSyms = [...flow.childrenSyms] ;
newChildrenSyms.splice(idx,0,symId) ;
const newFlow = {
...flow,
childrenSyms:newChildrenSyms,
} ;
setItem(flowId,newFlow)
} ;
return (
<Stack direction="column">
{flow.childrenSyms.map((symId, idx) => (
<>
{idx === 0 ? null : <Arrow />}
<Box sx={{display:"flex",justifyContent:"center",width:baseSetting.size.width}}>
<Button onClick={()=>handleAddSym(idx)} sx={{width:"fit-content"}}>追加</Button>
</Box>
<RectSym itemId={symId} />
<Box sx={{display:"flex",justifyContent:"center",width:baseSetting.size.width}}>
<Button onClick={()=>handleAddSym(idx+1)} sx={{width:"fit-content"}}>追加</Button>
</Box>
</>
))}
{/* 子要素がない */}
{flow.childrenSyms.length === 0 ?
<>
子要素がありません
+ <Button onClick={()=>handleAddSym(0)}>
記号を追加する
</Button>
</>
: ""}
</Stack>
);
};
export default FlowComp;
IDを自動生成する関数を作成する
新たな記号などを追加するとき、以下のように適当なIDをランダムに生成していました。
const symId = `rect-id-${Math.floor(Math.random()*100000)}` ;
この記述ではランダムなIDを生成している処理であることが分かりにくいため、ランダムなIDを返す関数createRandomItemId()
を作成します。これはフローに限ら内処理なのでプロジェクトルート/src/sym/util.ts
に作成します。
export function createRandomItemId(itemType:string){
return `${itemType}-id-${Math.floor(Math.random()*100000)}` ;
}
呼び出すときは次のように使用します。
import Box from "@mui/material/Box";
import Stack from "@mui/material/Stack";
import Button from "components/util/Button";
import { FC } from "react";
import { useItem, useItemOperations } from "redux/items/hooks";
import { ItemId,Flow, Sym } from "redux/items/types";
import { baseSetting } from "sym/base/SymBase";
import RectSym from "sym/rect/RectSym";
+ import { createRandomItemId } from "sym/util";
import Arrow from "./Arrow";
export interface FlowProps {
flowId:ItemId,
}
const FlowComp: FC<FlowProps> = ({flowId}) => {
const flow = useItem(flowId) as Flow;
const { setItem } = useItemOperations() ;
//追加処理
const handleAddSym = (idx:number)=>{
//子要素の追加処理
//idxで指定した位置に追加する
const sym :Sym = {
itemType:"rect",
options:[],
} ;
+ const symId = createRandomItemId(sym.itemType) ;
setItem(symId,sym);
const newChildrenSyms = [...flow.childrenSyms] ;
newChildrenSyms.splice(idx,0,symId) ;
const newFlow = {
...flow,
childrenSyms:newChildrenSyms,
} ;
setItem(flowId,newFlow)
} ;
return (
<Stack direction="column">
{flow.childrenSyms.map((symId, idx) => (
<>
{idx === 0 ? null : <Arrow />}
<Box sx={{display:"flex",justifyContent:"center",width:baseSetting.size.width}}>
<Button onClick={()=>handleAddSym(idx)} sx={{width:"fit-content"}}>追加</Button>
</Box>
<RectSym itemId={symId} />
<Box sx={{display:"flex",justifyContent:"center",width:baseSetting.size.width}}>
<Button onClick={()=>handleAddSym(idx+1)} sx={{width:"fit-content"}}>追加</Button>
</Box>
</>
))}
{/* 子要素がない */}
{flow.childrenSyms.length === 0 ?
<>
子要素がありません
<Button onClick={()=>handleAddSym(0)}>
記号を追加する
</Button>
</>
: ""}
</Stack>
);
};
export default FlowComp;
アイテムオブジェクトを生成する処理を関数化する
アイテムオブジェクト(記号オブジェクト・フローオブジェクト)を作成するときに毎回{ itemType:"〇〇", ...}
と書くのは面倒です。今は([]
で)省略していますが、本来はoptionsにOptionを設定する必要もあります。なのでこれを関数化します。だいぶ前の章で触れましたが、アイテムオブジェクトを作成する関数をアイテムクリエイターと呼ぶことにしていました。アイテムクリエイターを記号やフローごとに定義します。
まずはrect(長方形)のアイテムクリエイターです。
import { Sym } from "redux/items/types";
export default function rectCreator() :Sym{
return {
itemType:"rect", //アイテムのプロパティ
options:[], //rectのプロパティ
} ;
}
つづいてフローのアイテムクリエイターです。
import { Flow } from "redux/items/types";
export default function flowCreator() :Flow{
return {
itemType:"flow", //アイテムのプロパティ
childrenSyms:[], //フローのプロパティ
} ;
}
長方形記号もフローもどちらもアイテムです。なのでそれらのアイテムオブジェクトにはitemType
プロパティが含まれます。なのでこれもitemCreator
として共通化してしまいましょう。
import { Item } from "redux/items/types";
export default function itemCreator(itemType:string) :Item{
return {
itemType,
} ;
}
これを使って長方形記号のアイテムクリエイターを定義しなおすと次のようになります。(これでアイテムクリエイターは完成なのでファイルに記述してもOKです)
import { Sym } from "redux/items/types";
import itemCreator from "sym/base/creator";
export default function rectCreator() :Sym{
return {
...itemCreator("rect"),
options:[],
} ;
}
フローのアイテムクリエイターも定義し直します。
import { Flow } from "redux/items/types";
import itemCreator from "sym/base/creator";
export default function flowCreator():Flow{
return {
...itemCreator("flow"),
childrenSyms:[],
} ;
}
これをそれぞれ追加処理を行う場所で利用します。
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import Stack from "@mui/material/Stack";
import { FC } from "react" ;
import { useItems,useItemOperations } from "redux/items/hooks";
import { Flow } from "redux/items/types";
import { useFlows } from "redux/meta/hooks";
+ import flowCreator from "sym/flow/creator";
import FlowComp from "sym/flow/Flow";
export interface BuildPanelProps{
}
const BuildPanel :FC<BuildPanelProps> = ({})=>{
const {
flows:flowIds,
addFlow,
} = useFlows();
const flows = useItems(flowIds) ;
const { setItem } = useItemOperations() ;
//フローを追加する処理
const handleAddFlow = ()=>{
//フローオブジェクト作成
+ const flow = flowCreator() ;
//フローのIDを決定(ランダム)
const flowId = `id-flow-${Math.floor(Math.random()*10000000)}` ;
//idとオブジェクトを紐づける(setItem呼び出し)
setItem(flowId,flow);
//meta.flowsにフローのID追加する
addFlow(flowId);
} ;
return (
<div>
<Stack spacing={2}>
{Object.entries(flows).map(([flowId,_item])=>{
return (
<FlowComp flowId={flowId}/>
) ;
})}
<Box sx={{border:"dashed 1px black",p:2,width:"fit-content"}}>
<Button onClick={handleAddFlow}>フローを追加</Button>
</Box>
</Stack>
</div>
)
}
export default BuildPanel ;
import Box from "@mui/material/Box";
import Stack from "@mui/material/Stack";
import Button from "components/util/Button";
import { FC } from "react";
import { useItem, useItemOperations } from "redux/items/hooks";
import { ItemId,Flow, Sym } from "redux/items/types";
import { baseSetting } from "sym/base/SymBase";
+ import rectCreator from "sym/rect/creator";
import RectSym from "sym/rect/RectSym";
import { createRandomItemId } from "sym/util";
import Arrow from "./Arrow";
export interface FlowProps {
flowId:ItemId,
}
const FlowComp: FC<FlowProps> = ({flowId}) => {
const flow = useItem(flowId) as Flow;
const { setItem } = useItemOperations() ;
//追加処理
const handleAddSym = (idx:number)=>{
//子要素の追加処理
//idxで指定した位置に追加する
+ const sym :Sym = rectCreator() ;
const symId = createRandomItemId(sym.itemType) ;
setItem(symId,sym);
const newChildrenSyms = [...flow.childrenSyms] ;
newChildrenSyms.splice(idx,0,symId) ;
const newFlow = {
...flow,
childrenSyms:newChildrenSyms,
} ;
setItem(flowId,newFlow)
} ;
return (
<Stack direction="column">
{flow.childrenSyms.map((symId, idx) => (
<>
{idx === 0 ? null : <Arrow />}
<Box sx={{display:"flex",justifyContent:"center",width:baseSetting.size.width}}>
<Button onClick={()=>handleAddSym(idx)} sx={{width:"fit-content"}}>追加</Button>
</Box>
<RectSym itemId={symId} />
<Box sx={{display:"flex",justifyContent:"center",width:baseSetting.size.width}}>
<Button onClick={()=>handleAddSym(idx+1)} sx={{width:"fit-content"}}>追加</Button>
</Box>
</>
))}
{/* 子要素がない */}
{flow.childrenSyms.length === 0 ?
<>
子要素がありません
<Button onClick={()=>handleAddSym(0)}>
記号を追加する
</Button>
</>
: ""}
</Stack>
);
};
export default FlowComp;
これでアイテムオブジェクトに変更があっても(オプションの追加など)変更しなければいけないファイルが1つになります。
ここまでのソースコード
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import Stack from "@mui/material/Stack";
import { FC } from "react" ;
import { useItems,useItemOperations } from "redux/items/hooks";
import { Flow } from "redux/items/types";
import { useFlows } from "redux/meta/hooks";
import flowCreator from "sym/flow/creator";
import FlowComp from "sym/flow/Flow";
export interface BuildPanelProps{
}
const BuildPanel :FC<BuildPanelProps> = ({})=>{
const {
flows:flowIds,
addFlow,
} = useFlows();
const flows = useItems(flowIds) ;
const { setItem } = useItemOperations() ;
//フローを追加する処理
const handleAddFlow = ()=>{
//フローオブジェクト作成
const flow = flowCreator() ;
//フローのIDを決定(ランダム)
const flowId = `id-flow-${Math.floor(Math.random()*10000000)}` ;
//idとオブジェクトを紐づける(setItem呼び出し)
setItem(flowId,flow);
//meta.flowsにフローのID追加する
addFlow(flowId);
} ;
return (
<div>
<Stack spacing={2}>
{Object.entries(flows).map(([flowId,_item])=>{
return (
<FlowComp flowId={flowId}/>
) ;
})}
<Box sx={{border:"dashed 1px black",p:2,width:"fit-content"}}>
<Button onClick={handleAddFlow}>フローを追加</Button>
</Box>
</Stack>
</div>
)
}
export default BuildPanel ;
import Box from "@mui/material/Box";
import Stack from "@mui/material/Stack";
import Button from "components/util/Button";
import { FC } from "react";
import { useItem, useItemOperations } from "redux/items/hooks";
import { ItemId,Flow, Sym } from "redux/items/types";
import { baseSetting } from "sym/base/SymBase";
import rectCreator from "sym/rect/creator";
import RectSym from "sym/rect/RectSym";
import { createRandomItemId } from "sym/util";
import Arrow from "./Arrow";
export interface FlowProps {
flowId:ItemId,
}
const FlowComp: FC<FlowProps> = ({flowId}) => {
const flow = useItem(flowId) as Flow;
const { setItem } = useItemOperations() ;
//追加処理
const handleAddSym = (idx:number)=>{
//子要素の追加処理
//idxで指定した位置に追加する
const sym :Sym = rectCreator() ;
const symId = createRandomItemId(sym.itemType) ;
setItem(symId,sym);
const newChildrenSyms = [...flow.childrenSyms] ;
newChildrenSyms.splice(idx,0,symId) ;
const newFlow = {
...flow,
childrenSyms:newChildrenSyms,
} ;
setItem(flowId,newFlow)
} ;
return (
<Stack direction="column">
{flow.childrenSyms.map((symId, idx) => (
<>
{idx === 0 ? null : <Arrow />}
<Box sx={{display:"flex",justifyContent:"center",width:baseSetting.size.width}}>
<Button onClick={()=>handleAddSym(idx)} sx={{width:"fit-content"}}>追加</Button>
</Box>
<RectSym itemId={symId} />
<Box sx={{display:"flex",justifyContent:"center",width:baseSetting.size.width}}>
<Button onClick={()=>handleAddSym(idx+1)} sx={{width:"fit-content"}}>追加</Button>
</Box>
</>
))}
{/* 子要素がない */}
{flow.childrenSyms.length === 0 ?
<>
子要素がありません
<Button onClick={()=>handleAddSym(0)}>
記号を追加する
</Button>
</>
: ""}
</Stack>
);
};
export default FlowComp;
import { Sym } from "redux/items/types";
import itemCreator from "sym/base/creator";
export default function rectCreator() :Sym{
return {
...itemCreator("rect"),
options:[],
} ;
}
import { Flow } from "redux/items/types";
import itemCreator from "sym/base/creator";
export default function flowCreator():Flow{
return {
...itemCreator("flow"),
childrenSyms:[],
} ;
}
import { Item } from "redux/items/types";
export default function itemCreator(itemType:string) :Item{
return {
itemType,
} ;
}
export function createRandomItemId(itemType:string){
return `${itemType}-id-${Math.floor(Math.random()*100000)}` ;
}