@tooee/view 0.1.11 → 0.1.14

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 (84) hide show
  1. package/dist/DirectoryView.js.map +1 -1
  2. package/dist/View.d.ts.map +1 -1
  3. package/dist/View.js +41 -353
  4. package/dist/View.js.map +1 -1
  5. package/dist/components/SubviewLayout.d.ts +15 -0
  6. package/dist/components/SubviewLayout.d.ts.map +1 -0
  7. package/dist/components/SubviewLayout.js +28 -0
  8. package/dist/components/SubviewLayout.js.map +1 -0
  9. package/dist/components/subviews/CodeSubview.d.ts +8 -0
  10. package/dist/components/subviews/CodeSubview.d.ts.map +1 -0
  11. package/dist/components/subviews/CodeSubview.js +71 -0
  12. package/dist/components/subviews/CodeSubview.js.map +1 -0
  13. package/dist/components/subviews/CustomSubview.d.ts +9 -0
  14. package/dist/components/subviews/CustomSubview.d.ts.map +1 -0
  15. package/dist/components/subviews/CustomSubview.js +87 -0
  16. package/dist/components/subviews/CustomSubview.js.map +1 -0
  17. package/dist/components/subviews/ImageSubview.d.ts +8 -0
  18. package/dist/components/subviews/ImageSubview.d.ts.map +1 -0
  19. package/dist/components/subviews/ImageSubview.js +32 -0
  20. package/dist/components/subviews/ImageSubview.js.map +1 -0
  21. package/dist/components/subviews/MarkdownSubview.d.ts +8 -0
  22. package/dist/components/subviews/MarkdownSubview.d.ts.map +1 -0
  23. package/dist/components/subviews/MarkdownSubview.js +84 -0
  24. package/dist/components/subviews/MarkdownSubview.js.map +1 -0
  25. package/dist/components/subviews/TableSubview.d.ts +8 -0
  26. package/dist/components/subviews/TableSubview.d.ts.map +1 -0
  27. package/dist/components/subviews/TableSubview.js +113 -0
  28. package/dist/components/subviews/TableSubview.js.map +1 -0
  29. package/dist/components/subviews/index.d.ts +8 -0
  30. package/dist/components/subviews/index.d.ts.map +1 -0
  31. package/dist/components/subviews/index.js +7 -0
  32. package/dist/components/subviews/index.js.map +1 -0
  33. package/dist/components/subviews/types.d.ts +15 -0
  34. package/dist/components/subviews/types.d.ts.map +1 -0
  35. package/dist/components/subviews/types.js +2 -0
  36. package/dist/components/subviews/types.js.map +1 -0
  37. package/dist/hooks/index.d.ts +5 -0
  38. package/dist/hooks/index.d.ts.map +1 -0
  39. package/dist/hooks/index.js +5 -0
  40. package/dist/hooks/index.js.map +1 -0
  41. package/dist/hooks/useContentLoader.d.ts +10 -0
  42. package/dist/hooks/useContentLoader.d.ts.map +1 -0
  43. package/dist/hooks/useContentLoader.js +125 -0
  44. package/dist/hooks/useContentLoader.js.map +1 -0
  45. package/dist/hooks/useMarkState.d.ts +13 -0
  46. package/dist/hooks/useMarkState.d.ts.map +1 -0
  47. package/dist/hooks/useMarkState.js +71 -0
  48. package/dist/hooks/useMarkState.js.map +1 -0
  49. package/dist/hooks/useViewCommandContext.d.ts +18 -0
  50. package/dist/hooks/useViewCommandContext.d.ts.map +1 -0
  51. package/dist/hooks/useViewCommandContext.js +24 -0
  52. package/dist/hooks/useViewCommandContext.js.map +1 -0
  53. package/dist/hooks/useViewCommands.d.ts +13 -0
  54. package/dist/hooks/useViewCommands.d.ts.map +1 -0
  55. package/dist/hooks/useViewCommands.js +20 -0
  56. package/dist/hooks/useViewCommands.js.map +1 -0
  57. package/dist/index.d.ts +1 -1
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +1 -1
  60. package/dist/index.js.map +1 -1
  61. package/dist/launch.d.ts.map +1 -1
  62. package/dist/launch.js.map +1 -1
  63. package/dist/types.d.ts +8 -0
  64. package/dist/types.d.ts.map +1 -1
  65. package/dist/types.js.map +1 -1
  66. package/package.json +24 -23
  67. package/src/DirectoryView.tsx +1 -1
  68. package/src/View.tsx +49 -462
  69. package/src/components/SubviewLayout.tsx +57 -0
  70. package/src/components/subviews/CodeSubview.tsx +112 -0
  71. package/src/components/subviews/CustomSubview.tsx +139 -0
  72. package/src/components/subviews/ImageSubview.tsx +64 -0
  73. package/src/components/subviews/MarkdownSubview.tsx +122 -0
  74. package/src/components/subviews/TableSubview.tsx +153 -0
  75. package/src/components/subviews/index.ts +7 -0
  76. package/src/components/subviews/types.ts +15 -0
  77. package/src/hooks/index.ts +4 -0
  78. package/src/hooks/useContentLoader.ts +147 -0
  79. package/src/hooks/useMarkState.ts +99 -0
  80. package/src/hooks/useViewCommandContext.ts +50 -0
  81. package/src/hooks/useViewCommands.ts +36 -0
  82. package/src/index.ts +6 -1
  83. package/src/launch.tsx +1 -6
  84. package/src/types.ts +9 -0
@@ -0,0 +1,112 @@
1
+ import { useEffect, useMemo, useRef } from "react"
2
+ import { CodeView, type RowDocumentRenderable } from "@tooee/renderers"
3
+ import { useTheme } from "@tooee/themes"
4
+ import { useViewCommandContext } from "../../hooks/useViewCommandContext.js"
5
+ import { findMatchingLines, useCopy, useNavigation, useSearch } from "@tooee/shell"
6
+ import type { CodeContent, TextContent } from "../../types.js"
7
+ import { useMarkState } from "../../hooks/useMarkState.js"
8
+ import { useViewCommands } from "../../hooks/useViewCommands.js"
9
+ import { SubviewLayout } from "../SubviewLayout.js"
10
+ import type { SubviewProps } from "./types.js"
11
+
12
+ interface CodeSubviewProps extends SubviewProps {
13
+ content: CodeContent | TextContent
14
+ }
15
+
16
+ export function CodeSubview({
17
+ content,
18
+ providerMarks,
19
+ userMarks,
20
+ setMarkSet,
21
+ clearMarkNamespace,
22
+ clearAllUserMarks,
23
+ reload,
24
+ streaming,
25
+ actions,
26
+ }: CodeSubviewProps) {
27
+ const { theme } = useTheme()
28
+ const docRef = useRef<RowDocumentRenderable>(null)
29
+ const textContent = content.format === "code" ? content.code : content.text
30
+ const lines = useMemo(() => textContent.split("\n"), [textContent])
31
+ const lineCount = lines.length
32
+
33
+ const nav = useNavigation({
34
+ rowCount: lineCount,
35
+ multiSelect: true,
36
+ })
37
+ const search = useSearch({
38
+ match: (query) => findMatchingLines(textContent, query),
39
+ onJump: nav.setCursor,
40
+ })
41
+ useCopy({
42
+ getRowText: (index) => lines[index] ?? "",
43
+ cursor: nav.cursor,
44
+ selection: nav.selection,
45
+ toggledIndices: nav.toggledIndices,
46
+ })
47
+ const layoutNav = { ...nav, ...search }
48
+
49
+ useEffect(() => {
50
+ if (nav.cursor !== null) {
51
+ docRef.current?.scrollToRow(nav.cursor, "nearest")
52
+ }
53
+ }, [nav.cursor])
54
+
55
+ const { themeName, showLineNumbers } = useViewCommands({ content, textContent, actions })
56
+
57
+ const markState = useMarkState({
58
+ nav,
59
+ search,
60
+ theme,
61
+ providerMarks,
62
+ userMarks,
63
+ })
64
+
65
+ useViewCommandContext({
66
+ content,
67
+ nav,
68
+ reload,
69
+ providerMarks,
70
+ userMarks,
71
+ setMarkSet,
72
+ clearMarkNamespace,
73
+ clearAllUserMarks,
74
+ })
75
+
76
+ const text = content.format === "code" ? content.code : content.text
77
+
78
+ const extraStatusItems = useMemo(() => {
79
+ const selectionCount =
80
+ nav.selection != null ? nav.selection.end - nav.selection.start + 1 : 0
81
+ const toggledCount = nav.toggledIndices.size
82
+ const selectionItems =
83
+ toggledCount > 0
84
+ ? [{ label: "Selected:", value: String(toggledCount) }]
85
+ : selectionCount > 0
86
+ ? [{ label: "Selected:", value: String(selectionCount) }]
87
+ : []
88
+ return [
89
+ { label: "Format:", value: content.format },
90
+ { label: "Lines:", value: String(lineCount) },
91
+ ...selectionItems,
92
+ ]
93
+ }, [content.format, lineCount, nav.selection, nav.toggledIndices])
94
+
95
+ return (
96
+ <SubviewLayout
97
+ content={content}
98
+ nav={layoutNav}
99
+ streaming={streaming}
100
+ themeName={themeName}
101
+ extraStatusItems={extraStatusItems}
102
+ >
103
+ <CodeView
104
+ content={text}
105
+ language={content.format === "code" ? content.language : undefined}
106
+ showLineNumbers={showLineNumbers}
107
+ marks={markState}
108
+ docRef={docRef}
109
+ />
110
+ </SubviewLayout>
111
+ )
112
+ }
@@ -0,0 +1,139 @@
1
+ import { useEffect, useMemo, useRef } from "react"
2
+ import { CodeView, type RowDocumentRenderable } from "@tooee/renderers"
3
+ import { useTheme } from "@tooee/themes"
4
+ import { useViewCommandContext } from "../../hooks/useViewCommandContext.js"
5
+ import { findMatchingLines, useCopy, useNavigation, useSearch } from "@tooee/shell"
6
+ import { getTextContent, type CustomContent, type ContentRenderer } from "../../types.js"
7
+ import { useMarkState } from "../../hooks/useMarkState.js"
8
+ import { useViewCommands } from "../../hooks/useViewCommands.js"
9
+ import { SubviewLayout } from "../SubviewLayout.js"
10
+ import type { SubviewProps } from "./types.js"
11
+
12
+ interface CustomSubviewProps extends SubviewProps {
13
+ content: CustomContent
14
+ renderers?: Record<string, ContentRenderer>
15
+ }
16
+
17
+ export function CustomSubview({
18
+ content,
19
+ providerMarks,
20
+ userMarks,
21
+ setMarkSet,
22
+ clearMarkNamespace,
23
+ clearAllUserMarks,
24
+ reload,
25
+ streaming,
26
+ actions,
27
+ renderers,
28
+ }: CustomSubviewProps) {
29
+ const { theme } = useTheme()
30
+ const docRef = useRef<RowDocumentRenderable>(null)
31
+ const textContent = useMemo(() => getTextContent(content), [content])
32
+ const lines = useMemo(() => textContent.split("\n"), [textContent])
33
+ const lineCount = lines.length
34
+
35
+ const nav = useNavigation({
36
+ rowCount: lineCount,
37
+ multiSelect: true,
38
+ })
39
+ const search = useSearch({
40
+ match: (query) => findMatchingLines(textContent, query),
41
+ onJump: nav.setCursor,
42
+ })
43
+ useCopy({
44
+ getRowText: (index) => lines[index] ?? "",
45
+ cursor: nav.cursor,
46
+ selection: nav.selection,
47
+ toggledIndices: nav.toggledIndices,
48
+ })
49
+ const layoutNav = { ...nav, ...search }
50
+
51
+ useEffect(() => {
52
+ if (nav.cursor !== null) {
53
+ docRef.current?.scrollToRow(nav.cursor, "nearest")
54
+ }
55
+ }, [nav.cursor])
56
+
57
+ const { themeName } = useViewCommands({ content, textContent, actions })
58
+
59
+ const markState = useMarkState({
60
+ nav,
61
+ search,
62
+ theme,
63
+ providerMarks,
64
+ userMarks,
65
+ })
66
+
67
+ useViewCommandContext({
68
+ content,
69
+ nav,
70
+ reload,
71
+ providerMarks,
72
+ userMarks,
73
+ setMarkSet,
74
+ clearMarkNamespace,
75
+ clearAllUserMarks,
76
+ })
77
+
78
+ const extraStatusItems = useMemo(() => {
79
+ const selectionCount =
80
+ nav.selection != null ? nav.selection.end - nav.selection.start + 1 : 0
81
+ const toggledCount = nav.toggledIndices.size
82
+ const selectionItems =
83
+ toggledCount > 0
84
+ ? [{ label: "Selected:", value: String(toggledCount) }]
85
+ : selectionCount > 0
86
+ ? [{ label: "Selected:", value: String(selectionCount) }]
87
+ : []
88
+ return [
89
+ { label: "Format:", value: content.format },
90
+ { label: "Lines:", value: String(lineCount) },
91
+ ...selectionItems,
92
+ ]
93
+ }, [content.format, lineCount, nav.selection, nav.toggledIndices])
94
+
95
+ const customRenderer = renderers?.[content.format]
96
+ if (customRenderer) {
97
+ const cursorLine = nav.cursor ?? undefined
98
+ const selectionStart = nav.selection?.start ?? undefined
99
+ const selectionEnd = nav.selection?.end ?? undefined
100
+
101
+ return (
102
+ <SubviewLayout
103
+ content={content}
104
+ nav={layoutNav}
105
+ streaming={streaming}
106
+ themeName={themeName}
107
+ extraStatusItems={extraStatusItems}
108
+ >
109
+ {customRenderer({
110
+ content,
111
+ lineCount,
112
+ cursor: cursorLine,
113
+ selectionStart,
114
+ selectionEnd,
115
+ marks: markState,
116
+ })}
117
+ </SubviewLayout>
118
+ )
119
+ }
120
+
121
+ // No renderer for this custom format -- fall back to text
122
+ const text = getTextContent(content)
123
+ return (
124
+ <SubviewLayout
125
+ content={content}
126
+ nav={layoutNav}
127
+ streaming={streaming}
128
+ themeName={themeName}
129
+ extraStatusItems={extraStatusItems}
130
+ >
131
+ <CodeView
132
+ content={text}
133
+ showLineNumbers={false}
134
+ marks={markState}
135
+ docRef={docRef}
136
+ />
137
+ </SubviewLayout>
138
+ )
139
+ }
@@ -0,0 +1,64 @@
1
+ import { useMemo } from "react"
2
+ import { ImageView } from "@tooee/renderers"
3
+ import { useViewCommandContext } from "../../hooks/useViewCommandContext.js"
4
+ import { useNavigation, useSearch } from "@tooee/shell"
5
+ import type { ImageContent } from "../../types.js"
6
+ import { useViewCommands } from "../../hooks/useViewCommands.js"
7
+ import { SubviewLayout } from "../SubviewLayout.js"
8
+ import type { SubviewProps } from "./types.js"
9
+
10
+ interface ImageSubviewProps extends SubviewProps {
11
+ content: ImageContent
12
+ }
13
+
14
+ export function ImageSubview({
15
+ content,
16
+ providerMarks,
17
+ userMarks,
18
+ setMarkSet,
19
+ clearMarkNamespace,
20
+ clearAllUserMarks,
21
+ reload,
22
+ streaming,
23
+ actions,
24
+ }: ImageSubviewProps) {
25
+ const nav = useNavigation({
26
+ rowCount: 0,
27
+ multiSelect: false,
28
+ })
29
+ const search = useSearch({
30
+ match: () => [],
31
+ onJump: () => {},
32
+ })
33
+ const layoutNav = { ...nav, ...search }
34
+
35
+ const { themeName } = useViewCommands({ content, textContent: content.src, actions })
36
+
37
+ useViewCommandContext({
38
+ content,
39
+ nav,
40
+ reload,
41
+ providerMarks,
42
+ userMarks,
43
+ setMarkSet,
44
+ clearMarkNamespace,
45
+ clearAllUserMarks,
46
+ })
47
+
48
+ const extraStatusItems = useMemo(
49
+ () => [{ label: "Format:", value: content.format }],
50
+ [content.format],
51
+ )
52
+
53
+ return (
54
+ <SubviewLayout
55
+ content={content}
56
+ nav={layoutNav}
57
+ streaming={streaming}
58
+ themeName={themeName}
59
+ extraStatusItems={extraStatusItems}
60
+ >
61
+ <ImageView src={content.src} />
62
+ </SubviewLayout>
63
+ )
64
+ }
@@ -0,0 +1,122 @@
1
+ import { useEffect, useMemo, useRef } from "react"
2
+ import { marked } from "marked"
3
+ import { MarkdownView, flattenTokens, type RowDocumentRenderable } from "@tooee/renderers"
4
+ import { useTheme } from "@tooee/themes"
5
+ import { useViewCommandContext } from "../../hooks/useViewCommandContext.js"
6
+ import { useCopy, useNavigation, useSearch } from "@tooee/shell"
7
+ import type { MarkdownContent } from "../../types.js"
8
+ import { useMarkState } from "../../hooks/useMarkState.js"
9
+ import { useViewCommands } from "../../hooks/useViewCommands.js"
10
+ import { SubviewLayout } from "../SubviewLayout.js"
11
+ import type { SubviewProps } from "./types.js"
12
+
13
+ interface MarkdownSubviewProps extends SubviewProps {
14
+ content: MarkdownContent
15
+ }
16
+
17
+ export function MarkdownSubview({
18
+ content,
19
+ providerMarks,
20
+ userMarks,
21
+ setMarkSet,
22
+ clearMarkNamespace,
23
+ clearAllUserMarks,
24
+ reload,
25
+ streaming,
26
+ actions,
27
+ }: MarkdownSubviewProps) {
28
+ const { theme } = useTheme()
29
+ const docRef = useRef<RowDocumentRenderable>(null)
30
+ const textContent = content.markdown
31
+ const lineCount = useMemo(() => textContent.split("\n").length, [textContent])
32
+ const blocks = useMemo(() => flattenTokens(marked.lexer(content.markdown)), [content.markdown])
33
+
34
+ const nav = useNavigation({
35
+ rowCount: blocks.length,
36
+ multiSelect: true,
37
+ })
38
+ const search = useSearch({
39
+ match: (query) => {
40
+ const lowerQuery = query.toLowerCase()
41
+ return blocks.flatMap((block, index) => {
42
+ const { token } = block
43
+ const raw = "raw" in token && typeof token.raw === "string" ? token.raw : ""
44
+ return raw.toLowerCase().includes(lowerQuery) ? [index] : []
45
+ })
46
+ },
47
+ onJump: nav.setCursor,
48
+ })
49
+ useCopy({
50
+ getRowText: (index) => {
51
+ const block = blocks[index]
52
+ if (!block) return ""
53
+ const { token } = block
54
+ return "raw" in token && typeof token.raw === "string" ? token.raw : ""
55
+ },
56
+ cursor: nav.cursor,
57
+ selection: nav.selection,
58
+ toggledIndices: nav.toggledIndices,
59
+ })
60
+ const layoutNav = { ...nav, ...search }
61
+
62
+ useEffect(() => {
63
+ if (nav.cursor !== null) {
64
+ docRef.current?.scrollToRow(nav.cursor, "nearest")
65
+ }
66
+ }, [nav.cursor])
67
+
68
+ const { themeName, showLineNumbers } = useViewCommands({ content, textContent, actions })
69
+
70
+ const markState = useMarkState({
71
+ nav,
72
+ search,
73
+ theme,
74
+ providerMarks,
75
+ userMarks,
76
+ })
77
+
78
+ useViewCommandContext({
79
+ content,
80
+ nav,
81
+ reload,
82
+ providerMarks,
83
+ userMarks,
84
+ setMarkSet,
85
+ clearMarkNamespace,
86
+ clearAllUserMarks,
87
+ })
88
+
89
+ const extraStatusItems = useMemo(() => {
90
+ const selectionCount =
91
+ nav.selection != null ? nav.selection.end - nav.selection.start + 1 : 0
92
+ const toggledCount = nav.toggledIndices.size
93
+ const selectionItems =
94
+ toggledCount > 0
95
+ ? [{ label: "Selected:", value: String(toggledCount) }]
96
+ : selectionCount > 0
97
+ ? [{ label: "Selected:", value: String(selectionCount) }]
98
+ : []
99
+ return [
100
+ { label: "Format:", value: content.format },
101
+ { label: "Lines:", value: String(lineCount) },
102
+ ...selectionItems,
103
+ ]
104
+ }, [content.format, lineCount, nav.selection, nav.toggledIndices])
105
+
106
+ return (
107
+ <SubviewLayout
108
+ content={content}
109
+ nav={layoutNav}
110
+ streaming={streaming}
111
+ themeName={themeName}
112
+ extraStatusItems={extraStatusItems}
113
+ >
114
+ <MarkdownView
115
+ content={content.markdown}
116
+ showLineNumbers={showLineNumbers}
117
+ marks={markState}
118
+ docRef={docRef}
119
+ />
120
+ </SubviewLayout>
121
+ )
122
+ }
@@ -0,0 +1,153 @@
1
+ import { useEffect, useMemo, useRef } from "react"
2
+ import { Table, type RowDocumentRenderable } from "@tooee/renderers"
3
+ import { useTheme } from "@tooee/themes"
4
+ import { useViewCommandContext } from "../../hooks/useViewCommandContext.js"
5
+ import { useCopy, useNavigation, useSearch } from "@tooee/shell"
6
+ import { getTextContent, type TableContent } from "../../types.js"
7
+ import { useMarkState } from "../../hooks/useMarkState.js"
8
+ import { useViewCommands } from "../../hooks/useViewCommands.js"
9
+ import { SubviewLayout } from "../SubviewLayout.js"
10
+ import type { SubviewProps } from "./types.js"
11
+
12
+ interface TableSubviewProps extends SubviewProps {
13
+ content: TableContent
14
+ }
15
+
16
+ export function TableSubview({
17
+ content,
18
+ providerMarks,
19
+ userMarks,
20
+ setMarkSet,
21
+ clearMarkNamespace,
22
+ clearAllUserMarks,
23
+ reload,
24
+ streaming,
25
+ actions,
26
+ }: TableSubviewProps) {
27
+ const { theme } = useTheme()
28
+ const docRef = useRef<RowDocumentRenderable>(null)
29
+ const textContent = useMemo(() => getTextContent(content), [content])
30
+
31
+ const nav = useNavigation({
32
+ rowCount: content.rows.length,
33
+ multiSelect: true,
34
+ })
35
+ const search = useSearch({
36
+ match: (query) => {
37
+ const lowerQuery = query.toLowerCase()
38
+ return content.rows.flatMap((row, index) =>
39
+ content.columns.some((column) => stringifyRowCell(row[column.key]).toLowerCase().includes(lowerQuery))
40
+ ? [index]
41
+ : [],
42
+ )
43
+ },
44
+ onJump: nav.setCursor,
45
+ })
46
+ useCopy({
47
+ getRowText: (index) =>
48
+ content.columns
49
+ .map((column) => stringifyRowCell(content.rows[index]?.[column.key]))
50
+ .join("\t"),
51
+ cursor: nav.cursor,
52
+ selection: nav.selection,
53
+ toggledIndices: nav.toggledIndices,
54
+ })
55
+ const layoutNav = { ...nav, ...search }
56
+
57
+ useEffect(() => {
58
+ if (nav.cursor !== null) {
59
+ docRef.current?.scrollToRow(nav.cursor, "nearest")
60
+ }
61
+ }, [nav.cursor])
62
+
63
+ const { themeName, showLineNumbers } = useViewCommands({ content, textContent, actions })
64
+
65
+ const markState = useMarkState({
66
+ nav,
67
+ search,
68
+ theme,
69
+ providerMarks,
70
+ userMarks,
71
+ })
72
+
73
+ function getActiveRow(): Record<string, unknown> | undefined {
74
+ if (nav.cursor === null) return undefined
75
+ return content.rows[nav.cursor]
76
+ }
77
+
78
+ function getSelectedRows(): Record<string, unknown>[] {
79
+ if (nav.toggledIndices.size) {
80
+ return Array.from(nav.toggledIndices)
81
+ .map((i) => content.rows[i])
82
+ .filter(Boolean)
83
+ }
84
+ if (nav.selection) {
85
+ const start = nav.selection.start
86
+ const end = nav.selection.end
87
+ return content.rows.slice(start, end + 1)
88
+ }
89
+ return []
90
+ }
91
+
92
+ useViewCommandContext({
93
+ content,
94
+ nav,
95
+ reload,
96
+ providerMarks,
97
+ userMarks,
98
+ setMarkSet,
99
+ clearMarkNamespace,
100
+ clearAllUserMarks,
101
+ extras: {
102
+ activeRow: getActiveRow(),
103
+ selectedRows: getSelectedRows(),
104
+ },
105
+ })
106
+
107
+ const extraStatusItems = useMemo(() => {
108
+ const selectionCount =
109
+ nav.selection != null ? nav.selection.end - nav.selection.start + 1 : 0
110
+ const toggledCount = nav.toggledIndices.size
111
+ const selectionItems =
112
+ toggledCount > 0
113
+ ? [{ label: "Selected:", value: String(toggledCount) }]
114
+ : selectionCount > 0
115
+ ? [{ label: "Selected:", value: String(selectionCount) }]
116
+ : []
117
+ return [
118
+ { label: "Format:", value: content.format },
119
+ { label: "Rows:", value: String(content.rows.length) },
120
+ { label: "Cols:", value: String(content.columns.length) },
121
+ ...selectionItems,
122
+ ]
123
+ }, [content.format, content.rows.length, content.columns.length, nav.selection, nav.toggledIndices])
124
+
125
+ return (
126
+ <SubviewLayout
127
+ content={content}
128
+ nav={layoutNav}
129
+ streaming={streaming}
130
+ themeName={themeName}
131
+ extraStatusItems={extraStatusItems}
132
+ >
133
+ <Table
134
+ columns={content.columns}
135
+ rows={content.rows}
136
+ showLineNumbers={showLineNumbers}
137
+ marks={markState}
138
+ docRef={docRef}
139
+ />
140
+ </SubviewLayout>
141
+ )
142
+ }
143
+
144
+ function stringifyRowCell(value: unknown): string {
145
+ if (value == null) return ""
146
+ if (typeof value === "string") return value
147
+ if (typeof value === "number" || typeof value === "boolean") return String(value)
148
+ try {
149
+ return JSON.stringify(value)
150
+ } catch {
151
+ return String(value)
152
+ }
153
+ }
@@ -0,0 +1,7 @@
1
+ export { MarkdownSubview } from "./MarkdownSubview.js"
2
+ export { CodeSubview } from "./CodeSubview.js"
3
+ export { TableSubview } from "./TableSubview.js"
4
+ export { ImageSubview } from "./ImageSubview.js"
5
+ export { CustomSubview } from "./CustomSubview.js"
6
+ export { SubviewLayout } from "../SubviewLayout.js"
7
+ export type { SubviewProps } from "./types.js"
@@ -0,0 +1,15 @@
1
+ import type { MarkSet } from "@tooee/marks"
2
+ import type { ActionDefinition } from "@tooee/commands"
3
+ import type { AnyContent } from "../../types.js"
4
+
5
+ export interface SubviewProps {
6
+ content: AnyContent
7
+ providerMarks: MarkSet[]
8
+ userMarks: MarkSet[]
9
+ setMarkSet: (set: MarkSet) => void
10
+ clearMarkNamespace: (namespace: string) => void
11
+ clearAllUserMarks: () => void
12
+ reload: () => void
13
+ streaming: boolean
14
+ actions?: ActionDefinition[]
15
+ }
@@ -0,0 +1,4 @@
1
+ export { useContentLoader } from "./useContentLoader.js"
2
+ export { useMarkState } from "./useMarkState.js"
3
+ export { useViewCommands } from "./useViewCommands.js"
4
+ export { useViewCommandContext } from "./useViewCommandContext.js"