@contentful/experience-design-system-cli 2.7.1 → 2.7.2-dev-build-bc65c2b.0
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/dist/package.json +1 -1
- package/dist/src/analyze/select/tui/App.js +28 -62
- package/dist/src/analyze/select/tui/components/ComponentDetail.d.ts +2 -3
- package/dist/src/analyze/select/tui/components/ComponentDetail.js +3 -3
- package/dist/src/analyze/select/tui/components/JsonEditor.d.ts +2 -3
- package/dist/src/analyze/select/tui/components/JsonEditor.js +39 -62
- package/package.json +2 -2
package/dist/package.json
CHANGED
|
@@ -3,7 +3,6 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
|
3
3
|
import { Box, Text, useStdout } from 'ink';
|
|
4
4
|
import { readFile } from 'node:fs/promises';
|
|
5
5
|
import { createReviewSessionDetail } from '../types.js';
|
|
6
|
-
import { stripScoringFields } from '../../../types.js';
|
|
7
6
|
import { TopBar } from './components/TopBar.js';
|
|
8
7
|
import { Sidebar } from './components/Sidebar.js';
|
|
9
8
|
import { ComponentDetail } from './components/ComponentDetail.js';
|
|
@@ -41,11 +40,6 @@ export function App({ sessionId, artifactsRoot, reviewRoot }) {
|
|
|
41
40
|
const [finalizedResult, setFinalizedResult] = useState(null);
|
|
42
41
|
const [sidebarScrollOffset, setSidebarScrollOffset] = useState(0);
|
|
43
42
|
const [jsonScrollOffset, setJsonScrollOffset] = useState(0);
|
|
44
|
-
// Keeps the visual sort order in sync for use inside keymap handlers (which close over a stale render)
|
|
45
|
-
const sortedIdsRef = useRef([]);
|
|
46
|
-
// Source code kept separate from session state so lazy loading never mutates
|
|
47
|
-
// session.components — that would invalidate useMemo(sessionSummary) and flash the sidebar
|
|
48
|
-
const [sourceCodeById, setSourceCodeById] = useState({});
|
|
49
43
|
const [previewAnnotations, setPreviewAnnotations] = useState(() => {
|
|
50
44
|
const raw = process.env['EDS_PREVIEW_ANNOTATIONS'];
|
|
51
45
|
if (!raw)
|
|
@@ -144,22 +138,13 @@ export function App({ sessionId, artifactsRoot, reviewRoot }) {
|
|
|
144
138
|
clearTimeout(previewDebounceRef.current);
|
|
145
139
|
};
|
|
146
140
|
}, []);
|
|
147
|
-
// Sync loaded session into local state
|
|
148
|
-
// and will be corrected to the first sorted item on first render via the effect below
|
|
141
|
+
// Sync loaded session into local state
|
|
149
142
|
useEffect(() => {
|
|
150
143
|
if (loadedSession && !session) {
|
|
151
144
|
setSession(loadedSession);
|
|
152
|
-
setSelectedId(null);
|
|
145
|
+
setSelectedId(loadedSession.components[0]?.id ?? null);
|
|
153
146
|
}
|
|
154
147
|
}, [loadedSession]);
|
|
155
|
-
// Once the sort order is known (after first render), select the first sorted item.
|
|
156
|
-
// Runs only when session transitions from null → loaded.
|
|
157
|
-
const sessionLoaded = session !== null;
|
|
158
|
-
useEffect(() => {
|
|
159
|
-
if (sessionLoaded && selectedId === null && sortedIdsRef.current.length > 0) {
|
|
160
|
-
setSelectedId(sortedIdsRef.current[0]);
|
|
161
|
-
}
|
|
162
|
-
}, [sessionLoaded]);
|
|
163
148
|
useEffect(() => {
|
|
164
149
|
if (session && !previewResponse) {
|
|
165
150
|
const raw = process.env['EDS_PREVIEW_COUNTS'];
|
|
@@ -187,22 +172,26 @@ export function App({ sessionId, artifactsRoot, reviewRoot }) {
|
|
|
187
172
|
}
|
|
188
173
|
}
|
|
189
174
|
}, [session]);
|
|
190
|
-
// Lazy source code loading
|
|
191
|
-
// so it doesn't invalidate useMemo(sessionSummary) and cause a sidebar flash
|
|
175
|
+
// Lazy source code loading
|
|
192
176
|
useEffect(() => {
|
|
193
177
|
if (!session || !selectedId)
|
|
194
178
|
return;
|
|
195
|
-
if (sourceCodeById[selectedId] !== undefined)
|
|
196
|
-
return; // already loaded
|
|
197
179
|
const selectedComponent = session.components.find((c) => c.id === selectedId);
|
|
198
|
-
if (!selectedComponent)
|
|
180
|
+
if (!selectedComponent || selectedComponent.sourceCode !== null)
|
|
199
181
|
return;
|
|
200
182
|
readFile(selectedComponent.resolvedSourcePath, 'utf8')
|
|
201
183
|
.then((code) => {
|
|
202
|
-
|
|
184
|
+
setSession((prev) => {
|
|
185
|
+
if (!prev)
|
|
186
|
+
return prev;
|
|
187
|
+
return {
|
|
188
|
+
...prev,
|
|
189
|
+
components: prev.components.map((c) => (c.id === selectedComponent.id ? { ...c, sourceCode: code } : c)),
|
|
190
|
+
};
|
|
191
|
+
});
|
|
203
192
|
})
|
|
204
193
|
.catch(() => {
|
|
205
|
-
|
|
194
|
+
// Leave as null; SourcePanel shows [No source available]
|
|
206
195
|
});
|
|
207
196
|
}, [selectedId]);
|
|
208
197
|
// SIGINT handler
|
|
@@ -246,10 +235,9 @@ export function App({ sessionId, artifactsRoot, reviewRoot }) {
|
|
|
246
235
|
onSidebarUp: () => {
|
|
247
236
|
if (!session)
|
|
248
237
|
return;
|
|
249
|
-
const
|
|
250
|
-
const idx = ids.indexOf(selectedId ?? '');
|
|
238
|
+
const idx = session.components.findIndex((c) => c.id === selectedId);
|
|
251
239
|
if (idx > 0) {
|
|
252
|
-
setSelectedId(
|
|
240
|
+
setSelectedId(session.components[idx - 1].id);
|
|
253
241
|
setJsonScrollOffset(0);
|
|
254
242
|
setSidebarScrollOffset((prev) => Math.min(prev, idx - 1));
|
|
255
243
|
}
|
|
@@ -257,10 +245,9 @@ export function App({ sessionId, artifactsRoot, reviewRoot }) {
|
|
|
257
245
|
onSidebarDown: () => {
|
|
258
246
|
if (!session)
|
|
259
247
|
return;
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
setSelectedId(ids[idx + 1]);
|
|
248
|
+
const idx = session.components.findIndex((c) => c.id === selectedId);
|
|
249
|
+
if (idx < session.components.length - 1) {
|
|
250
|
+
setSelectedId(session.components[idx + 1].id);
|
|
264
251
|
setJsonScrollOffset(0);
|
|
265
252
|
setSidebarScrollOffset((prev) => {
|
|
266
253
|
const newIdx = idx + 1;
|
|
@@ -286,7 +273,7 @@ export function App({ sessionId, artifactsRoot, reviewRoot }) {
|
|
|
286
273
|
setEditMode(true);
|
|
287
274
|
setDraftsByComponentId((prev) => ({
|
|
288
275
|
...prev,
|
|
289
|
-
[selectedId]: prev[selectedId] ?? JSON.stringify(
|
|
276
|
+
[selectedId]: prev[selectedId] ?? JSON.stringify(component.editedProposal, null, 2),
|
|
290
277
|
}));
|
|
291
278
|
},
|
|
292
279
|
onToggleSource: () => {
|
|
@@ -328,9 +315,7 @@ export function App({ sessionId, artifactsRoot, reviewRoot }) {
|
|
|
328
315
|
},
|
|
329
316
|
onToggleHelp: () => setShowHelp((prev) => !prev),
|
|
330
317
|
});
|
|
331
|
-
//
|
|
332
|
-
// Memoised above early returns (React rules of hooks) so the array reference
|
|
333
|
-
// is stable between renders — prevents Sidebar repainting on scroll/select.
|
|
318
|
+
// Must be before early returns — Rules of Hooks
|
|
334
319
|
const sessionSummary = useMemo(() => (session?.components ?? [])
|
|
335
320
|
.map((c) => ({
|
|
336
321
|
id: c.id,
|
|
@@ -341,18 +326,12 @@ export function App({ sessionId, artifactsRoot, reviewRoot }) {
|
|
|
341
326
|
needsReview: c.originalProposal.needsReview ?? false,
|
|
342
327
|
}))
|
|
343
328
|
.sort((a, b) => {
|
|
344
|
-
const
|
|
345
|
-
const
|
|
346
|
-
if (
|
|
347
|
-
return
|
|
348
|
-
|
|
349
|
-
const aConf = a.extractionConfidence ?? 6;
|
|
350
|
-
const bConf = b.extractionConfidence ?? 6;
|
|
351
|
-
return aConf - bConf;
|
|
329
|
+
const aF = a.needsReview && a.status === 'needs-review' ? 0 : 1;
|
|
330
|
+
const bF = b.needsReview && b.status === 'needs-review' ? 0 : 1;
|
|
331
|
+
if (aF !== bF)
|
|
332
|
+
return aF - bF;
|
|
333
|
+
return (a.extractionConfidence ?? 6) - (b.extractionConfidence ?? 6);
|
|
352
334
|
}), [session?.components, previewAnnotations]);
|
|
353
|
-
// Stable ID order — kept in a ref for use inside keymap handlers
|
|
354
|
-
const sortedIds = useMemo(() => sessionSummary.map((c) => c.id), [sessionSummary]);
|
|
355
|
-
sortedIdsRef.current = sortedIds;
|
|
356
335
|
if (loading) {
|
|
357
336
|
return _jsx(Text, { children: "Loading session..." });
|
|
358
337
|
}
|
|
@@ -384,17 +363,13 @@ export function App({ sessionId, artifactsRoot, reviewRoot }) {
|
|
|
384
363
|
{ key: 'q', label: 'quit' },
|
|
385
364
|
];
|
|
386
365
|
const collapsed = terminalWidth < 80;
|
|
387
|
-
|
|
388
|
-
const CHROME_ROWS = 5;
|
|
389
|
-
const terminalRows = stdout?.rows ?? 24;
|
|
390
|
-
const visibleCount = Math.max(1, terminalRows - CHROME_ROWS);
|
|
366
|
+
const visibleCount = 20;
|
|
391
367
|
const longestName = session.components.reduce((max, c) => Math.max(max, c.name.length), 0);
|
|
392
368
|
// icon + space + name + 2 border chars; min 14, max 22
|
|
393
369
|
const sidebarWidth = collapsed ? 3 : Math.min(Math.max(longestName + 4, 14), 22);
|
|
394
|
-
const handleDraftSave = async () => {
|
|
370
|
+
const handleDraftSave = async (draft) => {
|
|
395
371
|
if (!selectedId || !session || !paths)
|
|
396
372
|
return;
|
|
397
|
-
const draft = draftsByComponentId[selectedId];
|
|
398
373
|
if (!draft)
|
|
399
374
|
return;
|
|
400
375
|
try {
|
|
@@ -503,16 +478,7 @@ export function App({ sessionId, artifactsRoot, reviewRoot }) {
|
|
|
503
478
|
}, onCancel: () => setShowQuitDialog(false) })), !showHelp && !showFinalizeDialog && !showQuitDialog && (_jsxs(Box, { flexGrow: 1, children: [_jsx(Sidebar, { components: sessionSummary, selectedId: selectedId, focused: sidebarFocused, scrollOffset: sidebarScrollOffset, visibleCount: visibleCount, onSelect: (id) => {
|
|
504
479
|
setSelectedId(id);
|
|
505
480
|
setJsonScrollOffset(0);
|
|
506
|
-
}, onScrollChange: setSidebarScrollOffset, collapsed: collapsed, width: sidebarWidth }), _jsx(Box, { flexGrow: 1, paddingLeft: 1, children: selectedDetail ? (_jsx(ComponentDetail, { component: selectedDetail, sourceCode:
|
|
507
|
-
if (!selectedId)
|
|
508
|
-
return;
|
|
509
|
-
setDraftsByComponentId((prev) => ({
|
|
510
|
-
...prev,
|
|
511
|
-
[selectedId]: value,
|
|
512
|
-
}));
|
|
513
|
-
}, onSaveDraft: () => {
|
|
514
|
-
void handleDraftSave();
|
|
515
|
-
}, onDiscardDraft: handleDraftDiscard, onScrollChange: setJsonScrollOffset })) : (_jsx(Text, { dimColor: true, children: "No component selected" })) })] })), _jsx(PreviewSummaryBar, { preview: previewResponse, loading: previewLoading }), previewError && _jsx(Text, { color: "yellow", children: '⚠ Preview: ' + previewError }), saveError && _jsx(Text, { color: "red", children: '⚠ ' + saveError }), !dialogOpen && (_jsx(StatusBar, { accepted: acceptedCount, rejected: rejectedCount, reviewed: reviewedCount, needsReview: needsReviewCount, onApproveAll: () => { }, onFinalize: () => setShowFinalizeDialog(true) }))] }));
|
|
481
|
+
}, onScrollChange: setSidebarScrollOffset, collapsed: collapsed, width: sidebarWidth }), _jsx(Box, { flexGrow: 1, paddingLeft: 1, children: selectedDetail ? (_jsx(ComponentDetail, { component: selectedDetail, sourceCode: selectedRecord?.sourceCode ?? null, draftValue: selectedId ? (draftsByComponentId[selectedId] ?? '') : '', editMode: editMode, sourceVisible: sourceVisible, jsonScrollOffset: jsonScrollOffset, sourceScrollX: 0, sourceScrollY: 0, terminalWidth: terminalWidth, previewAnnotation: selectedRecord ? previewAnnotations[selectedRecord.name] : undefined, onSaveDraft: (value) => void handleDraftSave(value), onDiscardDraft: handleDraftDiscard, onScrollChange: setJsonScrollOffset })) : (_jsx(Text, { dimColor: true, children: "No component selected" })) })] })), _jsx(PreviewSummaryBar, { preview: previewResponse, loading: previewLoading }), previewError && _jsx(Text, { color: "yellow", children: '⚠ Preview: ' + previewError }), saveError && _jsx(Text, { color: "red", children: '⚠ ' + saveError }), !dialogOpen && (_jsx(StatusBar, { accepted: acceptedCount, rejected: rejectedCount, reviewed: reviewedCount, needsReview: needsReviewCount, onApproveAll: () => { }, onFinalize: () => setShowFinalizeDialog(true) }))] }));
|
|
516
482
|
}
|
|
517
483
|
function FinalizedScreen({ result, }) {
|
|
518
484
|
useImmediateInput((_input, key) => {
|
|
@@ -11,10 +11,9 @@ type ComponentDetailProps = {
|
|
|
11
11
|
sourceScrollY: number;
|
|
12
12
|
terminalWidth: number;
|
|
13
13
|
previewAnnotation?: PreviewAnnotation;
|
|
14
|
-
|
|
15
|
-
onSaveDraft: () => void;
|
|
14
|
+
onSaveDraft: (value: string) => void;
|
|
16
15
|
onDiscardDraft: () => void;
|
|
17
16
|
onScrollChange: (offset: number) => void;
|
|
18
17
|
};
|
|
19
|
-
export declare function ComponentDetail({ component, sourceCode, draftValue, editMode, sourceVisible, jsonScrollOffset, sourceScrollX, sourceScrollY, terminalWidth, previewAnnotation,
|
|
18
|
+
export declare function ComponentDetail({ component, sourceCode, draftValue, editMode, sourceVisible, jsonScrollOffset, sourceScrollX, sourceScrollY, terminalWidth, previewAnnotation, onSaveDraft, onDiscardDraft, }: ComponentDetailProps): React.ReactElement;
|
|
20
19
|
export {};
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import { Box, Text } from 'ink';
|
|
3
3
|
import { stripScoringFields } from '../../../../types.js';
|
|
4
4
|
import { JsonPanel } from './JsonPanel.js';
|
|
5
|
-
import {
|
|
5
|
+
import { JsonEditor } from './JsonEditor.js';
|
|
6
6
|
import { SourcePanel } from './SourcePanel.js';
|
|
7
7
|
function annotationLabel(annotation) {
|
|
8
8
|
switch (annotation) {
|
|
@@ -18,7 +18,7 @@ function annotationLabel(annotation) {
|
|
|
18
18
|
return null;
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
-
export function ComponentDetail({ component, sourceCode, draftValue, editMode, sourceVisible, jsonScrollOffset, sourceScrollX, sourceScrollY, terminalWidth, previewAnnotation,
|
|
21
|
+
export function ComponentDetail({ component, sourceCode, draftValue, editMode, sourceVisible, jsonScrollOffset, sourceScrollX, sourceScrollY, terminalWidth, previewAnnotation, onSaveDraft, onDiscardDraft, }) {
|
|
22
22
|
const sidebarWidth = terminalWidth < 80 ? 5 : 20;
|
|
23
23
|
const availableWidth = terminalWidth - sidebarWidth - 2;
|
|
24
24
|
const panelHeight = 20;
|
|
@@ -44,5 +44,5 @@ export function ComponentDetail({ component, sourceCode, draftValue, editMode, s
|
|
|
44
44
|
return (_jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: component.name }), (() => {
|
|
45
45
|
const ann = annotationLabel(previewAnnotation);
|
|
46
46
|
return ann ? _jsx(Text, { color: ann.color, children: ann.text }) : null;
|
|
47
|
-
})(), _jsx(Text, { color: confColor, children: ' — ' + confLabel }), _jsx(Box, { flexGrow: 1 }), _jsxs(Text, { dimColor: true, children: [sourceVisible ? '[s] hide src' : '[s] src', editMode ? '' : ' [e] edit'] })] }), _jsxs(Box, { children: [_jsx(JsonPanel, { label: "ORIGINAL (read-only)", value: originalJson, scrollOffset: jsonScrollOffset, width: originalWidth, height: panelHeight, active: false }), _jsx(Text, { children: " " }), editMode ? (_jsx(
|
|
47
|
+
})(), _jsx(Text, { color: confColor, children: ' — ' + confLabel }), _jsx(Box, { flexGrow: 1 }), _jsxs(Text, { dimColor: true, children: [sourceVisible ? '[s] hide src' : '[s] src', editMode ? '' : ' [e] edit'] })] }), _jsxs(Box, { children: [_jsx(JsonPanel, { label: "ORIGINAL (read-only)", value: originalJson, scrollOffset: jsonScrollOffset, width: originalWidth, height: panelHeight, active: false }), _jsx(Text, { children: " " }), editMode ? (_jsx(JsonEditor, { value: draftValue || editedJson, width: editWidth, height: panelHeight, onSave: onSaveDraft, onDiscard: onDiscardDraft })) : (_jsx(JsonPanel, { label: "EDIT (draft)", value: draftValue || editedJson, scrollOffset: jsonScrollOffset, width: editWidth, height: panelHeight, active: true })), sourceVisible && sourceWidth > 0 && (_jsxs(_Fragment, { children: [_jsx(Text, { children: " " }), _jsx(SourcePanel, { sourceCode: sourceCode, filePath: component.originalProposal.source, width: sourceWidth, height: panelHeight, scrollX: sourceScrollX, scrollY: sourceScrollY })] }))] }), !editMode && _jsx(Text, { dimColor: true, children: ' [a] accept [r] reject [e] edit [A] accept all [↑↓] scroll' })] }));
|
|
48
48
|
}
|
|
@@ -3,9 +3,8 @@ type JsonEditorProps = {
|
|
|
3
3
|
value: string;
|
|
4
4
|
width: number;
|
|
5
5
|
height: number;
|
|
6
|
-
|
|
7
|
-
onSave: () => void;
|
|
6
|
+
onSave: (value: string) => void;
|
|
8
7
|
onDiscard: () => void;
|
|
9
8
|
};
|
|
10
|
-
export declare function JsonEditor({ value, width, height,
|
|
9
|
+
export declare function JsonEditor({ value, width, height, onSave, onDiscard }: JsonEditorProps): React.ReactElement;
|
|
11
10
|
export {};
|
|
@@ -1,43 +1,36 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { useState } from 'react';
|
|
3
3
|
import { Box, Text } from 'ink';
|
|
4
4
|
import { useUndo } from '../hooks/useUndo.js';
|
|
5
5
|
import { useImmediateInput } from '../hooks/useImmediateInput.js';
|
|
6
|
-
export function JsonEditor({ value, width, height,
|
|
6
|
+
export function JsonEditor({ value, width, height, onSave, onDiscard }) {
|
|
7
7
|
const undo = useUndo({
|
|
8
8
|
lines: value.split('\n'),
|
|
9
9
|
cursorRow: 0,
|
|
10
10
|
cursorCol: 0,
|
|
11
11
|
});
|
|
12
12
|
const [scrollRow, setScrollRow] = useState(0);
|
|
13
|
-
const [scrollCol] = useState(0);
|
|
14
13
|
const [validationError, setValidationError] = useState(null);
|
|
15
|
-
const [cursorVisible, setCursorVisible] = useState(true);
|
|
16
|
-
// Blinking cursor
|
|
17
|
-
useEffect(() => {
|
|
18
|
-
const interval = setInterval(() => setCursorVisible((v) => !v), 500);
|
|
19
|
-
return () => clearInterval(interval);
|
|
20
|
-
}, []);
|
|
21
14
|
const { lines, cursorRow, cursorCol } = undo.current;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
15
|
+
const scrollCol = 0;
|
|
16
|
+
// Sync scroll with cursor — pure derivation, no setState needed when within bounds
|
|
17
|
+
let effectiveScrollRow = scrollRow;
|
|
18
|
+
if (cursorRow < scrollRow)
|
|
19
|
+
effectiveScrollRow = cursorRow;
|
|
20
|
+
if (cursorRow >= scrollRow + height)
|
|
21
|
+
effectiveScrollRow = cursorRow - height + 1;
|
|
22
|
+
if (effectiveScrollRow !== scrollRow)
|
|
23
|
+
setScrollRow(effectiveScrollRow);
|
|
29
24
|
useImmediateInput((input, key) => {
|
|
30
25
|
const currentLines = undo.current.lines;
|
|
31
26
|
const currentRow = undo.current.cursorRow;
|
|
32
27
|
const currentCol = undo.current.cursorCol;
|
|
33
28
|
if (key.ctrl && input === 's') {
|
|
34
|
-
// Validate and save
|
|
35
29
|
const text = currentLines.join('\n');
|
|
36
30
|
try {
|
|
37
31
|
JSON.parse(text);
|
|
38
32
|
setValidationError(null);
|
|
39
|
-
|
|
40
|
-
onSave();
|
|
33
|
+
onSave(text);
|
|
41
34
|
}
|
|
42
35
|
catch (e) {
|
|
43
36
|
setValidationError(e instanceof Error ? e.message : String(e));
|
|
@@ -50,7 +43,6 @@ export function JsonEditor({ value, width, height, onChange, onSave, onDiscard }
|
|
|
50
43
|
}
|
|
51
44
|
if (key.ctrl && input === 'z') {
|
|
52
45
|
undo.undo();
|
|
53
|
-
onChange(undo.current.lines.join('\n'));
|
|
54
46
|
return;
|
|
55
47
|
}
|
|
56
48
|
let newLines = [...currentLines];
|
|
@@ -63,44 +55,39 @@ export function JsonEditor({ value, width, height, onChange, onSave, onDiscard }
|
|
|
63
55
|
newRow = currentRow + 1;
|
|
64
56
|
newCol = 0;
|
|
65
57
|
}
|
|
66
|
-
else if (key.backspace
|
|
67
|
-
if (
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
newCol = currentCol - 1;
|
|
71
|
-
}
|
|
72
|
-
else if (currentRow > 0) {
|
|
73
|
-
const prevLen = newLines[currentRow - 1].length;
|
|
74
|
-
newLines[currentRow - 1] = newLines[currentRow - 1] + newLines[currentRow];
|
|
75
|
-
newLines = [...newLines.slice(0, currentRow), ...newLines.slice(currentRow + 1)];
|
|
76
|
-
newRow = currentRow - 1;
|
|
77
|
-
newCol = prevLen;
|
|
78
|
-
}
|
|
58
|
+
else if (key.backspace) {
|
|
59
|
+
if (currentCol > 0) {
|
|
60
|
+
newLines[currentRow] = newLines[currentRow].slice(0, currentCol - 1) + newLines[currentRow].slice(currentCol);
|
|
61
|
+
newCol = currentCol - 1;
|
|
79
62
|
}
|
|
80
|
-
else {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
63
|
+
else if (currentRow > 0) {
|
|
64
|
+
const prevLen = newLines[currentRow - 1].length;
|
|
65
|
+
newLines[currentRow - 1] = newLines[currentRow - 1] + newLines[currentRow];
|
|
66
|
+
newLines = [...newLines.slice(0, currentRow), ...newLines.slice(currentRow + 1)];
|
|
67
|
+
newRow = currentRow - 1;
|
|
68
|
+
newCol = prevLen;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else if (key.delete) {
|
|
72
|
+
if (currentCol < newLines[currentRow].length) {
|
|
73
|
+
newLines[currentRow] = newLines[currentRow].slice(0, currentCol) + newLines[currentRow].slice(currentCol + 1);
|
|
74
|
+
}
|
|
75
|
+
else if (currentRow < newLines.length - 1) {
|
|
76
|
+
newLines[currentRow] = newLines[currentRow] + newLines[currentRow + 1];
|
|
77
|
+
newLines = [...newLines.slice(0, currentRow + 1), ...newLines.slice(currentRow + 2)];
|
|
89
78
|
}
|
|
90
79
|
}
|
|
91
80
|
else if (key.leftArrow) {
|
|
92
|
-
if (currentCol > 0)
|
|
81
|
+
if (currentCol > 0)
|
|
93
82
|
newCol = currentCol - 1;
|
|
94
|
-
}
|
|
95
83
|
else if (currentRow > 0) {
|
|
96
84
|
newRow = currentRow - 1;
|
|
97
85
|
newCol = newLines[currentRow - 1].length;
|
|
98
86
|
}
|
|
99
87
|
}
|
|
100
88
|
else if (key.rightArrow) {
|
|
101
|
-
if (currentCol < newLines[currentRow].length)
|
|
89
|
+
if (currentCol < newLines[currentRow].length)
|
|
102
90
|
newCol = currentCol + 1;
|
|
103
|
-
}
|
|
104
91
|
else if (currentRow < newLines.length - 1) {
|
|
105
92
|
newRow = currentRow + 1;
|
|
106
93
|
newCol = 0;
|
|
@@ -118,36 +105,26 @@ export function JsonEditor({ value, width, height, onChange, onSave, onDiscard }
|
|
|
118
105
|
newCol = Math.min(currentCol, newLines[currentRow + 1].length);
|
|
119
106
|
}
|
|
120
107
|
}
|
|
121
|
-
else if (input === '\x1b[H' || input === '\x1b[1~') {
|
|
122
|
-
// Home key
|
|
123
|
-
newCol = 0;
|
|
124
|
-
}
|
|
125
|
-
else if (input === '\x1b[F' || input === '\x1b[4~') {
|
|
126
|
-
// End key
|
|
127
|
-
newCol = newLines[currentRow].length;
|
|
128
|
-
}
|
|
129
108
|
else if (input && input.length === 1 && !key.ctrl && !key.meta) {
|
|
130
|
-
|
|
131
|
-
|
|
109
|
+
newLines[currentRow] =
|
|
110
|
+
newLines[currentRow].slice(0, currentCol) + input + newLines[currentRow].slice(currentCol);
|
|
132
111
|
newCol = currentCol + 1;
|
|
133
112
|
}
|
|
134
113
|
else {
|
|
135
|
-
return;
|
|
114
|
+
return;
|
|
136
115
|
}
|
|
137
116
|
undo.push({ lines: newLines, cursorRow: newRow, cursorCol: newCol });
|
|
138
|
-
onChange(newLines.join('\n'));
|
|
139
117
|
});
|
|
140
118
|
const innerWidth = Math.max(1, width - 2);
|
|
141
|
-
const visibleLines = lines.slice(
|
|
119
|
+
const visibleLines = lines.slice(effectiveScrollRow, effectiveScrollRow + height);
|
|
142
120
|
return (_jsxs(Box, { flexDirection: "column", width: width, borderStyle: "single", borderColor: "white", children: [_jsx(Text, { bold: true, children: 'EDIT [EDITING — Ctrl+S save · Esc discard]' }), visibleLines.map((line, displayRow) => {
|
|
143
|
-
const actualRow = displayRow +
|
|
121
|
+
const actualRow = displayRow + effectiveScrollRow;
|
|
144
122
|
const displayLine = line.slice(scrollCol, scrollCol + innerWidth);
|
|
145
123
|
if (actualRow === cursorRow) {
|
|
146
|
-
// Render cursor on this line
|
|
147
124
|
const beforeCursor = displayLine.slice(0, cursorCol - scrollCol);
|
|
148
125
|
const cursorChar = displayLine[cursorCol - scrollCol] ?? ' ';
|
|
149
126
|
const afterCursor = displayLine.slice(cursorCol - scrollCol + 1);
|
|
150
|
-
return (_jsxs(Box, { children: [_jsx(Text, { children: beforeCursor }), _jsx(Text, { inverse:
|
|
127
|
+
return (_jsxs(Box, { children: [_jsx(Text, { children: beforeCursor }), _jsx(Text, { inverse: true, children: cursorChar }), _jsx(Text, { children: afterCursor })] }, displayRow));
|
|
151
128
|
}
|
|
152
129
|
return _jsx(Text, { children: displayLine }, displayRow);
|
|
153
130
|
}), validationError && _jsx(Text, { color: "red", children: '✗ Invalid JSON: ' + validationError })] }));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentful/experience-design-system-cli",
|
|
3
|
-
"version": "2.7.
|
|
3
|
+
"version": "2.7.2-dev-build-bc65c2b.0",
|
|
4
4
|
"description": "Contentful Experiences design system import CLI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"react-dom": "^18.3.1",
|
|
37
37
|
"ts-morph": "^27.0.2",
|
|
38
38
|
"typescript": "^5.9.3",
|
|
39
|
-
"@contentful/experience-design-system-types": "2.7.
|
|
39
|
+
"@contentful/experience-design-system-types": "2.7.2-dev-build-bc65c2b.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@tsconfig/node24": "^24.0.3",
|