@workbench-kit/jdw-editor 0.0.1-prototype.0 → 0.0.2-prototype.0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -3
- package/src/JdwSampleScreenExplorer.tsx +181 -181
- package/src/ScreenNodeInspector.tsx +203 -203
- package/src/ScreenSpecEditor.tsx +196 -196
- package/src/index.ts +14 -14
- package/src/useScreenSpecPipeline.ts +88 -88
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@workbench-kit/jdw-editor",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2-prototype.0.1.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
"!src/**/*.stories.tsx"
|
|
15
15
|
],
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@workbench-kit/jdw": "0.0.
|
|
18
|
-
"@workbench-kit/react": "0.0.
|
|
17
|
+
"@workbench-kit/jdw": "0.0.2-prototype.0.1.4",
|
|
18
|
+
"@workbench-kit/react": "0.0.2-prototype.0.1.4"
|
|
19
19
|
},
|
|
20
20
|
"peerDependencies": {
|
|
21
21
|
"react": "^19.0.0"
|
|
@@ -1,181 +1,181 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react';
|
|
2
|
-
|
|
3
|
-
import { compileScreenSpecText } from '@workbench-kit/jdw';
|
|
4
|
-
import { JdwPreview } from '@workbench-kit/react/jdw/preview';
|
|
5
|
-
import {
|
|
6
|
-
JDW_SAMPLE_SCREENS,
|
|
7
|
-
formatJdwSampleScreenSpec,
|
|
8
|
-
type JdwSampleScreenDefinition,
|
|
9
|
-
} from '@workbench-kit/react/jdw/samples';
|
|
10
|
-
import {
|
|
11
|
-
Field,
|
|
12
|
-
Panel,
|
|
13
|
-
PanelBody,
|
|
14
|
-
PanelHeader,
|
|
15
|
-
Select,
|
|
16
|
-
SegmentedControl,
|
|
17
|
-
WorkbenchParseError,
|
|
18
|
-
} from '@workbench-kit/react/primitives';
|
|
19
|
-
import { SplitView } from '@workbench-kit/react/workbench/shell';
|
|
20
|
-
|
|
21
|
-
import { ScreenSpecEditor } from './ScreenSpecEditor.js';
|
|
22
|
-
import { useScreenSpecPipeline } from './useScreenSpecPipeline.js';
|
|
23
|
-
|
|
24
|
-
export type JdwSampleSourceView = 'editor' | 'jdw';
|
|
25
|
-
|
|
26
|
-
export interface JdwSampleScreenExplorerProps {
|
|
27
|
-
readonly samples?: readonly JdwSampleScreenDefinition[] | undefined;
|
|
28
|
-
readonly initialSampleId?: string | undefined;
|
|
29
|
-
readonly initialSourceView?: JdwSampleSourceView | undefined;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function resolveSample(
|
|
33
|
-
samples: readonly JdwSampleScreenDefinition[],
|
|
34
|
-
sampleId: string,
|
|
35
|
-
): JdwSampleScreenDefinition {
|
|
36
|
-
return samples.find((entry) => entry.id === sampleId) ?? samples[0]!;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const SOURCE_VIEW_OPTIONS = [
|
|
40
|
-
{ label: 'Screen editor', testId: 'jdw-sample-source-editor', value: 'editor' as const },
|
|
41
|
-
{ label: 'JDW JSON', testId: 'jdw-sample-source-jdw', value: 'jdw' as const },
|
|
42
|
-
];
|
|
43
|
-
|
|
44
|
-
export function JdwSampleScreenExplorer({
|
|
45
|
-
samples = JDW_SAMPLE_SCREENS,
|
|
46
|
-
initialSampleId,
|
|
47
|
-
initialSourceView = 'editor',
|
|
48
|
-
}: JdwSampleScreenExplorerProps) {
|
|
49
|
-
const [sampleId, setSampleId] = useState(initialSampleId ?? samples[0]?.id ?? '');
|
|
50
|
-
const [sourceView, setSourceView] = useState<JdwSampleSourceView>(initialSourceView);
|
|
51
|
-
const activeSample = resolveSample(samples, sampleId);
|
|
52
|
-
const pipeline = useScreenSpecPipeline(activeSample);
|
|
53
|
-
const { resetSpec } = pipeline;
|
|
54
|
-
const [editorError, setEditorError] = useState<string | null>(null);
|
|
55
|
-
|
|
56
|
-
useEffect(() => {
|
|
57
|
-
resetSpec(resolveSample(samples, sampleId));
|
|
58
|
-
setEditorError(null);
|
|
59
|
-
}, [resetSpec, sampleId, samples]);
|
|
60
|
-
|
|
61
|
-
if (samples.length === 0) {
|
|
62
|
-
return <div data-testid="jdw-sample-explorer-empty">No sample screens configured.</div>;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const compileError = pipeline.compileError ?? editorError;
|
|
66
|
-
|
|
67
|
-
const handleSourceViewChange = (nextView: JdwSampleSourceView) => {
|
|
68
|
-
if (nextView === 'jdw') {
|
|
69
|
-
const compiled = compileScreenSpecText(formatJdwSampleScreenSpec(pipeline.spec));
|
|
70
|
-
if (compiled.json) {
|
|
71
|
-
pipeline.setJson(compiled.json);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
setSourceView(nextView);
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
return (
|
|
78
|
-
<div className="jdw-sample-explorer" data-testid="jdw-sample-explorer">
|
|
79
|
-
<Panel
|
|
80
|
-
className="jdw-sample-explorer__panel"
|
|
81
|
-
style={{ display: 'flex', flexDirection: 'column', minHeight: 0, flex: 1 }}
|
|
82
|
-
>
|
|
83
|
-
<PanelHeader
|
|
84
|
-
actions={
|
|
85
|
-
<div className="jdw-sample-explorer__header-actions">
|
|
86
|
-
<SegmentedControl
|
|
87
|
-
ariaLabel="Source view"
|
|
88
|
-
options={SOURCE_VIEW_OPTIONS}
|
|
89
|
-
value={sourceView}
|
|
90
|
-
onChange={handleSourceViewChange}
|
|
91
|
-
/>
|
|
92
|
-
<Field label="Sample screen" htmlFor="jdw-sample-screen-select" inline>
|
|
93
|
-
<Select
|
|
94
|
-
id="jdw-sample-screen-select"
|
|
95
|
-
aria-label="Sample screen"
|
|
96
|
-
data-testid="jdw-sample-screen-select"
|
|
97
|
-
controlWidth="wide"
|
|
98
|
-
value={activeSample.id}
|
|
99
|
-
onValueChange={setSampleId}
|
|
100
|
-
>
|
|
101
|
-
{samples.map((sample) => (
|
|
102
|
-
<option key={sample.id} value={sample.id}>
|
|
103
|
-
{sample.title}
|
|
104
|
-
</option>
|
|
105
|
-
))}
|
|
106
|
-
</Select>
|
|
107
|
-
</Field>
|
|
108
|
-
</div>
|
|
109
|
-
}
|
|
110
|
-
>
|
|
111
|
-
JDW Sample Explorer
|
|
112
|
-
</PanelHeader>
|
|
113
|
-
<PanelBody
|
|
114
|
-
className="jdw-sample-explorer__body"
|
|
115
|
-
style={{
|
|
116
|
-
display: 'flex',
|
|
117
|
-
flexDirection: 'column',
|
|
118
|
-
gap: 8,
|
|
119
|
-
minHeight: 0,
|
|
120
|
-
flex: 1,
|
|
121
|
-
paddingTop: 0,
|
|
122
|
-
}}
|
|
123
|
-
>
|
|
124
|
-
<p className="jdw-sample-explorer__description">{activeSample.description}</p>
|
|
125
|
-
{compileError ? (
|
|
126
|
-
<WorkbenchParseError role="alert" data-testid="jdw-sample-explorer-error">
|
|
127
|
-
{compileError}
|
|
128
|
-
</WorkbenchParseError>
|
|
129
|
-
) : null}
|
|
130
|
-
<SplitView
|
|
131
|
-
className="jdw-sample-explorer__split"
|
|
132
|
-
defaultPrimarySizePercent={46}
|
|
133
|
-
minPrimarySizePercent={24}
|
|
134
|
-
maxPrimarySizePercent={72}
|
|
135
|
-
primary={
|
|
136
|
-
<section
|
|
137
|
-
aria-label={sourceView === 'editor' ? 'Screen spec editor' : 'JDW JSON source'}
|
|
138
|
-
className="jdw-sample-explorer__pane"
|
|
139
|
-
data-testid="jdw-sample-explorer-source-pane"
|
|
140
|
-
>
|
|
141
|
-
<header className="jdw-sample-explorer__pane-header">
|
|
142
|
-
{sourceView === 'editor' ? 'Screen editor' : 'JDW JSON'}
|
|
143
|
-
</header>
|
|
144
|
-
<div className="jdw-sample-explorer__pane-body">
|
|
145
|
-
{sourceView === 'editor' ? (
|
|
146
|
-
<ScreenSpecEditor
|
|
147
|
-
value={pipeline.spec}
|
|
148
|
-
onChange={pipeline.setSpec}
|
|
149
|
-
onCompileError={setEditorError}
|
|
150
|
-
/>
|
|
151
|
-
) : (
|
|
152
|
-
<textarea
|
|
153
|
-
aria-label="JDW JSON source"
|
|
154
|
-
className="jdw-sample-explorer__json-source"
|
|
155
|
-
data-testid="jdw-sample-explorer-json"
|
|
156
|
-
value={pipeline.json}
|
|
157
|
-
onChange={(event) => pipeline.setJson(event.target.value)}
|
|
158
|
-
spellCheck={false}
|
|
159
|
-
/>
|
|
160
|
-
)}
|
|
161
|
-
</div>
|
|
162
|
-
</section>
|
|
163
|
-
}
|
|
164
|
-
secondary={
|
|
165
|
-
<section
|
|
166
|
-
aria-label="Rendered preview"
|
|
167
|
-
className="jdw-sample-explorer__pane"
|
|
168
|
-
data-testid="jdw-sample-explorer-preview-pane"
|
|
169
|
-
>
|
|
170
|
-
<header className="jdw-sample-explorer__pane-header">Preview</header>
|
|
171
|
-
<div className="jdw-sample-explorer__pane-body">
|
|
172
|
-
<JdwPreview json={pipeline.json} layoutConstraints={pipeline.layoutConstraints} />
|
|
173
|
-
</div>
|
|
174
|
-
</section>
|
|
175
|
-
}
|
|
176
|
-
/>
|
|
177
|
-
</PanelBody>
|
|
178
|
-
</Panel>
|
|
179
|
-
</div>
|
|
180
|
-
);
|
|
181
|
-
}
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import { compileScreenSpecText } from '@workbench-kit/jdw';
|
|
4
|
+
import { JdwPreview } from '@workbench-kit/react/jdw/preview';
|
|
5
|
+
import {
|
|
6
|
+
JDW_SAMPLE_SCREENS,
|
|
7
|
+
formatJdwSampleScreenSpec,
|
|
8
|
+
type JdwSampleScreenDefinition,
|
|
9
|
+
} from '@workbench-kit/react/jdw/samples';
|
|
10
|
+
import {
|
|
11
|
+
Field,
|
|
12
|
+
Panel,
|
|
13
|
+
PanelBody,
|
|
14
|
+
PanelHeader,
|
|
15
|
+
Select,
|
|
16
|
+
SegmentedControl,
|
|
17
|
+
WorkbenchParseError,
|
|
18
|
+
} from '@workbench-kit/react/primitives';
|
|
19
|
+
import { SplitView } from '@workbench-kit/react/workbench/shell';
|
|
20
|
+
|
|
21
|
+
import { ScreenSpecEditor } from './ScreenSpecEditor.js';
|
|
22
|
+
import { useScreenSpecPipeline } from './useScreenSpecPipeline.js';
|
|
23
|
+
|
|
24
|
+
export type JdwSampleSourceView = 'editor' | 'jdw';
|
|
25
|
+
|
|
26
|
+
export interface JdwSampleScreenExplorerProps {
|
|
27
|
+
readonly samples?: readonly JdwSampleScreenDefinition[] | undefined;
|
|
28
|
+
readonly initialSampleId?: string | undefined;
|
|
29
|
+
readonly initialSourceView?: JdwSampleSourceView | undefined;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function resolveSample(
|
|
33
|
+
samples: readonly JdwSampleScreenDefinition[],
|
|
34
|
+
sampleId: string,
|
|
35
|
+
): JdwSampleScreenDefinition {
|
|
36
|
+
return samples.find((entry) => entry.id === sampleId) ?? samples[0]!;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const SOURCE_VIEW_OPTIONS = [
|
|
40
|
+
{ label: 'Screen editor', testId: 'jdw-sample-source-editor', value: 'editor' as const },
|
|
41
|
+
{ label: 'JDW JSON', testId: 'jdw-sample-source-jdw', value: 'jdw' as const },
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
export function JdwSampleScreenExplorer({
|
|
45
|
+
samples = JDW_SAMPLE_SCREENS,
|
|
46
|
+
initialSampleId,
|
|
47
|
+
initialSourceView = 'editor',
|
|
48
|
+
}: JdwSampleScreenExplorerProps) {
|
|
49
|
+
const [sampleId, setSampleId] = useState(initialSampleId ?? samples[0]?.id ?? '');
|
|
50
|
+
const [sourceView, setSourceView] = useState<JdwSampleSourceView>(initialSourceView);
|
|
51
|
+
const activeSample = resolveSample(samples, sampleId);
|
|
52
|
+
const pipeline = useScreenSpecPipeline(activeSample);
|
|
53
|
+
const { resetSpec } = pipeline;
|
|
54
|
+
const [editorError, setEditorError] = useState<string | null>(null);
|
|
55
|
+
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
resetSpec(resolveSample(samples, sampleId));
|
|
58
|
+
setEditorError(null);
|
|
59
|
+
}, [resetSpec, sampleId, samples]);
|
|
60
|
+
|
|
61
|
+
if (samples.length === 0) {
|
|
62
|
+
return <div data-testid="jdw-sample-explorer-empty">No sample screens configured.</div>;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const compileError = pipeline.compileError ?? editorError;
|
|
66
|
+
|
|
67
|
+
const handleSourceViewChange = (nextView: JdwSampleSourceView) => {
|
|
68
|
+
if (nextView === 'jdw') {
|
|
69
|
+
const compiled = compileScreenSpecText(formatJdwSampleScreenSpec(pipeline.spec));
|
|
70
|
+
if (compiled.json) {
|
|
71
|
+
pipeline.setJson(compiled.json);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
setSourceView(nextView);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<div className="jdw-sample-explorer" data-testid="jdw-sample-explorer">
|
|
79
|
+
<Panel
|
|
80
|
+
className="jdw-sample-explorer__panel"
|
|
81
|
+
style={{ display: 'flex', flexDirection: 'column', minHeight: 0, flex: 1 }}
|
|
82
|
+
>
|
|
83
|
+
<PanelHeader
|
|
84
|
+
actions={
|
|
85
|
+
<div className="jdw-sample-explorer__header-actions">
|
|
86
|
+
<SegmentedControl
|
|
87
|
+
ariaLabel="Source view"
|
|
88
|
+
options={SOURCE_VIEW_OPTIONS}
|
|
89
|
+
value={sourceView}
|
|
90
|
+
onChange={handleSourceViewChange}
|
|
91
|
+
/>
|
|
92
|
+
<Field label="Sample screen" htmlFor="jdw-sample-screen-select" inline>
|
|
93
|
+
<Select
|
|
94
|
+
id="jdw-sample-screen-select"
|
|
95
|
+
aria-label="Sample screen"
|
|
96
|
+
data-testid="jdw-sample-screen-select"
|
|
97
|
+
controlWidth="wide"
|
|
98
|
+
value={activeSample.id}
|
|
99
|
+
onValueChange={setSampleId}
|
|
100
|
+
>
|
|
101
|
+
{samples.map((sample) => (
|
|
102
|
+
<option key={sample.id} value={sample.id}>
|
|
103
|
+
{sample.title}
|
|
104
|
+
</option>
|
|
105
|
+
))}
|
|
106
|
+
</Select>
|
|
107
|
+
</Field>
|
|
108
|
+
</div>
|
|
109
|
+
}
|
|
110
|
+
>
|
|
111
|
+
JDW Sample Explorer
|
|
112
|
+
</PanelHeader>
|
|
113
|
+
<PanelBody
|
|
114
|
+
className="jdw-sample-explorer__body"
|
|
115
|
+
style={{
|
|
116
|
+
display: 'flex',
|
|
117
|
+
flexDirection: 'column',
|
|
118
|
+
gap: 8,
|
|
119
|
+
minHeight: 0,
|
|
120
|
+
flex: 1,
|
|
121
|
+
paddingTop: 0,
|
|
122
|
+
}}
|
|
123
|
+
>
|
|
124
|
+
<p className="jdw-sample-explorer__description">{activeSample.description}</p>
|
|
125
|
+
{compileError ? (
|
|
126
|
+
<WorkbenchParseError role="alert" data-testid="jdw-sample-explorer-error">
|
|
127
|
+
{compileError}
|
|
128
|
+
</WorkbenchParseError>
|
|
129
|
+
) : null}
|
|
130
|
+
<SplitView
|
|
131
|
+
className="jdw-sample-explorer__split"
|
|
132
|
+
defaultPrimarySizePercent={46}
|
|
133
|
+
minPrimarySizePercent={24}
|
|
134
|
+
maxPrimarySizePercent={72}
|
|
135
|
+
primary={
|
|
136
|
+
<section
|
|
137
|
+
aria-label={sourceView === 'editor' ? 'Screen spec editor' : 'JDW JSON source'}
|
|
138
|
+
className="jdw-sample-explorer__pane"
|
|
139
|
+
data-testid="jdw-sample-explorer-source-pane"
|
|
140
|
+
>
|
|
141
|
+
<header className="jdw-sample-explorer__pane-header">
|
|
142
|
+
{sourceView === 'editor' ? 'Screen editor' : 'JDW JSON'}
|
|
143
|
+
</header>
|
|
144
|
+
<div className="jdw-sample-explorer__pane-body">
|
|
145
|
+
{sourceView === 'editor' ? (
|
|
146
|
+
<ScreenSpecEditor
|
|
147
|
+
value={pipeline.spec}
|
|
148
|
+
onChange={pipeline.setSpec}
|
|
149
|
+
onCompileError={setEditorError}
|
|
150
|
+
/>
|
|
151
|
+
) : (
|
|
152
|
+
<textarea
|
|
153
|
+
aria-label="JDW JSON source"
|
|
154
|
+
className="jdw-sample-explorer__json-source"
|
|
155
|
+
data-testid="jdw-sample-explorer-json"
|
|
156
|
+
value={pipeline.json}
|
|
157
|
+
onChange={(event) => pipeline.setJson(event.target.value)}
|
|
158
|
+
spellCheck={false}
|
|
159
|
+
/>
|
|
160
|
+
)}
|
|
161
|
+
</div>
|
|
162
|
+
</section>
|
|
163
|
+
}
|
|
164
|
+
secondary={
|
|
165
|
+
<section
|
|
166
|
+
aria-label="Rendered preview"
|
|
167
|
+
className="jdw-sample-explorer__pane"
|
|
168
|
+
data-testid="jdw-sample-explorer-preview-pane"
|
|
169
|
+
>
|
|
170
|
+
<header className="jdw-sample-explorer__pane-header">Preview</header>
|
|
171
|
+
<div className="jdw-sample-explorer__pane-body">
|
|
172
|
+
<JdwPreview json={pipeline.json} layoutConstraints={pipeline.layoutConstraints} />
|
|
173
|
+
</div>
|
|
174
|
+
</section>
|
|
175
|
+
}
|
|
176
|
+
/>
|
|
177
|
+
</PanelBody>
|
|
178
|
+
</Panel>
|
|
179
|
+
</div>
|
|
180
|
+
);
|
|
181
|
+
}
|