@tooee/view 0.1.21 → 0.2.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 (83) hide show
  1. package/README.md +83 -0
  2. package/dist/View.d.ts.map +1 -1
  3. package/dist/View.js +5 -1
  4. package/dist/View.js.map +1 -1
  5. package/dist/components/ViewScreen.d.ts +28 -0
  6. package/dist/components/ViewScreen.d.ts.map +1 -0
  7. package/dist/components/ViewScreen.js +29 -0
  8. package/dist/components/ViewScreen.js.map +1 -0
  9. package/dist/components/subviews/CodeSubview.d.ts +1 -1
  10. package/dist/components/subviews/CodeSubview.d.ts.map +1 -1
  11. package/dist/components/subviews/CodeSubview.js +20 -91
  12. package/dist/components/subviews/CodeSubview.js.map +1 -1
  13. package/dist/components/subviews/CustomSubview.d.ts +1 -1
  14. package/dist/components/subviews/CustomSubview.d.ts.map +1 -1
  15. package/dist/components/subviews/CustomSubview.js +19 -94
  16. package/dist/components/subviews/CustomSubview.js.map +1 -1
  17. package/dist/components/subviews/MarkdownSubview.d.ts +1 -1
  18. package/dist/components/subviews/MarkdownSubview.d.ts.map +1 -1
  19. package/dist/components/subviews/MarkdownSubview.js +32 -108
  20. package/dist/components/subviews/MarkdownSubview.js.map +1 -1
  21. package/dist/components/subviews/TableSubview.d.ts +1 -1
  22. package/dist/components/subviews/TableSubview.d.ts.map +1 -1
  23. package/dist/components/subviews/TableSubview.js +22 -125
  24. package/dist/components/subviews/TableSubview.js.map +1 -1
  25. package/dist/components/subviews/index.d.ts +0 -1
  26. package/dist/components/subviews/index.d.ts.map +1 -1
  27. package/dist/components/subviews/index.js +0 -1
  28. package/dist/components/subviews/index.js.map +1 -1
  29. package/dist/components/subviews/types.d.ts +6 -0
  30. package/dist/components/subviews/types.d.ts.map +1 -1
  31. package/dist/default-provider.d.ts +6 -3
  32. package/dist/default-provider.d.ts.map +1 -1
  33. package/dist/default-provider.js +24 -34
  34. package/dist/default-provider.js.map +1 -1
  35. package/dist/hooks/index.d.ts +3 -3
  36. package/dist/hooks/index.d.ts.map +1 -1
  37. package/dist/hooks/index.js +2 -3
  38. package/dist/hooks/index.js.map +1 -1
  39. package/dist/hooks/useContentCommands.d.ts +15 -0
  40. package/dist/hooks/useContentCommands.d.ts.map +1 -0
  41. package/dist/hooks/useContentCommands.js +21 -0
  42. package/dist/hooks/useContentCommands.js.map +1 -0
  43. package/dist/hooks/useViewCommandContext.d.ts +24 -25
  44. package/dist/hooks/useViewCommandContext.d.ts.map +1 -1
  45. package/dist/hooks/useViewCommandContext.js +26 -21
  46. package/dist/hooks/useViewCommandContext.js.map +1 -1
  47. package/dist/index.d.ts +3 -0
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +1 -0
  50. package/dist/index.js.map +1 -1
  51. package/dist/types.d.ts +15 -16
  52. package/dist/types.d.ts.map +1 -1
  53. package/dist/types.js.map +1 -1
  54. package/package.json +14 -14
  55. package/src/View.tsx +6 -1
  56. package/src/components/ViewScreen.tsx +76 -0
  57. package/src/components/subviews/CodeSubview.tsx +30 -126
  58. package/src/components/subviews/CustomSubview.tsx +32 -123
  59. package/src/components/subviews/MarkdownSubview.tsx +49 -137
  60. package/src/components/subviews/TableSubview.tsx +36 -170
  61. package/src/components/subviews/index.ts +0 -1
  62. package/src/components/subviews/types.ts +6 -0
  63. package/src/default-provider.ts +37 -34
  64. package/src/hooks/index.ts +7 -3
  65. package/src/hooks/useContentCommands.ts +29 -0
  66. package/src/hooks/useViewCommandContext.ts +62 -49
  67. package/src/index.ts +10 -0
  68. package/src/types.ts +15 -16
  69. package/dist/components/SubviewLayout.d.ts +0 -16
  70. package/dist/components/SubviewLayout.d.ts.map +0 -1
  71. package/dist/components/SubviewLayout.js +0 -18
  72. package/dist/components/SubviewLayout.js.map +0 -1
  73. package/dist/hooks/useMarkState.d.ts +0 -14
  74. package/dist/hooks/useMarkState.d.ts.map +0 -1
  75. package/dist/hooks/useMarkState.js +0 -71
  76. package/dist/hooks/useMarkState.js.map +0 -1
  77. package/dist/hooks/useViewCommands.d.ts +0 -13
  78. package/dist/hooks/useViewCommands.d.ts.map +0 -1
  79. package/dist/hooks/useViewCommands.js +0 -20
  80. package/dist/hooks/useViewCommands.js.map +0 -1
  81. package/src/components/SubviewLayout.tsx +0 -48
  82. package/src/hooks/useMarkState.ts +0 -100
  83. package/src/hooks/useViewCommands.ts +0 -36
@@ -1,6 +1,10 @@
1
1
  import { parseAuto } from "@tooee/renderers"
2
2
  import type { Content, ContentFormat, ContentProvider } from "./types.js"
3
3
 
4
+ export interface CreateProviderOptions {
5
+ renderer?: ContentFormat
6
+ }
7
+
4
8
  function detectFormat(filePath: string): { format: ContentFormat; language?: string } {
5
9
  const ext = filePath.split(".").pop()?.toLowerCase()
6
10
  if (!ext) return { format: "text" }
@@ -45,59 +49,58 @@ function detectFormat(filePath: string): { format: ContentFormat; language?: str
45
49
  return { format: "text" }
46
50
  }
47
51
 
48
- export function createFileProvider(filePath: string): ContentProvider {
52
+ function contentFromText(
53
+ text: string,
54
+ format: ContentFormat,
55
+ title: string | undefined,
56
+ language?: string,
57
+ ): Content {
58
+ switch (format) {
59
+ case "markdown":
60
+ return { format: "markdown", markdown: text, title }
61
+ case "code":
62
+ return { format: "code", code: text, language, title }
63
+ case "table": {
64
+ const parsed = parseAuto(text)
65
+ return { format: "table", columns: parsed.columns, rows: parsed.rows, title }
66
+ }
67
+ case "text":
68
+ default:
69
+ return { format: "text", text, title }
70
+ }
71
+ }
72
+
73
+ export function createFileProvider(
74
+ filePath: string,
75
+ options: CreateProviderOptions = {},
76
+ ): ContentProvider {
49
77
  return {
50
78
  async load(): Promise<Content> {
51
- const { format, language } = detectFormat(filePath)
79
+ const detected = detectFormat(filePath)
80
+ const format = options.renderer ?? detected.format
52
81
  const title = filePath.split("/").pop()
53
82
 
54
83
  const file = Bun.file(filePath)
55
- if (format === "table") {
56
- const text = await file.text()
57
- const parsed = parseAuto(text)
58
- return { format: "table", columns: parsed.columns, rows: parsed.rows, title }
59
- }
60
84
  const text = await file.text()
61
- switch (format) {
62
- case "markdown":
63
- return { format: "markdown", markdown: text, title }
64
- case "code":
65
- return { format: "code", code: text, language, title }
66
- case "text":
67
- default:
68
- return { format: "text", text, title }
69
- }
85
+ return contentFromText(text, format, title, detected.language)
70
86
  },
71
87
  }
72
88
  }
73
89
 
74
- export function createStdinProvider(): ContentProvider {
90
+ export function createStdinProvider(options: CreateProviderOptions = {}): ContentProvider {
75
91
  return {
76
92
  async load(): Promise<Content> {
77
93
  const text = await new Response(Bun.stdin.stream() as unknown as ReadableStream).text()
78
- return { format: "markdown", markdown: text, title: "stdin" }
94
+ const format = options.renderer ?? "markdown"
95
+ return contentFromText(text, format, "stdin")
79
96
  },
80
97
  }
81
98
  }
82
99
 
83
100
  export function createTableFileProvider(filePath: string): ContentProvider {
84
- return {
85
- async load(): Promise<Content> {
86
- const title = filePath.split("/").pop()
87
- const file = Bun.file(filePath)
88
- const text = await file.text()
89
- const parsed = parseAuto(text)
90
- return { format: "table", columns: parsed.columns, rows: parsed.rows, title }
91
- },
92
- }
101
+ return createFileProvider(filePath, { renderer: "table" })
93
102
  }
94
103
 
95
104
  export function createTableStdinProvider(): ContentProvider {
96
- return {
97
- async load(): Promise<Content> {
98
- const text = await new Response(Bun.stdin.stream() as unknown as ReadableStream).text()
99
- const parsed = parseAuto(text)
100
- return { format: "table", columns: parsed.columns, rows: parsed.rows, title: "stdin" }
101
- },
102
- }
105
+ return createStdinProvider({ renderer: "table" })
103
106
  }
@@ -1,4 +1,8 @@
1
1
  export { useContentLoader } from "./useContentLoader.js"
2
- export { useMarkState } from "./useMarkState.js"
3
- export { useViewCommands } from "./useViewCommands.js"
4
- export { useViewCommandContext } from "./useViewCommandContext.js"
2
+ export { useContentCommands } from "./useContentCommands.js"
3
+ export { createViewCommandContext, useProvideViewCommandContext } from "./useViewCommandContext.js"
4
+ export type {
5
+ CreateViewCommandContextOptions,
6
+ ProvideViewCommandContextOptions,
7
+ ViewCommandContext,
8
+ } from "./useViewCommandContext.js"
@@ -0,0 +1,29 @@
1
+ import { useState } from "react"
2
+ import { useCopyCommand, useToggleLineNumbersCommand } from "@tooee/shell"
3
+ import { useConfig } from "@tooee/config"
4
+ import type { AnyContent } from "../types.js"
5
+
6
+ interface UseContentCommandsParams {
7
+ content: AnyContent | null
8
+ textContent: string
9
+ }
10
+
11
+ /**
12
+ * The commands a content viewer owns on top of `DocumentScreen`: copying the
13
+ * whole document and toggling the line-number gutter. Theme, quit, actions and
14
+ * every row-level command belong to the document controller and its screen.
15
+ */
16
+ export function useContentCommands({ content, textContent }: UseContentCommandsParams) {
17
+ const config = useConfig()
18
+ const [showLineNumbers, setShowLineNumbers] = useState(config.view?.gutter ?? true)
19
+
20
+ useCopyCommand({
21
+ getText: () => (content ? textContent : undefined),
22
+ })
23
+ useToggleLineNumbersCommand({
24
+ showLineNumbers,
25
+ onToggle: () => setShowLineNumbers((v) => !v),
26
+ })
27
+
28
+ return { showLineNumbers }
29
+ }
@@ -1,17 +1,20 @@
1
- import { useProvideCommandContext, useMode } from "@tooee/commands"
2
- import type { Mode } from "@tooee/commands"
3
- import type { NavigationState } from "@tooee/shell"
1
+ import { useProvideCommandContextKey } from "@tooee/commands"
4
2
  import type { MarkSet } from "@tooee/marks"
5
3
  import type { AnyContent } from "../types.js"
6
4
 
7
- /** The `view` field contributed to the command context (see augmentation below). */
5
+ /**
6
+ * The `view` field contributed to the command context (see augmentation below).
7
+ *
8
+ * This slice is content-only. Row state — cursor, selection, active and
9
+ * selected rows — is generic to every row document and lives on `ctx.document`,
10
+ * which `DocumentScreen` provides alongside this.
11
+ */
8
12
  export interface ViewCommandContext {
9
13
  content: AnyContent
10
14
  format: string
11
- cursor: number | null
12
- selection: { start: number; end: number } | null
13
- mode: Mode
14
- toggledIndices: Set<number>
15
+ title?: string
16
+ data?: unknown
17
+ /** Reload the content from its provider. */
15
18
  reload: () => void
16
19
  marks: {
17
20
  setMarkSet: (set: MarkSet) => void
@@ -20,8 +23,6 @@ export interface ViewCommandContext {
20
23
  userMarks: MarkSet[]
21
24
  providerMarks: MarkSet[]
22
25
  }
23
- /** Subview extras (e.g. activeRow/selectedRows for tables). */
24
- [key: string]: unknown
25
26
  }
26
27
 
27
28
  declare module "@tooee/commands" {
@@ -30,48 +31,60 @@ declare module "@tooee/commands" {
30
31
  }
31
32
  }
32
33
 
33
- interface UseViewCommandContextParams {
34
- content: AnyContent
35
- nav: NavigationState
36
- reload: () => void
37
- providerMarks: MarkSet[]
38
- userMarks: MarkSet[]
39
- setMarkSet: (set: MarkSet) => void
40
- clearMarkNamespace: (namespace: string) => void
41
- clearAllUserMarks: () => void
42
- /** Extra fields merged into the view context (e.g. activeRow, selectedRows for table) */
43
- extras?: Record<string, unknown>
34
+ const noop = () => {}
35
+
36
+ export interface CreateViewCommandContextOptions {
37
+ /**
38
+ * Content represented by this command context. Custom/headless surfaces may
39
+ * omit it; the builder will synthesize a minimal custom content object.
40
+ */
41
+ content?: AnyContent
42
+ format?: string
43
+ title?: string
44
+ data?: unknown
45
+ reload?: () => void
46
+ marks?: Partial<ViewCommandContext["marks"]>
44
47
  }
45
48
 
46
- export function useViewCommandContext({
49
+ export type ProvideViewCommandContextOptions = CreateViewCommandContextOptions
50
+
51
+ export function createViewCommandContext({
47
52
  content,
48
- nav,
53
+ format,
54
+ title,
55
+ data,
49
56
  reload,
50
- providerMarks,
51
- userMarks,
52
- setMarkSet,
53
- clearMarkNamespace,
54
- clearAllUserMarks,
55
- extras,
56
- }: UseViewCommandContextParams) {
57
- const mode = useMode()
58
- useProvideCommandContext(() => ({
59
- view: {
60
- content,
61
- format: content.format,
62
- cursor: nav.cursor,
63
- selection: nav.selection,
64
- mode,
65
- toggledIndices: nav.toggledIndices,
66
- reload,
67
- marks: {
68
- setMarkSet,
69
- clearNamespace: clearMarkNamespace,
70
- clearAll: clearAllUserMarks,
71
- userMarks,
72
- providerMarks,
73
- },
74
- ...extras,
57
+ marks,
58
+ }: CreateViewCommandContextOptions): ViewCommandContext {
59
+ const resolvedFormat = format ?? content?.format ?? "custom"
60
+ const resolvedContent: AnyContent =
61
+ content ??
62
+ ({
63
+ format: resolvedFormat,
64
+ data,
65
+ title,
66
+ } satisfies AnyContent)
67
+
68
+ return {
69
+ content: resolvedContent,
70
+ format: resolvedFormat,
71
+ title: title ?? content?.title,
72
+ data: data ?? ("data" in resolvedContent ? resolvedContent.data : undefined),
73
+ reload: reload ?? noop,
74
+ marks: {
75
+ setMarkSet: marks?.setMarkSet ?? noop,
76
+ clearNamespace: marks?.clearNamespace ?? noop,
77
+ clearAll: marks?.clearAll ?? noop,
78
+ userMarks: marks?.userMarks ?? [],
79
+ providerMarks: marks?.providerMarks ?? [],
75
80
  },
76
- }))
81
+ }
82
+ }
83
+
84
+ export function useProvideViewCommandContext(
85
+ options: ProvideViewCommandContextOptions | (() => ProvideViewCommandContextOptions),
86
+ ) {
87
+ useProvideCommandContextKey("view", () =>
88
+ createViewCommandContext(typeof options === "function" ? options() : options),
89
+ )
77
90
  }
package/src/index.ts CHANGED
@@ -8,8 +8,18 @@ export {
8
8
  createTableFileProvider,
9
9
  createTableStdinProvider,
10
10
  } from "./default-provider.js"
11
+ export type { CreateProviderOptions } from "./default-provider.js"
11
12
  export { listDirectoryFiles } from "./directory-provider.js"
12
13
  export type { DirectoryEntry } from "./directory-provider.js"
14
+ export {
15
+ createViewCommandContext,
16
+ useProvideViewCommandContext,
17
+ } from "./hooks/useViewCommandContext.js"
18
+ export type {
19
+ CreateViewCommandContextOptions,
20
+ ProvideViewCommandContextOptions,
21
+ ViewCommandContext,
22
+ } from "./hooks/useViewCommandContext.js"
13
23
  export type {
14
24
  AnyContent,
15
25
  Content,
package/src/types.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { ReactNode } from "react"
2
- import type { ColumnDef, TableRow } from "@tooee/renderers"
3
- import type { MarkSet, MarkState } from "@tooee/marks"
2
+ import type { ColumnDef, SourceLineRow, TableRow } from "@tooee/renderers"
3
+ import type { DocumentController } from "@tooee/shell"
4
+ import type { MarkSet } from "@tooee/marks"
4
5
 
5
6
  // === Built-in content types ===
6
7
 
@@ -51,22 +52,20 @@ export type AnyContent = Content | CustomContent
51
52
 
52
53
  export interface ContentRendererProps {
53
54
  content: CustomContent
54
- lineCount: number
55
- cursor?: number
56
- selectionStart?: number
57
- selectionEnd?: number
58
- /** Combined mark state (nav + provider + user marks) */
59
- marks?: MarkState
60
55
  /**
61
- * Select a row by index — the mouse equivalent of the keyboard cursor move.
62
- * A custom renderer that has a notion of rows should call this from its own
63
- * `onMouseDown`/`onRowClick` handlers to make left-click select a row, the
64
- * same way the built-in code/markdown/table views do. Selection is a no-op
65
- * while a modal overlay is open (the host guards it), so renderers can wire
66
- * it unconditionally. Renderers that own a `RowDocumentRenderable` can map a
67
- * click's screen-Y to a row via its `getRowAtScreenY(event.y)` helper.
56
+ * The host's document controller. Its rows are the content's source lines
57
+ * (`SourceLineRow`), which is also the unit navigation, search and copy work
58
+ * in; `row.text` is the plain-text line and `row.source` its provenance.
59
+ *
60
+ * A renderer that owns a `<row-document>` binds the controller directly — it
61
+ * satisfies `DocumentBindings`, so `ref`, `decorations` and `onMouseDown`
62
+ * spread onto the element the way the built-in views wire them. A renderer
63
+ * with its own markup reads `activeIndex` and `navigation.selection` for
64
+ * cursor state and calls `selectRow(index)` from its mouse handlers;
65
+ * `selectRow` stands down while a modal overlay is open, so it can be wired
66
+ * unconditionally.
68
67
  */
69
- onSelectRow?: (index: number) => void
68
+ document: DocumentController<SourceLineRow>
70
69
  }
71
70
 
72
71
  export type ContentRenderer = (props: ContentRendererProps) => ReactNode
@@ -1,16 +0,0 @@
1
- import type { ReactNode } from "react";
2
- import { type StatusBarItem } from "@tooee/layout";
3
- import type { NavigationState } from "@tooee/shell";
4
- import type { SearchState } from "@tooee/search";
5
- import type { AnyContent } from "../types.js";
6
- interface SubviewLayoutProps {
7
- content: AnyContent;
8
- nav: NavigationState & SearchState;
9
- streaming: boolean;
10
- themeName: string;
11
- extraStatusItems?: StatusBarItem[];
12
- children: ReactNode;
13
- }
14
- export declare function SubviewLayout({ content, nav, streaming, themeName, extraStatusItems, children, }: SubviewLayoutProps): ReactNode;
15
- export {};
16
- //# sourceMappingURL=SubviewLayout.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SubviewLayout.d.ts","sourceRoot":"","sources":["../../src/components/SubviewLayout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,EAAa,KAAK,aAAa,EAAE,MAAM,eAAe,CAAA;AAE7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAE7C,UAAU,kBAAkB;IAC1B,OAAO,EAAE,UAAU,CAAA;IACnB,GAAG,EAAE,eAAe,GAAG,WAAW,CAAA;IAClC,SAAS,EAAE,OAAO,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,gBAAgB,CAAC,EAAE,aAAa,EAAE,CAAA;IAClC,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,GAAG,EACH,SAAS,EACT,SAAS,EACT,gBAAgB,EAChB,QAAQ,GACT,EAAE,kBAAkB,aAwBpB"}
@@ -1,18 +0,0 @@
1
- import { jsx as _jsx } from "@opentui/react/jsx-runtime";
2
- import { AppLayout } from "@tooee/layout";
3
- import { useMode } from "@tooee/commands";
4
- export function SubviewLayout({ content, nav, streaming, themeName, extraStatusItems, children, }) {
5
- const mode = useMode();
6
- const statusItems = [
7
- { label: "Theme:", value: themeName },
8
- ...(extraStatusItems ?? []),
9
- { label: "Mode:", value: mode },
10
- { label: "Cursor:", value: nav.cursor !== null ? String(nav.cursor) : "-" },
11
- ...(streaming ? [{ label: "Status:", value: "streaming" }] : []),
12
- ...(nav.searchActive ? [{ label: "Search:", value: nav.searchQuery }] : []),
13
- ];
14
- return (_jsx(AppLayout, { titleBar: content.title
15
- ? { title: content.title, subtitle: content.format }
16
- : { title: content.format }, statusBar: { items: statusItems }, searchBar: nav, children: children }));
17
- }
18
- //# sourceMappingURL=SubviewLayout.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SubviewLayout.js","sourceRoot":"","sources":["../../src/components/SubviewLayout.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAsB,MAAM,eAAe,CAAA;AAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAczC,MAAM,UAAU,aAAa,CAAC,EAC5B,OAAO,EACP,GAAG,EACH,SAAS,EACT,SAAS,EACT,gBAAgB,EAChB,QAAQ,GACW;IACnB,MAAM,IAAI,GAAG,OAAO,EAAE,CAAA;IACtB,MAAM,WAAW,GAAG;QAClB,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE;QACrC,GAAG,CAAC,gBAAgB,IAAI,EAAE,CAAC;QAC3B,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE;QAC/B,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;QAC3E,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5E,CAAA;IAED,OAAO,CACL,KAAC,SAAS,IACR,QAAQ,EACN,OAAO,CAAC,KAAK;YACX,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,MAAM,EAAE;YACpD,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,EAE/B,SAAS,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,EACjC,SAAS,EAAE,GAAG,YAEb,QAAQ,GACC,CACb,CAAA;AACH,CAAC"}
@@ -1,14 +0,0 @@
1
- import type { MarkSet, MarkState } from "@tooee/marks";
2
- import type { NavigationState } from "@tooee/shell";
3
- import type { SearchState } from "@tooee/search";
4
- import type { ResolvedTheme } from "@tooee/themes";
5
- interface UseMarkStateParams {
6
- nav: Pick<NavigationState, "cursor" | "selection" | "toggledIndices">;
7
- search: Pick<SearchState, "matchingLines" | "currentMatchIndex">;
8
- theme: ResolvedTheme;
9
- providerMarks: MarkSet[];
10
- userMarks: MarkSet[];
11
- }
12
- export declare function useMarkState({ nav, search, theme, providerMarks, userMarks, }: UseMarkStateParams): MarkState | undefined;
13
- export {};
14
- //# sourceMappingURL=useMarkState.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useMarkState.d.ts","sourceRoot":"","sources":["../../src/hooks/useMarkState.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAElD,UAAU,kBAAkB;IAC1B,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,QAAQ,GAAG,WAAW,GAAG,gBAAgB,CAAC,CAAA;IACrE,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,eAAe,GAAG,mBAAmB,CAAC,CAAA;IAChE,KAAK,EAAE,aAAa,CAAA;IACpB,aAAa,EAAE,OAAO,EAAE,CAAA;IACxB,SAAS,EAAE,OAAO,EAAE,CAAA;CACrB;AAED,wBAAgB,YAAY,CAAC,EAC3B,GAAG,EACH,MAAM,EACN,KAAK,EACL,aAAa,EACb,SAAS,GACV,EAAE,kBAAkB,GAAG,SAAS,GAAG,SAAS,CA8E5C"}
@@ -1,71 +0,0 @@
1
- import { useMemo } from "react";
2
- import { MarkSetBuilder, createMarkState, MarkPriorities } from "@tooee/marks";
3
- export function useMarkState({ nav, search, theme, providerMarks, userMarks, }) {
4
- return useMemo(() => {
5
- const sets = [];
6
- // Search matches
7
- if (search.matchingLines.length > 0) {
8
- const mapped = new Set(search.matchingLines);
9
- const builder = new MarkSetBuilder();
10
- for (const idx of mapped) {
11
- builder.addLine(idx, {
12
- background: theme.warning,
13
- signBefore: "\u25CF",
14
- foreground: theme.warning,
15
- });
16
- }
17
- sets.push(builder.build("search", MarkPriorities.SEARCH_MATCH));
18
- }
19
- // Toggled lines
20
- if (nav.toggledIndices.size > 0) {
21
- const mapped = new Set(nav.toggledIndices);
22
- const builder = new MarkSetBuilder();
23
- for (const idx of mapped) {
24
- builder.addLine(idx, { background: theme.backgroundPanel });
25
- }
26
- sets.push(builder.build("toggled", MarkPriorities.TOGGLED));
27
- }
28
- // Selection range
29
- if (nav.selection) {
30
- const builder = new MarkSetBuilder();
31
- builder.addRange({ line: nav.selection.start }, { line: nav.selection.end }, { background: theme.selection });
32
- sets.push(builder.build("selection", MarkPriorities.SELECTION));
33
- }
34
- // Current match highlight
35
- if (search.matchingLines.length > 0) {
36
- const currentLine = search.matchingLines[search.currentMatchIndex];
37
- if (currentLine != null) {
38
- const builder = new MarkSetBuilder();
39
- builder.addLine(currentLine, {
40
- background: theme.primary,
41
- signBefore: "\u25CF",
42
- foreground: theme.primary,
43
- });
44
- sets.push(builder.build("currentMatch", MarkPriorities.CURRENT_MATCH));
45
- }
46
- }
47
- // Cursor
48
- if (nav.cursor !== null) {
49
- const builder = new MarkSetBuilder();
50
- builder.addLine(nav.cursor, {
51
- background: theme.cursorLine,
52
- signBefore: "\u25B8",
53
- foreground: theme.primary,
54
- });
55
- sets.push(builder.build("cursor", MarkPriorities.CURSOR));
56
- }
57
- // Provider and user marks
58
- sets.push(...providerMarks, ...userMarks);
59
- return sets.length > 0 ? createMarkState(sets) : undefined;
60
- }, [
61
- search.matchingLines,
62
- search.currentMatchIndex,
63
- nav.toggledIndices,
64
- nav.selection,
65
- nav.cursor,
66
- theme,
67
- providerMarks,
68
- userMarks,
69
- ]);
70
- }
71
- //# sourceMappingURL=useMarkState.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useMarkState.js","sourceRoot":"","sources":["../../src/hooks/useMarkState.ts"],"names":[],"mappings":"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"}
@@ -1,13 +0,0 @@
1
- import type { ActionDefinition } from "@tooee/commands";
2
- import type { AnyContent } from "../types.js";
3
- interface UseViewCommandsParams {
4
- content: AnyContent | null;
5
- textContent: string;
6
- actions?: ActionDefinition[];
7
- }
8
- export declare function useViewCommands({ content, textContent, actions }: UseViewCommandsParams): {
9
- themeName: string;
10
- showLineNumbers: boolean;
11
- };
12
- export {};
13
- //# sourceMappingURL=useViewCommands.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useViewCommands.d.ts","sourceRoot":"","sources":["../../src/hooks/useViewCommands.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAEvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAE7C,UAAU,qBAAqB;IAC7B,OAAO,EAAE,UAAU,GAAG,IAAI,CAAA;IAC1B,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAA;CAC7B;AAED,wBAAgB,eAAe,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,qBAAqB;;;EAiBvF"}
@@ -1,20 +0,0 @@
1
- import { useState } from "react";
2
- import { useThemeCommands, useQuitCommand, useCopyCommand, useToggleLineNumbersCommand, } from "@tooee/shell";
3
- import { useActions } from "@tooee/commands";
4
- import { useConfig } from "@tooee/config";
5
- export function useViewCommands({ content, textContent, actions }) {
6
- const config = useConfig();
7
- const [showLineNumbers, setShowLineNumbers] = useState(config.view?.gutter ?? true);
8
- const { name: themeName } = useThemeCommands();
9
- useQuitCommand();
10
- useCopyCommand({
11
- getText: () => (content ? textContent : undefined),
12
- });
13
- useToggleLineNumbersCommand({
14
- showLineNumbers,
15
- onToggle: () => setShowLineNumbers((v) => !v),
16
- });
17
- useActions(actions);
18
- return { themeName, showLineNumbers };
19
- }
20
- //# sourceMappingURL=useViewCommands.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useViewCommands.js","sourceRoot":"","sources":["../../src/hooks/useViewCommands.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAChC,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,2BAA2B,GAC5B,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAE5C,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AASzC,MAAM,UAAU,eAAe,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAyB;IACtF,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAC1B,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,IAAI,IAAI,CAAC,CAAA;IAEnF,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,gBAAgB,EAAE,CAAA;IAC9C,cAAc,EAAE,CAAA;IAChB,cAAc,CAAC;QACb,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC;KACnD,CAAC,CAAA;IACF,2BAA2B,CAAC;QAC1B,eAAe;QACf,QAAQ,EAAE,GAAG,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;KAC9C,CAAC,CAAA;IAEF,UAAU,CAAC,OAAO,CAAC,CAAA;IAEnB,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,CAAA;AACvC,CAAC"}
@@ -1,48 +0,0 @@
1
- import type { ReactNode } from "react"
2
- import { AppLayout, type StatusBarItem } from "@tooee/layout"
3
- import { useMode } from "@tooee/commands"
4
- import type { NavigationState } from "@tooee/shell"
5
- import type { SearchState } from "@tooee/search"
6
- import type { AnyContent } from "../types.js"
7
-
8
- interface SubviewLayoutProps {
9
- content: AnyContent
10
- nav: NavigationState & SearchState
11
- streaming: boolean
12
- themeName: string
13
- extraStatusItems?: StatusBarItem[]
14
- children: ReactNode
15
- }
16
-
17
- export function SubviewLayout({
18
- content,
19
- nav,
20
- streaming,
21
- themeName,
22
- extraStatusItems,
23
- children,
24
- }: SubviewLayoutProps) {
25
- const mode = useMode()
26
- const statusItems = [
27
- { label: "Theme:", value: themeName },
28
- ...(extraStatusItems ?? []),
29
- { label: "Mode:", value: mode },
30
- { label: "Cursor:", value: nav.cursor !== null ? String(nav.cursor) : "-" },
31
- ...(streaming ? [{ label: "Status:", value: "streaming" }] : []),
32
- ...(nav.searchActive ? [{ label: "Search:", value: nav.searchQuery }] : []),
33
- ]
34
-
35
- return (
36
- <AppLayout
37
- titleBar={
38
- content.title
39
- ? { title: content.title, subtitle: content.format }
40
- : { title: content.format }
41
- }
42
- statusBar={{ items: statusItems }}
43
- searchBar={nav}
44
- >
45
- {children}
46
- </AppLayout>
47
- )
48
- }