@tooee/view 0.2.3 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -15
- package/dist/components/subviews/{CodeSubview.d.ts → code-subview.d.ts} +2 -2
- package/dist/components/subviews/code-subview.d.ts.map +1 -0
- package/dist/components/subviews/{CodeSubview.js → code-subview.js} +8 -8
- package/dist/components/subviews/code-subview.js.map +1 -0
- package/dist/components/subviews/custom-subview.d.ts +9 -0
- package/dist/components/subviews/custom-subview.d.ts.map +1 -0
- package/dist/components/subviews/{CustomSubview.js → custom-subview.js} +7 -7
- package/dist/components/subviews/custom-subview.js.map +1 -0
- package/dist/components/subviews/index.d.ts +4 -4
- package/dist/components/subviews/index.d.ts.map +1 -1
- package/dist/components/subviews/index.js +4 -4
- package/dist/components/subviews/index.js.map +1 -1
- package/dist/components/subviews/markdown-subview.d.ts +11 -0
- package/dist/components/subviews/markdown-subview.d.ts.map +1 -0
- package/dist/components/subviews/{MarkdownSubview.js → markdown-subview.js} +28 -26
- package/dist/components/subviews/markdown-subview.js.map +1 -0
- package/dist/components/subviews/table-subview.d.ts +8 -0
- package/dist/components/subviews/table-subview.d.ts.map +1 -0
- package/dist/components/subviews/{TableSubview.js → table-subview.js} +40 -22
- package/dist/components/subviews/table-subview.js.map +1 -0
- package/dist/components/subviews/types.d.ts.map +1 -1
- package/dist/components/{ViewScreen.d.ts → view-screen.d.ts} +3 -3
- package/dist/components/view-screen.d.ts.map +1 -0
- package/dist/components/{ViewScreen.js → view-screen.js} +11 -11
- package/dist/components/view-screen.js.map +1 -0
- package/dist/content-loader-store.d.ts +11 -7
- package/dist/content-loader-store.d.ts.map +1 -1
- package/dist/content-loader-store.js +70 -50
- package/dist/content-loader-store.js.map +1 -1
- package/dist/default-provider.d.ts +4 -4
- package/dist/default-provider.d.ts.map +1 -1
- package/dist/default-provider.js +48 -39
- package/dist/default-provider.js.map +1 -1
- package/dist/directory-provider.d.ts +2 -2
- package/dist/directory-provider.d.ts.map +1 -1
- package/dist/directory-provider.js +13 -10
- package/dist/directory-provider.js.map +1 -1
- package/dist/directory-view.d.ts +8 -0
- package/dist/directory-view.d.ts.map +1 -0
- package/dist/{DirectoryView.js → directory-view.js} +18 -12
- package/dist/directory-view.js.map +1 -0
- package/dist/hooks/index.d.ts +4 -4
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +3 -3
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/{useContentCommands.d.ts → use-content-commands.d.ts} +2 -2
- package/dist/hooks/use-content-commands.d.ts.map +1 -0
- package/dist/hooks/{useContentCommands.js → use-content-commands.js} +6 -4
- package/dist/hooks/use-content-commands.js.map +1 -0
- package/dist/hooks/{useContentLoader.d.ts → use-content-loader.d.ts} +4 -4
- package/dist/hooks/use-content-loader.d.ts.map +1 -0
- package/dist/hooks/use-content-loader.js +81 -0
- package/dist/hooks/use-content-loader.js.map +1 -0
- package/dist/hooks/{useViewCommandContext.d.ts → use-view-command-context.d.ts} +3 -3
- package/dist/hooks/use-view-command-context.d.ts.map +1 -0
- package/dist/hooks/{useViewCommandContext.js → use-view-command-context.js} +15 -13
- package/dist/hooks/use-view-command-context.js.map +1 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/launch.d.ts +2 -2
- package/dist/launch.d.ts.map +1 -1
- package/dist/launch.js +6 -6
- package/dist/launch.js.map +1 -1
- package/dist/types.d.ts +4 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +46 -24
- package/dist/types.js.map +1 -1
- package/dist/view.d.ts +18 -0
- package/dist/view.d.ts.map +1 -0
- package/dist/{View.js → view.js} +20 -14
- package/dist/view.js.map +1 -0
- package/package.json +10 -10
- package/src/components/subviews/{CodeSubview.tsx → code-subview.tsx} +25 -19
- package/src/components/subviews/{CustomSubview.tsx → custom-subview.tsx} +23 -21
- package/src/components/subviews/index.ts +5 -5
- package/src/components/subviews/{MarkdownSubview.tsx → markdown-subview.tsx} +55 -52
- package/src/components/subviews/table-subview.tsx +95 -0
- package/src/components/subviews/types.ts +14 -14
- package/src/components/{ViewScreen.tsx → view-screen.tsx} +33 -32
- package/src/content-loader-store.ts +131 -99
- package/src/default-provider.ts +84 -64
- package/src/directory-provider.ts +32 -24
- package/src/directory-view.tsx +79 -0
- package/src/hooks/index.ts +7 -4
- package/src/hooks/{useContentCommands.ts → use-content-commands.ts} +19 -14
- package/src/hooks/use-content-loader.ts +92 -0
- package/src/hooks/{useViewCommandContext.ts → use-view-command-context.ts} +40 -38
- package/src/index.ts +14 -14
- package/src/launch.tsx +20 -18
- package/src/types.ts +107 -78
- package/src/view.tsx +114 -0
- package/dist/DirectoryView.d.ts +0 -7
- package/dist/DirectoryView.d.ts.map +0 -1
- package/dist/DirectoryView.js.map +0 -1
- package/dist/View.d.ts +0 -16
- package/dist/View.d.ts.map +0 -1
- package/dist/View.js.map +0 -1
- package/dist/components/ViewScreen.d.ts.map +0 -1
- package/dist/components/ViewScreen.js.map +0 -1
- package/dist/components/subviews/CodeSubview.d.ts.map +0 -1
- package/dist/components/subviews/CodeSubview.js.map +0 -1
- package/dist/components/subviews/CustomSubview.d.ts +0 -9
- package/dist/components/subviews/CustomSubview.d.ts.map +0 -1
- package/dist/components/subviews/CustomSubview.js.map +0 -1
- package/dist/components/subviews/MarkdownSubview.d.ts +0 -10
- package/dist/components/subviews/MarkdownSubview.d.ts.map +0 -1
- package/dist/components/subviews/MarkdownSubview.js.map +0 -1
- package/dist/components/subviews/TableSubview.d.ts +0 -8
- package/dist/components/subviews/TableSubview.d.ts.map +0 -1
- package/dist/components/subviews/TableSubview.js.map +0 -1
- package/dist/hooks/useContentCommands.d.ts.map +0 -1
- package/dist/hooks/useContentCommands.js.map +0 -1
- package/dist/hooks/useContentLoader.d.ts.map +0 -1
- package/dist/hooks/useContentLoader.js +0 -55
- package/dist/hooks/useContentLoader.js.map +0 -1
- package/dist/hooks/useViewCommandContext.d.ts.map +0 -1
- package/dist/hooks/useViewCommandContext.js.map +0 -1
- package/src/DirectoryView.tsx +0 -68
- package/src/View.tsx +0 -94
- package/src/components/subviews/TableSubview.tsx +0 -65
- package/src/hooks/useContentLoader.ts +0 -72
|
@@ -1,30 +1,36 @@
|
|
|
1
|
-
import { useMemo } from "react"
|
|
2
|
-
import { CodeView, sourceLines, sourceLineAdapter
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
import { CodeView, sourceLines, sourceLineAdapter } from "@tooee/renderers";
|
|
3
|
+
import type { SourceLineRow } from "@tooee/renderers";
|
|
4
|
+
import { useDocumentController } from "@tooee/shell";
|
|
5
|
+
import type { CodeContent, TextContent } from "../../types.js";
|
|
6
|
+
import { useContentCommands } from "../../hooks/use-content-commands.js";
|
|
7
|
+
import { ViewScreen } from "../view-screen.js";
|
|
8
|
+
import type { SubviewProps } from "./types.js";
|
|
8
9
|
|
|
9
10
|
interface CodeSubviewProps extends SubviewProps {
|
|
10
|
-
content: CodeContent | TextContent
|
|
11
|
+
content: CodeContent | TextContent;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
export
|
|
14
|
-
|
|
14
|
+
export const CodeSubview = function CodeSubview({
|
|
15
|
+
content,
|
|
16
|
+
decorations,
|
|
17
|
+
actions,
|
|
18
|
+
...screen
|
|
19
|
+
}: CodeSubviewProps): React.ReactNode {
|
|
20
|
+
const textContent = content.format === "code" ? content.code : content.text;
|
|
15
21
|
// One navigation row per physical source line; row index is the source line.
|
|
16
|
-
const lineRows = useMemo(() => sourceLines(textContent), [textContent])
|
|
22
|
+
const lineRows = useMemo(() => sourceLines(textContent), [textContent]);
|
|
17
23
|
|
|
18
|
-
const { showLineNumbers } = useContentCommands({ content, textContent })
|
|
24
|
+
const { showLineNumbers } = useContentCommands({ content, textContent });
|
|
19
25
|
|
|
20
26
|
const document = useDocumentController<SourceLineRow>({
|
|
21
|
-
rows: lineRows,
|
|
22
27
|
adapter: sourceLineAdapter,
|
|
23
|
-
multiSelect: true,
|
|
24
|
-
decorations,
|
|
25
28
|
// The controller projects the screen's actions onto menu entries at open time.
|
|
26
29
|
contextMenu: actions,
|
|
27
|
-
|
|
30
|
+
decorations,
|
|
31
|
+
multiSelect: true,
|
|
32
|
+
rows: lineRows,
|
|
33
|
+
});
|
|
28
34
|
|
|
29
35
|
const statusItems = useMemo(
|
|
30
36
|
() => [
|
|
@@ -32,7 +38,7 @@ export function CodeSubview({ content, decorations, actions, ...screen }: CodeSu
|
|
|
32
38
|
{ label: "Lines:", value: String(lineRows.length) },
|
|
33
39
|
],
|
|
34
40
|
[content.format, lineRows.length],
|
|
35
|
-
)
|
|
41
|
+
);
|
|
36
42
|
|
|
37
43
|
return (
|
|
38
44
|
<ViewScreen
|
|
@@ -49,5 +55,5 @@ export function CodeSubview({ content, decorations, actions, ...screen }: CodeSu
|
|
|
49
55
|
document={document}
|
|
50
56
|
/>
|
|
51
57
|
</ViewScreen>
|
|
52
|
-
)
|
|
53
|
-
}
|
|
58
|
+
);
|
|
59
|
+
};
|
|
@@ -1,36 +1,38 @@
|
|
|
1
|
-
import { useMemo } from "react"
|
|
2
|
-
import { CodeView, sourceLines, sourceLineAdapter
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
import { CodeView, sourceLines, sourceLineAdapter } from "@tooee/renderers";
|
|
3
|
+
import type { SourceLineRow } from "@tooee/renderers";
|
|
4
|
+
import { useDocumentController } from "@tooee/shell";
|
|
5
|
+
import { getTextContent } from "../../types.js";
|
|
6
|
+
import type { CustomContent, ContentRenderer } from "../../types.js";
|
|
7
|
+
import { useContentCommands } from "../../hooks/use-content-commands.js";
|
|
8
|
+
import { ViewScreen } from "../view-screen.js";
|
|
9
|
+
import type { SubviewProps } from "./types.js";
|
|
8
10
|
|
|
9
11
|
interface CustomSubviewProps extends SubviewProps {
|
|
10
|
-
content: CustomContent
|
|
11
|
-
renderers?: Record<string, ContentRenderer
|
|
12
|
+
content: CustomContent;
|
|
13
|
+
renderers?: Record<string, ContentRenderer>;
|
|
12
14
|
}
|
|
13
15
|
|
|
14
|
-
export function CustomSubview({
|
|
16
|
+
export const CustomSubview = function CustomSubview({
|
|
15
17
|
content,
|
|
16
18
|
decorations,
|
|
17
19
|
actions,
|
|
18
20
|
renderers,
|
|
19
21
|
...screen
|
|
20
|
-
}: CustomSubviewProps) {
|
|
21
|
-
const textContent = useMemo(() => getTextContent(content), [content])
|
|
22
|
+
}: CustomSubviewProps): React.ReactNode {
|
|
23
|
+
const textContent = useMemo(() => getTextContent(content), [content]);
|
|
22
24
|
// Fallback rows are source lines; row index is the source line.
|
|
23
|
-
const lineRows = useMemo(() => sourceLines(textContent), [textContent])
|
|
25
|
+
const lineRows = useMemo(() => sourceLines(textContent), [textContent]);
|
|
24
26
|
|
|
25
|
-
useContentCommands({ content, textContent })
|
|
27
|
+
useContentCommands({ content, textContent });
|
|
26
28
|
|
|
27
29
|
// Custom content has no action rows of its own, so no context menu is bound.
|
|
28
30
|
const document = useDocumentController<SourceLineRow>({
|
|
29
|
-
rows: lineRows,
|
|
30
31
|
adapter: sourceLineAdapter,
|
|
31
|
-
multiSelect: true,
|
|
32
32
|
decorations,
|
|
33
|
-
|
|
33
|
+
multiSelect: true,
|
|
34
|
+
rows: lineRows,
|
|
35
|
+
});
|
|
34
36
|
|
|
35
37
|
const statusItems = useMemo(
|
|
36
38
|
() => [
|
|
@@ -38,9 +40,9 @@ export function CustomSubview({
|
|
|
38
40
|
{ label: "Lines:", value: String(lineRows.length) },
|
|
39
41
|
],
|
|
40
42
|
[content.format, lineRows.length],
|
|
41
|
-
)
|
|
43
|
+
);
|
|
42
44
|
|
|
43
|
-
const customRenderer = renderers?.[content.format]
|
|
45
|
+
const customRenderer = renderers?.[content.format];
|
|
44
46
|
|
|
45
47
|
return (
|
|
46
48
|
<ViewScreen
|
|
@@ -56,5 +58,5 @@ export function CustomSubview({
|
|
|
56
58
|
<CodeView content={textContent} showLineNumbers={false} document={document} />
|
|
57
59
|
)}
|
|
58
60
|
</ViewScreen>
|
|
59
|
-
)
|
|
60
|
-
}
|
|
61
|
+
);
|
|
62
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { MarkdownSubview } from "./
|
|
2
|
-
export { CodeSubview } from "./
|
|
3
|
-
export { TableSubview } from "./
|
|
4
|
-
export { CustomSubview } from "./
|
|
5
|
-
export type { SubviewProps } from "./types.js"
|
|
1
|
+
export { MarkdownSubview } from "./markdown-subview.js";
|
|
2
|
+
export { CodeSubview } from "./code-subview.js";
|
|
3
|
+
export { TableSubview } from "./table-subview.js";
|
|
4
|
+
export { CustomSubview } from "./custom-subview.js";
|
|
5
|
+
export type { SubviewProps } from "./types.js";
|
|
@@ -1,26 +1,23 @@
|
|
|
1
|
-
import { useMemo, useRef } from "react"
|
|
2
|
-
import type { TextBufferRenderable } from "@opentui/core"
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
} from "
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import type { MarkdownContent } from "../../types.js"
|
|
13
|
-
import { useContentCommands } from "../../hooks/useContentCommands.js"
|
|
14
|
-
import { ViewScreen } from "../ViewScreen.js"
|
|
15
|
-
import type { SubviewProps } from "./types.js"
|
|
1
|
+
import { useMemo, useRef } from "react";
|
|
2
|
+
import type { TextBufferRenderable } from "@opentui/core";
|
|
3
|
+
import { MarkdownView, flattenMarkdown, getFlatBlockText } from "@tooee/renderers";
|
|
4
|
+
import type { CodeBlockRenderer, FlatBlock, MarkdownLinkHandler } from "@tooee/renderers";
|
|
5
|
+
import { useCommand } from "@tooee/commands";
|
|
6
|
+
import { useDocumentController } from "@tooee/shell";
|
|
7
|
+
import type { DocumentRowAdapter } from "@tooee/shell";
|
|
8
|
+
import type { MarkdownContent } from "../../types.js";
|
|
9
|
+
import { useContentCommands } from "../../hooks/use-content-commands.js";
|
|
10
|
+
import { ViewScreen } from "../view-screen.js";
|
|
11
|
+
import type { SubviewProps } from "./types.js";
|
|
16
12
|
|
|
17
13
|
interface MarkdownSubviewProps extends SubviewProps {
|
|
18
|
-
content: MarkdownContent
|
|
19
|
-
codeBlockRenderers?: Record<string, CodeBlockRenderer
|
|
14
|
+
content: MarkdownContent;
|
|
15
|
+
codeBlockRenderers?: Record<string, CodeBlockRenderer>;
|
|
16
|
+
onLinkActivate?: MarkdownLinkHandler;
|
|
20
17
|
}
|
|
21
18
|
|
|
22
19
|
/** Columns moved per h/l press when scrolling a wide block horizontally. */
|
|
23
|
-
const BLOCK_HSCROLL_STEP = 4
|
|
20
|
+
const BLOCK_HSCROLL_STEP = 4;
|
|
24
21
|
|
|
25
22
|
/**
|
|
26
23
|
* Blocks are the row unit. `getFlatBlockText` keeps search/copy in step with the
|
|
@@ -28,59 +25,64 @@ const BLOCK_HSCROLL_STEP = 4
|
|
|
28
25
|
* each block's Markdown provenance onto the controller's anchors.
|
|
29
26
|
*/
|
|
30
27
|
const MARKDOWN_BLOCK_ADAPTER: DocumentRowAdapter<FlatBlock> = {
|
|
31
|
-
getText: (block) => getFlatBlockText(block),
|
|
32
28
|
getSource: (block) => block.source,
|
|
33
|
-
|
|
29
|
+
getText: (block) => getFlatBlockText(block),
|
|
30
|
+
};
|
|
34
31
|
|
|
35
|
-
export function MarkdownSubview({
|
|
32
|
+
export const MarkdownSubview = function MarkdownSubview({
|
|
36
33
|
content,
|
|
37
34
|
codeBlockRenderers,
|
|
35
|
+
onLinkActivate,
|
|
38
36
|
decorations,
|
|
39
37
|
actions,
|
|
40
38
|
...screen
|
|
41
|
-
}: MarkdownSubviewProps) {
|
|
42
|
-
const textContent = content.markdown
|
|
43
|
-
const lineCount = useMemo(() => textContent.split("\n").length, [textContent])
|
|
44
|
-
const blocks = useMemo(() => flattenMarkdown(content.markdown), [content.markdown])
|
|
39
|
+
}: MarkdownSubviewProps): React.ReactNode {
|
|
40
|
+
const textContent = content.markdown;
|
|
41
|
+
const lineCount = useMemo(() => textContent.split("\n").length, [textContent]);
|
|
42
|
+
const blocks = useMemo(() => flattenMarkdown(content.markdown), [content.markdown]);
|
|
45
43
|
|
|
46
|
-
const { showLineNumbers } = useContentCommands({ content, textContent })
|
|
44
|
+
const { showLineNumbers } = useContentCommands({ content, textContent });
|
|
47
45
|
|
|
48
46
|
const document = useDocumentController<FlatBlock>({
|
|
49
|
-
rows: blocks,
|
|
50
47
|
adapter: MARKDOWN_BLOCK_ADAPTER,
|
|
51
|
-
multiSelect: true,
|
|
52
|
-
decorations,
|
|
53
48
|
// The controller projects the screen's actions onto menu entries at open time.
|
|
54
49
|
contextMenu: actions,
|
|
55
|
-
|
|
50
|
+
decorations,
|
|
51
|
+
multiSelect: true,
|
|
52
|
+
rows: blocks,
|
|
53
|
+
});
|
|
56
54
|
|
|
57
|
-
const hScrollableBlocksRef = useRef<Map<number, TextBufferRenderable>>(new Map())
|
|
55
|
+
const hScrollableBlocksRef = useRef<Map<number, TextBufferRenderable>>(new Map());
|
|
58
56
|
const cursorScrollable = () =>
|
|
59
|
-
document.activeIndex
|
|
60
|
-
?
|
|
61
|
-
:
|
|
57
|
+
document.activeIndex === null
|
|
58
|
+
? undefined
|
|
59
|
+
: hScrollableBlocksRef.current.get(document.activeIndex);
|
|
62
60
|
useCommand({
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
handler: () => {
|
|
62
|
+
const target = cursorScrollable();
|
|
63
|
+
if (target) {
|
|
64
|
+
target.scrollX -= BLOCK_HSCROLL_STEP;
|
|
65
|
+
}
|
|
66
|
+
},
|
|
65
67
|
hotkey: "h",
|
|
68
|
+
id: "block-scroll-left",
|
|
66
69
|
modes: ["cursor"],
|
|
67
|
-
|
|
70
|
+
title: "Scroll block left",
|
|
71
|
+
when: () => cursorScrollable() !== undefined,
|
|
72
|
+
});
|
|
73
|
+
useCommand({
|
|
68
74
|
handler: () => {
|
|
69
|
-
const target = cursorScrollable()
|
|
70
|
-
if (target)
|
|
75
|
+
const target = cursorScrollable();
|
|
76
|
+
if (target) {
|
|
77
|
+
target.scrollX += BLOCK_HSCROLL_STEP;
|
|
78
|
+
}
|
|
71
79
|
},
|
|
72
|
-
})
|
|
73
|
-
useCommand({
|
|
74
|
-
id: "block-scroll-right",
|
|
75
|
-
title: "Scroll block right",
|
|
76
80
|
hotkey: "l",
|
|
81
|
+
id: "block-scroll-right",
|
|
77
82
|
modes: ["cursor"],
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (target) target.scrollX += BLOCK_HSCROLL_STEP
|
|
82
|
-
},
|
|
83
|
-
})
|
|
83
|
+
title: "Scroll block right",
|
|
84
|
+
when: () => cursorScrollable() !== undefined,
|
|
85
|
+
});
|
|
84
86
|
|
|
85
87
|
const statusItems = useMemo(
|
|
86
88
|
() => [
|
|
@@ -88,7 +90,7 @@ export function MarkdownSubview({
|
|
|
88
90
|
{ label: "Lines:", value: String(lineCount) },
|
|
89
91
|
],
|
|
90
92
|
[content.format, lineCount],
|
|
91
|
-
)
|
|
93
|
+
);
|
|
92
94
|
|
|
93
95
|
return (
|
|
94
96
|
<ViewScreen
|
|
@@ -105,7 +107,8 @@ export function MarkdownSubview({
|
|
|
105
107
|
document={document}
|
|
106
108
|
hScrollableBlocksRef={hScrollableBlocksRef}
|
|
107
109
|
codeBlockRenderers={codeBlockRenderers}
|
|
110
|
+
onLinkActivate={onLinkActivate}
|
|
108
111
|
/>
|
|
109
112
|
</ViewScreen>
|
|
110
|
-
)
|
|
111
|
-
}
|
|
113
|
+
);
|
|
114
|
+
};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
import { Table } from "@tooee/renderers";
|
|
3
|
+
import type { TableRow } from "@tooee/renderers";
|
|
4
|
+
import { useDocumentController } from "@tooee/shell";
|
|
5
|
+
import { getTextContent } from "../../types.js";
|
|
6
|
+
import type { TableContent } from "../../types.js";
|
|
7
|
+
import { useContentCommands } from "../../hooks/use-content-commands.js";
|
|
8
|
+
import { ViewScreen } from "../view-screen.js";
|
|
9
|
+
import type { SubviewProps } from "./types.js";
|
|
10
|
+
|
|
11
|
+
interface TableSubviewProps extends SubviewProps {
|
|
12
|
+
content: TableContent;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const stringifyRowCell = function stringifyRowCell(value: unknown): string {
|
|
16
|
+
if (value === null || value === undefined) {
|
|
17
|
+
return "";
|
|
18
|
+
}
|
|
19
|
+
if (typeof value === "string") {
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
23
|
+
return String(value);
|
|
24
|
+
}
|
|
25
|
+
if (typeof value === "string") {
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
if (
|
|
29
|
+
typeof value === "number" ||
|
|
30
|
+
typeof value === "bigint" ||
|
|
31
|
+
typeof value === "boolean" ||
|
|
32
|
+
typeof value === "symbol"
|
|
33
|
+
) {
|
|
34
|
+
return value.toString();
|
|
35
|
+
}
|
|
36
|
+
if (value === null || value === undefined) {
|
|
37
|
+
return String(value);
|
|
38
|
+
}
|
|
39
|
+
if (typeof value === "function") {
|
|
40
|
+
return Function.prototype.toString.call(value);
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
return JSON.stringify(value);
|
|
44
|
+
} catch {
|
|
45
|
+
return Array.isArray(value) ? value.join(",") : Object.prototype.toString.call(value);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const TableSubview = function TableSubview({
|
|
50
|
+
content,
|
|
51
|
+
decorations,
|
|
52
|
+
actions,
|
|
53
|
+
...screen
|
|
54
|
+
}: TableSubviewProps): React.ReactNode {
|
|
55
|
+
const textContent = useMemo(() => getTextContent(content), [content]);
|
|
56
|
+
const { showLineNumbers } = useContentCommands({ content, textContent });
|
|
57
|
+
|
|
58
|
+
const { columns, rows } = content;
|
|
59
|
+
const adapter = useMemo(
|
|
60
|
+
() => ({
|
|
61
|
+
getText: (row: TableRow) =>
|
|
62
|
+
columns.map((column) => stringifyRowCell(row[column.key])).join("\t"),
|
|
63
|
+
}),
|
|
64
|
+
[columns],
|
|
65
|
+
);
|
|
66
|
+
const document = useDocumentController<TableRow>({
|
|
67
|
+
adapter,
|
|
68
|
+
// The controller projects the screen's actions onto menu entries at open time.
|
|
69
|
+
contextMenu: actions,
|
|
70
|
+
decorations,
|
|
71
|
+
multiSelect: true,
|
|
72
|
+
rows,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const statusItems = useMemo(
|
|
76
|
+
() => [
|
|
77
|
+
{ label: "Format:", value: content.format },
|
|
78
|
+
{ label: "Rows:", value: String(rows.length) },
|
|
79
|
+
{ label: "Cols:", value: String(columns.length) },
|
|
80
|
+
],
|
|
81
|
+
[content.format, rows.length, columns.length],
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<ViewScreen
|
|
86
|
+
content={content}
|
|
87
|
+
controller={document}
|
|
88
|
+
actions={actions}
|
|
89
|
+
statusItems={statusItems}
|
|
90
|
+
{...screen}
|
|
91
|
+
>
|
|
92
|
+
<Table columns={columns} rows={rows} showLineNumbers={showLineNumbers} document={document} />
|
|
93
|
+
</ViewScreen>
|
|
94
|
+
);
|
|
95
|
+
};
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import type { MarkSet } from "@tooee/marks"
|
|
2
|
-
import type { ActionDefinition } from "@tooee/commands"
|
|
3
|
-
import type { DecorationLayer } from "@tooee/renderers"
|
|
4
|
-
import type { AnyContent } from "../../types.js"
|
|
1
|
+
import type { MarkSet } from "@tooee/marks";
|
|
2
|
+
import type { ActionDefinition } from "@tooee/commands";
|
|
3
|
+
import type { DecorationLayer } from "@tooee/renderers";
|
|
4
|
+
import type { AnyContent } from "../../types.js";
|
|
5
5
|
|
|
6
6
|
export interface SubviewProps {
|
|
7
|
-
content: AnyContent
|
|
7
|
+
content: AnyContent;
|
|
8
8
|
/**
|
|
9
9
|
* Provider and user mark sets as decoration layers. They compose with the
|
|
10
10
|
* interaction layers (search, selection, cursor) the controller generates.
|
|
11
11
|
*/
|
|
12
|
-
decorations: DecorationLayer[]
|
|
13
|
-
providerMarks: MarkSet[]
|
|
14
|
-
userMarks: MarkSet[]
|
|
15
|
-
setMarkSet: (set: MarkSet) => void
|
|
16
|
-
clearMarkNamespace: (namespace: string) => void
|
|
17
|
-
clearAllUserMarks: () => void
|
|
18
|
-
reload: () => void
|
|
19
|
-
streaming: boolean
|
|
20
|
-
actions?: ActionDefinition[]
|
|
12
|
+
decorations: DecorationLayer[];
|
|
13
|
+
providerMarks: MarkSet[];
|
|
14
|
+
userMarks: MarkSet[];
|
|
15
|
+
setMarkSet: (set: MarkSet) => void;
|
|
16
|
+
clearMarkNamespace: (namespace: string) => void;
|
|
17
|
+
clearAllUserMarks: () => void;
|
|
18
|
+
reload: () => void;
|
|
19
|
+
streaming: boolean;
|
|
20
|
+
actions?: ActionDefinition[];
|
|
21
21
|
}
|
|
@@ -1,25 +1,26 @@
|
|
|
1
|
-
import type { ReactNode } from "react"
|
|
2
|
-
import type { ActionDefinition } from "@tooee/commands"
|
|
3
|
-
import type { StatusBarItem } from "@tooee/layout"
|
|
4
|
-
import type { MarkSet } from "@tooee/marks"
|
|
5
|
-
import { DocumentScreen
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import type { ActionDefinition } from "@tooee/commands";
|
|
3
|
+
import type { StatusBarItem } from "@tooee/layout";
|
|
4
|
+
import type { MarkSet } from "@tooee/marks";
|
|
5
|
+
import { DocumentScreen } from "@tooee/shell";
|
|
6
|
+
import type { DocumentController } from "@tooee/shell";
|
|
7
|
+
import { useProvideViewCommandContext } from "../hooks/use-view-command-context.js";
|
|
8
|
+
import type { AnyContent } from "../types.js";
|
|
8
9
|
|
|
9
10
|
export interface ViewScreenProps<T> {
|
|
10
|
-
content: AnyContent
|
|
11
|
-
controller: DocumentController<T
|
|
12
|
-
streaming: boolean
|
|
13
|
-
actions?: ActionDefinition[]
|
|
11
|
+
content: AnyContent;
|
|
12
|
+
controller: DocumentController<T>;
|
|
13
|
+
streaming: boolean;
|
|
14
|
+
actions?: ActionDefinition[];
|
|
14
15
|
/** Content-shaped status (format, line/row counts), rendered before Mode. */
|
|
15
|
-
statusItems?: StatusBarItem[]
|
|
16
|
-
reload: () => void
|
|
17
|
-
providerMarks: MarkSet[]
|
|
18
|
-
userMarks: MarkSet[]
|
|
19
|
-
setMarkSet: (set: MarkSet) => void
|
|
20
|
-
clearMarkNamespace: (namespace: string) => void
|
|
21
|
-
clearAllUserMarks: () => void
|
|
22
|
-
children: ReactNode
|
|
16
|
+
statusItems?: StatusBarItem[];
|
|
17
|
+
reload: () => void;
|
|
18
|
+
providerMarks: MarkSet[];
|
|
19
|
+
userMarks: MarkSet[];
|
|
20
|
+
setMarkSet: (set: MarkSet) => void;
|
|
21
|
+
clearMarkNamespace: (namespace: string) => void;
|
|
22
|
+
clearAllUserMarks: () => void;
|
|
23
|
+
children: ReactNode;
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
/**
|
|
@@ -27,7 +28,7 @@ export interface ViewScreenProps<T> {
|
|
|
27
28
|
* (theme/quit commands, actions, `ctx.document`, layout, standard status) plus
|
|
28
29
|
* the content-only `ctx.view` slice that viewers contribute on top.
|
|
29
30
|
*/
|
|
30
|
-
export function ViewScreen<T>({
|
|
31
|
+
export const ViewScreen = function ViewScreen<T>({
|
|
31
32
|
content,
|
|
32
33
|
controller,
|
|
33
34
|
streaming,
|
|
@@ -40,37 +41,37 @@ export function ViewScreen<T>({
|
|
|
40
41
|
clearMarkNamespace,
|
|
41
42
|
clearAllUserMarks,
|
|
42
43
|
children,
|
|
43
|
-
}: ViewScreenProps<T>) {
|
|
44
|
+
}: ViewScreenProps<T>): ReactNode {
|
|
44
45
|
useProvideViewCommandContext({
|
|
45
46
|
content,
|
|
46
|
-
reload,
|
|
47
47
|
marks: {
|
|
48
|
-
setMarkSet,
|
|
49
|
-
clearNamespace: clearMarkNamespace,
|
|
50
48
|
clearAll: clearAllUserMarks,
|
|
51
|
-
|
|
49
|
+
clearNamespace: clearMarkNamespace,
|
|
52
50
|
providerMarks,
|
|
51
|
+
setMarkSet,
|
|
52
|
+
userMarks,
|
|
53
53
|
},
|
|
54
|
-
|
|
54
|
+
reload,
|
|
55
|
+
});
|
|
55
56
|
|
|
56
57
|
const items: StatusBarItem[] = [
|
|
57
58
|
...(statusItems ?? []),
|
|
58
59
|
...(streaming ? [{ label: "Status:", value: "streaming" }] : []),
|
|
59
|
-
]
|
|
60
|
+
];
|
|
60
61
|
|
|
61
62
|
return (
|
|
62
63
|
<DocumentScreen
|
|
63
64
|
controller={controller}
|
|
64
65
|
titleBar={
|
|
65
|
-
content.title
|
|
66
|
-
? {
|
|
66
|
+
content.title !== undefined && content.title !== ""
|
|
67
|
+
? { subtitle: content.format, title: content.title }
|
|
67
68
|
: { title: content.format }
|
|
68
69
|
}
|
|
69
70
|
statusItems={items}
|
|
70
71
|
actions={actions}
|
|
71
|
-
context={{ kind: content.format, title: content.title
|
|
72
|
+
context={{ kind: content.format, reload, title: content.title }}
|
|
72
73
|
>
|
|
73
74
|
{children}
|
|
74
75
|
</DocumentScreen>
|
|
75
|
-
)
|
|
76
|
-
}
|
|
76
|
+
);
|
|
77
|
+
};
|