@contentful/experience-design-system-cli 2.2.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/README.md +532 -0
- package/bin/cli.js +58 -0
- package/dist/package.json +56 -0
- package/dist/src/analyze/command.d.ts +3 -0
- package/dist/src/analyze/command.js +175 -0
- package/dist/src/analyze/extract/astro.d.ts +5 -0
- package/dist/src/analyze/extract/astro.js +280 -0
- package/dist/src/analyze/extract/pipeline.d.ts +6 -0
- package/dist/src/analyze/extract/pipeline.js +298 -0
- package/dist/src/analyze/extract/react.d.ts +2 -0
- package/dist/src/analyze/extract/react.js +1949 -0
- package/dist/src/analyze/extract/slot-detection.d.ts +35 -0
- package/dist/src/analyze/extract/slot-detection.js +101 -0
- package/dist/src/analyze/extract/stencil.d.ts +2 -0
- package/dist/src/analyze/extract/stencil.js +293 -0
- package/dist/src/analyze/extract/tsx-shared.d.ts +8 -0
- package/dist/src/analyze/extract/tsx-shared.js +263 -0
- package/dist/src/analyze/extract/vue-tsx.d.ts +2 -0
- package/dist/src/analyze/extract/vue-tsx.js +498 -0
- package/dist/src/analyze/extract/vue.d.ts +5 -0
- package/dist/src/analyze/extract/vue.js +647 -0
- package/dist/src/analyze/extract/web-components.d.ts +2 -0
- package/dist/src/analyze/extract/web-components.js +866 -0
- package/dist/src/analyze/pre-classify.d.ts +17 -0
- package/dist/src/analyze/pre-classify.js +144 -0
- package/dist/src/analyze/select/command.d.ts +2 -0
- package/dist/src/analyze/select/command.js +256 -0
- package/dist/src/analyze/select/index.d.ts +6 -0
- package/dist/src/analyze/select/index.js +5 -0
- package/dist/src/analyze/select/parser.d.ts +6 -0
- package/dist/src/analyze/select/parser.js +53 -0
- package/dist/src/analyze/select/persistence.d.ts +9 -0
- package/dist/src/analyze/select/persistence.js +42 -0
- package/dist/src/analyze/select/stdout.d.ts +7 -0
- package/dist/src/analyze/select/stdout.js +3 -0
- package/dist/src/analyze/select/tui/App.d.ts +8 -0
- package/dist/src/analyze/select/tui/App.js +491 -0
- package/dist/src/analyze/select/tui/components/ComponentDetail.d.ts +20 -0
- package/dist/src/analyze/select/tui/components/ComponentDetail.js +43 -0
- package/dist/src/analyze/select/tui/components/FieldEditor.d.ts +11 -0
- package/dist/src/analyze/select/tui/components/FieldEditor.js +531 -0
- package/dist/src/analyze/select/tui/components/FinalizeDialog.d.ts +10 -0
- package/dist/src/analyze/select/tui/components/FinalizeDialog.js +15 -0
- package/dist/src/analyze/select/tui/components/HelpOverlay.d.ts +7 -0
- package/dist/src/analyze/select/tui/components/HelpOverlay.js +11 -0
- package/dist/src/analyze/select/tui/components/JsonEditor.d.ts +11 -0
- package/dist/src/analyze/select/tui/components/JsonEditor.js +154 -0
- package/dist/src/analyze/select/tui/components/JsonPanel.d.ts +11 -0
- package/dist/src/analyze/select/tui/components/JsonPanel.js +62 -0
- package/dist/src/analyze/select/tui/components/PreviewSummaryBar.d.ts +8 -0
- package/dist/src/analyze/select/tui/components/PreviewSummaryBar.js +29 -0
- package/dist/src/analyze/select/tui/components/QuitDialog.d.ts +8 -0
- package/dist/src/analyze/select/tui/components/QuitDialog.js +14 -0
- package/dist/src/analyze/select/tui/components/Sidebar.d.ts +15 -0
- package/dist/src/analyze/select/tui/components/Sidebar.js +48 -0
- package/dist/src/analyze/select/tui/components/SourcePanel.d.ts +11 -0
- package/dist/src/analyze/select/tui/components/SourcePanel.js +52 -0
- package/dist/src/analyze/select/tui/components/StatusBar.d.ts +11 -0
- package/dist/src/analyze/select/tui/components/StatusBar.js +6 -0
- package/dist/src/analyze/select/tui/components/TopBar.d.ts +10 -0
- package/dist/src/analyze/select/tui/components/TopBar.js +5 -0
- package/dist/src/analyze/select/tui/hooks/useImmediateInput.d.ts +24 -0
- package/dist/src/analyze/select/tui/hooks/useImmediateInput.js +68 -0
- package/dist/src/analyze/select/tui/hooks/useKeymap.d.ts +24 -0
- package/dist/src/analyze/select/tui/hooks/useKeymap.js +67 -0
- package/dist/src/analyze/select/tui/hooks/useSession.d.ts +19 -0
- package/dist/src/analyze/select/tui/hooks/useSession.js +52 -0
- package/dist/src/analyze/select/tui/hooks/useUndo.d.ts +8 -0
- package/dist/src/analyze/select/tui/hooks/useUndo.js +26 -0
- package/dist/src/analyze/select/types.d.ts +46 -0
- package/dist/src/analyze/select/types.js +20 -0
- package/dist/src/analyze/select-agent/command.d.ts +2 -0
- package/dist/src/analyze/select-agent/command.js +208 -0
- package/dist/src/analyze/tui/AnalyzeView.d.ts +24 -0
- package/dist/src/analyze/tui/AnalyzeView.js +38 -0
- package/dist/src/apply/api-client.d.ts +35 -0
- package/dist/src/apply/api-client.js +143 -0
- package/dist/src/apply/command.d.ts +6 -0
- package/dist/src/apply/command.js +787 -0
- package/dist/src/apply/manifest.d.ts +1 -0
- package/dist/src/apply/manifest.js +1 -0
- package/dist/src/apply/tui/SelectView.d.ts +18 -0
- package/dist/src/apply/tui/SelectView.js +34 -0
- package/dist/src/apply/tui/ServerApplyView.d.ts +32 -0
- package/dist/src/apply/tui/ServerApplyView.js +42 -0
- package/dist/src/apply/tui/ServerPreviewView.d.ts +9 -0
- package/dist/src/apply/tui/ServerPreviewView.js +21 -0
- package/dist/src/credentials-store.d.ts +8 -0
- package/dist/src/credentials-store.js +30 -0
- package/dist/src/generate/agent-runner.d.ts +86 -0
- package/dist/src/generate/agent-runner.js +314 -0
- package/dist/src/generate/command.d.ts +2 -0
- package/dist/src/generate/command.js +545 -0
- package/dist/src/generate/edit/command.d.ts +2 -0
- package/dist/src/generate/edit/command.js +126 -0
- package/dist/src/generate/prompt-builder.d.ts +18 -0
- package/dist/src/generate/prompt-builder.js +202 -0
- package/dist/src/generate/tui/GenerateView.d.ts +12 -0
- package/dist/src/generate/tui/GenerateView.js +10 -0
- package/dist/src/import/command.d.ts +2 -0
- package/dist/src/import/command.js +96 -0
- package/dist/src/import/orchestrator.d.ts +37 -0
- package/dist/src/import/orchestrator.js +374 -0
- package/dist/src/import/path-utils.d.ts +15 -0
- package/dist/src/import/path-utils.js +30 -0
- package/dist/src/import/tui/WizardApp.d.ts +10 -0
- package/dist/src/import/tui/WizardApp.js +906 -0
- package/dist/src/import/tui/steps/CredentialsStep.d.ts +15 -0
- package/dist/src/import/tui/steps/CredentialsStep.js +79 -0
- package/dist/src/import/tui/steps/DoneStep.d.ts +20 -0
- package/dist/src/import/tui/steps/DoneStep.js +17 -0
- package/dist/src/import/tui/steps/ErrorStep.d.ts +8 -0
- package/dist/src/import/tui/steps/ErrorStep.js +11 -0
- package/dist/src/import/tui/steps/GateStep.d.ts +14 -0
- package/dist/src/import/tui/steps/GateStep.js +20 -0
- package/dist/src/import/tui/steps/GenerateReviewStep.d.ts +8 -0
- package/dist/src/import/tui/steps/GenerateReviewStep.js +208 -0
- package/dist/src/import/tui/steps/PathValidationStep.d.ts +10 -0
- package/dist/src/import/tui/steps/PathValidationStep.js +151 -0
- package/dist/src/import/tui/steps/PreviewStep.d.ts +21 -0
- package/dist/src/import/tui/steps/PreviewStep.js +36 -0
- package/dist/src/import/tui/steps/RunningStep.d.ts +10 -0
- package/dist/src/import/tui/steps/RunningStep.js +20 -0
- package/dist/src/import/tui/steps/TokenInputStep.d.ts +8 -0
- package/dist/src/import/tui/steps/TokenInputStep.js +70 -0
- package/dist/src/import/tui/steps/WelcomeStep.d.ts +7 -0
- package/dist/src/import/tui/steps/WelcomeStep.js +33 -0
- package/dist/src/import/tui/steps/WizardPreviewStep.d.ts +15 -0
- package/dist/src/import/tui/steps/WizardPreviewStep.js +121 -0
- package/dist/src/import/tui/steps/preview-diff.d.ts +10 -0
- package/dist/src/import/tui/steps/preview-diff.js +132 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +2 -0
- package/dist/src/output/format.d.ts +23 -0
- package/dist/src/output/format.js +110 -0
- package/dist/src/print/command.d.ts +2 -0
- package/dist/src/print/command.js +199 -0
- package/dist/src/print/validate/tui/ValidateView.d.ts +15 -0
- package/dist/src/print/validate/tui/ValidateView.js +37 -0
- package/dist/src/print/validate/validators/cdf-validator.d.ts +2 -0
- package/dist/src/print/validate/validators/cdf-validator.js +104 -0
- package/dist/src/print/validate/validators/dtcg-validator.d.ts +2 -0
- package/dist/src/print/validate/validators/dtcg-validator.js +110 -0
- package/dist/src/print/validate/validators/format-errors.d.ts +12 -0
- package/dist/src/print/validate/validators/format-errors.js +18 -0
- package/dist/src/program.d.ts +2 -0
- package/dist/src/program.js +25 -0
- package/dist/src/session/command.d.ts +2 -0
- package/dist/src/session/command.js +261 -0
- package/dist/src/session/db.d.ts +111 -0
- package/dist/src/session/db.js +1114 -0
- package/dist/src/session/migration.d.ts +4 -0
- package/dist/src/session/migration.js +117 -0
- package/dist/src/session/session-id.d.ts +1 -0
- package/dist/src/session/session-id.js +212 -0
- package/dist/src/session/stats.d.ts +27 -0
- package/dist/src/session/stats.js +89 -0
- package/dist/src/setup/command.d.ts +2 -0
- package/dist/src/setup/command.js +765 -0
- package/dist/src/types.d.ts +48 -0
- package/dist/src/types.js +1 -0
- package/package.json +55 -0
- package/skills/generate-components.md +361 -0
- package/skills/generate-tokens.md +194 -0
- package/skills/select-components.md +180 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import { Box, Text } from 'ink';
|
|
4
|
+
import { useUndo } from '../hooks/useUndo.js';
|
|
5
|
+
import { useImmediateInput } from '../hooks/useImmediateInput.js';
|
|
6
|
+
export function JsonEditor({ value, width, height, onChange, onSave, onDiscard }) {
|
|
7
|
+
const undo = useUndo({
|
|
8
|
+
lines: value.split('\n'),
|
|
9
|
+
cursorRow: 0,
|
|
10
|
+
cursorCol: 0,
|
|
11
|
+
});
|
|
12
|
+
const [scrollRow, setScrollRow] = useState(0);
|
|
13
|
+
const [scrollCol] = useState(0);
|
|
14
|
+
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
|
+
const { lines, cursorRow, cursorCol } = undo.current;
|
|
22
|
+
// Keep scroll in sync with cursor
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
if (cursorRow < scrollRow)
|
|
25
|
+
setScrollRow(cursorRow);
|
|
26
|
+
if (cursorRow >= scrollRow + height)
|
|
27
|
+
setScrollRow(cursorRow - height + 1);
|
|
28
|
+
}, [cursorRow, scrollRow, height]);
|
|
29
|
+
useImmediateInput((input, key) => {
|
|
30
|
+
const currentLines = undo.current.lines;
|
|
31
|
+
const currentRow = undo.current.cursorRow;
|
|
32
|
+
const currentCol = undo.current.cursorCol;
|
|
33
|
+
if (key.ctrl && input === 's') {
|
|
34
|
+
// Validate and save
|
|
35
|
+
const text = currentLines.join('\n');
|
|
36
|
+
try {
|
|
37
|
+
JSON.parse(text);
|
|
38
|
+
setValidationError(null);
|
|
39
|
+
onChange(text);
|
|
40
|
+
onSave();
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
setValidationError(e instanceof Error ? e.message : String(e));
|
|
44
|
+
}
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (key.escape) {
|
|
48
|
+
onDiscard();
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (key.ctrl && input === 'z') {
|
|
52
|
+
undo.undo();
|
|
53
|
+
onChange(undo.current.lines.join('\n'));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
let newLines = [...currentLines];
|
|
57
|
+
let newRow = currentRow;
|
|
58
|
+
let newCol = currentCol;
|
|
59
|
+
if (key.return) {
|
|
60
|
+
const before = newLines[currentRow].slice(0, currentCol);
|
|
61
|
+
const after = newLines[currentRow].slice(currentCol);
|
|
62
|
+
newLines = [...newLines.slice(0, currentRow), before, after, ...newLines.slice(currentRow + 1)];
|
|
63
|
+
newRow = currentRow + 1;
|
|
64
|
+
newCol = 0;
|
|
65
|
+
}
|
|
66
|
+
else if (key.backspace || key.delete) {
|
|
67
|
+
if (key.backspace) {
|
|
68
|
+
if (currentCol > 0) {
|
|
69
|
+
newLines[currentRow] = newLines[currentRow].slice(0, currentCol - 1) + newLines[currentRow].slice(currentCol);
|
|
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
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
// Delete key
|
|
82
|
+
if (currentCol < newLines[currentRow].length) {
|
|
83
|
+
newLines[currentRow] = newLines[currentRow].slice(0, currentCol) + newLines[currentRow].slice(currentCol + 1);
|
|
84
|
+
}
|
|
85
|
+
else if (currentRow < newLines.length - 1) {
|
|
86
|
+
newLines[currentRow] = newLines[currentRow] + newLines[currentRow + 1];
|
|
87
|
+
newLines = [...newLines.slice(0, currentRow + 1), ...newLines.slice(currentRow + 2)];
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else if (key.leftArrow) {
|
|
92
|
+
if (currentCol > 0) {
|
|
93
|
+
newCol = currentCol - 1;
|
|
94
|
+
}
|
|
95
|
+
else if (currentRow > 0) {
|
|
96
|
+
newRow = currentRow - 1;
|
|
97
|
+
newCol = newLines[currentRow - 1].length;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
else if (key.rightArrow) {
|
|
101
|
+
if (currentCol < newLines[currentRow].length) {
|
|
102
|
+
newCol = currentCol + 1;
|
|
103
|
+
}
|
|
104
|
+
else if (currentRow < newLines.length - 1) {
|
|
105
|
+
newRow = currentRow + 1;
|
|
106
|
+
newCol = 0;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else if (key.upArrow) {
|
|
110
|
+
if (currentRow > 0) {
|
|
111
|
+
newRow = currentRow - 1;
|
|
112
|
+
newCol = Math.min(currentCol, newLines[currentRow - 1].length);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
else if (key.downArrow) {
|
|
116
|
+
if (currentRow < newLines.length - 1) {
|
|
117
|
+
newRow = currentRow + 1;
|
|
118
|
+
newCol = Math.min(currentCol, newLines[currentRow + 1].length);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
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
|
+
else if (input && input.length === 1 && !key.ctrl && !key.meta) {
|
|
130
|
+
// Printable character
|
|
131
|
+
newLines[currentRow] = newLines[currentRow].slice(0, currentCol) + input + newLines[currentRow].slice(currentCol);
|
|
132
|
+
newCol = currentCol + 1;
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
return; // No change
|
|
136
|
+
}
|
|
137
|
+
undo.push({ lines: newLines, cursorRow: newRow, cursorCol: newCol });
|
|
138
|
+
onChange(newLines.join('\n'));
|
|
139
|
+
});
|
|
140
|
+
const innerWidth = Math.max(1, width - 2);
|
|
141
|
+
const visibleLines = lines.slice(scrollRow, scrollRow + height);
|
|
142
|
+
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 + scrollRow;
|
|
144
|
+
const displayLine = line.slice(scrollCol, scrollCol + innerWidth);
|
|
145
|
+
if (actualRow === cursorRow) {
|
|
146
|
+
// Render cursor on this line
|
|
147
|
+
const beforeCursor = displayLine.slice(0, cursorCol - scrollCol);
|
|
148
|
+
const cursorChar = displayLine[cursorCol - scrollCol] ?? ' ';
|
|
149
|
+
const afterCursor = displayLine.slice(cursorCol - scrollCol + 1);
|
|
150
|
+
return (_jsxs(Box, { children: [_jsx(Text, { children: beforeCursor }), _jsx(Text, { inverse: cursorVisible, children: cursorChar }), _jsx(Text, { children: afterCursor })] }, displayRow));
|
|
151
|
+
}
|
|
152
|
+
return _jsx(Text, { children: displayLine }, displayRow);
|
|
153
|
+
}), validationError && _jsx(Text, { color: "red", children: '✗ Invalid JSON: ' + validationError })] }));
|
|
154
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
type JsonPanelProps = {
|
|
3
|
+
label: string;
|
|
4
|
+
value: string;
|
|
5
|
+
scrollOffset: number;
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
active: boolean;
|
|
9
|
+
};
|
|
10
|
+
export declare function JsonPanel({ label, value, scrollOffset, width, height, active }: JsonPanelProps): React.ReactElement;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
function highlightJson(line) {
|
|
4
|
+
// Simple regex-based syntax highlighting
|
|
5
|
+
const parts = [];
|
|
6
|
+
let remaining = line;
|
|
7
|
+
while (remaining.length > 0) {
|
|
8
|
+
// Object key: "key":
|
|
9
|
+
const keyMatch = remaining.match(/^("(?:[^"\\]|\\.)*"\s*:)/);
|
|
10
|
+
if (keyMatch) {
|
|
11
|
+
parts.push({ text: keyMatch[1], color: 'cyan' });
|
|
12
|
+
remaining = remaining.slice(keyMatch[1].length);
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
// String value
|
|
16
|
+
const strMatch = remaining.match(/^("(?:[^"\\]|\\.)*")/);
|
|
17
|
+
if (strMatch) {
|
|
18
|
+
parts.push({ text: strMatch[1], color: 'green' });
|
|
19
|
+
remaining = remaining.slice(strMatch[1].length);
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
// Number
|
|
23
|
+
const numMatch = remaining.match(/^(-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)/);
|
|
24
|
+
if (numMatch) {
|
|
25
|
+
parts.push({ text: numMatch[1], color: 'yellow' });
|
|
26
|
+
remaining = remaining.slice(numMatch[1].length);
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
// Boolean
|
|
30
|
+
const boolMatch = remaining.match(/^(true|false)/);
|
|
31
|
+
if (boolMatch) {
|
|
32
|
+
parts.push({ text: boolMatch[1], color: 'magenta' });
|
|
33
|
+
remaining = remaining.slice(boolMatch[1].length);
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
// Null
|
|
37
|
+
const nullMatch = remaining.match(/^(null)/);
|
|
38
|
+
if (nullMatch) {
|
|
39
|
+
parts.push({ text: nullMatch[1], color: 'red', dim: true });
|
|
40
|
+
remaining = remaining.slice(nullMatch[1].length);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
// Take one character as-is (punctuation, whitespace, etc.)
|
|
44
|
+
parts.push({ text: remaining[0] });
|
|
45
|
+
remaining = remaining.slice(1);
|
|
46
|
+
}
|
|
47
|
+
return (_jsx(_Fragment, { children: parts.map((part, i) => (_jsx(Text, { color: part.color, dimColor: part.dim, children: part.text }, i))) }));
|
|
48
|
+
}
|
|
49
|
+
function truncateLine(line, maxWidth) {
|
|
50
|
+
if (line.length <= maxWidth)
|
|
51
|
+
return line;
|
|
52
|
+
return line.slice(0, maxWidth - 1) + '…';
|
|
53
|
+
}
|
|
54
|
+
export function JsonPanel({ label, value, scrollOffset, width, height, active }) {
|
|
55
|
+
const allLines = value.split('\n');
|
|
56
|
+
const visibleLines = allLines.slice(scrollOffset, scrollOffset + height);
|
|
57
|
+
const innerWidth = Math.max(1, width - 2); // subtract border
|
|
58
|
+
return (_jsxs(Box, { flexDirection: "column", width: width, height: height + 2, borderStyle: "single", borderColor: active ? 'white' : undefined, children: [_jsx(Text, { bold: true, dimColor: !active, children: label }), visibleLines.map((line, i) => {
|
|
59
|
+
const truncated = truncateLine(line, innerWidth);
|
|
60
|
+
return _jsx(Box, { children: highlightJson(truncated) }, i);
|
|
61
|
+
})] }));
|
|
62
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { ServerPreviewResponse } from '@contentful/experience-design-system-types';
|
|
3
|
+
type PreviewSummaryBarProps = {
|
|
4
|
+
preview: ServerPreviewResponse | null;
|
|
5
|
+
loading: boolean;
|
|
6
|
+
};
|
|
7
|
+
export declare function PreviewSummaryBar({ preview, loading }: PreviewSummaryBarProps): React.ReactElement;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
export function PreviewSummaryBar({ preview, loading }) {
|
|
4
|
+
if (!preview && !loading) {
|
|
5
|
+
return _jsx(Box, {});
|
|
6
|
+
}
|
|
7
|
+
if (loading && !preview) {
|
|
8
|
+
return (_jsx(Box, { gap: 1, children: _jsx(Text, { dimColor: true, children: "\u21BB Loading preview..." }) }));
|
|
9
|
+
}
|
|
10
|
+
const comp = preview.components;
|
|
11
|
+
const tok = preview.tokens;
|
|
12
|
+
const parts = [];
|
|
13
|
+
const newCount = comp.new.length + tok.new.length;
|
|
14
|
+
const changedCount = comp.changed.length + tok.changed.length;
|
|
15
|
+
const removedCount = comp.removed.length + tok.removed.length;
|
|
16
|
+
const unchangedCount = comp.unchanged.length + tok.unchanged.length;
|
|
17
|
+
if (newCount > 0)
|
|
18
|
+
parts.push({ label: `${newCount} new`, color: 'green' });
|
|
19
|
+
if (changedCount > 0)
|
|
20
|
+
parts.push({ label: `${changedCount} changed`, color: 'yellow' });
|
|
21
|
+
if (removedCount > 0)
|
|
22
|
+
parts.push({ label: `${removedCount} removed`, color: 'red' });
|
|
23
|
+
if (unchangedCount > 0)
|
|
24
|
+
parts.push({ label: `${unchangedCount} unchanged`, color: 'gray' });
|
|
25
|
+
if (parts.length === 0 && !loading) {
|
|
26
|
+
return (_jsx(Box, { gap: 1, children: _jsx(Text, { dimColor: true, children: "Preview: no changes detected" }) }));
|
|
27
|
+
}
|
|
28
|
+
return (_jsxs(Box, { gap: 1, children: [_jsx(Text, { dimColor: true, children: "Preview:" }), parts.map((part, i) => (_jsx(Text, { color: part.color, children: part.label }, i))), loading && _jsx(Text, { dimColor: true, children: "\u21BB" })] }));
|
|
29
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
type QuitDialogProps = {
|
|
3
|
+
hasUnsavedDrafts: boolean;
|
|
4
|
+
onConfirm: () => void;
|
|
5
|
+
onCancel: () => void;
|
|
6
|
+
};
|
|
7
|
+
export declare function QuitDialog({ hasUnsavedDrafts, onConfirm, onCancel }: QuitDialogProps): React.ReactElement;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
import { useImmediateInput } from '../hooks/useImmediateInput.js';
|
|
4
|
+
export function QuitDialog({ hasUnsavedDrafts, onConfirm, onCancel }) {
|
|
5
|
+
useImmediateInput((input, key) => {
|
|
6
|
+
if (input === 'y' || key.return) {
|
|
7
|
+
onConfirm();
|
|
8
|
+
}
|
|
9
|
+
else if (input === 'n' || key.escape) {
|
|
10
|
+
onCancel();
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", padding: 1, width: 50, children: [_jsx(Text, { bold: true, children: '─'.repeat(19) + ' Quit ' + '─'.repeat(19) }), _jsx(Text, { children: " " }), hasUnsavedDrafts ? (_jsxs(_Fragment, { children: [_jsx(Text, { children: "You have unsaved draft edits." }), _jsx(Text, { children: 'Session state is preserved — you can resume' }), _jsx(Text, { children: 'by running the same review command again.' })] })) : (_jsx(Text, { children: "Session is saved. Quit without finalizing?" })), _jsx(Text, { children: " " }), _jsx(Text, { children: ' [y / Enter] Quit [n / Esc] Stay' })] }));
|
|
14
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { ReviewComponentSummary } from '../../types.js';
|
|
3
|
+
type SidebarProps = {
|
|
4
|
+
components: ReviewComponentSummary[];
|
|
5
|
+
selectedId: string | null;
|
|
6
|
+
focused: boolean;
|
|
7
|
+
scrollOffset: number;
|
|
8
|
+
visibleCount: number;
|
|
9
|
+
onSelect: (id: string) => void;
|
|
10
|
+
onScrollChange: (offset: number) => void;
|
|
11
|
+
collapsed?: boolean;
|
|
12
|
+
width?: number;
|
|
13
|
+
};
|
|
14
|
+
export declare function Sidebar({ components, selectedId, focused, scrollOffset, visibleCount, collapsed, width: widthProp, }: SidebarProps): React.ReactElement;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
function statusIcon(status) {
|
|
4
|
+
switch (status) {
|
|
5
|
+
case 'accepted':
|
|
6
|
+
return '✓';
|
|
7
|
+
case 'rejected':
|
|
8
|
+
return '✗';
|
|
9
|
+
case 'reviewed':
|
|
10
|
+
return '~';
|
|
11
|
+
case 'needs-review':
|
|
12
|
+
return '·';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function statusColor(status) {
|
|
16
|
+
switch (status) {
|
|
17
|
+
case 'accepted':
|
|
18
|
+
return 'green';
|
|
19
|
+
case 'rejected':
|
|
20
|
+
return 'red';
|
|
21
|
+
case 'reviewed':
|
|
22
|
+
return 'yellow';
|
|
23
|
+
case 'needs-review':
|
|
24
|
+
return 'white';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function truncateName(name, maxLen) {
|
|
28
|
+
if (name.length <= maxLen)
|
|
29
|
+
return name;
|
|
30
|
+
return name.slice(0, maxLen) + '…';
|
|
31
|
+
}
|
|
32
|
+
export function Sidebar({ components, selectedId, focused, scrollOffset, visibleCount, collapsed = false, width: widthProp, }) {
|
|
33
|
+
const visible = components.slice(scrollOffset, scrollOffset + visibleCount);
|
|
34
|
+
const showScrollUp = scrollOffset > 0;
|
|
35
|
+
const showScrollDown = scrollOffset + visibleCount < components.length;
|
|
36
|
+
const width = collapsed ? 3 : (widthProp ?? 18);
|
|
37
|
+
return (_jsxs(Box, { flexDirection: "column", width: width, borderStyle: "single", borderColor: focused ? 'white' : undefined, children: [showScrollUp && !collapsed && _jsx(Text, { dimColor: true, children: "\u25B2" }), visible.map((component) => {
|
|
38
|
+
const isSelected = component.id === selectedId;
|
|
39
|
+
const icon = statusIcon(component.status);
|
|
40
|
+
const color = statusColor(component.status);
|
|
41
|
+
const maxNameLen = Math.max(1, width - 5);
|
|
42
|
+
const name = truncateName(component.name, maxNameLen);
|
|
43
|
+
if (collapsed) {
|
|
44
|
+
return (_jsx(Box, { children: _jsx(Text, { color: color, inverse: isSelected && focused, underline: isSelected && !focused, children: icon }) }, component.id));
|
|
45
|
+
}
|
|
46
|
+
return (_jsx(Box, { children: _jsx(Text, { color: color, inverse: isSelected && focused, underline: isSelected && !focused, wrap: "truncate", children: icon + ' ' + name }) }, component.id));
|
|
47
|
+
}), showScrollDown && !collapsed && _jsx(Text, { dimColor: true, children: "\u25BC" })] }));
|
|
48
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
type SourcePanelProps = {
|
|
3
|
+
sourceCode: string | null;
|
|
4
|
+
filePath: string;
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
scrollX: number;
|
|
8
|
+
scrollY: number;
|
|
9
|
+
};
|
|
10
|
+
export declare function SourcePanel({ sourceCode, filePath, width, height, scrollX, scrollY, }: SourcePanelProps): React.ReactElement;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
const KEYWORDS = /\b(function|export|const|let|import|return|interface|type|default|class|extends|implements|from|async|await)\b/;
|
|
4
|
+
function highlightSourceLine(line) {
|
|
5
|
+
const parts = [];
|
|
6
|
+
let remaining = line;
|
|
7
|
+
while (remaining.length > 0) {
|
|
8
|
+
// String literal
|
|
9
|
+
const strMatch = remaining.match(/^("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|`(?:[^`\\]|\\.)*`)/);
|
|
10
|
+
if (strMatch) {
|
|
11
|
+
parts.push({ text: strMatch[1], color: 'green' });
|
|
12
|
+
remaining = remaining.slice(strMatch[1].length);
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
// Keyword
|
|
16
|
+
const kwMatch = remaining.match(KEYWORDS);
|
|
17
|
+
if (kwMatch && kwMatch.index === 0) {
|
|
18
|
+
parts.push({ text: kwMatch[0], color: 'cyan' });
|
|
19
|
+
remaining = remaining.slice(kwMatch[0].length);
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
parts.push({ text: remaining[0] });
|
|
23
|
+
remaining = remaining.slice(1);
|
|
24
|
+
}
|
|
25
|
+
return (_jsx(_Fragment, { children: parts.map((part, i) => (_jsx(Text, { color: part.color, children: part.text }, i))) }));
|
|
26
|
+
}
|
|
27
|
+
function truncateFilePath(filePath, maxWidth) {
|
|
28
|
+
if (filePath.length <= maxWidth)
|
|
29
|
+
return filePath;
|
|
30
|
+
const filename = filePath.split('/').pop() ?? filePath;
|
|
31
|
+
if (filename.length >= maxWidth)
|
|
32
|
+
return filename.slice(0, maxWidth - 1) + '…';
|
|
33
|
+
return '…' + filePath.slice(filePath.length - (maxWidth - 1));
|
|
34
|
+
}
|
|
35
|
+
export function SourcePanel({ sourceCode, filePath, width, height, scrollX, scrollY, }) {
|
|
36
|
+
const innerWidth = Math.max(1, width - 2);
|
|
37
|
+
const header = truncateFilePath(filePath, innerWidth);
|
|
38
|
+
if (!sourceCode) {
|
|
39
|
+
return (_jsxs(Box, { flexDirection: "column", width: width, height: height + 2, borderStyle: "single", children: [_jsx(Text, { dimColor: true, children: header }), _jsx(Box, { justifyContent: "center", alignItems: "center", height: height, children: _jsx(Text, { dimColor: true, children: "[No source available]" }) })] }));
|
|
40
|
+
}
|
|
41
|
+
const allLines = sourceCode.split('\n');
|
|
42
|
+
const visibleLines = allLines.slice(scrollY, scrollY + height);
|
|
43
|
+
const showScrollUp = scrollY > 0;
|
|
44
|
+
const showScrollDown = scrollY + height < allLines.length;
|
|
45
|
+
const maxLineWidth = Math.max(...visibleLines.map((l) => l.length));
|
|
46
|
+
const showScrollLeft = scrollX > 0;
|
|
47
|
+
const showScrollRight = scrollX + innerWidth < maxLineWidth;
|
|
48
|
+
return (_jsxs(Box, { flexDirection: "column", width: width, height: height + 2, borderStyle: "single", children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsx(Text, { dimColor: true, children: header }), _jsxs(Text, { dimColor: true, children: [showScrollUp ? '▲' : ' ', showScrollDown ? '▼' : ' ', showScrollLeft ? '◀' : ' ', showScrollRight ? '▶' : ' '] })] }), visibleLines.map((line, i) => {
|
|
49
|
+
const sliced = line.slice(scrollX, scrollX + innerWidth);
|
|
50
|
+
return _jsx(Box, { children: highlightSourceLine(sliced) }, i);
|
|
51
|
+
})] }));
|
|
52
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
type StatusBarProps = {
|
|
3
|
+
accepted: number;
|
|
4
|
+
rejected: number;
|
|
5
|
+
reviewed: number;
|
|
6
|
+
needsReview: number;
|
|
7
|
+
onApproveAll: () => void;
|
|
8
|
+
onFinalize: () => void;
|
|
9
|
+
};
|
|
10
|
+
export declare function StatusBar({ accepted, rejected, reviewed, needsReview }: StatusBarProps): React.ReactElement;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
export function StatusBar({ accepted, rejected, reviewed, needsReview }) {
|
|
4
|
+
const allResolved = needsReview === 0;
|
|
5
|
+
return (_jsxs(Box, { gap: 2, flexWrap: "wrap", children: [_jsxs(Text, { color: "green", children: [accepted, " accepted"] }), _jsxs(Text, { color: "red", children: [rejected, " rejected"] }), _jsxs(Text, { dimColor: true, children: [needsReview, " pending"] }), _jsxs(Text, { color: "cyan", children: [reviewed, " reviewed"] }), _jsx(Text, { dimColor: true, children: "\u00B7" }), _jsx(Text, { dimColor: true, children: "[A] accept all" }), _jsx(Text, { bold: allResolved, color: allResolved ? 'green' : 'white', children: "[F] finalize" })] }));
|
|
6
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
export function TopBar({ subcommand, hints }) {
|
|
4
|
+
return (_jsxs(Box, { justifyContent: "space-between", children: [_jsx(Text, { bold: true, children: 'experience-design-system-cli ' + subcommand }), _jsx(Text, { dimColor: true, children: hints.map((h) => `[${h.key}] ${h.label}`).join(' ') })] }));
|
|
5
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
type Key = {
|
|
2
|
+
upArrow: boolean;
|
|
3
|
+
downArrow: boolean;
|
|
4
|
+
leftArrow: boolean;
|
|
5
|
+
rightArrow: boolean;
|
|
6
|
+
pageDown: boolean;
|
|
7
|
+
pageUp: boolean;
|
|
8
|
+
return: boolean;
|
|
9
|
+
escape: boolean;
|
|
10
|
+
ctrl: boolean;
|
|
11
|
+
shift: boolean;
|
|
12
|
+
tab: boolean;
|
|
13
|
+
backspace: boolean;
|
|
14
|
+
delete: boolean;
|
|
15
|
+
meta: boolean;
|
|
16
|
+
};
|
|
17
|
+
type InputHandler = (input: string, key: Key) => void;
|
|
18
|
+
/**
|
|
19
|
+
* Like Ink's useInput, but uses useLayoutEffect so the listener is registered
|
|
20
|
+
* synchronously after render. This allows stdin.write() calls in tests to work
|
|
21
|
+
* immediately after render() without awaiting effects.
|
|
22
|
+
*/
|
|
23
|
+
export declare function useImmediateInput(handler: InputHandler): void;
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { useLayoutEffect, useRef } from 'react';
|
|
2
|
+
import { useStdin } from 'ink';
|
|
3
|
+
function parseInput(data) {
|
|
4
|
+
const key = {
|
|
5
|
+
upArrow: data === '\x1b[A',
|
|
6
|
+
downArrow: data === '\x1b[B',
|
|
7
|
+
leftArrow: data === '\x1b[D',
|
|
8
|
+
rightArrow: data === '\x1b[C',
|
|
9
|
+
pageDown: data === '\x1b[6~',
|
|
10
|
+
pageUp: data === '\x1b[5~',
|
|
11
|
+
return: data === '\r' || data === '\n',
|
|
12
|
+
escape: data === '\x1b',
|
|
13
|
+
ctrl: false,
|
|
14
|
+
shift: false,
|
|
15
|
+
tab: data === '\t',
|
|
16
|
+
backspace: data === '\x7f' || data === '\b',
|
|
17
|
+
delete: data === '\x1b[3~',
|
|
18
|
+
meta: data === '\x1b',
|
|
19
|
+
};
|
|
20
|
+
let input = data;
|
|
21
|
+
// Ctrl+letter: data is \x01-\x1a (Ctrl+A through Ctrl+Z)
|
|
22
|
+
if (data.length === 1) {
|
|
23
|
+
const code = data.charCodeAt(0);
|
|
24
|
+
if (code >= 1 && code <= 26) {
|
|
25
|
+
key.ctrl = true;
|
|
26
|
+
input = String.fromCharCode(code + 96); // convert to lowercase letter
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// Arrow keys and special keys produce no printable input
|
|
30
|
+
if (key.upArrow ||
|
|
31
|
+
key.downArrow ||
|
|
32
|
+
key.leftArrow ||
|
|
33
|
+
key.rightArrow ||
|
|
34
|
+
key.pageUp ||
|
|
35
|
+
key.pageDown ||
|
|
36
|
+
key.return ||
|
|
37
|
+
key.escape ||
|
|
38
|
+
key.tab ||
|
|
39
|
+
key.backspace ||
|
|
40
|
+
key.delete) {
|
|
41
|
+
if (!key.ctrl)
|
|
42
|
+
input = '';
|
|
43
|
+
}
|
|
44
|
+
return { input, key };
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Like Ink's useInput, but uses useLayoutEffect so the listener is registered
|
|
48
|
+
* synchronously after render. This allows stdin.write() calls in tests to work
|
|
49
|
+
* immediately after render() without awaiting effects.
|
|
50
|
+
*/
|
|
51
|
+
export function useImmediateInput(handler) {
|
|
52
|
+
const { stdin, setRawMode } = useStdin();
|
|
53
|
+
const handlerRef = useRef(handler);
|
|
54
|
+
handlerRef.current = handler;
|
|
55
|
+
useLayoutEffect(() => {
|
|
56
|
+
setRawMode(true);
|
|
57
|
+
const handleData = (data) => {
|
|
58
|
+
const str = Buffer.isBuffer(data) ? data.toString('utf8') : data;
|
|
59
|
+
const { input, key } = parseInput(str);
|
|
60
|
+
handlerRef.current(input, key);
|
|
61
|
+
};
|
|
62
|
+
stdin.on('data', handleData);
|
|
63
|
+
return () => {
|
|
64
|
+
stdin.off('data', handleData);
|
|
65
|
+
setRawMode(false);
|
|
66
|
+
};
|
|
67
|
+
}, [stdin, setRawMode]);
|
|
68
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
type KeymapContext = {
|
|
2
|
+
sidebarFocused: boolean;
|
|
3
|
+
editMode: boolean;
|
|
4
|
+
dialogOpen: boolean;
|
|
5
|
+
disabled: boolean;
|
|
6
|
+
};
|
|
7
|
+
type KeymapHandlers = {
|
|
8
|
+
onSidebarUp: () => void;
|
|
9
|
+
onSidebarDown: () => void;
|
|
10
|
+
onSidebarSelect: () => void;
|
|
11
|
+
onAccept: () => void;
|
|
12
|
+
onReject: () => void;
|
|
13
|
+
onEnterEditMode: () => void;
|
|
14
|
+
onToggleSource: () => void;
|
|
15
|
+
onScrollUp: () => void;
|
|
16
|
+
onScrollDown: () => void;
|
|
17
|
+
onToggleFocus: () => void;
|
|
18
|
+
onApproveAll: () => void;
|
|
19
|
+
onFinalize: () => void;
|
|
20
|
+
onQuit: () => void;
|
|
21
|
+
onToggleHelp: () => void;
|
|
22
|
+
};
|
|
23
|
+
export declare function useKeymap(context: KeymapContext, handlers: KeymapHandlers): void;
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { useImmediateInput } from './useImmediateInput.js';
|
|
2
|
+
export function useKeymap(context, handlers) {
|
|
3
|
+
useImmediateInput((input, key) => {
|
|
4
|
+
if (context.disabled)
|
|
5
|
+
return;
|
|
6
|
+
if (context.dialogOpen)
|
|
7
|
+
return;
|
|
8
|
+
if (context.editMode)
|
|
9
|
+
return;
|
|
10
|
+
if (input === 'q') {
|
|
11
|
+
handlers.onQuit();
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
if (input === '?') {
|
|
15
|
+
handlers.onToggleHelp();
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (key.tab) {
|
|
19
|
+
handlers.onToggleFocus();
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (input === 'A') {
|
|
23
|
+
handlers.onApproveAll();
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (input === 'F') {
|
|
27
|
+
handlers.onFinalize();
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
// a/r/e/s work regardless of sidebar focus
|
|
31
|
+
if (input === 'a') {
|
|
32
|
+
handlers.onAccept();
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (input === 'r') {
|
|
36
|
+
handlers.onReject();
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (input === 'e') {
|
|
40
|
+
handlers.onEnterEditMode();
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (input === 's') {
|
|
44
|
+
handlers.onToggleSource();
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (context.sidebarFocused) {
|
|
48
|
+
if (key.upArrow || input === 'k') {
|
|
49
|
+
handlers.onSidebarUp();
|
|
50
|
+
}
|
|
51
|
+
else if (key.downArrow || input === 'j') {
|
|
52
|
+
handlers.onSidebarDown();
|
|
53
|
+
}
|
|
54
|
+
else if (key.return) {
|
|
55
|
+
handlers.onSidebarSelect();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
if (key.upArrow || input === 'k') {
|
|
60
|
+
handlers.onScrollUp();
|
|
61
|
+
}
|
|
62
|
+
else if (key.downArrow || input === 'j') {
|
|
63
|
+
handlers.onScrollDown();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|