@mak-98/dirvi-app 0.0.0-stage → 0.11.0-beta.3
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/LICENSE +674 -0
- package/dist/application/create-app-api.d.ts +11 -0
- package/dist/application/create-app-api.d.ts.map +1 -0
- package/dist/application/create-app-api.js +33 -0
- package/dist/application/create-dirvi-api.d.ts +10 -0
- package/dist/application/create-dirvi-api.d.ts.map +1 -0
- package/dist/application/create-dirvi-api.js +23 -0
- package/dist/application/init-runtime.d.ts +20 -0
- package/dist/application/init-runtime.d.ts.map +1 -0
- package/dist/application/init-runtime.js +117 -0
- package/dist/application/package-loader.d.ts +9 -0
- package/dist/application/package-loader.d.ts.map +1 -0
- package/dist/application/package-loader.js +1 -0
- package/dist/application/shell-api.d.ts +5 -0
- package/dist/application/shell-api.d.ts.map +1 -0
- package/dist/application/shell-api.js +1 -0
- package/dist/domain/app-pack-ref.d.ts +17 -0
- package/dist/domain/app-pack-ref.d.ts.map +1 -0
- package/dist/domain/app-pack-ref.js +37 -0
- package/dist/domain/app.d.ts +39 -0
- package/dist/domain/app.d.ts.map +1 -0
- package/dist/domain/app.js +25 -0
- package/dist/domain/config.d.ts +402 -0
- package/dist/domain/config.d.ts.map +1 -0
- package/dist/domain/config.js +44 -0
- package/dist/domain/dirvi-api.d.ts +24 -0
- package/dist/domain/dirvi-api.d.ts.map +1 -0
- package/dist/domain/dirvi-api.js +1 -0
- package/dist/domain/ex-command.d.ts +12 -0
- package/dist/domain/ex-command.d.ts.map +1 -0
- package/dist/domain/ex-command.js +1 -0
- package/dist/domain/init-runtime.d.ts +41 -0
- package/dist/domain/init-runtime.d.ts.map +1 -0
- package/dist/domain/init-runtime.js +1 -0
- package/dist/domain/initialization.d.ts +20 -0
- package/dist/domain/initialization.d.ts.map +1 -0
- package/dist/domain/initialization.js +1 -0
- package/dist/domain/public-init-api.d.ts +42 -0
- package/dist/domain/public-init-api.d.ts.map +1 -0
- package/dist/domain/public-init-api.js +1 -0
- package/dist/domain/shell-api.d.ts +5 -0
- package/dist/domain/shell-api.d.ts.map +1 -0
- package/dist/domain/shell-api.js +1 -0
- package/dist/domain/theme.d.ts +536 -0
- package/dist/domain/theme.d.ts.map +1 -0
- package/dist/domain/theme.js +170 -0
- package/dist/domain/view-name-schema.d.ts +18 -0
- package/dist/domain/view-name-schema.d.ts.map +1 -0
- package/dist/domain/view-name-schema.js +68 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/theme.d.ts +536 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +170 -0
- package/dist/ui/App.d.ts +18 -0
- package/dist/ui/App.d.ts.map +1 -0
- package/dist/ui/App.js +225 -0
- package/dist/ui/AppSetup.d.ts +17 -0
- package/dist/ui/AppSetup.d.ts.map +1 -0
- package/dist/ui/AppSetup.js +88 -0
- package/dist/ui/Shell.d.ts +49 -0
- package/dist/ui/Shell.d.ts.map +1 -0
- package/dist/ui/Shell.js +54 -0
- package/dist/ui/app-screen-renderer.d.ts +28 -0
- package/dist/ui/app-screen-renderer.d.ts.map +1 -0
- package/dist/ui/app-screen-renderer.js +1 -0
- package/dist/ui/color-resolver.d.ts +3 -0
- package/dist/ui/color-resolver.d.ts.map +1 -0
- package/dist/ui/color-resolver.js +61 -0
- package/dist/ui/hooks/useView.d.ts +4 -0
- package/dist/ui/hooks/useView.d.ts.map +1 -0
- package/dist/ui/hooks/useView.js +32 -0
- package/dist/ui/loading-screen-renderer.d.ts +3 -0
- package/dist/ui/loading-screen-renderer.d.ts.map +1 -0
- package/dist/ui/loading-screen-renderer.js +1 -0
- package/dist/ui/view.d.ts +23 -0
- package/dist/ui/view.d.ts.map +1 -0
- package/dist/ui/view.js +74 -0
- package/package.json +34 -3
- package/README.md +0 -3
package/dist/theme.js
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
// =============================================================================
|
|
3
|
+
// Terminal colors
|
|
4
|
+
// =============================================================================
|
|
5
|
+
const HexColorSchema = z.string().regex(/^#[0-9a-fA-F]{6}$/, {
|
|
6
|
+
message: 'Expected a #rrggbb color',
|
|
7
|
+
});
|
|
8
|
+
const Ansi256ColorSchema = z.number().int().min(0).max(255);
|
|
9
|
+
/**
|
|
10
|
+
* Named ANSI foreground colors supported by Dirvi themes.
|
|
11
|
+
*
|
|
12
|
+
* Renderers translate these symbolic names into their own color APIs. The CLI
|
|
13
|
+
* renderer currently maps them to terminal colors; another renderer does not
|
|
14
|
+
* need to depend on Chalk to interpret the same theme.
|
|
15
|
+
*/
|
|
16
|
+
export const basicColorNames = [
|
|
17
|
+
'black',
|
|
18
|
+
'red',
|
|
19
|
+
'green',
|
|
20
|
+
'yellow',
|
|
21
|
+
'blue',
|
|
22
|
+
'cyan',
|
|
23
|
+
'magenta',
|
|
24
|
+
'white',
|
|
25
|
+
// Common aliases for blackBright.
|
|
26
|
+
'gray',
|
|
27
|
+
'grey',
|
|
28
|
+
'blackBright',
|
|
29
|
+
'redBright',
|
|
30
|
+
'greenBright',
|
|
31
|
+
'yellowBright',
|
|
32
|
+
'blueBright',
|
|
33
|
+
'cyanBright',
|
|
34
|
+
'magentaBright',
|
|
35
|
+
'whiteBright',
|
|
36
|
+
];
|
|
37
|
+
const BasicColorSchema = z.enum(basicColorNames);
|
|
38
|
+
export const ColorConfigSchema = z
|
|
39
|
+
.object({
|
|
40
|
+
hex: HexColorSchema.optional(),
|
|
41
|
+
ansi256: Ansi256ColorSchema.optional(),
|
|
42
|
+
basic: BasicColorSchema.optional(),
|
|
43
|
+
})
|
|
44
|
+
.refine((value) => value.hex !== undefined ||
|
|
45
|
+
value.ansi256 !== undefined ||
|
|
46
|
+
value.basic !== undefined, {
|
|
47
|
+
message: 'Expected at least one terminal color profile',
|
|
48
|
+
});
|
|
49
|
+
// =============================================================================
|
|
50
|
+
// Highlights
|
|
51
|
+
// =============================================================================
|
|
52
|
+
// Note: these schemas are meant to be non-strict
|
|
53
|
+
export const ForegroundHighlightConfigSchema = z.object({
|
|
54
|
+
fg: ColorConfigSchema,
|
|
55
|
+
});
|
|
56
|
+
export const OptionalForegroundHighlightConfigSchema = z.object({
|
|
57
|
+
fg: ColorConfigSchema.optional(),
|
|
58
|
+
});
|
|
59
|
+
export const BackgroundHighlightConfigSchema = z.object({
|
|
60
|
+
bg: ColorConfigSchema,
|
|
61
|
+
});
|
|
62
|
+
export const ForegroundBackgroundHighlightConfigSchema = z.object({
|
|
63
|
+
fg: ColorConfigSchema,
|
|
64
|
+
bg: ColorConfigSchema,
|
|
65
|
+
});
|
|
66
|
+
// =============================================================================
|
|
67
|
+
// Theme defaults
|
|
68
|
+
// =============================================================================
|
|
69
|
+
const black = {
|
|
70
|
+
hex: '#28282a',
|
|
71
|
+
ansi256: 235,
|
|
72
|
+
basic: 'black',
|
|
73
|
+
};
|
|
74
|
+
const lightGray = {
|
|
75
|
+
hex: '#eaeaec',
|
|
76
|
+
ansi256: 254,
|
|
77
|
+
basic: 'gray',
|
|
78
|
+
};
|
|
79
|
+
const leaf = {
|
|
80
|
+
hex: '#e5e5e5',
|
|
81
|
+
ansi256: 254,
|
|
82
|
+
basic: 'white',
|
|
83
|
+
};
|
|
84
|
+
const branch = {
|
|
85
|
+
hex: '#2472c8',
|
|
86
|
+
ansi256: 26,
|
|
87
|
+
basic: 'blue',
|
|
88
|
+
};
|
|
89
|
+
const folded = {
|
|
90
|
+
hex: '#808080',
|
|
91
|
+
ansi256: 245,
|
|
92
|
+
basic: 'gray',
|
|
93
|
+
};
|
|
94
|
+
const indentGuide = {
|
|
95
|
+
hex: '#808080',
|
|
96
|
+
ansi256: 245,
|
|
97
|
+
basic: 'gray',
|
|
98
|
+
};
|
|
99
|
+
const cursorLine = {
|
|
100
|
+
hex: '#3a3a3c',
|
|
101
|
+
ansi256: 237,
|
|
102
|
+
basic: 'gray',
|
|
103
|
+
};
|
|
104
|
+
const success = {
|
|
105
|
+
hex: '#238c4b',
|
|
106
|
+
ansi256: 28,
|
|
107
|
+
basic: 'green',
|
|
108
|
+
};
|
|
109
|
+
const error = {
|
|
110
|
+
hex: '#be2d2d',
|
|
111
|
+
ansi256: 160,
|
|
112
|
+
basic: 'red',
|
|
113
|
+
};
|
|
114
|
+
const themeDefaults = {
|
|
115
|
+
statusBar: {
|
|
116
|
+
command: { fg: black },
|
|
117
|
+
normal: { fg: black },
|
|
118
|
+
background: { bg: lightGray },
|
|
119
|
+
},
|
|
120
|
+
tree: {
|
|
121
|
+
leaf: { fg: leaf },
|
|
122
|
+
branch: { fg: branch },
|
|
123
|
+
folded: { fg: folded },
|
|
124
|
+
cursorLine: { bg: cursorLine },
|
|
125
|
+
indentGuide: { fg: indentGuide },
|
|
126
|
+
},
|
|
127
|
+
feedbackBar: {
|
|
128
|
+
message: {
|
|
129
|
+
fg: black,
|
|
130
|
+
bg: lightGray,
|
|
131
|
+
},
|
|
132
|
+
success: {
|
|
133
|
+
fg: success,
|
|
134
|
+
bg: lightGray,
|
|
135
|
+
},
|
|
136
|
+
error: {
|
|
137
|
+
fg: error,
|
|
138
|
+
bg: lightGray,
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
// =============================================================================
|
|
143
|
+
// Theme schema
|
|
144
|
+
// =============================================================================
|
|
145
|
+
export const ThemeSchema = z.object({
|
|
146
|
+
statusBar: z
|
|
147
|
+
.object({
|
|
148
|
+
command: ForegroundHighlightConfigSchema.default(themeDefaults.statusBar.command),
|
|
149
|
+
normal: ForegroundHighlightConfigSchema.default(themeDefaults.statusBar.normal),
|
|
150
|
+
background: BackgroundHighlightConfigSchema.default(themeDefaults.statusBar.background),
|
|
151
|
+
})
|
|
152
|
+
.default(themeDefaults.statusBar),
|
|
153
|
+
tree: z
|
|
154
|
+
.object({
|
|
155
|
+
leaf: ForegroundHighlightConfigSchema.default(themeDefaults.tree.leaf),
|
|
156
|
+
branch: ForegroundHighlightConfigSchema.default(themeDefaults.tree.branch),
|
|
157
|
+
folded: ForegroundHighlightConfigSchema.default(themeDefaults.tree.folded),
|
|
158
|
+
cursorLine: BackgroundHighlightConfigSchema.default(themeDefaults.tree.cursorLine),
|
|
159
|
+
indentGuide: OptionalForegroundHighlightConfigSchema.default(themeDefaults.tree.indentGuide),
|
|
160
|
+
})
|
|
161
|
+
.default(themeDefaults.tree),
|
|
162
|
+
feedbackBar: z
|
|
163
|
+
.object({
|
|
164
|
+
message: ForegroundBackgroundHighlightConfigSchema.default(themeDefaults.feedbackBar.message),
|
|
165
|
+
success: ForegroundBackgroundHighlightConfigSchema.default(themeDefaults.feedbackBar.success),
|
|
166
|
+
error: ForegroundBackgroundHighlightConfigSchema.default(themeDefaults.feedbackBar.error),
|
|
167
|
+
})
|
|
168
|
+
.default(themeDefaults.feedbackBar),
|
|
169
|
+
});
|
|
170
|
+
export const defaultTheme = ThemeSchema.parse({});
|
package/dist/ui/App.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { AppApi, EffectToAction, IntentToEffect, Reducer, SerializableKey, State } from 'dirvi-lib';
|
|
2
|
+
import type { Config } from '../domain/config.js';
|
|
3
|
+
import type { AppScreenRenderer } from './app-screen-renderer.js';
|
|
4
|
+
type AppProps<Id extends SerializableKey, Value, ViewKey = string> = {
|
|
5
|
+
screenRenderer: AppScreenRenderer;
|
|
6
|
+
appApi: AppApi<Id, Value, ViewKey>;
|
|
7
|
+
config: Config;
|
|
8
|
+
initialState: State<Id, Value>;
|
|
9
|
+
reducer: Reducer<Id, Value>;
|
|
10
|
+
intentToEffect: IntentToEffect<Id, Value>;
|
|
11
|
+
effectToAction: EffectToAction<Id, Value>;
|
|
12
|
+
stdout?: (message: string) => void;
|
|
13
|
+
clipboard?: (value: string) => void;
|
|
14
|
+
onError?: (error: Error) => void;
|
|
15
|
+
};
|
|
16
|
+
export declare function App<Id extends SerializableKey, Value, ViewKey = string>({ screenRenderer, appApi, config, initialState, reducer, intentToEffect, effectToAction, stdout, clipboard, onError, }: AppProps<Id, Value, ViewKey>): import("react").JSX.Element;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=App.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/ui/App.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,MAAM,EAEN,cAAc,EAEd,cAAc,EAEd,OAAO,EACP,eAAe,EACf,KAAK,EAGN,MAAM,WAAW,CAAC;AAEnB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAElD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAMlE,KAAK,QAAQ,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,IAAI;IACnE,cAAc,EAAE,iBAAiB,CAAC;IAClC,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAC/B,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAC5B,cAAc,EAAE,cAAc,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAC1C,cAAc,EAAE,cAAc,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAC1C,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC,CAAC;AAEF,wBAAgB,GAAG,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,EACvE,cAAc,EACd,MAAM,EACN,MAAM,EACN,YAAY,EACZ,OAAO,EACP,cAAc,EACd,cAAc,EACd,MAAM,EACN,SAAS,EACT,OAAO,GACR,EAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,+BAkT9B"}
|
package/dist/ui/App.js
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useEffect, useMemo, useReducer, useRef, useState, } from 'react';
|
|
3
|
+
import { createFeedbackApi, userInputToIntent } from 'dirvi-lib';
|
|
4
|
+
import { useView } from './hooks/useView.js';
|
|
5
|
+
function toError(error) {
|
|
6
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
7
|
+
}
|
|
8
|
+
export function App({ screenRenderer, appApi, config, initialState, reducer, intentToEffect, effectToAction, stdout, clipboard, onError, }) {
|
|
9
|
+
const ScreenRenderer = screenRenderer;
|
|
10
|
+
const [state, dispatch] = useReducer(reducer, initialState);
|
|
11
|
+
const stateRef = useRef(state); // Gives `subscribeToResync` callback a way to
|
|
12
|
+
// see current state
|
|
13
|
+
stateRef.current = state;
|
|
14
|
+
const navEntry = useMemo(() => {
|
|
15
|
+
const navigation = appApi.navNodeApi.from(state.root, state.folds);
|
|
16
|
+
if (navigation === undefined) {
|
|
17
|
+
throw new Error('Tree-surfer state root must be a loaded branch.');
|
|
18
|
+
}
|
|
19
|
+
return navigation;
|
|
20
|
+
}, [appApi.navNodeApi, state.root, state.folds]);
|
|
21
|
+
const [inputState, setInputState] = useState({
|
|
22
|
+
inputMode: 'normal',
|
|
23
|
+
normalBuffer: '',
|
|
24
|
+
});
|
|
25
|
+
const [feedback, setFeedback] = useState();
|
|
26
|
+
const [exitStatus, setExitStatus] = useState();
|
|
27
|
+
const [rowCount, setRowCount] = useState(0);
|
|
28
|
+
const handleRowsChange = useCallback((nextRows) => {
|
|
29
|
+
setRowCount((currentRows) => currentRows === nextRows ? currentRows : nextRows);
|
|
30
|
+
}, []);
|
|
31
|
+
// ===========================================================================
|
|
32
|
+
// Display hooks
|
|
33
|
+
// ===========================================================================
|
|
34
|
+
const feedbackApi = useMemo(() => createFeedbackApi((nextFeedback) => {
|
|
35
|
+
setFeedback(nextFeedback);
|
|
36
|
+
}), []);
|
|
37
|
+
const view = useView(navEntry, state, appApi.navNodeApi, appApi.cursorApi, rowCount);
|
|
38
|
+
// ===========================================================================
|
|
39
|
+
// Resync Subscriptions
|
|
40
|
+
// ===========================================================================
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
let active = true;
|
|
43
|
+
const unsubscribe = appApi.subscribeToResync(() => {
|
|
44
|
+
const oldState = stateRef.current;
|
|
45
|
+
void appApi.stateApi
|
|
46
|
+
.resync(oldState, appApi.loadBranches)
|
|
47
|
+
.then((newState) => {
|
|
48
|
+
if (!active) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
dispatch({
|
|
52
|
+
kind: 'setState',
|
|
53
|
+
oldState: oldState,
|
|
54
|
+
newState: newState,
|
|
55
|
+
});
|
|
56
|
+
})
|
|
57
|
+
.catch((error) => {
|
|
58
|
+
const appError = error instanceof Error ? error : new Error(String(error));
|
|
59
|
+
onError?.(appError);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
return () => {
|
|
63
|
+
active = false;
|
|
64
|
+
unsubscribe();
|
|
65
|
+
};
|
|
66
|
+
}, [appApi, onError]);
|
|
67
|
+
// ===========================================================================
|
|
68
|
+
// Executing Effects
|
|
69
|
+
// ===========================================================================
|
|
70
|
+
const executeEffect = useCallback((effect) => {
|
|
71
|
+
if (effect === undefined) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
switch (effect.effectType) {
|
|
75
|
+
case 'dispatchEffectAction':
|
|
76
|
+
const effectActionResult = effectToAction(effect.action, navEntry, state);
|
|
77
|
+
// A completed normal-mode command or submitted Ex command always
|
|
78
|
+
// leaves its input buffer, whether it succeeds, is rejected, or no-ops.
|
|
79
|
+
setInputState({
|
|
80
|
+
inputMode: 'normal',
|
|
81
|
+
normalBuffer: '',
|
|
82
|
+
});
|
|
83
|
+
switch (effectActionResult.kind) {
|
|
84
|
+
case 'action':
|
|
85
|
+
dispatch(effectActionResult.action);
|
|
86
|
+
return;
|
|
87
|
+
case 'rejected':
|
|
88
|
+
feedbackApi.addMessage(effectActionResult.message, 'error');
|
|
89
|
+
return;
|
|
90
|
+
case 'ignored':
|
|
91
|
+
return;
|
|
92
|
+
default:
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
case 'setInputState':
|
|
96
|
+
setInputState(effect.inputState);
|
|
97
|
+
return;
|
|
98
|
+
case 'loadBranchEntries': {
|
|
99
|
+
void appApi
|
|
100
|
+
.loadBranches(effect.path)
|
|
101
|
+
.then((entries) => {
|
|
102
|
+
dispatch({
|
|
103
|
+
kind: 'updateBranch',
|
|
104
|
+
path: effect.path,
|
|
105
|
+
entries,
|
|
106
|
+
});
|
|
107
|
+
})
|
|
108
|
+
.catch((error) => {
|
|
109
|
+
const appError = error instanceof Error ? error : new Error(String(error));
|
|
110
|
+
feedbackApi.addMessage(`Unable to open directory: ${appError.message}`);
|
|
111
|
+
});
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
case 'emitVisibleLeavesPaths':
|
|
115
|
+
const navigation = navEntry.children;
|
|
116
|
+
if (navigation === null) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const visibleLeavesPaths = appApi.navNodeApi.visibleLeavesPaths(navigation);
|
|
120
|
+
stdout?.(JSON.stringify({
|
|
121
|
+
type: 'displayed-leaves-paths',
|
|
122
|
+
paths: visibleLeavesPaths,
|
|
123
|
+
}));
|
|
124
|
+
setInputState({
|
|
125
|
+
inputMode: 'normal',
|
|
126
|
+
normalBuffer: '',
|
|
127
|
+
});
|
|
128
|
+
return;
|
|
129
|
+
case 'saveView': {
|
|
130
|
+
// void appApi.viewApi
|
|
131
|
+
// .save(appApi.viewKey, effect.name, stateRef.current)
|
|
132
|
+
// .then(() => {
|
|
133
|
+
// setInputState({
|
|
134
|
+
// inputMode: 'normal',
|
|
135
|
+
// normalBuffer: '',
|
|
136
|
+
// });
|
|
137
|
+
// feedbackApi.addMessage(`Saved view: ${effect.name}`);
|
|
138
|
+
// })
|
|
139
|
+
// .catch((error: unknown) => {
|
|
140
|
+
// feedbackApi.addMessage(
|
|
141
|
+
// `Unable to save view: ${toError(error).message}`,
|
|
142
|
+
// );
|
|
143
|
+
// });
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
case 'loadView': {
|
|
147
|
+
// void appApi.viewApi
|
|
148
|
+
// .load(appApi.viewKey, effect.name)
|
|
149
|
+
// .then((loadedState) => {
|
|
150
|
+
// if (loadedState === undefined) {
|
|
151
|
+
// throw new Error(`View not found: ${effect.name}`);
|
|
152
|
+
// }
|
|
153
|
+
//
|
|
154
|
+
// // The saved buffer may be stale because the filesystem could have
|
|
155
|
+
// // changed since the view was saved.
|
|
156
|
+
// return appApi.stateApi.resync(loadedState, appApi.loadBranches);
|
|
157
|
+
// })
|
|
158
|
+
// .then((newState) => {
|
|
159
|
+
// const oldState = stateRef.current;
|
|
160
|
+
//
|
|
161
|
+
// dispatch({
|
|
162
|
+
// kind: 'setState',
|
|
163
|
+
// oldState,
|
|
164
|
+
// newState,
|
|
165
|
+
// });
|
|
166
|
+
//
|
|
167
|
+
// setInputState({
|
|
168
|
+
// inputMode: 'normal',
|
|
169
|
+
// normalBuffer: '',
|
|
170
|
+
// });
|
|
171
|
+
// })
|
|
172
|
+
// .catch((error: unknown) => {
|
|
173
|
+
// onError?.(toError(error));
|
|
174
|
+
// });
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
// TODO: Add descriptions with `...` truncation.
|
|
178
|
+
case 'listFolds': {
|
|
179
|
+
const folds = state.folds;
|
|
180
|
+
const foldTrees = [...appApi.foldsApi.indexes(folds)].map((index) => ({
|
|
181
|
+
index,
|
|
182
|
+
info: appApi.foldsApi.getInfoAtIndex(folds, index),
|
|
183
|
+
active: appApi.foldsApi.isActiveAtIndex(folds, index),
|
|
184
|
+
}));
|
|
185
|
+
const indexWidth = Math.max(...foldTrees.map(({ index }) => String(index).length));
|
|
186
|
+
const lines = foldTrees.map(({ index, info, active }) => {
|
|
187
|
+
const status = active === true ? 'active' : 'inactive';
|
|
188
|
+
const name = info?.name ?? '<unavailable>';
|
|
189
|
+
return `${String(index).padStart(indexWidth)} ${status.padEnd(8)} ${name}`;
|
|
190
|
+
});
|
|
191
|
+
setInputState({
|
|
192
|
+
inputMode: 'normal',
|
|
193
|
+
normalBuffer: '',
|
|
194
|
+
});
|
|
195
|
+
feedbackApi.addMessage(['Fold trees:', ...lines].join('\n'));
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
case 'unrecognizedCommand':
|
|
199
|
+
feedbackApi.addMessage(`Unrecognized command: ${effect.commandLine}`, 'error');
|
|
200
|
+
return;
|
|
201
|
+
case 'quit':
|
|
202
|
+
setExitStatus(effect.exitMessage);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
}, [appApi, effectToAction, feedbackApi, navEntry, onError, state, stdout]);
|
|
206
|
+
// ===========================================================================
|
|
207
|
+
// Input hook
|
|
208
|
+
// ===========================================================================
|
|
209
|
+
const handleInput = useCallback((userInput) => {
|
|
210
|
+
const intent = userInputToIntent(userInput, inputState);
|
|
211
|
+
if (intent === undefined) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const effectResult = intentToEffect(intent, state);
|
|
215
|
+
if (effectResult === undefined) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
setFeedback(undefined);
|
|
219
|
+
executeEffect(effectResult);
|
|
220
|
+
}, [executeEffect, inputState, intentToEffect, state]);
|
|
221
|
+
// ===========================================================================
|
|
222
|
+
// Render
|
|
223
|
+
// ===========================================================================
|
|
224
|
+
return (_jsx(ScreenRenderer, { view: view, feedback: feedback, feedbackApi: feedbackApi, config: config, inputState: inputState, handleInput: handleInput, onRowsChange: handleRowsChange, exitStatus: exitStatus }));
|
|
225
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AppApi, SerializableKey } from 'dirvi-lib';
|
|
2
|
+
import type { LoadingScreenRenderer } from './loading-screen-renderer.js';
|
|
3
|
+
import type { AppScreenRenderer } from './app-screen-renderer.js';
|
|
4
|
+
import { ShellApi } from '../domain/shell-api.js';
|
|
5
|
+
import { Initialization } from '../domain/initialization.js';
|
|
6
|
+
type LoadingAppProps<Id extends SerializableKey, Value, ViewKey = string> = {
|
|
7
|
+
appScreenRenderer: AppScreenRenderer;
|
|
8
|
+
loadingScreenRenderer: LoadingScreenRenderer;
|
|
9
|
+
initialization: Initialization;
|
|
10
|
+
shellApi: ShellApi;
|
|
11
|
+
appApi: AppApi<Id, Value, ViewKey>;
|
|
12
|
+
stdout?: (message: string) => void;
|
|
13
|
+
clipboard?: (value: string) => void;
|
|
14
|
+
};
|
|
15
|
+
export declare function AppSetup<Id extends SerializableKey, Value, ViewKey = string>({ appScreenRenderer, loadingScreenRenderer, appApi, initialization, stdout, clipboard, }: LoadingAppProps<Id, Value, ViewKey>): import("react").JSX.Element;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=AppSetup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AppSetup.d.ts","sourceRoot":"","sources":["../../src/ui/AppSetup.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,eAAe,EAAS,MAAM,WAAW,CAAC;AAOhE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAGlE,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAE7D,KAAK,eAAe,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,IAAI;IAC1E,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,qBAAqB,EAAE,qBAAqB,CAAC;IAC7C,cAAc,EAAE,cAAc,CAAC;IAC/B,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IACnC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC,CAAC;AAEF,wBAAgB,QAAQ,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,EAC5E,iBAAiB,EACjB,qBAAqB,EACrB,MAAM,EACN,cAAc,EACd,MAAM,EACN,SAAS,GACV,EAAE,eAAe,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,+BAgIrC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
3
|
+
import { createEffectToAction, createIntentToEffect, createReducer, } from 'dirvi-lib';
|
|
4
|
+
import { App } from './App.js';
|
|
5
|
+
export function AppSetup({ appScreenRenderer, loadingScreenRenderer, appApi, initialization, stdout, clipboard, }) {
|
|
6
|
+
const [initialState, setInitialState] = useState();
|
|
7
|
+
const [config, setConfig] = useState(initialization.config);
|
|
8
|
+
// Load the initial configuration and keep it synchronized with changes made
|
|
9
|
+
// by another process or another running dirvi instance.
|
|
10
|
+
// useEffect(() => {
|
|
11
|
+
// let mounted = true;
|
|
12
|
+
// let latestLoad = 0;
|
|
13
|
+
//
|
|
14
|
+
// const loadConfig = (): void => {
|
|
15
|
+
// const loadNumber = ++latestLoad;
|
|
16
|
+
//
|
|
17
|
+
// void configApi
|
|
18
|
+
// .load()
|
|
19
|
+
// .then((nextConfig) => {
|
|
20
|
+
// // Ignore a stale read if a newer config read has begun meanwhile.
|
|
21
|
+
// if (!mounted || loadNumber !== latestLoad) {
|
|
22
|
+
// return;
|
|
23
|
+
// }
|
|
24
|
+
//
|
|
25
|
+
// setConfig(nextConfig);
|
|
26
|
+
// })
|
|
27
|
+
// .catch((cause: unknown) => {
|
|
28
|
+
// if (!mounted || loadNumber !== latestLoad) {
|
|
29
|
+
// return;
|
|
30
|
+
// }
|
|
31
|
+
//
|
|
32
|
+
// const nextError =
|
|
33
|
+
// cause instanceof Error ? cause : new Error(String(cause));
|
|
34
|
+
//
|
|
35
|
+
// setError(nextError);
|
|
36
|
+
// onError?.(nextError);
|
|
37
|
+
// });
|
|
38
|
+
// };
|
|
39
|
+
//
|
|
40
|
+
// // Subscribe before the first load so a change during startup is not missed.
|
|
41
|
+
// const unsubscribe = configApi.subscribeToResync(loadConfig);
|
|
42
|
+
// loadConfig();
|
|
43
|
+
//
|
|
44
|
+
// return () => {
|
|
45
|
+
// mounted = false;
|
|
46
|
+
// unsubscribe();
|
|
47
|
+
// };
|
|
48
|
+
// }, [configApi, onError]);
|
|
49
|
+
// Loading and setting initial state.
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
let mounted = true;
|
|
52
|
+
appApi
|
|
53
|
+
.createRoot()
|
|
54
|
+
.then((root) => {
|
|
55
|
+
if (!mounted) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
setInitialState({
|
|
59
|
+
root,
|
|
60
|
+
folds: appApi.foldsApi.create(appApi.rootId, {
|
|
61
|
+
name: 'default',
|
|
62
|
+
description: null,
|
|
63
|
+
}),
|
|
64
|
+
cursor: [],
|
|
65
|
+
});
|
|
66
|
+
})
|
|
67
|
+
.catch((cause) => {
|
|
68
|
+
const nextError = cause instanceof Error ? cause : new Error(String(cause));
|
|
69
|
+
if (!mounted) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
throw nextError;
|
|
73
|
+
});
|
|
74
|
+
return () => {
|
|
75
|
+
mounted = false;
|
|
76
|
+
};
|
|
77
|
+
}, [appApi]);
|
|
78
|
+
// --- Pure function deps ---
|
|
79
|
+
const reducer = useMemo(() => createReducer(appApi.treeNodeApi, appApi.foldsApi), [appApi.treeNodeApi, appApi.foldsApi]);
|
|
80
|
+
const intentToEffect = useMemo(() => createIntentToEffect(appApi.stateApi, appApi.cursorApi, appApi.treeNodeApi), [appApi.stateApi, appApi.cursorApi, appApi.treeNodeApi]);
|
|
81
|
+
const effectToAction = useMemo(() => createEffectToAction(appApi.foldsApi, appApi.cursorApi, appApi.navNodeApi), [appApi.navNodeApi, appApi.cursorApi, appApi.foldsApi]);
|
|
82
|
+
// --- JSX ---
|
|
83
|
+
const LoadingScreenRenderer = loadingScreenRenderer;
|
|
84
|
+
if (initialState === undefined) {
|
|
85
|
+
return _jsx(LoadingScreenRenderer, {});
|
|
86
|
+
}
|
|
87
|
+
return (_jsx(App, { screenRenderer: appScreenRenderer, appApi: appApi, config: config, initialState: initialState, reducer: reducer, intentToEffect: intentToEffect, effectToAction: effectToAction, ...(stdout === undefined ? {} : { stdout }), ...(clipboard === undefined ? {} : { clipboard }) }));
|
|
88
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { AppScreenRenderer } from './app-screen-renderer.js';
|
|
2
|
+
import type { LoadingScreenRenderer } from './loading-screen-renderer.js';
|
|
3
|
+
import type { Initialization } from '../domain/initialization.js';
|
|
4
|
+
import type { PackageLoader } from '../application/package-loader.js';
|
|
5
|
+
export type InitialAppOptions = Readonly<{
|
|
6
|
+
/**
|
|
7
|
+
* Requested app ID at startup.
|
|
8
|
+
*
|
|
9
|
+
* The Shell will later use this to override or select the app chosen by
|
|
10
|
+
* initialization.
|
|
11
|
+
*/
|
|
12
|
+
readonly app?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Host-provided startup input interpreted by the selected app.
|
|
15
|
+
*/
|
|
16
|
+
readonly input?: string;
|
|
17
|
+
}>;
|
|
18
|
+
/**
|
|
19
|
+
* Dependencies and output callbacks required by {@link Shell}.
|
|
20
|
+
*
|
|
21
|
+
* The API loader functions are injected so the shell does not depend directly
|
|
22
|
+
* on a platform-specific infrastructure implementation.
|
|
23
|
+
*/
|
|
24
|
+
export type ShellAppProps = {
|
|
25
|
+
/**
|
|
26
|
+
* Host-specific React implementation.
|
|
27
|
+
*/
|
|
28
|
+
readonly loadingScreenRenderer: LoadingScreenRenderer;
|
|
29
|
+
readonly appScreenRenderer: AppScreenRenderer;
|
|
30
|
+
readonly initialAppOptions: InitialAppOptions;
|
|
31
|
+
readonly initialization: Initialization;
|
|
32
|
+
readonly packageLoader: PackageLoader;
|
|
33
|
+
/** Writes non-interactive application output. */
|
|
34
|
+
readonly stdout?: (message: string) => void;
|
|
35
|
+
/** Copies a value to the platform clipboard. */
|
|
36
|
+
readonly clipboard?: (value: string) => void;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Hosts the currently active application inside the persistent terminal shell.
|
|
40
|
+
*
|
|
41
|
+
* Shell deliberately does not depend on a concrete AppApi type. OpenApp keeps
|
|
42
|
+
* each application's Id, Value, and ViewKey types coherent while hiding those
|
|
43
|
+
* details from shell-level concerns such as startup, app selection, terminal
|
|
44
|
+
* integration, clipboard access, and error reporting.
|
|
45
|
+
*
|
|
46
|
+
* AppSetup receives the concrete AppApi and mounts the app-specific tree UI.
|
|
47
|
+
*/
|
|
48
|
+
export declare function Shell({ loadingScreenRenderer, appScreenRenderer, initialAppOptions, initialization, packageLoader, stdout, clipboard, }: ShellAppProps): import("react").JSX.Element;
|
|
49
|
+
//# sourceMappingURL=Shell.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Shell.d.ts","sourceRoot":"","sources":["../../src/ui/Shell.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAE1E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAItE,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IACvC;;;;;OAKG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B;;OAEG;IACH,QAAQ,CAAC,qBAAqB,EAAE,qBAAqB,CAAC;IACtD,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAC;IAE9C,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAC;IAC9C,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IAEtC,iDAAiD;IACjD,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAE5C,gDAAgD;IAChD,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9C,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,KAAK,CAAC,EACpB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,MAAM,EACN,SAAS,GACV,EAAE,aAAa,+BAsEf"}
|
package/dist/ui/Shell.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
3
|
+
import { AppSetup } from './AppSetup.js';
|
|
4
|
+
import { createAppApiApplicator } from '../application/create-app-api.js';
|
|
5
|
+
/**
|
|
6
|
+
* Hosts the currently active application inside the persistent terminal shell.
|
|
7
|
+
*
|
|
8
|
+
* Shell deliberately does not depend on a concrete AppApi type. OpenApp keeps
|
|
9
|
+
* each application's Id, Value, and ViewKey types coherent while hiding those
|
|
10
|
+
* details from shell-level concerns such as startup, app selection, terminal
|
|
11
|
+
* integration, clipboard access, and error reporting.
|
|
12
|
+
*
|
|
13
|
+
* AppSetup receives the concrete AppApi and mounts the app-specific tree UI.
|
|
14
|
+
*/
|
|
15
|
+
export function Shell({ loadingScreenRenderer, appScreenRenderer, initialAppOptions, initialization, packageLoader, stdout, clipboard, }) {
|
|
16
|
+
const initialAppReference = initialization.registeredApps.get(initialization.initialAppId);
|
|
17
|
+
if (initialAppReference === undefined) {
|
|
18
|
+
throw new Error(`Startup app "${initialization.initialAppId}" has not been registered.`);
|
|
19
|
+
}
|
|
20
|
+
const [appApiApplicator, setAppApiApplicator] = useState(undefined);
|
|
21
|
+
const [appError, setAppError] = useState(undefined);
|
|
22
|
+
const shellApi = useMemo(() => {
|
|
23
|
+
return {
|
|
24
|
+
openApp: async (appId, input) => {
|
|
25
|
+
const appReference = initialization.registeredApps.get(appId);
|
|
26
|
+
if (appReference === undefined) {
|
|
27
|
+
throw new Error(`App "${appId}" has not been registered.`);
|
|
28
|
+
}
|
|
29
|
+
setAppApiApplicator(undefined);
|
|
30
|
+
setAppError(undefined);
|
|
31
|
+
const appPlugin = await packageLoader.loadAppPlugin(appReference);
|
|
32
|
+
const appDefinitionApplicator = appPlugin.createAppDefinitionApplicator(input);
|
|
33
|
+
const loadedAppApiApplicator = createAppApiApplicator(appDefinitionApplicator);
|
|
34
|
+
setAppApiApplicator(() => loadedAppApiApplicator);
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}, [initialization.registeredApps, packageLoader]);
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
void shellApi
|
|
40
|
+
.openApp(initialization.initialAppId, initialAppOptions.input)
|
|
41
|
+
.catch((error) => {
|
|
42
|
+
setAppError(error instanceof Error ? error : new Error(String(error)));
|
|
43
|
+
});
|
|
44
|
+
}, [initialAppOptions.input, initialization.initialAppId, shellApi]);
|
|
45
|
+
if (appError !== undefined) {
|
|
46
|
+
throw appError;
|
|
47
|
+
}
|
|
48
|
+
if (appApiApplicator === undefined) {
|
|
49
|
+
const LoadingScreenRenderer = loadingScreenRenderer;
|
|
50
|
+
return _jsx(LoadingScreenRenderer, {});
|
|
51
|
+
}
|
|
52
|
+
// Result type is specified here to be AppSetup
|
|
53
|
+
return appApiApplicator((appApi) => (_jsx(AppSetup, { appScreenRenderer: appScreenRenderer, loadingScreenRenderer: loadingScreenRenderer, initialization: initialization, shellApi: shellApi, appApi: appApi, ...(stdout === undefined ? {} : { stdout }), ...(clipboard === undefined ? {} : { clipboard }) })));
|
|
54
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ComponentType } from 'react';
|
|
2
|
+
import type { Feedback, FeedbackApi, InputModeState, UserInput } from 'dirvi-lib';
|
|
3
|
+
import type { Config } from '../domain/config.js';
|
|
4
|
+
import { View } from './view.js';
|
|
5
|
+
/**
|
|
6
|
+
* State and callbacks required by a React host screen.
|
|
7
|
+
*
|
|
8
|
+
* The screen owns host-specific concerns such as input subscription, viewport
|
|
9
|
+
* measurement, and host exit. App owns Dirvi state transitions and effects.
|
|
10
|
+
*/
|
|
11
|
+
export type AppScreenProps = {
|
|
12
|
+
readonly view: View;
|
|
13
|
+
readonly feedback: Feedback | undefined;
|
|
14
|
+
readonly feedbackApi: FeedbackApi;
|
|
15
|
+
readonly config: Config;
|
|
16
|
+
readonly inputState: InputModeState;
|
|
17
|
+
readonly handleInput: (userInput: UserInput) => void;
|
|
18
|
+
readonly onRowsChange: (rows: number) => void;
|
|
19
|
+
readonly exitStatus: string | undefined;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* A host-specific React implementation of the Dirvi application screen.
|
|
23
|
+
*
|
|
24
|
+
* InkScreen is the terminal implementation. A future web or React Native host
|
|
25
|
+
* can provide a different component that conforms to this same contract.
|
|
26
|
+
*/
|
|
27
|
+
export type AppScreenRenderer = ComponentType<AppScreenProps>;
|
|
28
|
+
//# sourceMappingURL=app-screen-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-screen-renderer.d.ts","sourceRoot":"","sources":["../../src/ui/app-screen-renderer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C,OAAO,KAAK,EACV,QAAQ,EACR,WAAW,EACX,cAAc,EACd,SAAS,EACV,MAAM,WAAW,CAAC;AAEnB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,cAAc,CAAC;IAEpC,QAAQ,CAAC,WAAW,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,IAAI,CAAC;IACrD,QAAQ,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAE9C,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;CACzC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,aAAa,CAAC,cAAc,CAAC,CAAC"}
|