@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.
Files changed (124) hide show
  1. package/README.md +15 -15
  2. package/dist/components/subviews/{CodeSubview.d.ts → code-subview.d.ts} +2 -2
  3. package/dist/components/subviews/code-subview.d.ts.map +1 -0
  4. package/dist/components/subviews/{CodeSubview.js → code-subview.js} +8 -8
  5. package/dist/components/subviews/code-subview.js.map +1 -0
  6. package/dist/components/subviews/custom-subview.d.ts +9 -0
  7. package/dist/components/subviews/custom-subview.d.ts.map +1 -0
  8. package/dist/components/subviews/{CustomSubview.js → custom-subview.js} +7 -7
  9. package/dist/components/subviews/custom-subview.js.map +1 -0
  10. package/dist/components/subviews/index.d.ts +4 -4
  11. package/dist/components/subviews/index.d.ts.map +1 -1
  12. package/dist/components/subviews/index.js +4 -4
  13. package/dist/components/subviews/index.js.map +1 -1
  14. package/dist/components/subviews/markdown-subview.d.ts +11 -0
  15. package/dist/components/subviews/markdown-subview.d.ts.map +1 -0
  16. package/dist/components/subviews/{MarkdownSubview.js → markdown-subview.js} +28 -26
  17. package/dist/components/subviews/markdown-subview.js.map +1 -0
  18. package/dist/components/subviews/table-subview.d.ts +8 -0
  19. package/dist/components/subviews/table-subview.d.ts.map +1 -0
  20. package/dist/components/subviews/{TableSubview.js → table-subview.js} +40 -22
  21. package/dist/components/subviews/table-subview.js.map +1 -0
  22. package/dist/components/subviews/types.d.ts.map +1 -1
  23. package/dist/components/{ViewScreen.d.ts → view-screen.d.ts} +3 -3
  24. package/dist/components/view-screen.d.ts.map +1 -0
  25. package/dist/components/{ViewScreen.js → view-screen.js} +11 -11
  26. package/dist/components/view-screen.js.map +1 -0
  27. package/dist/content-loader-store.d.ts +11 -7
  28. package/dist/content-loader-store.d.ts.map +1 -1
  29. package/dist/content-loader-store.js +70 -50
  30. package/dist/content-loader-store.js.map +1 -1
  31. package/dist/default-provider.d.ts +4 -4
  32. package/dist/default-provider.d.ts.map +1 -1
  33. package/dist/default-provider.js +48 -39
  34. package/dist/default-provider.js.map +1 -1
  35. package/dist/directory-provider.d.ts +2 -2
  36. package/dist/directory-provider.d.ts.map +1 -1
  37. package/dist/directory-provider.js +13 -10
  38. package/dist/directory-provider.js.map +1 -1
  39. package/dist/directory-view.d.ts +8 -0
  40. package/dist/directory-view.d.ts.map +1 -0
  41. package/dist/{DirectoryView.js → directory-view.js} +18 -12
  42. package/dist/directory-view.js.map +1 -0
  43. package/dist/hooks/index.d.ts +4 -4
  44. package/dist/hooks/index.d.ts.map +1 -1
  45. package/dist/hooks/index.js +3 -3
  46. package/dist/hooks/index.js.map +1 -1
  47. package/dist/hooks/{useContentCommands.d.ts → use-content-commands.d.ts} +2 -2
  48. package/dist/hooks/use-content-commands.d.ts.map +1 -0
  49. package/dist/hooks/{useContentCommands.js → use-content-commands.js} +6 -4
  50. package/dist/hooks/use-content-commands.js.map +1 -0
  51. package/dist/hooks/{useContentLoader.d.ts → use-content-loader.d.ts} +4 -4
  52. package/dist/hooks/use-content-loader.d.ts.map +1 -0
  53. package/dist/hooks/use-content-loader.js +81 -0
  54. package/dist/hooks/use-content-loader.js.map +1 -0
  55. package/dist/hooks/{useViewCommandContext.d.ts → use-view-command-context.d.ts} +3 -3
  56. package/dist/hooks/use-view-command-context.d.ts.map +1 -0
  57. package/dist/hooks/{useViewCommandContext.js → use-view-command-context.js} +15 -13
  58. package/dist/hooks/use-view-command-context.js.map +1 -0
  59. package/dist/index.d.ts +4 -4
  60. package/dist/index.d.ts.map +1 -1
  61. package/dist/index.js +3 -3
  62. package/dist/index.js.map +1 -1
  63. package/dist/launch.d.ts +2 -2
  64. package/dist/launch.d.ts.map +1 -1
  65. package/dist/launch.js +6 -6
  66. package/dist/launch.js.map +1 -1
  67. package/dist/types.d.ts +4 -4
  68. package/dist/types.d.ts.map +1 -1
  69. package/dist/types.js +46 -24
  70. package/dist/types.js.map +1 -1
  71. package/dist/view.d.ts +18 -0
  72. package/dist/view.d.ts.map +1 -0
  73. package/dist/{View.js → view.js} +20 -14
  74. package/dist/view.js.map +1 -0
  75. package/package.json +10 -10
  76. package/src/components/subviews/{CodeSubview.tsx → code-subview.tsx} +25 -19
  77. package/src/components/subviews/{CustomSubview.tsx → custom-subview.tsx} +23 -21
  78. package/src/components/subviews/index.ts +5 -5
  79. package/src/components/subviews/{MarkdownSubview.tsx → markdown-subview.tsx} +55 -52
  80. package/src/components/subviews/table-subview.tsx +95 -0
  81. package/src/components/subviews/types.ts +14 -14
  82. package/src/components/{ViewScreen.tsx → view-screen.tsx} +33 -32
  83. package/src/content-loader-store.ts +131 -99
  84. package/src/default-provider.ts +84 -64
  85. package/src/directory-provider.ts +32 -24
  86. package/src/directory-view.tsx +79 -0
  87. package/src/hooks/index.ts +7 -4
  88. package/src/hooks/{useContentCommands.ts → use-content-commands.ts} +19 -14
  89. package/src/hooks/use-content-loader.ts +92 -0
  90. package/src/hooks/{useViewCommandContext.ts → use-view-command-context.ts} +40 -38
  91. package/src/index.ts +14 -14
  92. package/src/launch.tsx +20 -18
  93. package/src/types.ts +107 -78
  94. package/src/view.tsx +114 -0
  95. package/dist/DirectoryView.d.ts +0 -7
  96. package/dist/DirectoryView.d.ts.map +0 -1
  97. package/dist/DirectoryView.js.map +0 -1
  98. package/dist/View.d.ts +0 -16
  99. package/dist/View.d.ts.map +0 -1
  100. package/dist/View.js.map +0 -1
  101. package/dist/components/ViewScreen.d.ts.map +0 -1
  102. package/dist/components/ViewScreen.js.map +0 -1
  103. package/dist/components/subviews/CodeSubview.d.ts.map +0 -1
  104. package/dist/components/subviews/CodeSubview.js.map +0 -1
  105. package/dist/components/subviews/CustomSubview.d.ts +0 -9
  106. package/dist/components/subviews/CustomSubview.d.ts.map +0 -1
  107. package/dist/components/subviews/CustomSubview.js.map +0 -1
  108. package/dist/components/subviews/MarkdownSubview.d.ts +0 -10
  109. package/dist/components/subviews/MarkdownSubview.d.ts.map +0 -1
  110. package/dist/components/subviews/MarkdownSubview.js.map +0 -1
  111. package/dist/components/subviews/TableSubview.d.ts +0 -8
  112. package/dist/components/subviews/TableSubview.d.ts.map +0 -1
  113. package/dist/components/subviews/TableSubview.js.map +0 -1
  114. package/dist/hooks/useContentCommands.d.ts.map +0 -1
  115. package/dist/hooks/useContentCommands.js.map +0 -1
  116. package/dist/hooks/useContentLoader.d.ts.map +0 -1
  117. package/dist/hooks/useContentLoader.js +0 -55
  118. package/dist/hooks/useContentLoader.js.map +0 -1
  119. package/dist/hooks/useViewCommandContext.d.ts.map +0 -1
  120. package/dist/hooks/useViewCommandContext.js.map +0 -1
  121. package/src/DirectoryView.tsx +0 -68
  122. package/src/View.tsx +0 -94
  123. package/src/components/subviews/TableSubview.tsx +0 -65
  124. package/src/hooks/useContentLoader.ts +0 -72
@@ -1,30 +1,36 @@
1
- import { useMemo } from "react"
2
- import { CodeView, sourceLines, sourceLineAdapter, type SourceLineRow } from "@tooee/renderers"
3
- import { useDocumentController } from "@tooee/shell"
4
- import type { CodeContent, TextContent } from "../../types.js"
5
- import { useContentCommands } from "../../hooks/useContentCommands.js"
6
- import { ViewScreen } from "../ViewScreen.js"
7
- import type { SubviewProps } from "./types.js"
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 function CodeSubview({ content, decorations, actions, ...screen }: CodeSubviewProps) {
14
- const textContent = content.format === "code" ? content.code : content.text
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, type SourceLineRow } from "@tooee/renderers"
3
- import { useDocumentController } from "@tooee/shell"
4
- import { getTextContent, type CustomContent, type ContentRenderer } from "../../types.js"
5
- import { useContentCommands } from "../../hooks/useContentCommands.js"
6
- import { ViewScreen } from "../ViewScreen.js"
7
- import type { SubviewProps } from "./types.js"
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 "./MarkdownSubview.js"
2
- export { CodeSubview } from "./CodeSubview.js"
3
- export { TableSubview } from "./TableSubview.js"
4
- export { CustomSubview } from "./CustomSubview.js"
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
- MarkdownView,
5
- flattenMarkdown,
6
- getFlatBlockText,
7
- type CodeBlockRenderer,
8
- type FlatBlock,
9
- } from "@tooee/renderers"
10
- import { useCommand } from "@tooee/commands"
11
- import { useDocumentController, type DocumentRowAdapter } from "@tooee/shell"
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 !== null
60
- ? hScrollableBlocksRef.current.get(document.activeIndex)
61
- : undefined
57
+ document.activeIndex === null
58
+ ? undefined
59
+ : hScrollableBlocksRef.current.get(document.activeIndex);
62
60
  useCommand({
63
- id: "block-scroll-left",
64
- title: "Scroll block left",
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
- when: () => cursorScrollable() != null,
70
+ title: "Scroll block left",
71
+ when: () => cursorScrollable() !== undefined,
72
+ });
73
+ useCommand({
68
74
  handler: () => {
69
- const target = cursorScrollable()
70
- if (target) target.scrollX -= BLOCK_HSCROLL_STEP
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
- when: () => cursorScrollable() != null,
79
- handler: () => {
80
- const target = cursorScrollable()
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, type DocumentController } from "@tooee/shell"
6
- import { useProvideViewCommandContext } from "../hooks/useViewCommandContext.js"
7
- import type { AnyContent } from "../types.js"
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
- userMarks,
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
- ? { title: content.title, subtitle: content.format }
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, reload }}
72
+ context={{ kind: content.format, reload, title: content.title }}
72
73
  >
73
74
  {children}
74
75
  </DocumentScreen>
75
- )
76
- }
76
+ );
77
+ };