@tooee/view 0.2.1 → 0.2.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"View.d.ts","sourceRoot":"","sources":["../src/View.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAEvD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACzD,OAAO,EAAmB,KAAK,eAAe,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAA;AASxF,UAAU,SAAS;IACjB,eAAe,EAAE,eAAe,CAAA;IAChC,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAA;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;IAC3C;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAA;CACvD;AAED,wBAAgB,IAAI,CAAC,EAAE,eAAe,EAAE,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,EAAE,SAAS,6BA0E1F"}
1
+ {"version":3,"file":"View.d.ts","sourceRoot":"","sources":["../src/View.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAEvD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACzD,OAAO,EAAmB,KAAK,eAAe,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAA;AASxF,UAAU,SAAS;IACjB,eAAe,EAAE,eAAe,CAAA;IAChC,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAA;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;IAC3C;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAA;CACvD;AAED,wBAAgB,IAAI,CAAC,EAAE,eAAe,EAAE,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,EAAE,SAAS,6BAoE1F"}
package/dist/View.js CHANGED
@@ -6,9 +6,7 @@ import { useContentLoader } from "./hooks/useContentLoader.js";
6
6
  import { MarkdownSubview, CodeSubview, TableSubview, CustomSubview, } from "./components/subviews/index.js";
7
7
  export function View({ contentProvider, actions, renderers, codeBlockRenderers }) {
8
8
  const { theme } = useTheme();
9
- const [reloadTrigger, setReloadTrigger] = useState(0);
10
- const reload = useCallback(() => setReloadTrigger((n) => n + 1), []);
11
- const { content, streaming, error, providerMarks } = useContentLoader(contentProvider, reloadTrigger);
9
+ const { content, streaming, error, providerMarks, reload } = useContentLoader(contentProvider);
12
10
  const [userMarks, setUserMarks] = useState([]);
13
11
  const setMarkSet = useCallback((set) => {
14
12
  setUserMarks((prev) => {
package/dist/View.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"View.js","sourceRoot":"","sources":["../src/View.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"View.js","sourceRoot":"","sources":["../src/View.tsx"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx } from "@opentui/react/jsx-runtime";
2
2
  import { useMemo } from "react";
3
3
  import { CodeView, sourceLines, sourceLineAdapter } from "@tooee/renderers";
4
- import { actionsToContextMenuEntries, useDocumentController } from "@tooee/shell";
4
+ import { useDocumentController } from "@tooee/shell";
5
5
  import { useContentCommands } from "../../hooks/useContentCommands.js";
6
6
  import { ViewScreen } from "../ViewScreen.js";
7
7
  export function CodeSubview({ content, decorations, actions, ...screen }) {
@@ -9,13 +9,13 @@ export function CodeSubview({ content, decorations, actions, ...screen }) {
9
9
  // One navigation row per physical source line; row index is the source line.
10
10
  const lineRows = useMemo(() => sourceLines(textContent), [textContent]);
11
11
  const { showLineNumbers } = useContentCommands({ content, textContent });
12
- const contextMenu = useMemo(() => actionsToContextMenuEntries(actions), [actions]);
13
12
  const document = useDocumentController({
14
13
  rows: lineRows,
15
14
  adapter: sourceLineAdapter,
16
15
  multiSelect: true,
17
16
  decorations,
18
- contextMenu,
17
+ // The controller projects the screen's actions onto menu entries at open time.
18
+ contextMenu: actions,
19
19
  });
20
20
  const statusItems = useMemo(() => [
21
21
  { label: "Format:", value: content.format },
@@ -1 +1 @@
1
- {"version":3,"file":"CodeSubview.js","sourceRoot":"","sources":["../../../src/components/subviews/CodeSubview.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAC/B,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,iBAAiB,EAAsB,MAAM,kBAAkB,CAAA;AAC/F,OAAO,EAAE,2BAA2B,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAEjF,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAA;AACtE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAO7C,MAAM,UAAU,WAAW,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,MAAM,EAAoB;IACxF,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAA;IAC3E,6EAA6E;IAC7E,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,WAAW,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAA;IAEvE,MAAM,EAAE,eAAe,EAAE,GAAG,kBAAkB,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAA;IACxE,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,2BAA2B,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAA;IAElF,MAAM,QAAQ,GAAG,qBAAqB,CAAgB;QACpD,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,iBAAiB;QAC1B,WAAW,EAAE,IAAI;QACjB,WAAW;QACX,WAAW;KACZ,CAAC,CAAA;IAEF,MAAM,WAAW,GAAG,OAAO,CACzB,GAAG,EAAE,CAAC;QACJ,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE;QAC3C,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE;KACpD,EACD,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAClC,CAAA;IAED,OAAO,CACL,KAAC,UAAU,IACT,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,QAAQ,EACpB,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,WAAW,KACpB,MAAM,YAEV,KAAC,QAAQ,IACP,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,OAAO,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,EAClE,eAAe,EAAE,eAAe,EAChC,QAAQ,EAAE,QAAQ,GAClB,GACS,CACd,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"CodeSubview.js","sourceRoot":"","sources":["../../../src/components/subviews/CodeSubview.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAC/B,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,iBAAiB,EAAsB,MAAM,kBAAkB,CAAA;AAC/F,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAEpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAA;AACtE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAO7C,MAAM,UAAU,WAAW,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,MAAM,EAAoB;IACxF,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAA;IAC3E,6EAA6E;IAC7E,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,WAAW,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAA;IAEvE,MAAM,EAAE,eAAe,EAAE,GAAG,kBAAkB,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAA;IAExE,MAAM,QAAQ,GAAG,qBAAqB,CAAgB;QACpD,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,iBAAiB;QAC1B,WAAW,EAAE,IAAI;QACjB,WAAW;QACX,+EAA+E;QAC/E,WAAW,EAAE,OAAO;KACrB,CAAC,CAAA;IAEF,MAAM,WAAW,GAAG,OAAO,CACzB,GAAG,EAAE,CAAC;QACJ,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE;QAC3C,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE;KACpD,EACD,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAClC,CAAA;IAED,OAAO,CACL,KAAC,UAAU,IACT,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,QAAQ,EACpB,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,WAAW,KACpB,MAAM,YAEV,KAAC,QAAQ,IACP,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,OAAO,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,EAClE,eAAe,EAAE,eAAe,EAChC,QAAQ,EAAE,QAAQ,GAClB,GACS,CACd,CAAA;AACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"MarkdownSubview.d.ts","sourceRoot":"","sources":["../../../src/components/subviews/MarkdownSubview.tsx"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,iBAAiB,EAEvB,MAAM,kBAAkB,CAAA;AAOzB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAGrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C,UAAU,oBAAqB,SAAQ,YAAY;IACjD,OAAO,EAAE,eAAe,CAAA;IACxB,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAA;CACvD;AAeD,wBAAgB,eAAe,CAAC,EAC9B,OAAO,EACP,kBAAkB,EAClB,WAAW,EACX,OAAO,EACP,GAAG,MAAM,EACV,EAAE,oBAAoB,6BAsEtB"}
1
+ {"version":3,"file":"MarkdownSubview.d.ts","sourceRoot":"","sources":["../../../src/components/subviews/MarkdownSubview.tsx"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,iBAAiB,EAEvB,MAAM,kBAAkB,CAAA;AAGzB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAGrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C,UAAU,oBAAqB,SAAQ,YAAY;IACjD,OAAO,EAAE,eAAe,CAAA;IACxB,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAA;CACvD;AAeD,wBAAgB,eAAe,CAAC,EAC9B,OAAO,EACP,kBAAkB,EAClB,WAAW,EACX,OAAO,EACP,GAAG,MAAM,EACV,EAAE,oBAAoB,6BAsEtB"}
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "@opentui/react/jsx-runtime";
2
2
  import { useMemo, useRef } from "react";
3
3
  import { MarkdownView, flattenMarkdown, getFlatBlockText, } from "@tooee/renderers";
4
4
  import { useCommand } from "@tooee/commands";
5
- import { actionsToContextMenuEntries, useDocumentController, } from "@tooee/shell";
5
+ import { useDocumentController } from "@tooee/shell";
6
6
  import { useContentCommands } from "../../hooks/useContentCommands.js";
7
7
  import { ViewScreen } from "../ViewScreen.js";
8
8
  /** Columns moved per h/l press when scrolling a wide block horizontally. */
@@ -21,13 +21,13 @@ export function MarkdownSubview({ content, codeBlockRenderers, decorations, acti
21
21
  const lineCount = useMemo(() => textContent.split("\n").length, [textContent]);
22
22
  const blocks = useMemo(() => flattenMarkdown(content.markdown), [content.markdown]);
23
23
  const { showLineNumbers } = useContentCommands({ content, textContent });
24
- const contextMenu = useMemo(() => actionsToContextMenuEntries(actions), [actions]);
25
24
  const document = useDocumentController({
26
25
  rows: blocks,
27
26
  adapter: MARKDOWN_BLOCK_ADAPTER,
28
27
  multiSelect: true,
29
28
  decorations,
30
- contextMenu,
29
+ // The controller projects the screen's actions onto menu entries at open time.
30
+ contextMenu: actions,
31
31
  });
32
32
  const hScrollableBlocksRef = useRef(new Map());
33
33
  const cursorScrollable = () => document.activeIndex !== null
@@ -1 +1 @@
1
- {"version":3,"file":"MarkdownSubview.js","sourceRoot":"","sources":["../../../src/components/subviews/MarkdownSubview.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MarkdownSubview.js","sourceRoot":"","sources":["../../../src/components/subviews/MarkdownSubview.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"TableSubview.d.ts","sourceRoot":"","sources":["../../../src/components/subviews/TableSubview.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAGlE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C,UAAU,iBAAkB,SAAQ,YAAY;IAC9C,OAAO,EAAE,YAAY,CAAA;CACtB;AAED,wBAAgB,YAAY,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,EAAE,iBAAiB,6BA0C3F"}
1
+ {"version":3,"file":"TableSubview.d.ts","sourceRoot":"","sources":["../../../src/components/subviews/TableSubview.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAGlE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C,UAAU,iBAAkB,SAAQ,YAAY;IAC9C,OAAO,EAAE,YAAY,CAAA;CACtB;AAED,wBAAgB,YAAY,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,EAAE,iBAAiB,6BAyC3F"}
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx } from "@opentui/react/jsx-runtime";
2
2
  import { useMemo } from "react";
3
3
  import { Table } from "@tooee/renderers";
4
- import { actionsToContextMenuEntries, useDocumentController } from "@tooee/shell";
4
+ import { useDocumentController } from "@tooee/shell";
5
5
  import { getTextContent } from "../../types.js";
6
6
  import { useContentCommands } from "../../hooks/useContentCommands.js";
7
7
  import { ViewScreen } from "../ViewScreen.js";
@@ -12,13 +12,13 @@ export function TableSubview({ content, decorations, actions, ...screen }) {
12
12
  const adapter = useMemo(() => ({
13
13
  getText: (row) => columns.map((column) => stringifyRowCell(row[column.key])).join("\t"),
14
14
  }), [columns]);
15
- const contextMenu = useMemo(() => actionsToContextMenuEntries(actions), [actions]);
16
15
  const document = useDocumentController({
17
16
  rows,
18
17
  adapter,
19
18
  multiSelect: true,
20
19
  decorations,
21
- contextMenu,
20
+ // The controller projects the screen's actions onto menu entries at open time.
21
+ contextMenu: actions,
22
22
  });
23
23
  const statusItems = useMemo(() => [
24
24
  { label: "Format:", value: content.format },
@@ -1 +1 @@
1
- {"version":3,"file":"TableSubview.js","sourceRoot":"","sources":["../../../src/components/subviews/TableSubview.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAC/B,OAAO,EAAE,KAAK,EAAiB,MAAM,kBAAkB,CAAA;AACvD,OAAO,EAAE,2BAA2B,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AACjF,OAAO,EAAE,cAAc,EAAqB,MAAM,gBAAgB,CAAA;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAA;AACtE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAO7C,MAAM,UAAU,YAAY,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,MAAM,EAAqB;IAC1F,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAA;IACrE,MAAM,EAAE,eAAe,EAAE,GAAG,kBAAkB,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAA;IAExE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,OAAO,CAAA;IACjC,MAAM,OAAO,GAAG,OAAO,CACrB,GAAG,EAAE,CAAC,CAAC;QACL,OAAO,EAAE,CAAC,GAAa,EAAE,EAAE,CACzB,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;KACxE,CAAC,EACF,CAAC,OAAO,CAAC,CACV,CAAA;IACD,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,2BAA2B,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAA;IAElF,MAAM,QAAQ,GAAG,qBAAqB,CAAW;QAC/C,IAAI;QACJ,OAAO;QACP,WAAW,EAAE,IAAI;QACjB,WAAW;QACX,WAAW;KACZ,CAAC,CAAA;IAEF,MAAM,WAAW,GAAG,OAAO,CACzB,GAAG,EAAE,CAAC;QACJ,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE;QAC3C,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;QAC9C,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;KAClD,EACD,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAC9C,CAAA;IAED,OAAO,CACL,KAAC,UAAU,IACT,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,QAAQ,EACpB,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,WAAW,KACpB,MAAM,YAEV,KAAC,KAAK,IAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,eAAe,EAAE,eAAe,EAAE,QAAQ,EAAE,QAAQ,GAAI,GAClF,CACd,CAAA;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAc;IACtC,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,EAAE,CAAA;IAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAA;IAC3C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAA;IACjF,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC,KAAK,CAAC,CAAA;IACtB,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"TableSubview.js","sourceRoot":"","sources":["../../../src/components/subviews/TableSubview.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAC/B,OAAO,EAAE,KAAK,EAAiB,MAAM,kBAAkB,CAAA;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AACpD,OAAO,EAAE,cAAc,EAAqB,MAAM,gBAAgB,CAAA;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAA;AACtE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAO7C,MAAM,UAAU,YAAY,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,MAAM,EAAqB;IAC1F,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAA;IACrE,MAAM,EAAE,eAAe,EAAE,GAAG,kBAAkB,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAA;IAExE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,OAAO,CAAA;IACjC,MAAM,OAAO,GAAG,OAAO,CACrB,GAAG,EAAE,CAAC,CAAC;QACL,OAAO,EAAE,CAAC,GAAa,EAAE,EAAE,CACzB,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;KACxE,CAAC,EACF,CAAC,OAAO,CAAC,CACV,CAAA;IACD,MAAM,QAAQ,GAAG,qBAAqB,CAAW;QAC/C,IAAI;QACJ,OAAO;QACP,WAAW,EAAE,IAAI;QACjB,WAAW;QACX,+EAA+E;QAC/E,WAAW,EAAE,OAAO;KACrB,CAAC,CAAA;IAEF,MAAM,WAAW,GAAG,OAAO,CACzB,GAAG,EAAE,CAAC;QACJ,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE;QAC3C,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;QAC9C,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;KAClD,EACD,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAC9C,CAAA;IAED,OAAO,CACL,KAAC,UAAU,IACT,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,QAAQ,EACpB,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,WAAW,KACpB,MAAM,YAEV,KAAC,KAAK,IAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,eAAe,EAAE,eAAe,EAAE,QAAQ,EAAE,QAAQ,GAAI,GAClF,CACd,CAAA;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAc;IACtC,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,EAAE,CAAA;IAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAA;IAC3C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAA;IACjF,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC,KAAK,CAAC,CAAA;IACtB,CAAC;AACH,CAAC"}
@@ -0,0 +1,53 @@
1
+ import type { MarkSet } from "@tooee/marks";
2
+ import type { AnyContent, ContentChunk } from "./types.js";
3
+ export type ContentLoaderStatus = "idle" | "loading" | "streaming" | "ready" | "error";
4
+ export interface ContentLoaderContext {
5
+ status: ContentLoaderStatus;
6
+ requestId: number;
7
+ loadSeq: number;
8
+ content: AnyContent | null;
9
+ error: string | null;
10
+ providerMarks: MarkSet[];
11
+ title: string | undefined;
12
+ }
13
+ export type ContentLoaderEvents = {
14
+ loadStarted: {
15
+ marks: MarkSet[];
16
+ title?: string;
17
+ };
18
+ streamStarted: {
19
+ requestId: number;
20
+ format: string;
21
+ };
22
+ chunkReceived: {
23
+ requestId: number;
24
+ chunk: ContentChunk;
25
+ };
26
+ loaded: {
27
+ requestId: number;
28
+ content: AnyContent;
29
+ };
30
+ streamEnded: {
31
+ requestId: number;
32
+ };
33
+ loadFailed: {
34
+ requestId: number;
35
+ error: string;
36
+ };
37
+ loadCancelled: {
38
+ requestId: number;
39
+ };
40
+ reloadRequested: {};
41
+ };
42
+ export declare function isAsyncIterable(value: unknown): value is AsyncIterable<ContentChunk>;
43
+ export declare function createEmptyContent(format: string, title?: string): AnyContent;
44
+ export declare function applyContentChunk(current: AnyContent | null, chunk: ContentChunk, title?: string): AnyContent;
45
+ export declare function normalizeError(error: unknown): string;
46
+ export declare function createContentLoaderStore(): import("@xstate/store").Store<ContentLoaderContext, ContentLoaderEvents, never>;
47
+ export declare const selectContent: (ctx: ContentLoaderContext) => AnyContent | null;
48
+ export declare const selectStatus: (ctx: ContentLoaderContext) => ContentLoaderStatus;
49
+ export declare const selectStreaming: (ctx: ContentLoaderContext) => boolean;
50
+ export declare const selectError: (ctx: ContentLoaderContext) => string | null;
51
+ export declare const selectProviderMarks: (ctx: ContentLoaderContext) => MarkSet[];
52
+ export declare const selectLoadSeq: (ctx: ContentLoaderContext) => number;
53
+ //# sourceMappingURL=content-loader-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-loader-store.d.ts","sourceRoot":"","sources":["../src/content-loader-store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAW,YAAY,EAAgC,MAAM,YAAY,CAAA;AAEjG,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,SAAS,GAAG,WAAW,GAAG,OAAO,GAAG,OAAO,CAAA;AAEtF,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,mBAAmB,CAAA;IAC3B,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,UAAU,GAAG,IAAI,CAAA;IAC1B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,aAAa,EAAE,OAAO,EAAE,CAAA;IACxB,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;CAC1B;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,WAAW,EAAE;QAAE,KAAK,EAAE,OAAO,EAAE,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACjD,aAAa,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IACpD,aAAa,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,YAAY,CAAA;KAAE,CAAA;IACzD,MAAM,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,UAAU,CAAA;KAAE,CAAA;IAClD,WAAW,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IAClC,UAAU,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;IAChD,aAAa,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IACpC,eAAe,EAAE,EAAE,CAAA;CACpB,CAAA;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,aAAa,CAAC,YAAY,CAAC,CAEpF;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,UAAU,CAa7E;AAaD,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,UAAU,GAAG,IAAI,EAC1B,KAAK,EAAE,YAAY,EACnB,KAAK,CAAC,EAAE,MAAM,GACb,UAAU,CA0BZ;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAErD;AAED,wBAAgB,wBAAwB,oFAqDvC;AAED,eAAO,MAAM,aAAa,GAAI,KAAK,oBAAoB,sBAAgB,CAAA;AACvE,eAAO,MAAM,YAAY,GAAI,KAAK,oBAAoB,wBAAe,CAAA;AACrE,eAAO,MAAM,eAAe,GAAI,KAAK,oBAAoB,YAA+B,CAAA;AACxF,eAAO,MAAM,WAAW,GAAI,KAAK,oBAAoB,kBAAc,CAAA;AACnE,eAAO,MAAM,mBAAmB,GAAI,KAAK,oBAAoB,cAAsB,CAAA;AACnF,eAAO,MAAM,aAAa,GAAI,KAAK,oBAAoB,WAAgB,CAAA"}
@@ -0,0 +1,111 @@
1
+ import { createStore } from "@xstate/store";
2
+ export function isAsyncIterable(value) {
3
+ return value != null && typeof value === "object" && Symbol.asyncIterator in value;
4
+ }
5
+ export function createEmptyContent(format, title) {
6
+ switch (format) {
7
+ case "markdown":
8
+ return { format, markdown: "", title };
9
+ case "code":
10
+ return { format, code: "", title };
11
+ case "text":
12
+ return { format, text: "", title };
13
+ case "table":
14
+ return { format, columns: [], rows: [], title };
15
+ default:
16
+ return { format, data: undefined, title };
17
+ }
18
+ }
19
+ function ensureContentFormat(current, format, title) {
20
+ if (!current || current.format !== format) {
21
+ return createEmptyContent(format, title);
22
+ }
23
+ return current;
24
+ }
25
+ export function applyContentChunk(current, chunk, title) {
26
+ switch (chunk.type) {
27
+ case "replace":
28
+ return chunk.content;
29
+ case "append":
30
+ if (chunk.format === "markdown") {
31
+ const target = ensureContentFormat(current, "markdown", title);
32
+ return { ...target, markdown: target.markdown + chunk.data };
33
+ }
34
+ if (chunk.format === "code") {
35
+ const target = ensureContentFormat(current, "code", title);
36
+ return {
37
+ ...target,
38
+ code: target.code + chunk.data,
39
+ language: chunk.language ?? target.language,
40
+ };
41
+ }
42
+ {
43
+ const target = ensureContentFormat(current, "text", title);
44
+ return { ...target, text: target.text + chunk.data };
45
+ }
46
+ case "patch":
47
+ return chunk.apply(current);
48
+ default:
49
+ return current ?? createEmptyContent("markdown", title);
50
+ }
51
+ }
52
+ export function normalizeError(error) {
53
+ return error instanceof Error ? error.message : String(error);
54
+ }
55
+ export function createContentLoaderStore() {
56
+ return createStore({
57
+ context: {
58
+ status: "idle",
59
+ requestId: 0,
60
+ loadSeq: 0,
61
+ content: null,
62
+ error: null,
63
+ providerMarks: [],
64
+ title: undefined,
65
+ },
66
+ on: {
67
+ loadStarted: (ctx, event) => ({
68
+ ...ctx,
69
+ status: "loading",
70
+ requestId: ctx.requestId + 1,
71
+ error: null,
72
+ providerMarks: event.marks,
73
+ title: event.title,
74
+ }),
75
+ streamStarted: (ctx, event) => event.requestId !== ctx.requestId
76
+ ? ctx
77
+ : {
78
+ ...ctx,
79
+ status: "streaming",
80
+ content: createEmptyContent(event.format, ctx.title),
81
+ },
82
+ chunkReceived: (ctx, event) => {
83
+ if (event.requestId !== ctx.requestId)
84
+ return ctx;
85
+ if (event.chunk.type === "marks") {
86
+ const markSet = event.chunk.set;
87
+ const providerMarks = [
88
+ ...ctx.providerMarks.filter((set) => set.namespace !== markSet.namespace),
89
+ markSet,
90
+ ];
91
+ return { ...ctx, providerMarks };
92
+ }
93
+ return { ...ctx, content: applyContentChunk(ctx.content, event.chunk, ctx.title) };
94
+ },
95
+ loaded: (ctx, event) => event.requestId !== ctx.requestId
96
+ ? ctx
97
+ : { ...ctx, status: "ready", content: event.content },
98
+ streamEnded: (ctx, event) => event.requestId !== ctx.requestId ? ctx : { ...ctx, status: "ready" },
99
+ loadFailed: (ctx, event) => event.requestId !== ctx.requestId ? ctx : { ...ctx, status: "error", error: event.error },
100
+ loadCancelled: (ctx, event) => event.requestId !== ctx.requestId ? ctx : { ...ctx, requestId: ctx.requestId + 1 },
101
+ reloadRequested: (ctx) => ({ ...ctx, loadSeq: ctx.loadSeq + 1 }),
102
+ },
103
+ });
104
+ }
105
+ export const selectContent = (ctx) => ctx.content;
106
+ export const selectStatus = (ctx) => ctx.status;
107
+ export const selectStreaming = (ctx) => ctx.status === "streaming";
108
+ export const selectError = (ctx) => ctx.error;
109
+ export const selectProviderMarks = (ctx) => ctx.providerMarks;
110
+ export const selectLoadSeq = (ctx) => ctx.loadSeq;
111
+ //# sourceMappingURL=content-loader-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-loader-store.js","sourceRoot":"","sources":["../src/content-loader-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AA2B3C,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,OAAO,KAAK,IAAI,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,aAAa,IAAI,KAAK,CAAA;AACpF,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAc,EAAE,KAAc;IAC/D,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,UAAU;YACb,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,CAAA;QACxC,KAAK,MAAM;YACT,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,CAAA;QACpC,KAAK,MAAM;YACT,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,CAAA;QACpC,KAAK,OAAO;YACV,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,CAAA;QACjD;YACE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAmB,CAAA;IAC9D,CAAC;AACH,CAAC;AAED,SAAS,mBAAmB,CAC1B,OAA0B,EAC1B,MAAS,EACT,KAAc;IAEd,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC1C,OAAO,kBAAkB,CAAC,MAAM,EAAE,KAAK,CAAoC,CAAA;IAC7E,CAAC;IACD,OAAO,OAA0C,CAAA;AACnD,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,OAA0B,EAC1B,KAAmB,EACnB,KAAc;IAEd,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,SAAS;YACZ,OAAO,KAAK,CAAC,OAAO,CAAA;QACtB,KAAK,QAAQ;YACX,IAAI,KAAK,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;gBAChC,MAAM,MAAM,GAAG,mBAAmB,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,CAAC,CAAA;gBAC9D,OAAO,EAAE,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,GAAG,KAAK,CAAC,IAAI,EAAE,CAAA;YAC9D,CAAC;YACD,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;gBAC5B,MAAM,MAAM,GAAG,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,CAAA;gBAC1D,OAAO;oBACL,GAAG,MAAM;oBACT,IAAI,EAAE,MAAM,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI;oBAC9B,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ;iBAC5C,CAAA;YACH,CAAC;YACD,CAAC;gBACC,MAAM,MAAM,GAAG,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,CAAA;gBAC1D,OAAO,EAAE,GAAG,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,CAAA;YACtD,CAAC;QACH,KAAK,OAAO;YACV,OAAO,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QAC7B;YACE,OAAO,OAAO,IAAI,kBAAkB,CAAC,UAAU,EAAE,KAAK,CAAC,CAAA;IAC3D,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AAC/D,CAAC;AAED,MAAM,UAAU,wBAAwB;IACtC,OAAO,WAAW,CAA4C;QAC5D,OAAO,EAAE;YACP,MAAM,EAAE,MAAM;YACd,SAAS,EAAE,CAAC;YACZ,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,IAAI;YACb,KAAK,EAAE,IAAI;YACX,aAAa,EAAE,EAAE;YACjB,KAAK,EAAE,SAAS;SACjB;QACD,EAAE,EAAE;YACF,WAAW,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;gBAC5B,GAAG,GAAG;gBACN,MAAM,EAAE,SAAS;gBACjB,SAAS,EAAE,GAAG,CAAC,SAAS,GAAG,CAAC;gBAC5B,KAAK,EAAE,IAAI;gBACX,aAAa,EAAE,KAAK,CAAC,KAAK;gBAC1B,KAAK,EAAE,KAAK,CAAC,KAAK;aACnB,CAAC;YACF,aAAa,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAC5B,KAAK,CAAC,SAAS,KAAK,GAAG,CAAC,SAAS;gBAC/B,CAAC,CAAC,GAAG;gBACL,CAAC,CAAC;oBACE,GAAG,GAAG;oBACN,MAAM,EAAE,WAAW;oBACnB,OAAO,EAAE,kBAAkB,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC;iBACrD;YACP,aAAa,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;gBAC5B,IAAI,KAAK,CAAC,SAAS,KAAK,GAAG,CAAC,SAAS;oBAAE,OAAO,GAAG,CAAA;gBACjD,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;oBACjC,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAA;oBAC/B,MAAM,aAAa,GAAG;wBACpB,GAAG,GAAG,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS,KAAK,OAAO,CAAC,SAAS,CAAC;wBACzE,OAAO;qBACR,CAAA;oBACD,OAAO,EAAE,GAAG,GAAG,EAAE,aAAa,EAAE,CAAA;gBAClC,CAAC;gBACD,OAAO,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,iBAAiB,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,CAAA;YACpF,CAAC;YACD,MAAM,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CACrB,KAAK,CAAC,SAAS,KAAK,GAAG,CAAC,SAAS;gBAC/B,CAAC,CAAC,GAAG;gBACL,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE;YACzD,WAAW,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAC1B,KAAK,CAAC,SAAS,KAAK,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE;YACvE,UAAU,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CACzB,KAAK,CAAC,SAAS,KAAK,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE;YAC3F,aAAa,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAC5B,KAAK,CAAC,SAAS,KAAK,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,GAAG,CAAC,EAAE;YACpF,eAAe,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC;SACjE;KACF,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,GAAyB,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAA;AACvE,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAyB,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAA;AACrE,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,GAAyB,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,KAAK,WAAW,CAAA;AACxF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,GAAyB,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAA;AACnE,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,GAAyB,EAAE,EAAE,CAAC,GAAG,CAAC,aAAa,CAAA;AACnF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,GAAyB,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAA"}
@@ -1,10 +1,10 @@
1
- import type { MarkSet } from "@tooee/marks";
2
- import type { AnyContent, ContentProvider } from "../types.js";
3
- export declare function useContentLoader(contentProvider: ContentProvider, reloadTrigger: number): {
4
- content: AnyContent | null;
1
+ import type { ContentProvider } from "../types.js";
2
+ export declare function useContentLoader(contentProvider: ContentProvider): {
3
+ content: import("../types.js").AnyContent | null;
5
4
  streaming: boolean;
6
5
  error: string | null;
7
- providerMarks: MarkSet[];
8
- setProviderMarks: import("react").Dispatch<import("react").SetStateAction<MarkSet[]>>;
6
+ providerMarks: import("@tooee/marks").MarkSet[];
7
+ status: import("../content-loader-store.js").ContentLoaderStatus;
8
+ reload: () => void;
9
9
  };
10
10
  //# sourceMappingURL=useContentLoader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useContentLoader.d.ts","sourceRoot":"","sources":["../../src/hooks/useContentLoader.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,KAAK,EACV,UAAU,EAGV,eAAe,EAGhB,MAAM,aAAa,CAAA;AAgEpB,wBAAgB,gBAAgB,CAAC,eAAe,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM;;;;;;EA+EvF"}
1
+ {"version":3,"file":"useContentLoader.d.ts","sourceRoot":"","sources":["../../src/hooks/useContentLoader.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAalD,wBAAgB,gBAAgB,CAAC,eAAe,EAAE,eAAe;;;;;;;EAwDhE"}
@@ -1,129 +1,55 @@
1
- import { useState, useEffect } from "react";
2
- function isAsyncIterable(value) {
3
- return value != null && typeof value === "object" && Symbol.asyncIterator in value;
4
- }
5
- function createEmptyContent(format, title) {
6
- switch (format) {
7
- case "markdown":
8
- return { format, markdown: "", title };
9
- case "code":
10
- return { format, code: "", title };
11
- case "text":
12
- return { format, text: "", title };
13
- case "table":
14
- return { format, columns: [], rows: [], title };
15
- default:
16
- return { format, data: undefined, title };
17
- }
18
- }
19
- function ensureContentFormat(current, format, title) {
20
- if (!current || current.format !== format) {
21
- return createEmptyContent(format, title);
22
- }
23
- return current;
24
- }
25
- function applyContentChunk(current, chunk, title) {
26
- switch (chunk.type) {
27
- case "replace":
28
- return chunk.content;
29
- case "append":
30
- if (chunk.format === "markdown") {
31
- const target = ensureContentFormat(current, "markdown", title);
32
- return { ...target, markdown: target.markdown + chunk.data };
33
- }
34
- if (chunk.format === "code") {
35
- const target = ensureContentFormat(current, "code", title);
36
- return {
37
- ...target,
38
- code: target.code + chunk.data,
39
- language: chunk.language ?? target.language,
40
- };
41
- }
42
- {
43
- const target = ensureContentFormat(current, "text", title);
44
- return { ...target, text: target.text + chunk.data };
45
- }
46
- case "patch":
47
- return chunk.apply(current);
48
- default:
49
- return current ?? createEmptyContent("markdown", title);
50
- }
51
- }
52
- export function useContentLoader(contentProvider, reloadTrigger) {
53
- const [content, setContent] = useState(null);
54
- const [streaming, setStreaming] = useState(false);
55
- const [error, setError] = useState(null);
56
- const [providerMarks, setProviderMarks] = useState([]);
1
+ import { useCallback, useEffect, useState } from "react";
2
+ import { useSelector } from "@xstate/store-react";
3
+ import { createContentLoaderStore, isAsyncIterable, normalizeError, selectContent, selectError, selectLoadSeq, selectProviderMarks, selectStatus, selectStreaming, } from "../content-loader-store.js";
4
+ export function useContentLoader(contentProvider) {
5
+ const [store] = useState(createContentLoaderStore);
6
+ const loadSeq = useSelector(store, (snapshot) => selectLoadSeq(snapshot.context));
57
7
  useEffect(() => {
58
- setError(null);
59
- setStreaming(false);
60
- // Reset provider marks on reload; initialize with static marks if provided
61
- setProviderMarks(contentProvider.marks ?? []);
8
+ store.trigger.loadStarted({
9
+ marks: contentProvider.marks ?? [],
10
+ title: contentProvider.title,
11
+ });
12
+ const requestId = store.getSnapshot().context.requestId;
62
13
  const loaded = contentProvider.load();
63
14
  if (isAsyncIterable(loaded)) {
64
- const fallbackFormat = contentProvider.format ?? "markdown";
65
- const title = contentProvider.title;
66
- let cancelled = false;
67
- let current = createEmptyContent(fallbackFormat, title);
68
- setContent(current);
69
- setStreaming(true);
70
- // Hold the iterator explicitly so cleanup can close it: a cleanup that
71
- // only flips `cancelled` leaves a pending next() (and the provider's
72
- // subprocess/file handle/network stream) alive until the next chunk.
15
+ store.trigger.streamStarted({
16
+ requestId,
17
+ format: contentProvider.format ?? "markdown",
18
+ });
73
19
  const iterator = loaded[Symbol.asyncIterator]();
74
20
  (async () => {
75
21
  try {
76
22
  while (true) {
77
23
  const result = await iterator.next();
78
- if (cancelled || result.done)
24
+ if (result.done)
79
25
  break;
80
- const chunk = result.value;
81
- if (chunk.type === "marks") {
82
- // Streamed mark set: merge by replacing any existing set with same namespace
83
- setProviderMarks((prev) => {
84
- const filtered = prev.filter((s) => s.namespace !== chunk.set.namespace);
85
- return [...filtered, chunk.set];
86
- });
87
- continue;
88
- }
89
- current = applyContentChunk(current, chunk, title);
90
- setContent(current);
26
+ store.trigger.chunkReceived({ requestId, chunk: result.value });
91
27
  }
28
+ store.trigger.streamEnded({ requestId });
92
29
  }
93
- catch (err) {
94
- if (!cancelled) {
95
- setError(err instanceof Error ? err.message : String(err));
96
- }
97
- }
98
- finally {
99
- if (!cancelled) {
100
- setStreaming(false);
101
- }
30
+ catch (error) {
31
+ store.trigger.loadFailed({ requestId, error: normalizeError(error) });
102
32
  }
103
33
  })();
104
34
  return () => {
105
- cancelled = true;
106
- // Close the iterator to release provider resources mid-stream.
35
+ store.trigger.loadCancelled({ requestId });
107
36
  Promise.resolve(iterator.return?.()).catch(() => { });
108
37
  };
109
38
  }
110
39
  if (loaded instanceof Promise) {
111
- let active = true;
112
40
  loaded
113
- .then((value) => {
114
- if (active)
115
- setContent(value);
116
- })
117
- .catch((err) => {
118
- if (active)
119
- setError(err instanceof Error ? err.message : String(err));
120
- });
121
- return () => {
122
- active = false;
123
- };
41
+ .then((content) => store.trigger.loaded({ requestId, content }))
42
+ .catch((error) => store.trigger.loadFailed({ requestId, error: normalizeError(error) }));
43
+ return () => store.trigger.loadCancelled({ requestId });
124
44
  }
125
- setContent(loaded);
126
- }, [contentProvider, reloadTrigger]);
127
- return { content, streaming, error, providerMarks, setProviderMarks };
45
+ store.trigger.loaded({ requestId, content: loaded });
46
+ }, [contentProvider, loadSeq, store]);
47
+ const content = useSelector(store, (snapshot) => selectContent(snapshot.context));
48
+ const streaming = useSelector(store, (snapshot) => selectStreaming(snapshot.context));
49
+ const error = useSelector(store, (snapshot) => selectError(snapshot.context));
50
+ const providerMarks = useSelector(store, (snapshot) => selectProviderMarks(snapshot.context));
51
+ const status = useSelector(store, (snapshot) => selectStatus(snapshot.context));
52
+ const reload = useCallback(() => store.trigger.reloadRequested({}), [store]);
53
+ return { content, streaming, error, providerMarks, status, reload };
128
54
  }
129
55
  //# sourceMappingURL=useContentLoader.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useContentLoader.js","sourceRoot":"","sources":["../../src/hooks/useContentLoader.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useContentLoader.js","sourceRoot":"","sources":["../../src/hooks/useContentLoader.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tooee/view",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Terminal content viewer for markdown, code, text, and tables",
5
5
  "keywords": [
6
6
  "cli",
@@ -37,15 +37,17 @@
37
37
  "typecheck": "tsc --noEmit"
38
38
  },
39
39
  "dependencies": {
40
- "@tooee/commands": "0.2.1",
41
- "@tooee/config": "0.2.1",
42
- "@tooee/layout": "0.2.1",
43
- "@tooee/marks": "0.2.1",
44
- "@tooee/overlays": "0.2.1",
45
- "@tooee/renderers": "0.2.1",
46
- "@tooee/search": "0.2.1",
47
- "@tooee/shell": "0.2.1",
48
- "@tooee/themes": "0.2.1",
40
+ "@tooee/commands": "0.2.3",
41
+ "@tooee/config": "0.2.3",
42
+ "@tooee/layout": "0.2.3",
43
+ "@tooee/marks": "0.2.3",
44
+ "@tooee/overlays": "0.2.3",
45
+ "@tooee/renderers": "0.2.3",
46
+ "@tooee/search": "0.2.3",
47
+ "@tooee/shell": "0.2.3",
48
+ "@tooee/themes": "0.2.3",
49
+ "@xstate/store": "^4",
50
+ "@xstate/store-react": "^2",
49
51
  "marked": "^17.0.4"
50
52
  },
51
53
  "devDependencies": {
package/src/View.tsx CHANGED
@@ -25,13 +25,7 @@ interface ViewProps {
25
25
 
26
26
  export function View({ contentProvider, actions, renderers, codeBlockRenderers }: ViewProps) {
27
27
  const { theme } = useTheme()
28
- const [reloadTrigger, setReloadTrigger] = useState(0)
29
- const reload = useCallback(() => setReloadTrigger((n) => n + 1), [])
30
-
31
- const { content, streaming, error, providerMarks } = useContentLoader(
32
- contentProvider,
33
- reloadTrigger,
34
- )
28
+ const { content, streaming, error, providerMarks, reload } = useContentLoader(contentProvider)
35
29
 
36
30
  const [userMarks, setUserMarks] = useState<MarkSet[]>([])
37
31
 
@@ -1,6 +1,6 @@
1
1
  import { useMemo } from "react"
2
2
  import { CodeView, sourceLines, sourceLineAdapter, type SourceLineRow } from "@tooee/renderers"
3
- import { actionsToContextMenuEntries, useDocumentController } from "@tooee/shell"
3
+ import { useDocumentController } from "@tooee/shell"
4
4
  import type { CodeContent, TextContent } from "../../types.js"
5
5
  import { useContentCommands } from "../../hooks/useContentCommands.js"
6
6
  import { ViewScreen } from "../ViewScreen.js"
@@ -16,14 +16,14 @@ export function CodeSubview({ content, decorations, actions, ...screen }: CodeSu
16
16
  const lineRows = useMemo(() => sourceLines(textContent), [textContent])
17
17
 
18
18
  const { showLineNumbers } = useContentCommands({ content, textContent })
19
- const contextMenu = useMemo(() => actionsToContextMenuEntries(actions), [actions])
20
19
 
21
20
  const document = useDocumentController<SourceLineRow>({
22
21
  rows: lineRows,
23
22
  adapter: sourceLineAdapter,
24
23
  multiSelect: true,
25
24
  decorations,
26
- contextMenu,
25
+ // The controller projects the screen's actions onto menu entries at open time.
26
+ contextMenu: actions,
27
27
  })
28
28
 
29
29
  const statusItems = useMemo(
@@ -8,11 +8,7 @@ import {
8
8
  type FlatBlock,
9
9
  } from "@tooee/renderers"
10
10
  import { useCommand } from "@tooee/commands"
11
- import {
12
- actionsToContextMenuEntries,
13
- useDocumentController,
14
- type DocumentRowAdapter,
15
- } from "@tooee/shell"
11
+ import { useDocumentController, type DocumentRowAdapter } from "@tooee/shell"
16
12
  import type { MarkdownContent } from "../../types.js"
17
13
  import { useContentCommands } from "../../hooks/useContentCommands.js"
18
14
  import { ViewScreen } from "../ViewScreen.js"
@@ -48,14 +44,14 @@ export function MarkdownSubview({
48
44
  const blocks = useMemo(() => flattenMarkdown(content.markdown), [content.markdown])
49
45
 
50
46
  const { showLineNumbers } = useContentCommands({ content, textContent })
51
- const contextMenu = useMemo(() => actionsToContextMenuEntries(actions), [actions])
52
47
 
53
48
  const document = useDocumentController<FlatBlock>({
54
49
  rows: blocks,
55
50
  adapter: MARKDOWN_BLOCK_ADAPTER,
56
51
  multiSelect: true,
57
52
  decorations,
58
- contextMenu,
53
+ // The controller projects the screen's actions onto menu entries at open time.
54
+ contextMenu: actions,
59
55
  })
60
56
 
61
57
  const hScrollableBlocksRef = useRef<Map<number, TextBufferRenderable>>(new Map())
@@ -1,6 +1,6 @@
1
1
  import { useMemo } from "react"
2
2
  import { Table, type TableRow } from "@tooee/renderers"
3
- import { actionsToContextMenuEntries, useDocumentController } from "@tooee/shell"
3
+ import { useDocumentController } from "@tooee/shell"
4
4
  import { getTextContent, type TableContent } from "../../types.js"
5
5
  import { useContentCommands } from "../../hooks/useContentCommands.js"
6
6
  import { ViewScreen } from "../ViewScreen.js"
@@ -22,14 +22,13 @@ export function TableSubview({ content, decorations, actions, ...screen }: Table
22
22
  }),
23
23
  [columns],
24
24
  )
25
- const contextMenu = useMemo(() => actionsToContextMenuEntries(actions), [actions])
26
-
27
25
  const document = useDocumentController<TableRow>({
28
26
  rows,
29
27
  adapter,
30
28
  multiSelect: true,
31
29
  decorations,
32
- contextMenu,
30
+ // The controller projects the screen's actions onto menu entries at open time.
31
+ contextMenu: actions,
33
32
  })
34
33
 
35
34
  const statusItems = useMemo(
@@ -0,0 +1,154 @@
1
+ import { createStore } from "@xstate/store"
2
+ import type { MarkSet } from "@tooee/marks"
3
+ import type { AnyContent, Content, ContentChunk, ContentFormat, CustomContent } from "./types.js"
4
+
5
+ export type ContentLoaderStatus = "idle" | "loading" | "streaming" | "ready" | "error"
6
+
7
+ export interface ContentLoaderContext {
8
+ status: ContentLoaderStatus
9
+ requestId: number
10
+ loadSeq: number
11
+ content: AnyContent | null
12
+ error: string | null
13
+ providerMarks: MarkSet[]
14
+ title: string | undefined
15
+ }
16
+
17
+ export type ContentLoaderEvents = {
18
+ loadStarted: { marks: MarkSet[]; title?: string }
19
+ streamStarted: { requestId: number; format: string }
20
+ chunkReceived: { requestId: number; chunk: ContentChunk }
21
+ loaded: { requestId: number; content: AnyContent }
22
+ streamEnded: { requestId: number }
23
+ loadFailed: { requestId: number; error: string }
24
+ loadCancelled: { requestId: number }
25
+ reloadRequested: {}
26
+ }
27
+
28
+ export function isAsyncIterable(value: unknown): value is AsyncIterable<ContentChunk> {
29
+ return value != null && typeof value === "object" && Symbol.asyncIterator in value
30
+ }
31
+
32
+ export function createEmptyContent(format: string, title?: string): AnyContent {
33
+ switch (format) {
34
+ case "markdown":
35
+ return { format, markdown: "", title }
36
+ case "code":
37
+ return { format, code: "", title }
38
+ case "text":
39
+ return { format, text: "", title }
40
+ case "table":
41
+ return { format, columns: [], rows: [], title }
42
+ default:
43
+ return { format, data: undefined, title } as CustomContent
44
+ }
45
+ }
46
+
47
+ function ensureContentFormat<F extends ContentFormat>(
48
+ current: AnyContent | null,
49
+ format: F,
50
+ title?: string,
51
+ ): Extract<Content, { format: F }> {
52
+ if (!current || current.format !== format) {
53
+ return createEmptyContent(format, title) as Extract<Content, { format: F }>
54
+ }
55
+ return current as Extract<Content, { format: F }>
56
+ }
57
+
58
+ export function applyContentChunk(
59
+ current: AnyContent | null,
60
+ chunk: ContentChunk,
61
+ title?: string,
62
+ ): AnyContent {
63
+ switch (chunk.type) {
64
+ case "replace":
65
+ return chunk.content
66
+ case "append":
67
+ if (chunk.format === "markdown") {
68
+ const target = ensureContentFormat(current, "markdown", title)
69
+ return { ...target, markdown: target.markdown + chunk.data }
70
+ }
71
+ if (chunk.format === "code") {
72
+ const target = ensureContentFormat(current, "code", title)
73
+ return {
74
+ ...target,
75
+ code: target.code + chunk.data,
76
+ language: chunk.language ?? target.language,
77
+ }
78
+ }
79
+ {
80
+ const target = ensureContentFormat(current, "text", title)
81
+ return { ...target, text: target.text + chunk.data }
82
+ }
83
+ case "patch":
84
+ return chunk.apply(current)
85
+ default:
86
+ return current ?? createEmptyContent("markdown", title)
87
+ }
88
+ }
89
+
90
+ export function normalizeError(error: unknown): string {
91
+ return error instanceof Error ? error.message : String(error)
92
+ }
93
+
94
+ export function createContentLoaderStore() {
95
+ return createStore<ContentLoaderContext, ContentLoaderEvents>({
96
+ context: {
97
+ status: "idle",
98
+ requestId: 0,
99
+ loadSeq: 0,
100
+ content: null,
101
+ error: null,
102
+ providerMarks: [],
103
+ title: undefined,
104
+ },
105
+ on: {
106
+ loadStarted: (ctx, event) => ({
107
+ ...ctx,
108
+ status: "loading",
109
+ requestId: ctx.requestId + 1,
110
+ error: null,
111
+ providerMarks: event.marks,
112
+ title: event.title,
113
+ }),
114
+ streamStarted: (ctx, event) =>
115
+ event.requestId !== ctx.requestId
116
+ ? ctx
117
+ : {
118
+ ...ctx,
119
+ status: "streaming",
120
+ content: createEmptyContent(event.format, ctx.title),
121
+ },
122
+ chunkReceived: (ctx, event) => {
123
+ if (event.requestId !== ctx.requestId) return ctx
124
+ if (event.chunk.type === "marks") {
125
+ const markSet = event.chunk.set
126
+ const providerMarks = [
127
+ ...ctx.providerMarks.filter((set) => set.namespace !== markSet.namespace),
128
+ markSet,
129
+ ]
130
+ return { ...ctx, providerMarks }
131
+ }
132
+ return { ...ctx, content: applyContentChunk(ctx.content, event.chunk, ctx.title) }
133
+ },
134
+ loaded: (ctx, event) =>
135
+ event.requestId !== ctx.requestId
136
+ ? ctx
137
+ : { ...ctx, status: "ready", content: event.content },
138
+ streamEnded: (ctx, event) =>
139
+ event.requestId !== ctx.requestId ? ctx : { ...ctx, status: "ready" },
140
+ loadFailed: (ctx, event) =>
141
+ event.requestId !== ctx.requestId ? ctx : { ...ctx, status: "error", error: event.error },
142
+ loadCancelled: (ctx, event) =>
143
+ event.requestId !== ctx.requestId ? ctx : { ...ctx, requestId: ctx.requestId + 1 },
144
+ reloadRequested: (ctx) => ({ ...ctx, loadSeq: ctx.loadSeq + 1 }),
145
+ },
146
+ })
147
+ }
148
+
149
+ export const selectContent = (ctx: ContentLoaderContext) => ctx.content
150
+ export const selectStatus = (ctx: ContentLoaderContext) => ctx.status
151
+ export const selectStreaming = (ctx: ContentLoaderContext) => ctx.status === "streaming"
152
+ export const selectError = (ctx: ContentLoaderContext) => ctx.error
153
+ export const selectProviderMarks = (ctx: ContentLoaderContext) => ctx.providerMarks
154
+ export const selectLoadSeq = (ctx: ContentLoaderContext) => ctx.loadSeq
@@ -1,153 +1,72 @@
1
- import { useState, useEffect } from "react"
2
- import type { MarkSet } from "@tooee/marks"
3
- import type {
4
- AnyContent,
5
- Content,
6
- ContentFormat,
7
- ContentProvider,
8
- ContentChunk,
9
- CustomContent,
10
- } from "../types.js"
1
+ import { useCallback, useEffect, useState } from "react"
2
+ import { useSelector } from "@xstate/store-react"
3
+ import type { ContentProvider } from "../types.js"
4
+ import {
5
+ createContentLoaderStore,
6
+ isAsyncIterable,
7
+ normalizeError,
8
+ selectContent,
9
+ selectError,
10
+ selectLoadSeq,
11
+ selectProviderMarks,
12
+ selectStatus,
13
+ selectStreaming,
14
+ } from "../content-loader-store.js"
11
15
 
12
- function isAsyncIterable(value: unknown): value is AsyncIterable<ContentChunk> {
13
- return value != null && typeof value === "object" && Symbol.asyncIterator in value
14
- }
15
-
16
- function createEmptyContent(format: string, title?: string): AnyContent {
17
- switch (format) {
18
- case "markdown":
19
- return { format, markdown: "", title }
20
- case "code":
21
- return { format, code: "", title }
22
- case "text":
23
- return { format, text: "", title }
24
- case "table":
25
- return { format, columns: [], rows: [], title }
26
- default:
27
- return { format, data: undefined, title } as CustomContent
28
- }
29
- }
30
-
31
- function ensureContentFormat<F extends ContentFormat>(
32
- current: AnyContent | null,
33
- format: F,
34
- title?: string,
35
- ): Extract<Content, { format: F }> {
36
- if (!current || current.format !== format) {
37
- return createEmptyContent(format, title) as Extract<Content, { format: F }>
38
- }
39
- return current as Extract<Content, { format: F }>
40
- }
41
-
42
- function applyContentChunk(
43
- current: AnyContent | null,
44
- chunk: ContentChunk,
45
- title?: string,
46
- ): AnyContent {
47
- switch (chunk.type) {
48
- case "replace":
49
- return chunk.content
50
- case "append":
51
- if (chunk.format === "markdown") {
52
- const target = ensureContentFormat(current, "markdown", title)
53
- return { ...target, markdown: target.markdown + chunk.data }
54
- }
55
- if (chunk.format === "code") {
56
- const target = ensureContentFormat(current, "code", title)
57
- return {
58
- ...target,
59
- code: target.code + chunk.data,
60
- language: chunk.language ?? target.language,
61
- }
62
- }
63
- {
64
- const target = ensureContentFormat(current, "text", title)
65
- return { ...target, text: target.text + chunk.data }
66
- }
67
- case "patch":
68
- return chunk.apply(current)
69
- default:
70
- return current ?? createEmptyContent("markdown", title)
71
- }
72
- }
73
-
74
- export function useContentLoader(contentProvider: ContentProvider, reloadTrigger: number) {
75
- const [content, setContent] = useState<AnyContent | null>(null)
76
- const [streaming, setStreaming] = useState(false)
77
- const [error, setError] = useState<string | null>(null)
78
- const [providerMarks, setProviderMarks] = useState<MarkSet[]>([])
16
+ export function useContentLoader(contentProvider: ContentProvider) {
17
+ const [store] = useState(createContentLoaderStore)
18
+ const loadSeq = useSelector(store, (snapshot) => selectLoadSeq(snapshot.context))
79
19
 
80
20
  useEffect(() => {
81
- setError(null)
82
- setStreaming(false)
83
- // Reset provider marks on reload; initialize with static marks if provided
84
- setProviderMarks(contentProvider.marks ?? [])
21
+ store.trigger.loadStarted({
22
+ marks: contentProvider.marks ?? [],
23
+ title: contentProvider.title,
24
+ })
25
+ const requestId = store.getSnapshot().context.requestId
85
26
  const loaded = contentProvider.load()
86
27
 
87
28
  if (isAsyncIterable(loaded)) {
88
- const fallbackFormat = contentProvider.format ?? "markdown"
89
- const title = contentProvider.title
90
- let cancelled = false
91
- let current: AnyContent | null = createEmptyContent(fallbackFormat, title)
92
- setContent(current)
93
- setStreaming(true)
94
-
95
- // Hold the iterator explicitly so cleanup can close it: a cleanup that
96
- // only flips `cancelled` leaves a pending next() (and the provider's
97
- // subprocess/file handle/network stream) alive until the next chunk.
29
+ store.trigger.streamStarted({
30
+ requestId,
31
+ format: contentProvider.format ?? "markdown",
32
+ })
98
33
  const iterator = loaded[Symbol.asyncIterator]()
99
-
100
34
  ;(async () => {
101
35
  try {
102
36
  while (true) {
103
37
  const result = await iterator.next()
104
- if (cancelled || result.done) break
105
- const chunk = result.value
106
- if (chunk.type === "marks") {
107
- // Streamed mark set: merge by replacing any existing set with same namespace
108
- setProviderMarks((prev) => {
109
- const filtered = prev.filter((s) => s.namespace !== chunk.set.namespace)
110
- return [...filtered, chunk.set]
111
- })
112
- continue
113
- }
114
- current = applyContentChunk(current, chunk, title)
115
- setContent(current)
116
- }
117
- } catch (err) {
118
- if (!cancelled) {
119
- setError(err instanceof Error ? err.message : String(err))
120
- }
121
- } finally {
122
- if (!cancelled) {
123
- setStreaming(false)
38
+ if (result.done) break
39
+ store.trigger.chunkReceived({ requestId, chunk: result.value })
124
40
  }
41
+ store.trigger.streamEnded({ requestId })
42
+ } catch (error) {
43
+ store.trigger.loadFailed({ requestId, error: normalizeError(error) })
125
44
  }
126
45
  })()
127
-
128
46
  return () => {
129
- cancelled = true
130
- // Close the iterator to release provider resources mid-stream.
47
+ store.trigger.loadCancelled({ requestId })
131
48
  Promise.resolve(iterator.return?.()).catch(() => {})
132
49
  }
133
50
  }
134
51
 
135
52
  if (loaded instanceof Promise) {
136
- let active = true
137
53
  loaded
138
- .then((value) => {
139
- if (active) setContent(value)
140
- })
141
- .catch((err: unknown) => {
142
- if (active) setError(err instanceof Error ? err.message : String(err))
143
- })
144
- return () => {
145
- active = false
146
- }
54
+ .then((content) => store.trigger.loaded({ requestId, content }))
55
+ .catch((error: unknown) =>
56
+ store.trigger.loadFailed({ requestId, error: normalizeError(error) }),
57
+ )
58
+ return () => store.trigger.loadCancelled({ requestId })
147
59
  }
148
60
 
149
- setContent(loaded)
150
- }, [contentProvider, reloadTrigger])
61
+ store.trigger.loaded({ requestId, content: loaded })
62
+ }, [contentProvider, loadSeq, store])
63
+
64
+ const content = useSelector(store, (snapshot) => selectContent(snapshot.context))
65
+ const streaming = useSelector(store, (snapshot) => selectStreaming(snapshot.context))
66
+ const error = useSelector(store, (snapshot) => selectError(snapshot.context))
67
+ const providerMarks = useSelector(store, (snapshot) => selectProviderMarks(snapshot.context))
68
+ const status = useSelector(store, (snapshot) => selectStatus(snapshot.context))
69
+ const reload = useCallback(() => store.trigger.reloadRequested({}), [store])
151
70
 
152
- return { content, streaming, error, providerMarks, setProviderMarks }
71
+ return { content, streaming, error, providerMarks, status, reload }
153
72
  }