@mak-98/dirvi-app 0.0.0-stage → 0.11.0-beta.13
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/app-api-applicator.d.ts +12 -0
- package/dist/application/app-api-applicator.d.ts.map +1 -0
- package/dist/application/app-api-applicator.js +1 -0
- package/dist/application/app-pack-ref.d.ts +12 -0
- package/dist/application/app-pack-ref.d.ts.map +1 -0
- package/dist/application/app-pack-ref.js +37 -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 +60 -0
- package/dist/application/create-app-methods.d.ts +11 -0
- package/dist/application/create-app-methods.d.ts.map +1 -0
- package/dist/application/create-app-methods.js +60 -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 +40 -0
- package/dist/application/init-runtime.d.ts.map +1 -0
- package/dist/application/init-runtime.error.d.ts +53 -0
- package/dist/application/init-runtime.error.d.ts.map +1 -0
- package/dist/application/init-runtime.error.js +77 -0
- package/dist/application/init-runtime.js +165 -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-input.d.ts +2 -0
- package/dist/domain/app-input.d.ts.map +1 -0
- package/dist/domain/app-input.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 +386 -0
- package/dist/domain/config.d.ts.map +1 -0
- package/dist/domain/config.js +44 -0
- package/dist/domain/dirvi-api/app-api.d.ts +7 -0
- package/dist/domain/dirvi-api/app-api.d.ts.map +1 -0
- package/dist/domain/dirvi-api/app-api.js +1 -0
- package/dist/domain/dirvi-api/dirvi-api.d.ts +17 -0
- package/dist/domain/dirvi-api/dirvi-api.d.ts.map +1 -0
- package/dist/domain/dirvi-api/dirvi-api.js +1 -0
- package/dist/domain/dirvi-api/shell-api.d.ts +35 -0
- package/dist/domain/dirvi-api/shell-api.d.ts.map +1 -0
- package/dist/domain/dirvi-api/shell-api.js +1 -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 +9 -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 +26 -0
- package/dist/domain/initialization.d.ts.map +1 -0
- package/dist/domain/initialization.js +1 -0
- package/dist/domain/node-presentation.d.ts +12 -0
- package/dist/domain/node-presentation.d.ts.map +1 -0
- package/dist/domain/node-presentation.js +1 -0
- package/dist/domain/public-init-api.d.ts +48 -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 +9 -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 +524 -0
- package/dist/domain/theme.d.ts.map +1 -0
- package/dist/domain/theme.js +164 -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 +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -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 +21 -0
- package/dist/ui/App.d.ts.map +1 -0
- package/dist/ui/App.js +248 -0
- package/dist/ui/AppSetup.d.ts +18 -0
- package/dist/ui/AppSetup.d.ts.map +1 -0
- package/dist/ui/AppSetup.js +60 -0
- package/dist/ui/Shell.d.ts +44 -0
- package/dist/ui/Shell.d.ts.map +1 -0
- package/dist/ui/Shell.js +73 -0
- package/dist/ui/app-screen-renderer.d.ts +27 -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 +5 -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 +28 -0
- package/dist/ui/view.d.ts.map +1 -0
- package/dist/ui/view.js +131 -0
- package/package.json +34 -3
- package/README.md +0 -3
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ComponentType } from 'react';
|
|
2
|
+
import type { Config } from 'dirvi-apis';
|
|
3
|
+
import type { Feedback, FeedbackApi, InputModeState, UserInput } from 'dirvi-lib';
|
|
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
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* A host-specific React implementation of the Dirvi application screen.
|
|
22
|
+
*
|
|
23
|
+
* InkScreen is the terminal implementation. A future web or React Native host
|
|
24
|
+
* can provide a different component that conforms to this same contract.
|
|
25
|
+
*/
|
|
26
|
+
export type AppScreenRenderer = ComponentType<AppScreenProps>;
|
|
27
|
+
//# 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,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,KAAK,EACV,QAAQ,EACR,WAAW,EACX,cAAc,EACd,SAAS,EACV,MAAM,WAAW,CAAC;AAEnB,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;CAC/C,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,aAAa,CAAC,cAAc,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"color-resolver.d.ts","sourceRoot":"","sources":["../../src/ui/color-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAuB9C,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,WAAW,EACxB,UAAU,GAAE,MAAuC,GAClD,MAAM,CA2BR"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const ansi16Colors = [
|
|
2
|
+
[0, 0, 0],
|
|
3
|
+
[205, 49, 49],
|
|
4
|
+
[13, 188, 121],
|
|
5
|
+
[229, 229, 16],
|
|
6
|
+
[36, 114, 200],
|
|
7
|
+
[188, 63, 188],
|
|
8
|
+
[17, 168, 205],
|
|
9
|
+
[229, 229, 229],
|
|
10
|
+
[102, 102, 102],
|
|
11
|
+
[241, 76, 76],
|
|
12
|
+
[35, 209, 139],
|
|
13
|
+
[245, 245, 67],
|
|
14
|
+
[59, 142, 234],
|
|
15
|
+
[214, 112, 214],
|
|
16
|
+
[41, 184, 219],
|
|
17
|
+
[255, 255, 255],
|
|
18
|
+
];
|
|
19
|
+
export function colorConfigToInkColor(colorConfig, colorDepth = process.stderr.getColorDepth()) {
|
|
20
|
+
const { hex, ansi256, basic } = colorConfig;
|
|
21
|
+
if (colorDepth >= 24 && hex !== undefined) {
|
|
22
|
+
return hex;
|
|
23
|
+
}
|
|
24
|
+
if (colorDepth >= 8 && ansi256 !== undefined) {
|
|
25
|
+
return toHex(ansi256ToRgb(ansi256));
|
|
26
|
+
}
|
|
27
|
+
if (basic !== undefined) {
|
|
28
|
+
return basic;
|
|
29
|
+
}
|
|
30
|
+
// A more specific value was not configured. Let Ink/Chalk reduce the
|
|
31
|
+
// available richer value for the current terminal where necessary.
|
|
32
|
+
if (ansi256 !== undefined) {
|
|
33
|
+
return toHex(ansi256ToRgb(ansi256));
|
|
34
|
+
}
|
|
35
|
+
if (hex !== undefined) {
|
|
36
|
+
return hex;
|
|
37
|
+
}
|
|
38
|
+
// ColorConfigSchema guarantees at least one profile is configured.
|
|
39
|
+
throw new Error('Expected at least one terminal color profile');
|
|
40
|
+
}
|
|
41
|
+
function ansi256ToRgb(color) {
|
|
42
|
+
if (color < 16) {
|
|
43
|
+
return ansi16Colors[color];
|
|
44
|
+
}
|
|
45
|
+
if (color >= 232) {
|
|
46
|
+
const component = 8 + (color - 232) * 10;
|
|
47
|
+
return [component, component, component];
|
|
48
|
+
}
|
|
49
|
+
const cubeColor = color - 16;
|
|
50
|
+
const red = Math.floor(cubeColor / 36);
|
|
51
|
+
const green = Math.floor((cubeColor % 36) / 6);
|
|
52
|
+
const blue = cubeColor % 6;
|
|
53
|
+
const components = [0, 95, 135, 175, 215, 255];
|
|
54
|
+
return [components[red], components[green], components[blue]];
|
|
55
|
+
}
|
|
56
|
+
function toHex([red, green, blue]) {
|
|
57
|
+
return `#${toHexComponent(red)}${toHexComponent(green)}${toHexComponent(blue)}`;
|
|
58
|
+
}
|
|
59
|
+
function toHexComponent(component) {
|
|
60
|
+
return component.toString(16).padStart(2, '0');
|
|
61
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { CursorMethods, NavBranch, NavMethods, SerializableKey, State, StateMethods } from 'dirvi-lib';
|
|
2
|
+
import type { PresentNode } from 'dirvi-apis';
|
|
3
|
+
import { View } from '../view.js';
|
|
4
|
+
export declare function useView<Id extends SerializableKey, Value>(navNode: NavBranch<Id>, state: State<Id, Value>, stateApi: StateMethods<Id, Value>, navNodeApi: NavMethods<Id, Value>, cursorMethods: CursorMethods<Id>, rowCount: number, presentNode: PresentNode<Id>): View;
|
|
5
|
+
//# sourceMappingURL=useView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useView.d.ts","sourceRoot":"","sources":["../../../src/ui/hooks/useView.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,aAAa,EACb,SAAS,EACT,UAAU,EACV,eAAe,EACf,KAAK,EAAE,YAAY,EACpB,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAgB,MAAM,YAAY,CAAC;AAMhD,wBAAgB,OAAO,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,EACvD,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC,EACtB,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,EACvB,QAAQ,EAAE,YAAY,CAAC,EAAE,EAAE,KAAK,CAAC,EACjC,UAAU,EAAE,UAAU,CAAC,EAAE,EAAE,KAAK,CAAC,EACjC,aAAa,EAAE,aAAa,CAAC,EAAE,CAAC,EAChC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,WAAW,CAAC,EAAE,CAAC,GAC3B,IAAI,CAyBN"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { useRef } from 'react';
|
|
2
|
+
import { View } from '../view.js';
|
|
3
|
+
const STATUS_BAR_HEIGHT = 1;
|
|
4
|
+
// Hooks that keeps Ref of the viewport's start, and returns View sliced to
|
|
5
|
+
// only the rows that should be visible.
|
|
6
|
+
export function useView(navNode, state, stateApi, navNodeApi, cursorMethods, rowCount, presentNode) {
|
|
7
|
+
const viewportStartRef = useRef(0);
|
|
8
|
+
const viewportHeight = Math.max(0, rowCount - STATUS_BAR_HEIGHT);
|
|
9
|
+
if (viewportHeight === 0) {
|
|
10
|
+
return { rows: [] };
|
|
11
|
+
}
|
|
12
|
+
const rows = View.createRows(navNode, navNodeApi, stateApi.getCursor(state), cursorMethods, presentNode);
|
|
13
|
+
viewportStartRef.current = viewportStart(rows, viewportHeight, viewportStartRef.current);
|
|
14
|
+
return View.create(navNode, navNodeApi, stateApi.getCursor(state), cursorMethods, viewportHeight, viewportStartRef.current, presentNode);
|
|
15
|
+
}
|
|
16
|
+
function viewportStart(rows, viewportHeight, currentViewportStart) {
|
|
17
|
+
const scrollMargin = 3;
|
|
18
|
+
const cursorIndex = rows.findIndex((row) => row.cursor);
|
|
19
|
+
const maximumViewportStart = Math.max(0, rows.length - viewportHeight);
|
|
20
|
+
let viewportStart = currentViewportStart;
|
|
21
|
+
if (cursorIndex >= 0) {
|
|
22
|
+
const firstVisibleCursorIndex = viewportStart + scrollMargin;
|
|
23
|
+
const lastVisibleCursorIndex = viewportStart + viewportHeight - 1 - scrollMargin;
|
|
24
|
+
if (cursorIndex < firstVisibleCursorIndex) {
|
|
25
|
+
viewportStart = cursorIndex - scrollMargin;
|
|
26
|
+
}
|
|
27
|
+
else if (cursorIndex > lastVisibleCursorIndex) {
|
|
28
|
+
viewportStart = cursorIndex - viewportHeight + 1 + scrollMargin;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return Math.max(0, Math.min(viewportStart, maximumViewportStart));
|
|
32
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loading-screen-renderer.d.ts","sourceRoot":"","sources":["../../src/ui/loading-screen-renderer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C,MAAM,MAAM,qBAAqB,GAAG,aAAa,CAAC,EAAE,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { HighlightToken, PresentNode } from 'dirvi-apis';
|
|
2
|
+
import type { Cursor, NavBranch, NavMethods, SerializableKey, CursorMethods } from 'dirvi-lib';
|
|
3
|
+
type ViewRowBase = {
|
|
4
|
+
id: string;
|
|
5
|
+
indent: number;
|
|
6
|
+
content: string;
|
|
7
|
+
cursor: boolean;
|
|
8
|
+
selected: boolean;
|
|
9
|
+
highlight: HighlightToken;
|
|
10
|
+
};
|
|
11
|
+
export type ViewRow = (ViewRowBase & {
|
|
12
|
+
type: 'leaf';
|
|
13
|
+
}) | (ViewRowBase & {
|
|
14
|
+
type: 'branch';
|
|
15
|
+
foldedCount: number;
|
|
16
|
+
}) | (ViewRowBase & {
|
|
17
|
+
type: 'fold';
|
|
18
|
+
foldedCount: number;
|
|
19
|
+
});
|
|
20
|
+
export type View = {
|
|
21
|
+
rows: ViewRow[];
|
|
22
|
+
};
|
|
23
|
+
export declare const View: {
|
|
24
|
+
createRows<Id extends SerializableKey, Value>(rootNode: NavBranch<Id>, navNodeApi: NavMethods<Id, Value>, cursor: Cursor<Id>, cursorMethods: CursorMethods<Id>, presentNode: PresentNode<Id>): ViewRow[];
|
|
25
|
+
create<Id extends SerializableKey, Value>(rootNode: NavBranch<Id>, navNodeApi: NavMethods<Id, Value>, cursor: Cursor<Id>, cursorMethods: CursorMethods<Id>, viewportHeight: number, viewportStart: number, presentNode: PresentNode<Id>): View;
|
|
26
|
+
};
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=view.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../src/ui/view.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,WAAW,EACZ,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EACV,MAAM,EAGN,SAAS,EAET,UAAU,EACV,eAAe,EAAE,aAAa,EAC/B,MAAM,WAAW,CAAC;AAEnB,KAAK,WAAW,GAAG;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,cAAc,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,OAAO,GACf,CAAC,WAAW,GAAG;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAC,GACF,CAAC,WAAW,GAAG;IACb,IAAI,EAAE,QAAQ,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC,GACF,CAAC,WAAW,GAAG;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC,CAAC;AAEP,MAAM,MAAM,IAAI,GAAG;IACjB,IAAI,EAAE,OAAO,EAAE,CAAC;CACjB,CAAC;AASF,eAAO,MAAM,IAAI;eACJ,EAAE,SAAS,eAAe,EAAE,KAAK,YAChC,SAAS,CAAC,EAAE,CAAC,cACX,UAAU,CAAC,EAAE,EAAE,KAAK,CAAC,UACzB,MAAM,CAAC,EAAE,CAAC,iBACH,aAAa,CAAC,EAAE,CAAC,eACnB,WAAW,CAAC,EAAE,CAAC,GAC3B,OAAO,EAAE;WAwCL,EAAE,SAAS,eAAe,EAAE,KAAK,YAC5B,SAAS,CAAC,EAAE,CAAC,cACX,UAAU,CAAC,EAAE,EAAE,KAAK,CAAC,UACzB,MAAM,CAAC,EAAE,CAAC,iBACH,aAAa,CAAC,EAAE,CAAC,kBAChB,MAAM,iBACP,MAAM,eACR,WAAW,CAAC,EAAE,CAAC,GAC3B,IAAI;CAOR,CAAC"}
|
package/dist/ui/view.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
function foldId(parentPath, firstId) {
|
|
2
|
+
return `fold:${JSON.stringify([...parentPath, firstId])}`;
|
|
3
|
+
}
|
|
4
|
+
export const View = {
|
|
5
|
+
createRows(rootNode, navNodeApi, cursor, cursorMethods, presentNode) {
|
|
6
|
+
const rootCursor = { path: [] };
|
|
7
|
+
const inlineFoldIds = new Set();
|
|
8
|
+
if (rootNode.children !== null) {
|
|
9
|
+
for (const position of navNodeApi.cursors(rootNode.children)) {
|
|
10
|
+
if (cursorMethods.isFoldCursor(position)) {
|
|
11
|
+
inlineFoldIds.add(foldId(position.parentPath, position.firstId));
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
const rootRow = viewRowForEntry(rootNode, null, cursorMethods.equal(cursor, rootCursor), navNodeApi, presentNode, inlineFoldIds);
|
|
16
|
+
if (rootNode.children === null) {
|
|
17
|
+
return [rootRow];
|
|
18
|
+
}
|
|
19
|
+
return [
|
|
20
|
+
rootRow,
|
|
21
|
+
...viewRowsAtNode(rootNode.children, [], navNodeApi, cursor, cursorMethods, presentNode, inlineFoldIds),
|
|
22
|
+
];
|
|
23
|
+
},
|
|
24
|
+
create(rootNode, navNodeApi, cursor, cursorMethods, viewportHeight, viewportStart, presentNode) {
|
|
25
|
+
const rows = View.createRows(rootNode, navNodeApi, cursor, cursorMethods, presentNode);
|
|
26
|
+
return {
|
|
27
|
+
rows: rows.slice(viewportStart, viewportStart + viewportHeight),
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Converts one NavNode and its descendants into display ViewRows.
|
|
33
|
+
*
|
|
34
|
+
* `parentPath` is the path of that directory. For example:
|
|
35
|
+
*
|
|
36
|
+
* [] root directory
|
|
37
|
+
* ['src'] root/src
|
|
38
|
+
* ['src', 'lib'] root/src/lib
|
|
39
|
+
*/
|
|
40
|
+
function viewRowsAtNode(node, parentPath, navNodeApi, cursor, cursorMethods, presentNode, inlineFoldIds) {
|
|
41
|
+
const rows = [];
|
|
42
|
+
for (const entry of node.entries) {
|
|
43
|
+
if (navNodeApi.entryIsFold(entry)) {
|
|
44
|
+
const firstEntry = entry.folded[0];
|
|
45
|
+
// Match navigation's guard for empty or richer future fold contents.
|
|
46
|
+
if (firstEntry === undefined || navNodeApi.entryIsFold(firstEntry)) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const id = foldId(parentPath, firstEntry.id);
|
|
50
|
+
// Unordered summaries belong to the parent, not separate rows.
|
|
51
|
+
if (!inlineFoldIds.has(id)) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const entryCursor = {
|
|
55
|
+
parentPath: [...parentPath],
|
|
56
|
+
firstId: firstEntry.id,
|
|
57
|
+
};
|
|
58
|
+
// Reuse the first hidden entry's highlight until folds have a presenter.
|
|
59
|
+
const { highlight } = presentNode(firstEntry.id, navNodeApi.entryIsBranch(firstEntry));
|
|
60
|
+
rows.push({
|
|
61
|
+
id,
|
|
62
|
+
indent: parentPath.length + 1,
|
|
63
|
+
content: `… ${entry.folded.length} folded`,
|
|
64
|
+
cursor: cursorMethods.equal(cursor, entryCursor),
|
|
65
|
+
selected: false,
|
|
66
|
+
highlight,
|
|
67
|
+
type: 'fold',
|
|
68
|
+
foldedCount: entry.folded.length,
|
|
69
|
+
});
|
|
70
|
+
// Hidden descendants are never rendered separately.
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const entryCursor = {
|
|
74
|
+
path: [...parentPath, entry.id],
|
|
75
|
+
};
|
|
76
|
+
const isCursor = cursorMethods.equal(cursor, entryCursor);
|
|
77
|
+
rows.push(viewRowForEntry(entry, parentPath, isCursor, navNodeApi, presentNode, inlineFoldIds));
|
|
78
|
+
// Case where there's no branches
|
|
79
|
+
if (!navNodeApi.entryIsBranch(entry) || entry.children === null) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
rows.push(...viewRowsAtNode(entry.children, [...parentPath, entry.id], navNodeApi, cursor, cursorMethods, presentNode, inlineFoldIds));
|
|
83
|
+
}
|
|
84
|
+
return rows;
|
|
85
|
+
}
|
|
86
|
+
function viewRowForEntry(entry, parentPath, cursor, navNodeApi, presentNode, inlineFoldIds) {
|
|
87
|
+
const id = entryId(parentPath ?? [], entry.id);
|
|
88
|
+
const indent = parentPath ? parentPath.length + 1 : 0;
|
|
89
|
+
const selected = false;
|
|
90
|
+
if (navNodeApi.entryIsBranch(entry)) {
|
|
91
|
+
const { content, highlight } = presentNode(entry.id, true);
|
|
92
|
+
const entryPath = parentPath === null ? [] : [...parentPath, entry.id];
|
|
93
|
+
const foldedCount = entry.children?.entries.reduce((count, entry) => {
|
|
94
|
+
if (!navNodeApi.entryIsFold(entry)) {
|
|
95
|
+
return count;
|
|
96
|
+
}
|
|
97
|
+
const firstEntry = entry.folded[0];
|
|
98
|
+
if (firstEntry === undefined || navNodeApi.entryIsFold(firstEntry)) {
|
|
99
|
+
return count;
|
|
100
|
+
}
|
|
101
|
+
// Ordered folds already have their own rows.
|
|
102
|
+
if (inlineFoldIds.has(foldId(entryPath, firstEntry.id))) {
|
|
103
|
+
return count;
|
|
104
|
+
}
|
|
105
|
+
return count + entry.folded.length;
|
|
106
|
+
}, 0) ?? 0;
|
|
107
|
+
return {
|
|
108
|
+
id,
|
|
109
|
+
indent,
|
|
110
|
+
selected,
|
|
111
|
+
cursor,
|
|
112
|
+
content: content,
|
|
113
|
+
highlight,
|
|
114
|
+
type: 'branch',
|
|
115
|
+
foldedCount,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
const { content, highlight } = presentNode(entry.id, false);
|
|
119
|
+
return {
|
|
120
|
+
id,
|
|
121
|
+
indent,
|
|
122
|
+
selected,
|
|
123
|
+
cursor,
|
|
124
|
+
content,
|
|
125
|
+
highlight,
|
|
126
|
+
type: 'leaf',
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function entryId(parentPath, entryName) {
|
|
130
|
+
return `entry:${JSON.stringify([...parentPath, entryName])}`;
|
|
131
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,37 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mak-98/dirvi-app",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.11.0-beta.13",
|
|
4
|
+
"description": "Shared React application logic for dirvi hosts.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "GPL-3.0-or-later",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"dirvi-apis": "0.11.0-beta.13",
|
|
20
|
+
"dirvi-lib": "0.11.0-beta.13",
|
|
21
|
+
"zod": "^4.4.3"
|
|
22
|
+
},
|
|
23
|
+
"peerDependencies": {
|
|
24
|
+
"react": "^19.0.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/node": "^22.20.1",
|
|
28
|
+
"@types/react": "^19.0.0",
|
|
29
|
+
"react": "^19.0.0",
|
|
30
|
+
"typescript": "^5.0.0"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsc -p tsconfig.json",
|
|
34
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
35
|
+
"format": "prettier . --write"
|
|
36
|
+
}
|
|
6
37
|
}
|
package/README.md
DELETED