Skip to content

Commit a10b29b

Browse files
chore(docs): extend stories for editing options
1 parent f9a9d8f commit a10b29b

2 files changed

Lines changed: 180 additions & 15 deletions

File tree

stories/FlowModeler.Editing.stories.mdx

Lines changed: 164 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,36 +10,185 @@ import { FlowModeler } from "../src/index";
1010
# FlowModeler
1111
## Editing Structure
1212

13+
<Props of={FlowModeler} exclude={Object.keys(FlowModeler.propTypes).filter(propName => propName !== "onChange" && propName !== "editActions")} />
14+
1315
Enable editing by providing an `onChange` callback function that will receive the updated `flow` after each structural change.
1416
This should then be stored in some external (e.g. Redux) store/state and provided as `flow` prop.
1517

16-
export const externalState = {
17-
flow: {
18-
firstElementId: "1",
19-
elements: {
20-
"1": { data: { label: "First" }, nextElementId: "2" },
21-
"2": { data: { label: "Second" }, nextElementId: "3" },
22-
"3": { data: { label: "Condition" }, nextElements: [
23-
{ id: "4.1", conditionData: { label: "Fulfilled" } },
24-
{ id: "4.2", conditionData: { label: "Not fulfilled" } }] },
25-
"4.1": { data: { label: "Option 1" }, nextElementId: "5" },
26-
"4.2": { data: { label: "Option 2" }, nextElementId: "5" },
27-
"5": { data: { label: "Follow-Up"}}
28-
}
18+
export const initialState = {
19+
firstElementId: "1",
20+
elements: {
21+
"1": { data: { label: "First" }, nextElementId: "2" },
22+
"2": { data: { label: "Second" }, nextElementId: "3" },
23+
"3": { data: { label: "Condition" }, nextElements: [
24+
{ id: "4.1", conditionData: { label: "Fulfilled" } },
25+
{ id: "4.2", conditionData: { label: "Not fulfilled" } }] },
26+
"4.1": { data: { label: "Option 1" }, nextElementId: "5" },
27+
"4.2": { data: { label: "Option 2" }, nextElementId: "5" },
28+
"5": { data: { label: "Follow-Up"}}
2929
}
3030
}
3131

32+
export const externalState = {
33+
flow1: initialState,
34+
flow2: initialState,
35+
flow3: initialState,
36+
flow4: initialState,
37+
flow5: initialState
38+
}
39+
3240
<Preview>
3341
<Story name="structure">
3442
<FlowModeler
35-
flow={externalState.flow}
43+
flow={externalState.flow1}
44+
renderStep={({ data }) => <span>{data && data.label}</span>}
45+
renderGatewayConditionType={({ data }) => <label>{data && data.label}</label>}
46+
renderGatewayConditionValue={({ data }) => <label>{data && data.label}</label>}
47+
onChange={({ changedFlow }) => {
48+
externalState.flow1 = changedFlow;
49+
forceReRender();
50+
}}
51+
/>
52+
</Story>
53+
</Preview>
54+
55+
If the elements themselves are supposed to be editable, you'll have to use the appropriate components within the
56+
`renderStep()`/`renderGatewayConditionType()`/`renderGatewayConditionValue()` functions and take care of the update of the state yourself.
57+
58+
<Preview>
59+
<Story name="elements">
60+
<FlowModeler
61+
flow={externalState.flow2}
62+
renderStep={({ id, data }) => (
63+
<input
64+
type="text"
65+
value={data ? data.label : ""}
66+
onChange={(event) => {
67+
externalState.flow2.elements[id].data = ({ label: event.target.value });
68+
forceReRender();
69+
}}
70+
/>
71+
)}
72+
renderGatewayConditionType={({ id, data }) => (
73+
<select
74+
value={data ? data.label : ""}
75+
onChange={(event) => {
76+
externalState.flow2.elements[id].data = ({ label: event.target.value });
77+
event.stopPropagation();
78+
forceReRender();
79+
}}>
80+
<option value="">n/a</option>
81+
<option value="Condition">Condition</option>
82+
<option value="Check">Check</option>
83+
</select>
84+
)}
85+
renderGatewayConditionValue={({ precedingElement, branchIndex, data }) => (
86+
<input
87+
type="text"
88+
value={data ? data.label : ""}
89+
onChange={(event) => {
90+
externalState.flow2.elements[precedingElement.id].nextElements[branchIndex].conditionData = ({ label: event.target.value });
91+
forceReRender();
92+
}}
93+
/>
94+
)}
95+
onChange={({ changedFlow }) => {
96+
externalState.flow2 = changedFlow;
97+
forceReRender();
98+
}}
99+
/>
100+
</Story>
101+
</Preview>
102+
103+
----
104+
105+
You can additionally customise the `editActions` to align the `<FlowModeler>` with the rest of your application and/or offer meaningful defaults.
106+
107+
Via the `editActions` you can specify your own `className` for each action in the edit context menu – e.g. enabling you to use your own icons.
108+
This completely replaces the standard styles (via which the standard symbols are associated),
109+
i.e. to build on-top of the existing styles, you'll need to include the standard css classes again.
110+
Additionally, you may specify an alternative `title` as tool-tip for each offered action.
111+
112+
<Preview>
113+
<Story name="menu styles and tool-tips">
114+
<FlowModeler
115+
flow={externalState.flow3}
36116
renderStep={({ data }) => <span>{data && data.label}</span>}
37117
renderGatewayConditionType={({ data }) => <label>{data && data.label}</label>}
38118
renderGatewayConditionValue={({ data }) => <label>{data && data.label}</label>}
39119
onChange={({ changedFlow }) => {
40-
externalState.flow = changedFlow;
120+
externalState.flow3 = changedFlow;
41121
forceReRender();
42122
}}
123+
editActions={{
124+
addDivergingBranch: { className: "menu-item add-branch customised-color-1", title: "Add Branch" },
125+
addFollowingStepElement: { className: "menu-item add-step customised-color-2", title: "Add Step Element" },
126+
addFollowingDivergingGateway: { className: "menu-item add-gateway customised-color-3", title: "Add Diverging Gateway" },
127+
changeNextElement: { className: "menu-item change-next customised-color-4", title: "Change next Element to…" },
128+
removeElement: { className: "menu-item remove customised-color-5", title: "Remove" }
129+
}}
130+
/>
131+
</Story>
132+
</Preview>
133+
134+
Via the `editActions` you can also influence the default contents of newly added step, diverging gateway or branches of diverging gateways
135+
– through the corresponding callbacks.
136+
137+
<Preview>
138+
<Story name="custom contents on creation">
139+
<FlowModeler
140+
flow={externalState.flow4}
141+
renderStep={({ data }) => <span>{data && data.label}</span>}
142+
renderGatewayConditionType={({ data }) => <label>{data && data.label}</label>}
143+
renderGatewayConditionValue={({ data }) => <label>{data && data.label}</label>}
144+
onChange={({ changedFlow }) => {
145+
externalState.flow4 = changedFlow;
146+
forceReRender();
147+
}}
148+
editActions={{
149+
addDivergingBranch: { getBranchConditionData: (gateway) => ({ label: `custom branch ${1 + gateway.followingBranches.length}` }) },
150+
addFollowingStepElement: { getStepData: () => ({ label: "custom element" }) },
151+
addFollowingDivergingGateway: {
152+
getGatewayData: () => ({ label: "custom gateway" }),
153+
getBranchConditionData: () => [{ label: "branch 1" }, { label: "branch 2" }, { label: "branch 3" }]
154+
}
155+
}}
156+
/>
157+
</Story>
158+
</Preview>
159+
160+
One more setting in the `editActions` is to answer in a particular context the question: `isActionAllowed`? This allows you to preserve certain parts
161+
of the model as-is while still allowing other parts to be changed. Or to completely disable certain actions, e.g. not even allow any gateways or
162+
additional branches to be added.
163+
164+
<Preview>
165+
<Story name="disabled actions">
166+
<FlowModeler
167+
flow={externalState.flow5}
168+
renderStep={({ data }) => <span>{data && data.label}</span>}
169+
renderGatewayConditionType={({ data }) => <label>{data && data.label}</label>}
170+
renderGatewayConditionValue={({ data }) => <label>{data && data.label}</label>}
171+
onChange={({ changedFlow }) => {
172+
externalState.flow5 = changedFlow;
173+
forceReRender();
174+
}}
175+
editActions={{
176+
addDivergingBranch: {
177+
isActionAllowed: (gateway) => (gateway.followingBranches.length < 3)
178+
},
179+
addFollowingStepElement: {
180+
isActionAllowed: (prior) => prior.type !== "step" || prior.followingElement.type !== "step"
181+
},
182+
addFollowingDivergingGateway: {
183+
isActionAllowed: (prior) => prior.type !== "conv-gw"
184+
},
185+
changeNextElement: {
186+
isActionAllowed: () => false
187+
},
188+
removeElement: {
189+
isActionAllowed: () => true
190+
}
191+
}}
43192
/>
44193
</Story>
45194
</Preview>

stories/style-overrides.css

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,19 @@ div.css-1dm44cd {
1010
.step-element > * {
1111
margin: 0.25em;
1212
}
13+
14+
.customised-color-1 {
15+
color: red;
16+
}
17+
.customised-color-2 {
18+
color: teal;
19+
}
20+
.customised-color-3 {
21+
color: turquoise;
22+
}
23+
.customised-color-4 {
24+
color: orange;
25+
}
26+
.customised-color-5 {
27+
color: orchid;
28+
}

0 commit comments

Comments
 (0)