epiq 0.0.2 → 0.0.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/dist/app.js +10 -4
- package/dist/board/components/Board.js +4 -12
- package/dist/board/components/CommandLine.d.ts +2 -0
- package/dist/board/components/CommandLine.js +26 -0
- package/dist/{components/Help.d.ts → board/components/ContextBar.d.ts} +1 -1
- package/dist/board/components/ContextBar.js +17 -0
- package/dist/board/components/Help.js +19 -12
- package/dist/board/components/Swimlane.d.ts +1 -0
- package/dist/board/components/Swimlane.js +6 -4
- package/dist/board/components/Swimlanes.js +8 -11
- package/dist/board/components/TextInput.d.ts +6 -0
- package/dist/board/components/TextInput.js +9 -0
- package/dist/board/components/TicketListItem.js +6 -5
- package/dist/board/components/TicketUI.js +6 -7
- package/dist/board/hints/hints.d.ts +7 -0
- package/dist/board/hints/hints.js +21 -0
- package/dist/board/mock/board.js +73 -27
- package/dist/cli.d.ts +2 -1
- package/dist/cli.js +21 -39
- package/dist/debug-logger.d.ts +2 -0
- package/dist/debug-logger.js +16 -0
- package/dist/init-project.d.ts +1 -0
- package/dist/init-project.js +1 -0
- package/dist/navigation/actions/add/add-actions.d.ts +2 -0
- package/dist/navigation/actions/add/add-actions.js +25 -0
- package/dist/navigation/actions/add/add-item-actions.d.ts +2 -0
- package/dist/navigation/actions/add/add-item-actions.js +25 -0
- package/dist/navigation/actions/add-item/add-item-actions.d.ts +3 -0
- package/dist/navigation/actions/add-item/add-item-actions.js +45 -0
- package/dist/navigation/actions/board-action-map.d.ts +10 -0
- package/dist/navigation/actions/board-action-map.js +12 -0
- package/dist/navigation/actions/default/default-action-utils.d.ts +8 -0
- package/dist/navigation/actions/default/default-action-utils.js +101 -0
- package/dist/navigation/actions/default/default-actions.d.ts +2 -0
- package/dist/navigation/actions/default/default-actions.js +64 -0
- package/dist/navigation/actions/default/navigation-action-utils.d.ts +16 -0
- package/dist/navigation/actions/default/navigation-action-utils.js +109 -0
- package/dist/navigation/actions/input/command-line-input.d.ts +2 -0
- package/dist/navigation/actions/input/command-line-input.js +18 -0
- package/dist/navigation/actions/input/input-actions-utils.d.ts +8 -0
- package/dist/navigation/actions/input/input-actions-utils.js +47 -0
- package/dist/navigation/actions/input/input-actions.d.ts +2 -0
- package/dist/navigation/actions/input/input-actions.js +44 -0
- package/dist/navigation/actions/move/move-actions-routes.d.ts +4 -0
- package/dist/navigation/actions/move/move-actions-routes.js +55 -0
- package/dist/navigation/actions/move/move-actions-utils.d.ts +4 -0
- package/dist/navigation/actions/move/move-actions-utils.js +66 -0
- package/dist/navigation/actions/move/move-actions.d.ts +4 -0
- package/dist/navigation/actions/move/move-actions.js +59 -0
- package/dist/{lib/utils/default-action-utils.d.ts → navigation/actions/navigate/navigation-action-utils.d.ts} +1 -1
- package/dist/navigation/actions/navigate/navigation-actions.d.ts +2 -0
- package/dist/navigation/actions/navigate/navigation-actions.js +78 -0
- package/dist/navigation/command-line/command-line-actions.d.ts +2 -0
- package/dist/navigation/command-line/command-line-actions.js +32 -0
- package/dist/navigation/command-line/command-line-intent.d.ts +7 -0
- package/dist/navigation/command-line/command-line-intent.js +29 -0
- package/dist/navigation/command-line/command-line-sequence-actions.d.ts +2 -0
- package/dist/navigation/command-line/command-line-sequence-actions.js +44 -0
- package/dist/navigation/command-line/command-line-sequence-intent.d.ts +8 -0
- package/dist/navigation/command-line/command-line-sequence-intent.js +32 -0
- package/dist/navigation/command-line/commands.d.ts +2 -0
- package/dist/navigation/command-line/commands.js +58 -0
- package/dist/navigation/keypress-listener.d.ts +1 -0
- package/dist/navigation/keypress-listener.js +33 -0
- package/dist/navigation/model/action-map.model.d.ts +17 -5
- package/dist/navigation/model/action-map.model.js +2 -0
- package/dist/navigation/model/navigation-ctx.model.d.ts +1 -16
- package/dist/navigation/model/navigation-ctx.model.js +0 -1
- package/dist/navigation/model/navigation-tree.model.d.ts +3 -1
- package/dist/navigation/navigation.d.ts +3 -10
- package/dist/navigation/navigation.js +74 -66
- package/dist/navigation/state/command-line.state.d.ts +18 -0
- package/dist/navigation/state/command-line.state.js +60 -0
- package/dist/navigation/state/state.d.ts +18 -9
- package/dist/navigation/state/state.js +36 -8
- package/dist/navigation/utils/get-command-line-intent.d.ts +3 -0
- package/dist/navigation/utils/get-command-line-intent.js +17 -0
- package/dist/navigation/utils/getKeyIntent.d.ts +5 -0
- package/dist/navigation/utils/getKeyIntent.js +71 -0
- package/dist/navigation/utils/key-intent.d.ts +21 -12
- package/dist/navigation/utils/key-intent.js +104 -50
- package/package.json +3 -3
- package/dist/board/actions/board-action-map.d.ts +0 -11
- package/dist/board/actions/board-action-map.js +0 -11
- package/dist/board/actions/move-actions-routes.d.ts +0 -4
- package/dist/board/actions/move-actions-routes.js +0 -31
- package/dist/board/actions/move-actions.d.ts +0 -5
- package/dist/board/actions/move-actions.js +0 -49
- package/dist/board/board-action-map.d.ts +0 -9
- package/dist/board/board-action-map.js +0 -7
- package/dist/board/move-actions-routes.d.ts +0 -4
- package/dist/board/move-actions-routes.js +0 -31
- package/dist/board/move-actions.d.ts +0 -5
- package/dist/board/move-actions.js +0 -49
- package/dist/components/Board.d.ts +0 -6
- package/dist/components/Board.js +0 -15
- package/dist/components/Help.js +0 -21
- package/dist/components/Swimlane.d.ts +0 -8
- package/dist/components/Swimlane.js +0 -10
- package/dist/components/TicketListItem.d.ts +0 -6
- package/dist/components/TicketListItem.js +0 -12
- package/dist/lib/actions/board-action-map.d.ts +0 -9
- package/dist/lib/actions/board-action-map.js +0 -7
- package/dist/lib/actions/move-actions-utils.d.ts +0 -5
- package/dist/lib/actions/move-actions-utils.js +0 -43
- package/dist/lib/actions/move-actions.d.ts +0 -4
- package/dist/lib/actions/move-actions.js +0 -31
- package/dist/lib/board/board-action-map.d.ts +0 -9
- package/dist/lib/board/board-action-map.js +0 -7
- package/dist/lib/board/move-actions-routes.d.ts +0 -4
- package/dist/lib/board/move-actions-routes.js +0 -31
- package/dist/lib/board/move-actions.d.ts +0 -5
- package/dist/lib/board/move-actions.js +0 -43
- package/dist/lib/board-utils.d.ts +0 -7
- package/dist/lib/board-utils.js +0 -33
- package/dist/lib/default-actions-routes.d.ts +0 -4
- package/dist/lib/default-actions-routes.js +0 -47
- package/dist/lib/default-actions.d.ts +0 -4
- package/dist/lib/default-actions.js +0 -47
- package/dist/lib/navigation-context.d.ts +0 -16
- package/dist/lib/navigation.d.ts +0 -10
- package/dist/lib/navigation.js +0 -74
- package/dist/lib/render-utils.d.ts +0 -10
- package/dist/lib/render-utils.js +0 -12
- package/dist/lib/state.d.ts +0 -8
- package/dist/lib/state.js +0 -8
- package/dist/lib/types/action-map.model.d.ts +0 -14
- package/dist/lib/types/action-map.model.js +0 -4
- package/dist/lib/types/board.model.d.ts +0 -21
- package/dist/lib/types/board.model.js +0 -5
- package/dist/lib/types/navigation.model.d.ts +0 -9
- package/dist/lib/utils/array-utils.d.ts +0 -5
- package/dist/lib/utils/array-utils.js +0 -7
- package/dist/lib/utils/default-action-utils.js +0 -50
- package/dist/lib/utils/default-actions.d.ts +0 -7
- package/dist/lib/utils/default-actions.js +0 -50
- package/dist/lib/utils/key-intent.d.ts +0 -16
- package/dist/lib/utils/key-intent.js +0 -65
- package/dist/lib/utils.d.ts +0 -10
- package/dist/lib/utils.js +0 -12
- package/dist/mock/board.d.ts +0 -2
- package/dist/mock/board.js +0 -139
- package/dist/navigation/actions/default-actions-routes.d.ts +0 -4
- package/dist/navigation/actions/default-actions-routes.js +0 -47
- package/dist/navigation/actions/default-actions.d.ts +0 -7
- /package/dist/navigation/actions/{default-actions.js → navigate/navigation-action-utils.js} +0 -0
- /package/dist/{lib/navigation-context.js → navigation/navigation-ctx.d.ts} +0 -0
- /package/dist/{lib/types/navigation.model.js → navigation/navigation-ctx.js} +0 -0
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { BoardItemTypes } from '../../board/model/board.model.js';
|
|
1
2
|
export type NavigationTree<TMeta = Record<string, unknown>> = {
|
|
2
3
|
id: string;
|
|
3
4
|
isSelected: boolean;
|
|
4
5
|
childrenRenderAxis: 'vertical' | 'horizontal';
|
|
5
6
|
name: string;
|
|
7
|
+
description?: string;
|
|
6
8
|
children: NavigationTree<unknown>[];
|
|
7
|
-
actionContext:
|
|
9
|
+
actionContext: (typeof BoardItemTypes)[keyof typeof BoardItemTypes];
|
|
8
10
|
enableChildNavigationAcrossContainers?: boolean;
|
|
9
11
|
} & TMeta;
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare
|
|
3
|
-
|
|
4
|
-
breadCrumb: Array<NavigationTree<NavigationTree>>;
|
|
5
|
-
callbacks: Partial<{
|
|
6
|
-
render: () => void;
|
|
7
|
-
onSelectChange: (s: T['children'][number], breadCrumb: T['children']) => void;
|
|
8
|
-
onConfirm: (s: T['children'][number]) => void;
|
|
9
|
-
}>;
|
|
10
|
-
}): void;
|
|
1
|
+
import { NavigateUtils } from './model/navigation-ctx.model.js';
|
|
2
|
+
export declare const navigationUtils: NavigateUtils;
|
|
3
|
+
export declare function initListeners(): void;
|
|
@@ -1,74 +1,82 @@
|
|
|
1
1
|
import readline from 'readline';
|
|
2
|
-
import {
|
|
2
|
+
import { appState, patchState, updateState } from './state/state.js';
|
|
3
3
|
import { getKeyIntent } from './utils/key-intent.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
getSelectedIndex() {
|
|
19
|
-
return this._selectedIndex;
|
|
20
|
-
},
|
|
21
|
-
select(i) {
|
|
22
|
-
this._selectedIndex = i;
|
|
23
|
-
updateSelection(ctx.navigationNode, breadCrumb, i, onSelectChange);
|
|
24
|
-
},
|
|
25
|
-
render,
|
|
26
|
-
reInvokeNavigate(index, breadCrumb) {
|
|
27
|
-
return reInvokeNavigate(index, breadCrumb);
|
|
28
|
-
},
|
|
29
|
-
confirm: sel => onConfirm(sel),
|
|
30
|
-
exit: () => {
|
|
31
|
-
cleanup();
|
|
32
|
-
process.exit(0);
|
|
33
|
-
},
|
|
34
|
-
enterChildNode: node => reInvokeNavigate(0, [...breadCrumb, node]),
|
|
35
|
-
enterParentNode: () => {
|
|
36
|
-
ctx.select(-1); // Clear all on this level
|
|
37
|
-
if (breadCrumb.length < 2)
|
|
38
|
-
return; // Need at least grandparent + parent
|
|
39
|
-
const ancestors = breadCrumb;
|
|
40
|
-
const parent = ancestors[ancestors.length - 1];
|
|
41
|
-
const grandParent = ancestors[ancestors.length - 2];
|
|
42
|
-
if (!parent || !grandParent)
|
|
43
|
-
return;
|
|
44
|
-
const parentIndex = grandParent?.children.findIndex(x => parent.id === x.id);
|
|
45
|
-
reInvokeNavigate(parentIndex, breadCrumb.slice(0, -1)); // Go to parent level
|
|
46
|
-
},
|
|
47
|
-
};
|
|
48
|
-
ctx.select(index);
|
|
49
|
-
function onKeyPress(_, key) {
|
|
50
|
-
if (key.ctrl && key.name === 'c')
|
|
51
|
-
return ctx.exit();
|
|
52
|
-
const filteredActions = navigationState.availableActions.filter(x => x.mode === navigationState.mode);
|
|
53
|
-
const action = filteredActions?.find(actionMeta => {
|
|
54
|
-
const intent = getKeyIntent(key, ctx);
|
|
55
|
-
return intent === actionMeta.intent;
|
|
4
|
+
let currentKeypressListener;
|
|
5
|
+
export const navigationUtils = {
|
|
6
|
+
updateSelection: (idx) => {
|
|
7
|
+
updateState(oldState => {
|
|
8
|
+
const currentNode = oldState.breadCrumb.at(-1) ?? oldState.breadCrumb[0];
|
|
9
|
+
if (!currentNode)
|
|
10
|
+
return oldState;
|
|
11
|
+
currentNode.children?.forEach((child, i) => (child.isSelected = i === idx));
|
|
12
|
+
return {
|
|
13
|
+
...oldState,
|
|
14
|
+
selectedIndex: idx,
|
|
15
|
+
currentNode: currentNode, // keep currentNode in sync
|
|
16
|
+
breadCrumb: [...oldState.breadCrumb], // keep reference fresh if you rely on it
|
|
17
|
+
};
|
|
56
18
|
});
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
19
|
+
},
|
|
20
|
+
selectNone() {
|
|
21
|
+
this.updateSelection(-1);
|
|
22
|
+
},
|
|
23
|
+
confirm(sel) {
|
|
24
|
+
console.log(sel);
|
|
25
|
+
},
|
|
26
|
+
exit() {
|
|
27
|
+
process.exit(0);
|
|
28
|
+
},
|
|
29
|
+
enterChildNode(childNode) {
|
|
30
|
+
patchState({
|
|
31
|
+
breadCrumb: [...appState.breadCrumb, childNode],
|
|
32
|
+
currentNode: childNode,
|
|
33
|
+
selectedIndex: 0,
|
|
34
|
+
});
|
|
35
|
+
this.updateSelection(0);
|
|
36
|
+
},
|
|
37
|
+
enterParentNode() {
|
|
38
|
+
const crumb = appState.breadCrumb;
|
|
39
|
+
if (crumb.length < 2)
|
|
40
|
+
return;
|
|
41
|
+
const newCrumb = crumb.slice(0, -1);
|
|
42
|
+
const parentLevelNode = newCrumb.at(-1);
|
|
43
|
+
// find old parent index inside grandparent
|
|
44
|
+
const grandParent = newCrumb.at(-2);
|
|
45
|
+
const parentIndex = grandParent?.children?.findIndex(x => x.id === parentLevelNode.id) ?? 0;
|
|
46
|
+
patchState({
|
|
47
|
+
breadCrumb: newCrumb,
|
|
48
|
+
currentNode: parentLevelNode,
|
|
49
|
+
selectedIndex: parentIndex,
|
|
50
|
+
});
|
|
51
|
+
this.updateSelection(parentIndex);
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
const getKeyPressListener = () => {
|
|
55
|
+
navigationUtils.updateSelection(appState.selectedIndex ?? 0);
|
|
56
|
+
return async function onKeyPress(_, key) {
|
|
57
|
+
if (key.ctrl && key.name === 'c')
|
|
58
|
+
return navigationUtils.exit();
|
|
59
|
+
const filteredActions = appState.availableActions.filter(a => a.mode === appState.mode);
|
|
60
|
+
const actionMeta = filteredActions.find(({ intent, mode }) => getKeyIntent(key, mode) === intent);
|
|
61
|
+
if (!actionMeta?.action)
|
|
62
|
+
return;
|
|
63
|
+
try {
|
|
64
|
+
const res = actionMeta.action(navigationUtils, actionMeta, key);
|
|
65
|
+
if (res instanceof Promise)
|
|
66
|
+
await res;
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
console.error(err);
|
|
70
|
+
}
|
|
64
71
|
};
|
|
65
|
-
|
|
72
|
+
};
|
|
73
|
+
export function initListeners() {
|
|
74
|
+
if (currentKeypressListener) {
|
|
75
|
+
process.stdin.removeListener('keypress', currentKeypressListener);
|
|
76
|
+
}
|
|
77
|
+
currentKeypressListener = getKeyPressListener();
|
|
66
78
|
readline.emitKeypressEvents(process.stdin);
|
|
67
79
|
if (process.stdin.isTTY)
|
|
68
80
|
process.stdin.setRawMode(true);
|
|
69
|
-
process.stdin.on('keypress',
|
|
70
|
-
}
|
|
71
|
-
function updateSelection({ children }, breadCrumb, idx, onSelectChange) {
|
|
72
|
-
children.forEach((c, i) => (c.isSelected = i === idx));
|
|
73
|
-
onSelectChange(children[idx], breadCrumb);
|
|
81
|
+
process.stdin.on('keypress', currentKeypressListener);
|
|
74
82
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const commandDelimiter = " ";
|
|
2
|
+
export type CommandLineState = {
|
|
3
|
+
value: string;
|
|
4
|
+
commandHistory: string[];
|
|
5
|
+
commandHistoryIndex: number;
|
|
6
|
+
};
|
|
7
|
+
export declare let commandLineState: CommandLineState;
|
|
8
|
+
type Listener = () => void;
|
|
9
|
+
export declare const subscribeCommandLineState: (listener: Listener) => () => boolean;
|
|
10
|
+
export declare const updateCommandLineState: (cb: (old: CommandLineState) => CommandLineState) => void;
|
|
11
|
+
export declare const updateCommandLineInput: (cb: (previous: string) => string) => void;
|
|
12
|
+
export declare const updateCommandHistory: () => void;
|
|
13
|
+
export declare const getPrevCommand: () => void;
|
|
14
|
+
export declare const getNextCommand: () => void;
|
|
15
|
+
export declare const clearCommandLine: () => void;
|
|
16
|
+
export declare const getCommandLineInput: () => string;
|
|
17
|
+
export declare const getCommandLineArgumentValue: () => string;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export const commandDelimiter = ' ';
|
|
2
|
+
export let commandLineState = {
|
|
3
|
+
commandHistory: [],
|
|
4
|
+
value: '',
|
|
5
|
+
commandHistoryIndex: -1,
|
|
6
|
+
};
|
|
7
|
+
const listeners = new Set();
|
|
8
|
+
const notify = () => {
|
|
9
|
+
for (const l of listeners)
|
|
10
|
+
l();
|
|
11
|
+
};
|
|
12
|
+
export const subscribeCommandLineState = (listener) => {
|
|
13
|
+
listeners.add(listener);
|
|
14
|
+
return () => listeners.delete(listener);
|
|
15
|
+
};
|
|
16
|
+
// ===== Updates =====
|
|
17
|
+
export const updateCommandLineState = (cb) => {
|
|
18
|
+
const next = cb(structuredClone(commandLineState));
|
|
19
|
+
commandLineState = next;
|
|
20
|
+
notify();
|
|
21
|
+
};
|
|
22
|
+
export const updateCommandLineInput = (cb) => {
|
|
23
|
+
updateCommandLineState(state => ({
|
|
24
|
+
...state,
|
|
25
|
+
value: cb(state.value),
|
|
26
|
+
}));
|
|
27
|
+
};
|
|
28
|
+
export const updateCommandHistory = () => {
|
|
29
|
+
updateCommandLineState(state => ({
|
|
30
|
+
...state,
|
|
31
|
+
commandHistory: [state.value, ...state.commandHistory].slice(0, 20),
|
|
32
|
+
}));
|
|
33
|
+
};
|
|
34
|
+
export const getPrevCommand = () => {
|
|
35
|
+
updateCommandLineState(s => {
|
|
36
|
+
const nextIndex = Math.min(s.commandHistoryIndex + 1, s.commandHistory.length - 1);
|
|
37
|
+
return {
|
|
38
|
+
...s,
|
|
39
|
+
commandHistoryIndex: nextIndex,
|
|
40
|
+
value: s.commandHistory[nextIndex] ?? '',
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
export const getNextCommand = () => {
|
|
45
|
+
updateCommandLineState(s => {
|
|
46
|
+
// typically you want to clamp down to -1 (meaning "no selection")
|
|
47
|
+
const nextIndex = Math.max(s.commandHistoryIndex - 1, -1);
|
|
48
|
+
return {
|
|
49
|
+
...s,
|
|
50
|
+
commandHistoryIndex: nextIndex,
|
|
51
|
+
value: nextIndex === -1 ? '' : s.commandHistory[nextIndex] ?? '',
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
export const clearCommandLine = () => updateCommandLineInput(() => '');
|
|
56
|
+
export const getCommandLineInput = () => commandLineState.value;
|
|
57
|
+
export const getCommandLineArgumentValue = () => {
|
|
58
|
+
const [_, ...rest] = commandLineState.value.split(commandDelimiter);
|
|
59
|
+
return rest.join(commandDelimiter);
|
|
60
|
+
};
|
|
@@ -1,11 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { Board } from '../../board/model/board.model.js';
|
|
2
|
+
import { ActionEntry, ModeUnion } from '../model/action-map.model.js';
|
|
3
3
|
import { NavigationTree } from '../model/navigation-tree.model.js';
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
export type AppState = {
|
|
5
|
+
readonly selectedIndex: number;
|
|
6
|
+
readonly mode: ModeUnion;
|
|
7
|
+
readonly availableActions: ActionEntry[];
|
|
8
|
+
readonly availableHints: readonly string[];
|
|
9
|
+
readonly currentNode: NavigationTree<NavigationTree>;
|
|
10
|
+
readonly breadCrumb: NavigationTree<NavigationTree>[];
|
|
11
|
+
readonly rootNode: Board;
|
|
10
12
|
};
|
|
11
|
-
export declare
|
|
13
|
+
export declare let appState: AppState;
|
|
14
|
+
export declare const initAppState: (board: Board) => void;
|
|
15
|
+
export declare const updateState: (cb: (oldState: typeof appState) => typeof appState, opts?: {
|
|
16
|
+
render?: boolean;
|
|
17
|
+
}) => void;
|
|
18
|
+
export declare const patchState: (patch: Partial<typeof appState>, opts?: {
|
|
19
|
+
render?: boolean;
|
|
20
|
+
}) => void;
|
|
@@ -1,10 +1,38 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { Hints } from '../../board/hints/hints.js';
|
|
2
|
+
import { renderBoard } from '../../cli.js';
|
|
3
|
+
import { ContextualActionMap } from '../actions/board-action-map.js';
|
|
4
|
+
import { DefaultActions } from '../actions/default/default-actions.js';
|
|
5
|
+
import { inputActions } from '../actions/input/input-actions.js';
|
|
6
|
+
export let appState;
|
|
7
|
+
const derived = (state) => {
|
|
8
|
+
const { currentNode, mode } = state;
|
|
9
|
+
const availableHints = Hints[currentNode.actionContext + mode] ?? Hints[currentNode.actionContext];
|
|
10
|
+
const actionContext = currentNode?.actionContext;
|
|
11
|
+
const availableActions = [
|
|
12
|
+
...DefaultActions,
|
|
13
|
+
...ContextualActionMap[actionContext],
|
|
14
|
+
...inputActions,
|
|
15
|
+
];
|
|
16
|
+
return {
|
|
17
|
+
...state,
|
|
18
|
+
availableHints,
|
|
19
|
+
availableActions,
|
|
20
|
+
};
|
|
7
21
|
};
|
|
8
|
-
export const
|
|
9
|
-
|
|
22
|
+
export const initAppState = (board) => {
|
|
23
|
+
appState = derived({
|
|
24
|
+
...appState,
|
|
25
|
+
rootNode: board,
|
|
26
|
+
breadCrumb: [board],
|
|
27
|
+
selectedIndex: 0,
|
|
28
|
+
mode: 'default',
|
|
29
|
+
currentNode: board,
|
|
30
|
+
});
|
|
31
|
+
renderBoard();
|
|
10
32
|
};
|
|
33
|
+
export const updateState = (cb, opts = { render: true }) => {
|
|
34
|
+
appState = derived(cb(appState));
|
|
35
|
+
if (opts.render)
|
|
36
|
+
renderBoard();
|
|
37
|
+
};
|
|
38
|
+
export const patchState = (patch, opts = { render: true }) => updateState(old => ({ ...old, ...patch }), opts);
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { Intent } from './key-intent.js';
|
|
2
|
+
import readline from 'readline';
|
|
3
|
+
export declare const getCommandLineIntent: (key: readline.Key) => Intent.Confirm | Intent.ToggleCommandLine | Intent.CaptureInput | Intent.EraseInput | Intent.GetLastCommandFromHistory | Intent.GetNextCommandFromHistory;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Intent } from './key-intent.js';
|
|
2
|
+
export const getCommandLineIntent = (key) => {
|
|
3
|
+
switch (key.name) {
|
|
4
|
+
case 'up':
|
|
5
|
+
return Intent.GetLastCommandFromHistory;
|
|
6
|
+
case 'down':
|
|
7
|
+
return Intent.GetNextCommandFromHistory;
|
|
8
|
+
case 'return':
|
|
9
|
+
return Intent.Confirm;
|
|
10
|
+
case 'backspace':
|
|
11
|
+
return Intent.EraseInput;
|
|
12
|
+
case 'escape':
|
|
13
|
+
return Intent.ToggleCommandLine;
|
|
14
|
+
default:
|
|
15
|
+
return Intent.CaptureInput;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import readline from 'readline';
|
|
2
|
+
import { ModeUnion } from '../model/action-map.model.js';
|
|
3
|
+
import { NavigateCtx } from '../model/navigation-ctx.model.js';
|
|
4
|
+
import { KeyIntent } from './key-intent.js';
|
|
5
|
+
export declare function getKeyIntent(key: readline.Key, ctx: NavigateCtx, mode: ModeUnion): KeyIntent | null;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Mode } from '../model/action-map.model.js';
|
|
2
|
+
import { KeyIntent, getDir, mapDirectionalIntent } from './key-intent.js';
|
|
3
|
+
export function getKeyIntent(key, ctx, mode) {
|
|
4
|
+
if (key.sequence === ':') {
|
|
5
|
+
return KeyIntent.ToggleCommandLine;
|
|
6
|
+
}
|
|
7
|
+
if (mode === Mode.COMMAND_LINE) {
|
|
8
|
+
switch (key.name) {
|
|
9
|
+
case 'return':
|
|
10
|
+
return KeyIntent.Confirm;
|
|
11
|
+
case 'backspace':
|
|
12
|
+
return KeyIntent.EraseInput;
|
|
13
|
+
case 'escape':
|
|
14
|
+
return KeyIntent.ToggleCommandLine;
|
|
15
|
+
default:
|
|
16
|
+
return KeyIntent.CaptureInput;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const axis = ctx.navigationNode.childrenRenderAxis;
|
|
20
|
+
const enableAcrossContainers = ctx.navigationNode.enableChildNavigationAcrossContainers;
|
|
21
|
+
if (key.name === 'escape' && mode === Mode.HELP) {
|
|
22
|
+
return KeyIntent.ToggleHelp;
|
|
23
|
+
}
|
|
24
|
+
// Hard exits
|
|
25
|
+
if (key.ctrl && key.name === 'c')
|
|
26
|
+
return KeyIntent.Exit;
|
|
27
|
+
if (key.name === 'escape')
|
|
28
|
+
return KeyIntent.Exit;
|
|
29
|
+
// Move mode
|
|
30
|
+
if (mode === Mode.MOVE) {
|
|
31
|
+
if (key.name === 'y')
|
|
32
|
+
return KeyIntent.ToggleMove;
|
|
33
|
+
const dir = getDir(key);
|
|
34
|
+
if (!dir)
|
|
35
|
+
return null;
|
|
36
|
+
return mapDirectionalIntent(dir, axis, Boolean(enableAcrossContainers), {
|
|
37
|
+
prevItem: KeyIntent.MovePreviousItem,
|
|
38
|
+
nextItem: KeyIntent.MoveNextItem,
|
|
39
|
+
prevContainer: KeyIntent.MoveToPreviousContainer,
|
|
40
|
+
nextContainer: KeyIntent.MoveToNextContainer,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
// Normal mode
|
|
44
|
+
if (key.name === 'y')
|
|
45
|
+
return KeyIntent.ToggleMove;
|
|
46
|
+
// Edit (vim-ish)
|
|
47
|
+
if (key.name === 'i')
|
|
48
|
+
return KeyIntent.Edit;
|
|
49
|
+
// Navigation (arrows + vim hjkl)
|
|
50
|
+
const dir = getDir(key);
|
|
51
|
+
if (dir) {
|
|
52
|
+
return mapDirectionalIntent(dir, axis, Boolean(enableAcrossContainers), {
|
|
53
|
+
prevItem: KeyIntent.NavPreviousItem,
|
|
54
|
+
nextItem: KeyIntent.NavNextItem,
|
|
55
|
+
prevContainer: KeyIntent.NavToPreviousContainer,
|
|
56
|
+
nextContainer: KeyIntent.NavToNextContainer,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
// Actions
|
|
60
|
+
switch (key.name) {
|
|
61
|
+
case 'a':
|
|
62
|
+
return KeyIntent.AddItem;
|
|
63
|
+
case 'return':
|
|
64
|
+
case 'e':
|
|
65
|
+
return KeyIntent.Confirm;
|
|
66
|
+
case 'q':
|
|
67
|
+
return KeyIntent.Exit;
|
|
68
|
+
default:
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
import readline from 'readline';
|
|
2
|
-
import {
|
|
3
|
-
export declare enum
|
|
4
|
-
NavPreviousItem = "
|
|
5
|
-
NavNextItem = "
|
|
6
|
-
NavToPreviousContainer = "
|
|
7
|
-
NavToNextContainer = "
|
|
8
|
-
MovePreviousItem = "
|
|
9
|
-
MoveNextItem = "
|
|
10
|
-
MoveToPreviousContainer = "
|
|
11
|
-
MoveToNextContainer = "
|
|
2
|
+
import { ModeUnion } from '../model/action-map.model.js';
|
|
3
|
+
export declare enum Intent {
|
|
4
|
+
NavPreviousItem = "navPreviousItem",
|
|
5
|
+
NavNextItem = "navNextItem",
|
|
6
|
+
NavToPreviousContainer = "navToPreviousContainer",
|
|
7
|
+
NavToNextContainer = "navToNextContainer",
|
|
8
|
+
MovePreviousItem = "movePreviousItem",
|
|
9
|
+
MoveNextItem = "moveNextItem",
|
|
10
|
+
MoveToPreviousContainer = "moveToPreviousContainer",
|
|
11
|
+
MoveToNextContainer = "moveToNextContainer",
|
|
12
12
|
Confirm = "confirm",
|
|
13
|
+
Edit = "edit",
|
|
13
14
|
Exit = "exit",
|
|
14
|
-
|
|
15
|
+
ViewHelp = "viewHelp",
|
|
16
|
+
HideHelp = "hideHelp",
|
|
17
|
+
InitMove = "initMove",
|
|
18
|
+
ToggleCommandLine = "toggleCommandLine",
|
|
19
|
+
CaptureInput = "captureInput",
|
|
20
|
+
EraseInput = "eraseInput",
|
|
21
|
+
AddItem = "addItem",
|
|
22
|
+
GetLastCommandFromHistory = "getLastCommandFromHistory",
|
|
23
|
+
GetNextCommandFromHistory = "getNextCommandFromHistory"
|
|
15
24
|
}
|
|
16
|
-
export declare function getKeyIntent(key: readline.Key,
|
|
25
|
+
export declare function getKeyIntent(key: readline.Key, mode: ModeUnion): Intent | null;
|
|
@@ -1,64 +1,118 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
case 'right':
|
|
30
|
-
return axis === 'horizontal'
|
|
31
|
-
? KeyIntent.MoveNextItem
|
|
32
|
-
: ctx.navigationNode.enableChildNavigationAcrossContainers
|
|
33
|
-
? KeyIntent.MoveToNextContainer
|
|
34
|
-
: null;
|
|
35
|
-
default:
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
1
|
+
import { Mode } from '../model/action-map.model.js';
|
|
2
|
+
import { appState } from '../state/state.js';
|
|
3
|
+
import { getCommandLineIntent } from './get-command-line-intent.js';
|
|
4
|
+
export var Intent;
|
|
5
|
+
(function (Intent) {
|
|
6
|
+
Intent["NavPreviousItem"] = "navPreviousItem";
|
|
7
|
+
Intent["NavNextItem"] = "navNextItem";
|
|
8
|
+
Intent["NavToPreviousContainer"] = "navToPreviousContainer";
|
|
9
|
+
Intent["NavToNextContainer"] = "navToNextContainer";
|
|
10
|
+
Intent["MovePreviousItem"] = "movePreviousItem";
|
|
11
|
+
Intent["MoveNextItem"] = "moveNextItem";
|
|
12
|
+
Intent["MoveToPreviousContainer"] = "moveToPreviousContainer";
|
|
13
|
+
Intent["MoveToNextContainer"] = "moveToNextContainer";
|
|
14
|
+
Intent["Confirm"] = "confirm";
|
|
15
|
+
Intent["Edit"] = "edit";
|
|
16
|
+
Intent["Exit"] = "exit";
|
|
17
|
+
Intent["ViewHelp"] = "viewHelp";
|
|
18
|
+
Intent["HideHelp"] = "hideHelp";
|
|
19
|
+
Intent["InitMove"] = "initMove";
|
|
20
|
+
// Command line
|
|
21
|
+
Intent["ToggleCommandLine"] = "toggleCommandLine";
|
|
22
|
+
Intent["CaptureInput"] = "captureInput";
|
|
23
|
+
Intent["EraseInput"] = "eraseInput";
|
|
24
|
+
Intent["AddItem"] = "addItem";
|
|
25
|
+
Intent["GetLastCommandFromHistory"] = "getLastCommandFromHistory";
|
|
26
|
+
Intent["GetNextCommandFromHistory"] = "getNextCommandFromHistory";
|
|
27
|
+
})(Intent || (Intent = {}));
|
|
28
|
+
function getDir(key) {
|
|
39
29
|
switch (key.name) {
|
|
30
|
+
// arrows
|
|
31
|
+
case 'up':
|
|
32
|
+
case 'down':
|
|
33
|
+
case 'left':
|
|
34
|
+
case 'right':
|
|
35
|
+
return key.name;
|
|
36
|
+
// vim
|
|
37
|
+
case 'k':
|
|
38
|
+
return 'up';
|
|
39
|
+
case 'j':
|
|
40
|
+
return 'down';
|
|
40
41
|
case 'h':
|
|
41
|
-
return
|
|
42
|
+
return 'left';
|
|
43
|
+
case 'l':
|
|
44
|
+
return 'right';
|
|
45
|
+
default:
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function mapDirectionalIntent(axis, dir, intents) {
|
|
50
|
+
const enableAcrossContainers = appState.currentNode.enableChildNavigationAcrossContainers;
|
|
51
|
+
switch (dir) {
|
|
42
52
|
case 'up':
|
|
43
|
-
return axis === 'vertical'
|
|
53
|
+
return axis === 'vertical'
|
|
54
|
+
? intents.prevItem
|
|
55
|
+
: enableAcrossContainers
|
|
56
|
+
? intents.prevContainer
|
|
57
|
+
: null;
|
|
44
58
|
case 'down':
|
|
45
|
-
return axis === 'vertical'
|
|
59
|
+
return axis === 'vertical'
|
|
60
|
+
? intents.nextItem
|
|
61
|
+
: enableAcrossContainers
|
|
62
|
+
? intents.nextContainer
|
|
63
|
+
: null;
|
|
46
64
|
case 'left':
|
|
47
65
|
return axis === 'horizontal'
|
|
48
|
-
?
|
|
49
|
-
:
|
|
50
|
-
?
|
|
66
|
+
? intents.prevItem
|
|
67
|
+
: enableAcrossContainers
|
|
68
|
+
? intents.prevContainer
|
|
51
69
|
: null;
|
|
52
70
|
case 'right':
|
|
53
71
|
return axis === 'horizontal'
|
|
54
|
-
?
|
|
55
|
-
:
|
|
56
|
-
?
|
|
72
|
+
? intents.nextItem
|
|
73
|
+
: enableAcrossContainers
|
|
74
|
+
? intents.nextContainer
|
|
57
75
|
: null;
|
|
58
|
-
|
|
59
|
-
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
export function getKeyIntent(key, mode) {
|
|
79
|
+
if (key.sequence === ':')
|
|
80
|
+
return Intent.ToggleCommandLine;
|
|
81
|
+
if (mode === Mode.COMMAND_LINE)
|
|
82
|
+
return getCommandLineIntent(key);
|
|
83
|
+
// Navigation keys
|
|
84
|
+
const dir = getDir(key);
|
|
85
|
+
if (dir) {
|
|
86
|
+
let dirMap = mode === Mode.MOVE
|
|
87
|
+
? {
|
|
88
|
+
prevItem: Intent.MovePreviousItem,
|
|
89
|
+
nextItem: Intent.MoveNextItem,
|
|
90
|
+
prevContainer: Intent.MoveToPreviousContainer,
|
|
91
|
+
nextContainer: Intent.MoveToNextContainer,
|
|
92
|
+
}
|
|
93
|
+
: {
|
|
94
|
+
prevItem: Intent.NavPreviousItem,
|
|
95
|
+
nextItem: Intent.NavNextItem,
|
|
96
|
+
prevContainer: Intent.NavToPreviousContainer,
|
|
97
|
+
nextContainer: Intent.NavToNextContainer,
|
|
98
|
+
};
|
|
99
|
+
return mapDirectionalIntent(appState.currentNode.childrenRenderAxis, dir, dirMap);
|
|
100
|
+
}
|
|
101
|
+
// Hard exit
|
|
102
|
+
if (key.ctrl && key.name === 'c')
|
|
103
|
+
return Intent.Exit;
|
|
104
|
+
// Default actions
|
|
105
|
+
switch (key.name) {
|
|
106
|
+
case 'i':
|
|
107
|
+
return Intent.Edit;
|
|
108
|
+
case 'y':
|
|
109
|
+
return Intent.InitMove;
|
|
60
110
|
case 'e':
|
|
61
|
-
|
|
111
|
+
case 'return':
|
|
112
|
+
return Intent.Confirm;
|
|
113
|
+
case 'q':
|
|
114
|
+
case 'escape':
|
|
115
|
+
return Intent.Exit;
|
|
62
116
|
default:
|
|
63
117
|
return null;
|
|
64
118
|
}
|