@contentful/experience-design-system-cli 2.7.1-dev-build-02830eb.0 → 2.7.1
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 +475 -54
- package/dist/src/analyze/select/tui/components/ComponentDetail.d.ts +5 -3
- package/dist/src/analyze/select/tui/components/ComponentDetail.js +3 -3
- package/dist/src/analyze/select/tui/components/FinalizeDialog.d.ts +1 -1
- package/dist/src/analyze/select/tui/components/FinalizeDialog.js +10 -2
- package/dist/src/analyze/select/tui/components/HelpOverlay.d.ts +1 -1
- package/dist/src/analyze/select/tui/components/HelpOverlay.js +7 -2
- package/dist/src/analyze/select/tui/components/JsonEditor.d.ts +5 -7
- package/dist/src/analyze/select/tui/components/JsonEditor.js +146 -15
- package/dist/src/analyze/select/tui/components/QuitDialog.d.ts +1 -1
- package/dist/src/analyze/select/tui/components/QuitDialog.js +10 -2
- package/dist/src/analyze/select/tui/components/Sidebar.d.ts +2 -0
- package/dist/src/analyze/select/tui/components/StatusBar.d.ts +2 -0
- package/dist/src/analyze/select/tui/hooks/useImmediateInput.d.ts +0 -5
- package/dist/src/analyze/select/tui/hooks/useImmediateInput.js +4 -7
- package/dist/src/analyze/select/tui/hooks/useKeymap.d.ts +23 -0
- package/dist/src/analyze/select/tui/hooks/useKeymap.js +67 -1
- package/dist/src/analyze/select/tui/hooks/useUndo.js +21 -15
- package/dist/src/analyze/tui/AnalyzeView.js +0 -2
- package/dist/src/import/tui/WizardApp.js +0 -2
- package/dist/src/import/tui/steps/GenerateReviewStep.js +11 -4
- package/dist/src/print/validate/tui/ValidateView.js +0 -2
- package/package.json +2 -2
- package/dist/src/analyze/select/tui/hooks/useRawMode.d.ts +0 -6
- package/dist/src/analyze/select/tui/hooks/useRawMode.js +0 -16
- package/dist/src/analyze/select/tui/hooks/useSideEffects.d.ts +0 -17
- package/dist/src/analyze/select/tui/hooks/useSideEffects.js +0 -226
- package/dist/src/analyze/select/tui/inputToAction.d.ts +0 -13
- package/dist/src/analyze/select/tui/inputToAction.js +0 -68
- package/dist/src/analyze/select/tui/state.d.ts +0 -136
- package/dist/src/analyze/select/tui/state.js +0 -385
- package/dist/src/analyze/select/tui/utils.d.ts +0 -5
- package/dist/src/analyze/select/tui/utils.js +0 -11
|
@@ -1,385 +0,0 @@
|
|
|
1
|
-
import { stripScoringFields } from '../../../types.js';
|
|
2
|
-
import { computeScrollOffset } from './utils.js';
|
|
3
|
-
function makeEditorState(value) {
|
|
4
|
-
return {
|
|
5
|
-
cursor: { lines: value.split('\n'), cursorRow: 0, cursorCol: 0 },
|
|
6
|
-
undoStack: [],
|
|
7
|
-
scrollRow: 0,
|
|
8
|
-
validationError: null,
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
function editorWithCursor(e, next) {
|
|
12
|
-
return {
|
|
13
|
-
...e,
|
|
14
|
-
cursor: next,
|
|
15
|
-
undoStack: e.undoStack.length >= 50 ? [...e.undoStack.slice(1), e.cursor] : [...e.undoStack, e.cursor],
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
function syncEditorScroll(e, visibleHeight) {
|
|
19
|
-
const { cursorRow } = e.cursor;
|
|
20
|
-
let { scrollRow } = e;
|
|
21
|
-
if (cursorRow < scrollRow)
|
|
22
|
-
scrollRow = cursorRow;
|
|
23
|
-
if (cursorRow >= scrollRow + visibleHeight)
|
|
24
|
-
scrollRow = cursorRow - visibleHeight + 1;
|
|
25
|
-
return scrollRow === e.scrollRow ? e : { ...e, scrollRow };
|
|
26
|
-
}
|
|
27
|
-
// Pure: apply one keypress to EditorState. Returns null if key has no effect.
|
|
28
|
-
export function applyEditorKey(e, input, key, visibleHeight) {
|
|
29
|
-
const { lines, cursorRow, cursorCol } = e.cursor;
|
|
30
|
-
// Ctrl+Z undo
|
|
31
|
-
if (key.ctrl && input === 'z') {
|
|
32
|
-
if (e.undoStack.length === 0)
|
|
33
|
-
return null;
|
|
34
|
-
const prev = e.undoStack[e.undoStack.length - 1];
|
|
35
|
-
return syncEditorScroll({ ...e, cursor: prev, undoStack: e.undoStack.slice(0, -1) }, visibleHeight);
|
|
36
|
-
}
|
|
37
|
-
let newLines = [...lines];
|
|
38
|
-
let newRow = cursorRow;
|
|
39
|
-
let newCol = cursorCol;
|
|
40
|
-
if (key.return) {
|
|
41
|
-
const before = newLines[cursorRow].slice(0, cursorCol);
|
|
42
|
-
const after = newLines[cursorRow].slice(cursorCol);
|
|
43
|
-
newLines = [...newLines.slice(0, cursorRow), before, after, ...newLines.slice(cursorRow + 1)];
|
|
44
|
-
newRow = cursorRow + 1;
|
|
45
|
-
newCol = 0;
|
|
46
|
-
}
|
|
47
|
-
else if (key.backspace) {
|
|
48
|
-
if (cursorCol > 0) {
|
|
49
|
-
newLines[cursorRow] = newLines[cursorRow].slice(0, cursorCol - 1) + newLines[cursorRow].slice(cursorCol);
|
|
50
|
-
newCol = cursorCol - 1;
|
|
51
|
-
}
|
|
52
|
-
else if (cursorRow > 0) {
|
|
53
|
-
const prevLen = newLines[cursorRow - 1].length;
|
|
54
|
-
newLines[cursorRow - 1] = newLines[cursorRow - 1] + newLines[cursorRow];
|
|
55
|
-
newLines = [...newLines.slice(0, cursorRow), ...newLines.slice(cursorRow + 1)];
|
|
56
|
-
newRow = cursorRow - 1;
|
|
57
|
-
newCol = prevLen;
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
else if (key.delete) {
|
|
64
|
-
if (cursorCol < newLines[cursorRow].length) {
|
|
65
|
-
newLines[cursorRow] = newLines[cursorRow].slice(0, cursorCol) + newLines[cursorRow].slice(cursorCol + 1);
|
|
66
|
-
}
|
|
67
|
-
else if (cursorRow < newLines.length - 1) {
|
|
68
|
-
newLines[cursorRow] = newLines[cursorRow] + newLines[cursorRow + 1];
|
|
69
|
-
newLines = [...newLines.slice(0, cursorRow + 1), ...newLines.slice(cursorRow + 2)];
|
|
70
|
-
}
|
|
71
|
-
else {
|
|
72
|
-
return null;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
else if (key.leftArrow) {
|
|
76
|
-
if (cursorCol > 0) {
|
|
77
|
-
newCol = cursorCol - 1;
|
|
78
|
-
}
|
|
79
|
-
else if (cursorRow > 0) {
|
|
80
|
-
newRow = cursorRow - 1;
|
|
81
|
-
newCol = newLines[cursorRow - 1].length;
|
|
82
|
-
}
|
|
83
|
-
else
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
|
-
else if (key.rightArrow) {
|
|
87
|
-
if (cursorCol < newLines[cursorRow].length) {
|
|
88
|
-
newCol = cursorCol + 1;
|
|
89
|
-
}
|
|
90
|
-
else if (cursorRow < newLines.length - 1) {
|
|
91
|
-
newRow = cursorRow + 1;
|
|
92
|
-
newCol = 0;
|
|
93
|
-
}
|
|
94
|
-
else
|
|
95
|
-
return null;
|
|
96
|
-
}
|
|
97
|
-
else if (key.upArrow) {
|
|
98
|
-
if (cursorRow === 0)
|
|
99
|
-
return null;
|
|
100
|
-
newRow = cursorRow - 1;
|
|
101
|
-
newCol = Math.min(cursorCol, newLines[newRow].length);
|
|
102
|
-
}
|
|
103
|
-
else if (key.downArrow) {
|
|
104
|
-
if (cursorRow >= newLines.length - 1)
|
|
105
|
-
return null;
|
|
106
|
-
newRow = cursorRow + 1;
|
|
107
|
-
newCol = Math.min(cursorCol, newLines[newRow].length);
|
|
108
|
-
}
|
|
109
|
-
else if (input === '\x1b[H' || input === '\x1b[1~') {
|
|
110
|
-
newCol = 0; // Home
|
|
111
|
-
}
|
|
112
|
-
else if (input === '\x1b[F' || input === '\x1b[4~') {
|
|
113
|
-
newCol = newLines[cursorRow].length; // End
|
|
114
|
-
}
|
|
115
|
-
else if (input && input.length === 1 && !key.ctrl && !key.meta) {
|
|
116
|
-
newLines[cursorRow] = newLines[cursorRow].slice(0, cursorCol) + input + newLines[cursorRow].slice(cursorCol);
|
|
117
|
-
newCol = cursorCol + 1;
|
|
118
|
-
}
|
|
119
|
-
else {
|
|
120
|
-
return null;
|
|
121
|
-
}
|
|
122
|
-
return syncEditorScroll(editorWithCursor(e, { lines: newLines, cursorRow: newRow, cursorCol: newCol }), visibleHeight);
|
|
123
|
-
}
|
|
124
|
-
export const initialState = {
|
|
125
|
-
mode: { type: 'browsing', sidebarFocused: true, sourceVisible: false },
|
|
126
|
-
session: null,
|
|
127
|
-
paths: null,
|
|
128
|
-
selectedId: null,
|
|
129
|
-
sortedIds: [],
|
|
130
|
-
sessionSummary: [],
|
|
131
|
-
sidebarScrollOffset: 0,
|
|
132
|
-
jsonScrollOffset: 0,
|
|
133
|
-
draftsByComponentId: {},
|
|
134
|
-
editor: null,
|
|
135
|
-
sourceCodeById: {},
|
|
136
|
-
previewAnnotations: (() => {
|
|
137
|
-
const raw = process.env['EDS_PREVIEW_ANNOTATIONS'];
|
|
138
|
-
if (!raw)
|
|
139
|
-
return {};
|
|
140
|
-
try {
|
|
141
|
-
return JSON.parse(raw);
|
|
142
|
-
}
|
|
143
|
-
catch {
|
|
144
|
-
return {};
|
|
145
|
-
}
|
|
146
|
-
})(),
|
|
147
|
-
previewResponse: null,
|
|
148
|
-
previewLoading: false,
|
|
149
|
-
previewError: null,
|
|
150
|
-
saveError: null,
|
|
151
|
-
};
|
|
152
|
-
// ── Derived data ──────────────────────────────────────────────────────────────
|
|
153
|
-
function computeSortedIds(components) {
|
|
154
|
-
return [...components]
|
|
155
|
-
.map((c) => ({
|
|
156
|
-
id: c.id,
|
|
157
|
-
needsReview: c.originalProposal.needsReview ?? false,
|
|
158
|
-
status: c.status,
|
|
159
|
-
conf: c.originalProposal.extractionConfidence ?? 6,
|
|
160
|
-
}))
|
|
161
|
-
.sort((a, b) => {
|
|
162
|
-
const aF = a.needsReview && a.status === 'needs-review' ? 0 : 1;
|
|
163
|
-
const bF = b.needsReview && b.status === 'needs-review' ? 0 : 1;
|
|
164
|
-
if (aF !== bF)
|
|
165
|
-
return aF - bF;
|
|
166
|
-
return a.conf - b.conf;
|
|
167
|
-
})
|
|
168
|
-
.map((c) => c.id);
|
|
169
|
-
}
|
|
170
|
-
// Builds a stable summary array for Sidebar — same reference if nothing changed.
|
|
171
|
-
// Keeping this in state means Sidebar never re-renders on scroll/selection alone.
|
|
172
|
-
function computeSessionSummary(components, annotations, sortedIds) {
|
|
173
|
-
return sortedIds
|
|
174
|
-
.map((id) => components.find((c) => c.id === id))
|
|
175
|
-
.filter((c) => !!c)
|
|
176
|
-
.map((c) => ({
|
|
177
|
-
id: c.id,
|
|
178
|
-
name: c.name,
|
|
179
|
-
status: c.status,
|
|
180
|
-
previewAnnotation: annotations[c.name],
|
|
181
|
-
extractionConfidence: c.originalProposal.extractionConfidence ?? null,
|
|
182
|
-
needsReview: c.originalProposal.needsReview ?? false,
|
|
183
|
-
}));
|
|
184
|
-
}
|
|
185
|
-
// Rebuild both sortedIds and sessionSummary from updated components + annotations.
|
|
186
|
-
function withUpdatedSession(state, components, annotations) {
|
|
187
|
-
const ann = annotations ?? state.previewAnnotations;
|
|
188
|
-
const sortedIds = computeSortedIds(components);
|
|
189
|
-
const sessionSummary = computeSessionSummary(components, ann, sortedIds);
|
|
190
|
-
return {
|
|
191
|
-
...state,
|
|
192
|
-
session: { ...state.session, components },
|
|
193
|
-
previewAnnotations: ann,
|
|
194
|
-
sortedIds,
|
|
195
|
-
sessionSummary,
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
function updateStatus(state, newStatus) {
|
|
199
|
-
if (!state.session || !state.selectedId)
|
|
200
|
-
return state;
|
|
201
|
-
const components = state.session.components.map((c) => (c.id === state.selectedId ? { ...c, status: newStatus } : c));
|
|
202
|
-
return withUpdatedSession(state, components);
|
|
203
|
-
}
|
|
204
|
-
// ── Reducer ───────────────────────────────────────────────────────────────────
|
|
205
|
-
export function reducer(state, action) {
|
|
206
|
-
switch (action.type) {
|
|
207
|
-
case 'SESSION_LOADED': {
|
|
208
|
-
const sortedIds = computeSortedIds(action.session.components);
|
|
209
|
-
const sessionSummary = computeSessionSummary(action.session.components, state.previewAnnotations, sortedIds);
|
|
210
|
-
return {
|
|
211
|
-
...state,
|
|
212
|
-
session: action.session,
|
|
213
|
-
paths: action.paths,
|
|
214
|
-
sortedIds,
|
|
215
|
-
sessionSummary,
|
|
216
|
-
selectedId: sortedIds[0] ?? null,
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
case 'SELECT':
|
|
220
|
-
return { ...state, selectedId: action.id, jsonScrollOffset: 0 };
|
|
221
|
-
case 'SIDEBAR_UP': {
|
|
222
|
-
if (!state.session || !state.selectedId)
|
|
223
|
-
return state;
|
|
224
|
-
const idx = state.sortedIds.indexOf(state.selectedId);
|
|
225
|
-
if (idx <= 0)
|
|
226
|
-
return state;
|
|
227
|
-
const ni = idx - 1;
|
|
228
|
-
return {
|
|
229
|
-
...state,
|
|
230
|
-
selectedId: state.sortedIds[ni],
|
|
231
|
-
jsonScrollOffset: 0,
|
|
232
|
-
sidebarScrollOffset: computeScrollOffset(ni, state.sidebarScrollOffset, action.visibleCount),
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
case 'SIDEBAR_DOWN': {
|
|
236
|
-
if (!state.session || !state.selectedId)
|
|
237
|
-
return state;
|
|
238
|
-
const idx = state.sortedIds.indexOf(state.selectedId);
|
|
239
|
-
if (idx >= state.sortedIds.length - 1)
|
|
240
|
-
return state;
|
|
241
|
-
const ni = idx + 1;
|
|
242
|
-
return {
|
|
243
|
-
...state,
|
|
244
|
-
selectedId: state.sortedIds[ni],
|
|
245
|
-
jsonScrollOffset: 0,
|
|
246
|
-
sidebarScrollOffset: computeScrollOffset(ni, state.sidebarScrollOffset, action.visibleCount),
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
case 'ACCEPT':
|
|
250
|
-
return updateStatus(state, 'accepted');
|
|
251
|
-
case 'REJECT':
|
|
252
|
-
return updateStatus(state, 'rejected');
|
|
253
|
-
case 'APPROVE_ALL': {
|
|
254
|
-
if (!state.session)
|
|
255
|
-
return state;
|
|
256
|
-
const components = state.session.components.map((c) => c.status === 'needs-review' ? { ...c, status: 'accepted' } : c);
|
|
257
|
-
return withUpdatedSession(state, components);
|
|
258
|
-
}
|
|
259
|
-
case 'ENTER_EDIT': {
|
|
260
|
-
if (state.mode.type !== 'browsing' || !state.selectedId || !state.session)
|
|
261
|
-
return state;
|
|
262
|
-
const component = state.session.components.find((c) => c.id === state.selectedId);
|
|
263
|
-
if (!component)
|
|
264
|
-
return state;
|
|
265
|
-
const existing = state.draftsByComponentId[state.selectedId];
|
|
266
|
-
const draft = existing ?? JSON.stringify(stripScoringFields(component.editedProposal), null, 2);
|
|
267
|
-
const editor = makeEditorState(draft);
|
|
268
|
-
return {
|
|
269
|
-
...state,
|
|
270
|
-
mode: { type: 'editing', componentId: state.selectedId },
|
|
271
|
-
draftsByComponentId: { ...state.draftsByComponentId, [state.selectedId]: draft },
|
|
272
|
-
editor,
|
|
273
|
-
};
|
|
274
|
-
}
|
|
275
|
-
case 'EDITOR_KEY': {
|
|
276
|
-
if (!state.editor || state.mode.type !== 'editing')
|
|
277
|
-
return state;
|
|
278
|
-
const next = applyEditorKey(state.editor, action.input, action.key, action.visibleHeight);
|
|
279
|
-
if (!next)
|
|
280
|
-
return state;
|
|
281
|
-
const newValue = next.cursor.lines.join('\n');
|
|
282
|
-
return {
|
|
283
|
-
...state,
|
|
284
|
-
editor: next,
|
|
285
|
-
draftsByComponentId: { ...state.draftsByComponentId, [state.mode.componentId]: newValue },
|
|
286
|
-
};
|
|
287
|
-
}
|
|
288
|
-
case 'EDITOR_VALIDATE': {
|
|
289
|
-
// inputToAction calls this on Ctrl+S — reducer does the parse check
|
|
290
|
-
if (!state.editor || state.mode.type !== 'editing')
|
|
291
|
-
return state;
|
|
292
|
-
const text = state.editor.cursor.lines.join('\n');
|
|
293
|
-
try {
|
|
294
|
-
JSON.parse(text);
|
|
295
|
-
// Valid — switch mode back to browsing; side effect will detect the transition and persist
|
|
296
|
-
return {
|
|
297
|
-
...state,
|
|
298
|
-
editor: { ...state.editor, validationError: null },
|
|
299
|
-
mode: { type: 'browsing', sidebarFocused: true, sourceVisible: false },
|
|
300
|
-
// keep draft in draftsByComponentId — side effect will persist it and clear it
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
catch (e) {
|
|
304
|
-
return {
|
|
305
|
-
...state,
|
|
306
|
-
editor: { ...state.editor, validationError: e instanceof Error ? e.message : String(e) },
|
|
307
|
-
};
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
case 'DRAFT_DISCARD': {
|
|
311
|
-
if (state.mode.type !== 'editing')
|
|
312
|
-
return state;
|
|
313
|
-
const { componentId } = state.mode;
|
|
314
|
-
const { [componentId]: _removed, ...remaining } = state.draftsByComponentId;
|
|
315
|
-
return {
|
|
316
|
-
...state,
|
|
317
|
-
mode: { type: 'browsing', sidebarFocused: true, sourceVisible: false },
|
|
318
|
-
draftsByComponentId: remaining,
|
|
319
|
-
editor: null,
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
case 'DRAFT_PERSIST_DONE': {
|
|
323
|
-
const { componentId, updatedComponents } = action;
|
|
324
|
-
const { [componentId]: _removed, ...remaining } = state.draftsByComponentId;
|
|
325
|
-
const base = withUpdatedSession(state, updatedComponents);
|
|
326
|
-
return { ...base, draftsByComponentId: remaining };
|
|
327
|
-
}
|
|
328
|
-
case 'TOGGLE_FOCUS': {
|
|
329
|
-
if (state.mode.type !== 'browsing')
|
|
330
|
-
return state;
|
|
331
|
-
return { ...state, mode: { ...state.mode, sidebarFocused: !state.mode.sidebarFocused } };
|
|
332
|
-
}
|
|
333
|
-
case 'SCROLL_UP':
|
|
334
|
-
return { ...state, jsonScrollOffset: Math.max(0, state.jsonScrollOffset - 1) };
|
|
335
|
-
case 'SCROLL_DOWN':
|
|
336
|
-
return { ...state, jsonScrollOffset: state.jsonScrollOffset + 1 };
|
|
337
|
-
case 'TOGGLE_SOURCE': {
|
|
338
|
-
if (state.mode.type !== 'browsing')
|
|
339
|
-
return state;
|
|
340
|
-
if (action.terminalWidth < 120)
|
|
341
|
-
return { ...state, saveError: 'Terminal too narrow for source panel (need 120+ cols)' };
|
|
342
|
-
return { ...state, mode: { ...state.mode, sourceVisible: !state.mode.sourceVisible } };
|
|
343
|
-
}
|
|
344
|
-
case 'OPEN_DIALOG':
|
|
345
|
-
return { ...state, mode: { type: 'dialog', which: action.which } };
|
|
346
|
-
case 'CLOSE_DIALOG':
|
|
347
|
-
return { ...state, mode: { type: 'browsing', sidebarFocused: true, sourceVisible: false } };
|
|
348
|
-
case 'FINALIZE_CONFIRM': {
|
|
349
|
-
if (!state.session)
|
|
350
|
-
return state;
|
|
351
|
-
const accepted = state.session.components.filter((c) => c.status === 'accepted').length;
|
|
352
|
-
const rejected = state.session.components.filter((c) => c.status === 'rejected').length;
|
|
353
|
-
const excluded = state.session.components.filter((c) => c.status === 'needs-review').length;
|
|
354
|
-
return { ...state, mode: { type: 'finalized', accepted, rejected, excluded } };
|
|
355
|
-
}
|
|
356
|
-
case 'QUIT_CONFIRM':
|
|
357
|
-
return state; // side effect handles exit
|
|
358
|
-
case 'SOURCE_LOADED':
|
|
359
|
-
return { ...state, sourceCodeById: { ...state.sourceCodeById, [action.componentId]: action.code } };
|
|
360
|
-
case 'PREVIEW_START':
|
|
361
|
-
return { ...state, previewLoading: true };
|
|
362
|
-
case 'PREVIEW_SUCCESS': {
|
|
363
|
-
const components = state.session?.components ?? [];
|
|
364
|
-
const sortedIds = computeSortedIds(components);
|
|
365
|
-
const sessionSummary = computeSessionSummary(components, action.annotations, sortedIds);
|
|
366
|
-
return {
|
|
367
|
-
...state,
|
|
368
|
-
previewResponse: action.response,
|
|
369
|
-
previewAnnotations: action.annotations,
|
|
370
|
-
previewLoading: false,
|
|
371
|
-
previewError: null,
|
|
372
|
-
sortedIds,
|
|
373
|
-
sessionSummary,
|
|
374
|
-
};
|
|
375
|
-
}
|
|
376
|
-
case 'PREVIEW_ERROR':
|
|
377
|
-
return { ...state, previewLoading: false, previewError: action.message };
|
|
378
|
-
case 'SAVE_ERROR':
|
|
379
|
-
return { ...state, saveError: action.message };
|
|
380
|
-
case 'CLEAR_ERRORS':
|
|
381
|
-
return { ...state, saveError: null, previewError: null };
|
|
382
|
-
default:
|
|
383
|
-
return state;
|
|
384
|
-
}
|
|
385
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Compute the new sidebar scroll offset after moving selection to `idx`.
|
|
3
|
-
* Keeps the selected item within the visible window.
|
|
4
|
-
*/
|
|
5
|
-
export function computeScrollOffset(idx, prev, visibleCount) {
|
|
6
|
-
if (idx < prev)
|
|
7
|
-
return idx;
|
|
8
|
-
if (idx >= prev + visibleCount)
|
|
9
|
-
return idx - visibleCount + 1;
|
|
10
|
-
return prev;
|
|
11
|
-
}
|