Skip to content

Commit a380871

Browse files
committed
0.33.0.
1 parent 6d12712 commit a380871

File tree

21 files changed

+457
-150
lines changed

21 files changed

+457
-150
lines changed

demos/react-app/src/App.tsx

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,53 @@
11
import { useState } from 'react';
22
import { Playground } from './playground/Playground';
33
import { NativeEditors } from './nativeEditors/NativeEditors';
4+
import { SaveRequiredEditor } from './saveRequiredEditor/SaveRequiredEditor';
45

5-
const pathKey = 'swdReactPath';
6-
type AppPath = 'playground' | 'nativeEditors';
6+
const TABS = [
7+
{
8+
label: '🍭 Playground',
9+
path: 'playground'
10+
},
11+
{
12+
label: '🔌 Native Editors',
13+
path: 'native-editors'
14+
},
15+
{
16+
label: '🔴 Save Required Editor',
17+
path: 'save-required-editor'
18+
}
19+
];
720

821
export function App() {
9-
const [path, setPath] = useState<AppPath>((localStorage[pathKey] as AppPath) || 'playground');
22+
const [path, setPath] = useState<string>(window.location.hash?.substring(1) || 'playground');
1023

11-
function changePath(path: AppPath) {
12-
localStorage[pathKey] = path;
24+
function changePath(path: string) {
25+
window.location.hash = path;
1326
setPath(path);
1427
}
1528

1629
return (
1730
<>
18-
<nav>
19-
<h1>SWD for React Demo</h1>
20-
<button onClick={() => changePath('playground')} className={path === 'playground' ? 'selected' : ''}>
21-
Playground
22-
</button>
23-
<button onClick={() => changePath('nativeEditors')} className={path === 'nativeEditors' ? 'selected' : ''}>
24-
Native editors
25-
</button>
26-
<a href="https://github.com/nocode-js/sequential-workflow-designer/tree/main/react" className="github">
27-
GitHub
28-
</a>
31+
<nav className="title-bar">
32+
<div className="column demo">
33+
Select Demo:{' '}
34+
<select defaultValue={path}>
35+
{TABS.map(t => (
36+
<option key={t.path} value={t.path} onClick={() => changePath(t.path)}>
37+
{t.label}
38+
</option>
39+
))}
40+
</select>
41+
</div>
42+
<div className="column link">
43+
<a href="https://github.com/nocode-js/sequential-workflow-designer/tree/main/react" className="github">
44+
SWD for React
45+
</a>
46+
</div>
2947
</nav>
3048
{path === 'playground' && <Playground />}
31-
{path === 'nativeEditors' && <NativeEditors />}
49+
{path === 'native-editors' && <NativeEditors />}
50+
{path === 'save-required-editor' && <SaveRequiredEditor />}
3251
</>
3352
);
3453
}

demos/react-app/src/index.css

Lines changed: 47 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,69 @@
11
body,
22
h1 {
33
font:
4-
13px/1.3em Arial,
4+
14px/1.3em 'Open Sans',
5+
Arial,
56
Verdana,
67
Serif;
78
}
8-
body {
9-
margin: 0;
10-
padding: 0;
11-
}
129

13-
nav {
14-
padding: 10px 5px 0;
15-
background: #333;
16-
}
17-
nav h1 {
18-
display: inline-block;
19-
margin: 0 15px;
10+
html,
11+
body,
12+
#root {
13+
margin: 0;
2014
padding: 0;
21-
color: #fff;
15+
width: 100%;
16+
height: 100%;
17+
background: #fff;
2218
}
23-
nav button {
24-
background: #999;
25-
border: 0;
26-
padding: 10px 15px;
27-
margin: 0 5px;
28-
cursor: pointer;
29-
border-top-left-radius: 8px;
30-
border-top-right-radius: 8px;
19+
#root {
20+
display: flex;
21+
flex-direction: column;
3122
}
32-
nav button.selected {
33-
background: #f9f9f9;
23+
24+
.title-bar {
25+
display: flex;
26+
min-height: 60px;
27+
align-items: center;
28+
width: 100%;
29+
background: #fff;
30+
box-shadow: inset 0 -2px 2px rgba(0, 0, 0, 0.06);
3431
}
35-
nav button:hover {
36-
opacity: 0.8;
32+
.title-bar .column {
33+
padding: 10px;
3734
}
38-
nav .github {
39-
margin: 0 5px;
40-
color: #fff;
35+
.title-bar .column.link {
36+
flex: 1;
37+
text-align: right;
4138
}
42-
nav .github:hover {
39+
.title-bar .column.link a {
40+
color: #222;
4341
text-decoration: none;
4442
}
45-
@media only screen and (max-width: 700px) {
46-
nav h1 {
47-
display: none;
48-
}
43+
.title-bar .column.link a:hover {
44+
text-decoration: underline;
4945
}
5046

47+
.designer {
48+
flex: 1;
49+
position: relative;
50+
}
5151
.sqd-designer-react {
52-
width: 100vw;
53-
height: 50vh;
52+
position: absolute;
53+
top: 0;
54+
bottom: 0;
55+
left: 0;
56+
right: 0;
57+
overflow: hidden;
5458
}
55-
.sqd-editor {
59+
.sqd-designer-react .sqd-editor {
5660
padding: 10px;
61+
line-height: 1.35em;
62+
}
63+
64+
.sidebar {
65+
flex: 1;
5766
}
58-
input:read-only {
59-
opacity: 0.35;
67+
.sidebar textarea {
68+
width: 100%;
6069
}

demos/react-app/src/index.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ import { App } from './App';
55
import './index.css';
66

77
import 'sequential-workflow-designer/css/designer.css';
8-
import 'sequential-workflow-designer/css/designer-light.css';
9-
import 'sequential-workflow-designer/css/designer-dark.css';
8+
import 'sequential-workflow-designer/css/designer-soft.css';
109

1110
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
1211
root.render(

demos/react-app/src/nativeEditors/NativeEditors.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,15 @@ export const startDefinition: Definition = {
1616
};
1717

1818
function rootEditorProvider(): HTMLElement {
19+
const h2 = document.createElement('h2');
20+
h2.innerText = '🔌 Native Editors Demo';
21+
22+
const p = document.createElement('p');
23+
p.innerHTML = 'This demo demonstrates how to use natively implemented editors inside React application.';
24+
1925
const editor = document.createElement('div');
20-
editor.innerHTML = 'Root editor';
26+
editor.appendChild(h2);
27+
editor.appendChild(p);
2128
return editor;
2229
}
2330

@@ -40,9 +47,10 @@ export function NativeEditors() {
4047
const [definition, setDefinition] = useState(() => wrapDefinition(startDefinition));
4148

4249
return (
43-
<>
50+
<div className="designer">
4451
<SequentialWorkflowDesigner
4552
definition={definition}
53+
theme="soft"
4654
onDefinitionChange={setDefinition}
4755
toolboxConfiguration={false}
4856
stepsConfiguration={{}}
@@ -51,6 +59,6 @@ export function NativeEditors() {
5159
rootEditor={rootEditorProvider}
5260
stepEditor={stepEditorProvider}
5361
/>
54-
</>
62+
</div>
5563
);
5664
}

demos/react-app/src/playground/Playground.tsx

Lines changed: 48 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -135,51 +135,55 @@ export function Playground() {
135135

136136
return (
137137
<>
138-
{isVisible && (
139-
<SequentialWorkflowDesigner
140-
undoStackSize={10}
141-
definition={definition}
142-
onDefinitionChange={setDefinition}
143-
selectedStepId={selectedStepId}
144-
isReadonly={isReadonly}
145-
onSelectedStepIdChanged={setSelectedStepId}
146-
toolboxConfiguration={toolboxConfiguration}
147-
isToolboxCollapsed={isToolboxCollapsed}
148-
onIsToolboxCollapsedChanged={setIsToolboxCollapsed}
149-
stepsConfiguration={stepsConfiguration}
150-
validatorConfiguration={validatorConfiguration}
151-
placeholderConfiguration={placeholderConfiguration}
152-
controlBar={true}
153-
rootEditor={<RootEditor />}
154-
stepEditor={<StepEditor />}
155-
isEditorCollapsed={isEditorCollapsed}
156-
onIsEditorCollapsedChanged={setIsEditorCollapsed}
157-
controller={controller}
158-
/>
159-
)}
160-
161-
<ul>
162-
<li>Definition: {definitionJson.length} bytes</li>
163-
<li>Selected step: {selectedStepId}</li>
164-
<li>Is readonly: {yesOrNo(isReadonly)}</li>
165-
<li>Is valid: {definition.isValid === undefined ? '?' : yesOrNo(definition.isValid)}</li>
166-
<li>Is toolbox collapsed: {yesOrNo(isToolboxCollapsed)}</li>
167-
<li>Is editor collapsed: {yesOrNo(isEditorCollapsed)}</li>
168-
</ul>
169-
170-
<div>
171-
<button onClick={toggleVisibilityClicked}>Toggle visibility</button>
172-
<button onClick={reloadDefinitionClicked}>Reload definition</button>
173-
<button onClick={toggleSelectionClicked}>Toggle selection</button>
174-
<button onClick={toggleIsReadonlyClicked}>Toggle readonly</button>
175-
<button onClick={toggleToolboxClicked}>Toggle toolbox</button>
176-
<button onClick={toggleEditorClicked}>Toggle editor</button>
177-
<button onClick={moveViewportToFirstStepClicked}>Move viewport to first step</button>
178-
<button onClick={appendStepClicked}>Append step</button>
138+
<div className="designer">
139+
{isVisible && (
140+
<SequentialWorkflowDesigner
141+
undoStackSize={10}
142+
theme="soft"
143+
definition={definition}
144+
onDefinitionChange={setDefinition}
145+
selectedStepId={selectedStepId}
146+
isReadonly={isReadonly}
147+
onSelectedStepIdChanged={setSelectedStepId}
148+
toolboxConfiguration={toolboxConfiguration}
149+
isToolboxCollapsed={isToolboxCollapsed}
150+
onIsToolboxCollapsedChanged={setIsToolboxCollapsed}
151+
stepsConfiguration={stepsConfiguration}
152+
validatorConfiguration={validatorConfiguration}
153+
placeholderConfiguration={placeholderConfiguration}
154+
controlBar={true}
155+
rootEditor={<RootEditor />}
156+
stepEditor={<StepEditor />}
157+
isEditorCollapsed={isEditorCollapsed}
158+
onIsEditorCollapsedChanged={setIsEditorCollapsed}
159+
controller={controller}
160+
/>
161+
)}
179162
</div>
180-
181-
<div>
182-
<textarea value={definitionJson} readOnly={true} cols={100} rows={15} />
163+
<div className="sidebar">
164+
<ul>
165+
<li>Definition: {definitionJson.length} bytes</li>
166+
<li>Selected step: {selectedStepId}</li>
167+
<li>Is readonly: {yesOrNo(isReadonly)}</li>
168+
<li>Is valid: {definition.isValid === undefined ? '?' : yesOrNo(definition.isValid)}</li>
169+
<li>Is toolbox collapsed: {yesOrNo(isToolboxCollapsed)}</li>
170+
<li>Is editor collapsed: {yesOrNo(isEditorCollapsed)}</li>
171+
</ul>
172+
173+
<div>
174+
<button onClick={toggleVisibilityClicked}>Toggle visibility</button>
175+
<button onClick={reloadDefinitionClicked}>Reload definition</button>
176+
<button onClick={toggleSelectionClicked}>Toggle selection</button>
177+
<button onClick={toggleIsReadonlyClicked}>Toggle readonly</button>
178+
<button onClick={toggleToolboxClicked}>Toggle toolbox</button>
179+
<button onClick={toggleEditorClicked}>Toggle editor</button>
180+
<button onClick={moveViewportToFirstStepClicked}>Move viewport to first step</button>
181+
<button onClick={appendStepClicked}>Append step</button>
182+
</div>
183+
184+
<div>
185+
<textarea value={definitionJson} readOnly={true} cols={100} rows={4} />
186+
</div>
183187
</div>
184188
</>
185189
);

demos/react-app/src/playground/RootEditor.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ export function RootEditor() {
1111

1212
return (
1313
<>
14-
<h2>Root editor</h2>
14+
<h2>🍭 Playground Demo</h2>
15+
16+
<p>This demo showcases how several features of the Sequential Workflow Designer can be used within a React application.</p>
1517

1618
<h4>Alfa</h4>
1719

demos/react-app/src/playground/StepEditor.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export function StepEditor() {
3131

3232
return (
3333
<>
34-
<h2>Step Editor {type}</h2>
34+
<h2>Step Editor - {type}</h2>
3535

3636
<h4>Name</h4>
3737
<input type="text" value={name} readOnly={isReadonly} onChange={onNameChanged} />
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { useEffect, useState } from 'react';
2+
import { SimpleEvent } from 'sequential-workflow-designer';
3+
4+
export class ChangeController {
5+
public readonly onIsChangedChanged = new SimpleEvent<boolean>();
6+
public isChanged = false;
7+
8+
public set(isChanged: boolean) {
9+
if (this.isChanged !== isChanged) {
10+
this.isChanged = isChanged;
11+
this.onIsChangedChanged.forward(isChanged);
12+
}
13+
}
14+
}
15+
16+
export interface ChangeControllerWrapper {
17+
controller: ChangeController;
18+
isChanged: boolean;
19+
}
20+
21+
export function useChangeControllerWrapper(controller: ChangeController): ChangeControllerWrapper {
22+
const [wrapper, setWrapper] = useState(() => ({
23+
controller,
24+
isChanged: controller.isChanged
25+
}));
26+
27+
useEffect(() => {
28+
function onIsDirtyChanged(isChanged: boolean) {
29+
setWrapper({
30+
...wrapper,
31+
isChanged
32+
});
33+
}
34+
35+
wrapper.controller.onIsChangedChanged.subscribe(onIsDirtyChanged);
36+
return () => {
37+
wrapper.controller.onIsChangedChanged.unsubscribe(onIsDirtyChanged);
38+
};
39+
}, [wrapper]);
40+
41+
return wrapper;
42+
}

0 commit comments

Comments
 (0)