@orz/ui-code 0.0.0-stage → 0.0.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 (44) hide show
  1. package/LICENSE +29 -0
  2. package/README.md +216 -2
  3. package/dist/capped-code-block.d.ts +21 -0
  4. package/dist/capped-code-block.d.ts.map +1 -0
  5. package/dist/capped-code-block.js +41 -0
  6. package/dist/capped-code-block.js.map +1 -0
  7. package/dist/code-block.d.ts +147 -0
  8. package/dist/code-block.d.ts.map +1 -0
  9. package/dist/code-block.js +494 -0
  10. package/dist/code-block.js.map +1 -0
  11. package/dist/code-worker.d.ts +28 -0
  12. package/dist/code-worker.d.ts.map +1 -0
  13. package/dist/code-worker.js +29 -0
  14. package/dist/code-worker.js.map +1 -0
  15. package/dist/content.d.ts +12 -0
  16. package/dist/content.d.ts.map +1 -0
  17. package/dist/content.js +35 -0
  18. package/dist/content.js.map +1 -0
  19. package/dist/file-text.d.ts +16 -0
  20. package/dist/file-text.d.ts.map +1 -0
  21. package/dist/file-text.js +37 -0
  22. package/dist/file-text.js.map +1 -0
  23. package/dist/index.d.ts +6 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +6 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/patch-commit.d.ts +27 -0
  28. package/dist/patch-commit.d.ts.map +1 -0
  29. package/dist/patch-commit.js +109 -0
  30. package/dist/patch-commit.js.map +1 -0
  31. package/dist/patch-content.d.ts +13 -0
  32. package/dist/patch-content.d.ts.map +1 -0
  33. package/dist/patch-content.js +43 -0
  34. package/dist/patch-content.js.map +1 -0
  35. package/dist/patch-view.d.ts +49 -0
  36. package/dist/patch-view.d.ts.map +1 -0
  37. package/dist/patch-view.js +167 -0
  38. package/dist/patch-view.js.map +1 -0
  39. package/dist/word-diff.d.ts +82 -0
  40. package/dist/word-diff.d.ts.map +1 -0
  41. package/dist/word-diff.js +209 -0
  42. package/dist/word-diff.js.map +1 -0
  43. package/package.json +63 -3
  44. package/styles.css +34 -0
@@ -0,0 +1,16 @@
1
+ import { type ContentProps, type ContentSource } from "@orz/ui-content";
2
+ import type { ReactNode } from "react";
3
+ export type FileSource = Extract<ContentSource, {
4
+ kind: "file";
5
+ }>;
6
+ /**
7
+ * A text file's contents, once loaded and without its final newline, drawn by `children`; while
8
+ * it loads, or when it fails or is declared over `TEXT_PREVIEW_HARD_MAX_BYTES`, the registry's
9
+ * fallback with a note. Between that and `TEXT_PREVIEW_MAX_BYTES` it loads: the viewer and the
10
+ * embed card ask first, and `children` draws text that large plain.
11
+ */
12
+ export declare function FileText(props: ContentProps & {
13
+ source: FileSource;
14
+ children: (text: string) => ReactNode;
15
+ }): import("react").JSX.Element;
16
+ //# sourceMappingURL=file-text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-text.d.ts","sourceRoot":"","sources":["../src/file-text.tsx"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,aAAa,EAGnB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,aAAa,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AA4DlE;;;;;GAKG;AACH,wBAAgB,QAAQ,CACtB,KAAK,EAAE,YAAY,GAAG;IACpB,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,SAAS,CAAC;CACvC,+BAaF"}
@@ -0,0 +1,37 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button } from "@orz/ui/components/button";
3
+ import { ContentFallback, TEXT_PREVIEW_HARD_MAX_BYTES, useSourceText, } from "@orz/ui-content";
4
+ /** A file declared over the hard cap is not loaded at all. */
5
+ function TooLargeFile({ source, placement, className, }) {
6
+ return (_jsxs("div", { className: className, children: [_jsx(ContentFallback, { source: source, placement: placement }), " ", _jsx("span", { children: "This file is too large to preview." })] }));
7
+ }
8
+ function LoadedText({ source, placement, className, children, }) {
9
+ const text = useSourceText(source);
10
+ if (text.status === "loading") {
11
+ return (_jsx(ContentFallback, { source: source, placement: placement, className: className }));
12
+ }
13
+ if (text.status === "error") {
14
+ return (_jsxs("div", { className: className, children: [_jsx(ContentFallback, { source: source, placement: placement }), " ", _jsx("span", { children: text.error.message }), " ", _jsx(Button, { size: "xs", variant: "outline", onClick: text.retry, children: "Retry" })] }));
15
+ }
16
+ // A code view only hands its className to pierre's view, which is not
17
+ // mounted while the plain-text stand-in shows; the wrapper keeps it on the
18
+ // root throughout.
19
+ return (_jsx("div", { className: className, children:
20
+ // pierre numbers the empty line after a file's final newline, so
21
+ // every well-formed file would end on a blank numbered line.
22
+ children(text.text.replace(/\r?\n$/, "")) }));
23
+ }
24
+ /**
25
+ * A text file's contents, once loaded and without its final newline, drawn by `children`; while
26
+ * it loads, or when it fails or is declared over `TEXT_PREVIEW_HARD_MAX_BYTES`, the registry's
27
+ * fallback with a note. Between that and `TEXT_PREVIEW_MAX_BYTES` it loads: the viewer and the
28
+ * embed card ask first, and `children` draws text that large plain.
29
+ */
30
+ export function FileText(props) {
31
+ const { source, placement, className } = props;
32
+ if (source.size !== undefined && source.size > TEXT_PREVIEW_HARD_MAX_BYTES) {
33
+ return (_jsx(TooLargeFile, { source: source, placement: placement, className: className }));
34
+ }
35
+ return _jsx(LoadedText, { ...props });
36
+ }
37
+ //# sourceMappingURL=file-text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-text.js","sourceRoot":"","sources":["../src/file-text.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AACnD,OAAO,EACL,eAAe,EAGf,2BAA2B,EAC3B,aAAa,GACd,MAAM,iBAAiB,CAAC;AAKzB,8DAA8D;AAC9D,SAAS,YAAY,CAAC,EACpB,MAAM,EACN,SAAS,EACT,SAAS,GAC6B;IACtC,OAAO,CACL,eAAK,SAAS,EAAE,SAAS,aACvB,KAAC,eAAe,IAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,GAAI,EAAC,GAAG,EAC7D,gEAA+C,IAC3C,CACP,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,EAClB,MAAM,EACN,SAAS,EACT,SAAS,EACT,QAAQ,GAIT;IACC,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACnC,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,CACL,KAAC,eAAe,IACd,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,SAAS,EACpB,SAAS,EAAE,SAAS,GACpB,CACH,CAAC;IACJ,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;QAC5B,OAAO,CACL,eAAK,SAAS,EAAE,SAAS,aACvB,KAAC,eAAe,IAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,GAAI,EAAC,GAAG,EAC7D,yBAAO,IAAI,CAAC,KAAK,CAAC,OAAO,GAAQ,EAAC,GAAG,EACrC,KAAC,MAAM,IAAC,IAAI,EAAC,IAAI,EAAC,OAAO,EAAC,SAAS,EAAC,OAAO,EAAE,IAAI,CAAC,KAAK,sBAE9C,IACL,CACP,CAAC;IACJ,CAAC;IACD,sEAAsE;IACtE,2EAA2E;IAC3E,mBAAmB;IACnB,OAAO,CACL,cAAK,SAAS,EAAE,SAAS;QAErB,iEAAiE;QACjE,6DAA6D;QAC7D,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,GAEvC,CACP,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CACtB,KAGC;IAED,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IAC/C,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,GAAG,2BAA2B,EAAE,CAAC;QAC3E,OAAO,CACL,KAAC,YAAY,IACX,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,SAAS,EACpB,SAAS,EAAE,SAAS,GACpB,CACH,CAAC;IACJ,CAAC;IACD,OAAO,KAAC,UAAU,OAAK,KAAK,GAAI,CAAC;AACnC,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { CodeBlock, CodeDiffBlock, fenceFilename, LazyMultiFileDiff, PIERRE_HIGHLIGHTER, PIERRE_THEME, PIERRE_THEME_TYPE, type SyntaxTheme, useSyntaxTheme, } from "./code-block.tsx";
2
+ export { type CodeWorkerFactory, CodeWorkerProvider, useCodeWorkerFactory, } from "./code-worker.tsx";
3
+ export { codeContent } from "./content.tsx";
4
+ export { patchContent } from "./patch-content.tsx";
5
+ export { LARGE_DIFF_LINES, PatchView, type PatchViewProps, } from "./patch-view.tsx";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,YAAY,EACZ,iBAAiB,EACjB,KAAK,WAAW,EAChB,cAAc,GACf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,KAAK,iBAAiB,EACtB,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EACL,gBAAgB,EAChB,SAAS,EACT,KAAK,cAAc,GACpB,MAAM,kBAAkB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export { CodeBlock, CodeDiffBlock, fenceFilename, LazyMultiFileDiff, PIERRE_HIGHLIGHTER, PIERRE_THEME, PIERRE_THEME_TYPE, useSyntaxTheme, } from "./code-block.js";
2
+ export { CodeWorkerProvider, useCodeWorkerFactory, } from "./code-worker.js";
3
+ export { codeContent } from "./content.js";
4
+ export { patchContent } from "./patch-content.js";
5
+ export { LARGE_DIFF_LINES, PatchView, } from "./patch-view.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,YAAY,EACZ,iBAAiB,EAEjB,cAAc,GACf,MAAM,iBAAkB,CAAC;AAC1B,OAAO,EAEL,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,kBAAmB,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,cAAe,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAqB,CAAC;AACnD,OAAO,EACL,gBAAgB,EAChB,SAAS,GAEV,MAAM,iBAAkB,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * What a patch says about the commit it came from, read off the text before
3
+ * its first file: `git format-patch` mail headers, or `git show` / `git log -p`
4
+ * output.
5
+ */
6
+ export type PatchCommit = {
7
+ /** The subject line, `[PATCH n/m]` taken off. Empty when there is none. */
8
+ subject: string;
9
+ /** `n/m` from `[PATCH n/m]`. */
10
+ series?: string;
11
+ author?: string;
12
+ /** As written; see `formatCommitDate`. */
13
+ date?: string;
14
+ hash?: string;
15
+ /** The message under the subject, without the `---` and `--stat` after it. */
16
+ body: string;
17
+ };
18
+ /**
19
+ * The commit a patch's preamble describes, or null when the preamble names
20
+ * none and carries nothing a reader would miss — a `diff -u a b` command line
21
+ * or an `Index:` banner, which only restate the file header under them.
22
+ * Free text that is neither stays as a body without a subject.
23
+ */
24
+ export declare function parsePatchCommit(preamble: string): PatchCommit | null;
25
+ /** A commit date as a short local date, or the text as written if unparsable. */
26
+ export declare function formatCommitDate(date: string): string;
27
+ //# sourceMappingURL=patch-commit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patch-commit.d.ts","sourceRoot":"","sources":["../src/patch-commit.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,2EAA2E;IAC3E,OAAO,EAAE,MAAM,CAAC;IAChB,gCAAgC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AA0EF;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAkBrE;AAED,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASrD"}
@@ -0,0 +1,109 @@
1
+ const FORMAT_PATCH_FROM = /^From ([0-9a-f]{7,40}) /;
2
+ const GIT_SHOW_COMMIT = /^commit ([0-9a-f]{7,40})\b/;
3
+ const PATCH_TAG = /^\[PATCH(?:[^\]]*?(\d+\/\d+))?[^\]]*\]\s*/;
4
+ function authorName(value) {
5
+ // `alice <noreply@example.com>` → `alice`; a bare address stays itself.
6
+ const name = value.replace(/\s*<[^>]*>\s*$/, "").trim();
7
+ return name === "" ? value.trim() : name.replace(/^"(.*)"$/, "$1");
8
+ }
9
+ function trimBlankLines(lines) {
10
+ let start = 0;
11
+ let end = lines.length;
12
+ while (start < end && lines[start].trim() === "")
13
+ start++;
14
+ while (end > start && lines[end - 1].trim() === "")
15
+ end--;
16
+ return lines.slice(start, end).join("\n");
17
+ }
18
+ function untag(subject) {
19
+ const tag = PATCH_TAG.exec(subject);
20
+ if (tag === null)
21
+ return { subject };
22
+ return { subject: subject.slice(tag[0].length), series: tag[1] };
23
+ }
24
+ /** `git format-patch`: mail headers, a blank line, the body, `---`, stat. */
25
+ function fromMail(lines) {
26
+ const headers = new Map();
27
+ let last;
28
+ let i = 0;
29
+ const hash = FORMAT_PATCH_FROM.exec(lines[0])?.[1];
30
+ if (hash !== undefined)
31
+ i = 1;
32
+ for (; i < lines.length && lines[i] !== ""; i++) {
33
+ const line = lines[i];
34
+ // RFC 5322 folding: a long Subject continues on indented lines.
35
+ if (/^[ \t]/.test(line) && last !== undefined) {
36
+ headers.set(last, `${headers.get(last)} ${line.trim()}`);
37
+ continue;
38
+ }
39
+ const field = /^([A-Za-z-]+):[ \t]*(.*)$/.exec(line);
40
+ if (field === null)
41
+ break;
42
+ last = field[1].toLowerCase();
43
+ headers.set(last, field[2]);
44
+ }
45
+ const rest = lines.slice(i);
46
+ const cut = rest.indexOf("---");
47
+ const from = headers.get("from");
48
+ return {
49
+ ...untag(headers.get("subject")?.trim() ?? ""),
50
+ author: from === undefined ? undefined : authorName(from),
51
+ date: headers.get("date"),
52
+ hash,
53
+ body: trimBlankLines(cut === -1 ? rest : rest.slice(0, cut)),
54
+ };
55
+ }
56
+ /** `git show`: `commit`, `Author:`, `Date:`, then the message indented. */
57
+ function fromShow(lines, hash) {
58
+ let author;
59
+ let date;
60
+ let i = 1;
61
+ for (; i < lines.length && lines[i] !== ""; i++) {
62
+ const field = /^([A-Za-z]+):\s*(.*)$/.exec(lines[i]);
63
+ if (field?.[1] === "Author")
64
+ author = authorName(field[2]);
65
+ if (field?.[1] === "Date")
66
+ date = field[2];
67
+ }
68
+ const message = lines.slice(i).map((line) => line.replace(/^ {4}/, ""));
69
+ const cut = message.indexOf("---");
70
+ const text = trimBlankLines(cut === -1 ? message : message.slice(0, cut));
71
+ const [subject = "", ...body] = text.split("\n");
72
+ return { subject, author, date, hash, body: trimBlankLines(body) };
73
+ }
74
+ /**
75
+ * The commit a patch's preamble describes, or null when the preamble names
76
+ * none and carries nothing a reader would miss — a `diff -u a b` command line
77
+ * or an `Index:` banner, which only restate the file header under them.
78
+ * Free text that is neither stays as a body without a subject.
79
+ */
80
+ export function parsePatchCommit(preamble) {
81
+ const lines = preamble.replace(/\r\n/g, "\n").split("\n");
82
+ while (lines.length > 0 && lines[0].trim() === "")
83
+ lines.shift();
84
+ if (lines.length === 0)
85
+ return null;
86
+ const shown = GIT_SHOW_COMMIT.exec(lines[0])?.[1];
87
+ if (shown !== undefined)
88
+ return fromShow(lines, shown);
89
+ if (FORMAT_PATCH_FROM.test(lines[0]) ||
90
+ /^(From|Subject|Date):/.test(lines[0])) {
91
+ return fromMail(lines);
92
+ }
93
+ const meaningful = lines.filter((line) => line.trim() !== "" && !/^(diff |Index: |={10,}|Only in )/.test(line));
94
+ if (meaningful.length === 0)
95
+ return null;
96
+ return { subject: "", body: trimBlankLines(lines) };
97
+ }
98
+ /** A commit date as a short local date, or the text as written if unparsable. */
99
+ export function formatCommitDate(date) {
100
+ const parsed = new Date(date);
101
+ return Number.isNaN(parsed.getTime())
102
+ ? date
103
+ : parsed.toLocaleDateString(undefined, {
104
+ year: "numeric",
105
+ month: "short",
106
+ day: "numeric",
107
+ });
108
+ }
109
+ //# sourceMappingURL=patch-commit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patch-commit.js","sourceRoot":"","sources":["../src/patch-commit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { type ContentRenderer } from "@orz/ui-content";
2
+ /**
3
+ * The registry entry for unified diffs: a source tagged `diff` or `patch` (a fenced block) and a
4
+ * file `isPatchFile` calls a patch, in either placement. Each is drawn as one diff per file under
5
+ * its commit's subject and message, with a file list and a toggle back to the text as written.
6
+ * Register it before `codeContent`, which takes every inline source and text file.
7
+ *
8
+ * A fence that is not a patch, such as a bare `+`/`-` snippet, stays highlighted text; a file
9
+ * that is not one says so above its text. The controls go into the title bar a surrounding card
10
+ * lends (`useContentTitleBar`), or into a frame of the patch's own.
11
+ */
12
+ export declare const patchContent: ContentRenderer;
13
+ //# sourceMappingURL=patch-content.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patch-content.d.ts","sourceRoot":"","sources":["../src/patch-content.tsx"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,eAAe,EAIrB,MAAM,iBAAiB,CAAC;AAkDzB;;;;;;;;;GASG;AACH,eAAO,MAAM,YAAY,EAAE,eAK1B,CAAC"}
@@ -0,0 +1,43 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { isPatchFile, useContentTitleBar, } from "@orz/ui-content";
3
+ import { fenceFilename } from "./code-block.js";
4
+ import { FileText } from "./file-text.js";
5
+ import { PatchView } from "./patch-view.js";
6
+ function accepts(source) {
7
+ if (source.kind === "inline") {
8
+ const lang = source.lang?.toLowerCase();
9
+ return lang === "diff" || lang === "patch";
10
+ }
11
+ return isPatchFile(source);
12
+ }
13
+ function Patch({ source, placement, className }) {
14
+ const titleBar = useContentTitleBar(source);
15
+ if (source.kind === "inline") {
16
+ return (_jsx("div", { className: className, children: _jsx(PatchView, { filename: fenceFilename(source.lang), text: source.text, titleBar: titleBar }) }));
17
+ }
18
+ return (_jsx(FileText, { source: source, placement: placement, className: className, children: (text) => (_jsx(PatchView, { filename: source.name, text: text, lineNumbers: true, invalidNote: true,
19
+ // A document that lends its title bar is a card, which hides what
20
+ // overflows its collapsed body.
21
+ fit: placement === "viewer"
22
+ ? "pane"
23
+ : titleBar !== undefined
24
+ ? "clipped"
25
+ : "flow", titleBar: titleBar })) }));
26
+ }
27
+ /**
28
+ * The registry entry for unified diffs: a source tagged `diff` or `patch` (a fenced block) and a
29
+ * file `isPatchFile` calls a patch, in either placement. Each is drawn as one diff per file under
30
+ * its commit's subject and message, with a file list and a toggle back to the text as written.
31
+ * Register it before `codeContent`, which takes every inline source and text file.
32
+ *
33
+ * A fence that is not a patch, such as a bare `+`/`-` snippet, stays highlighted text; a file
34
+ * that is not one says so above its text. The controls go into the title bar a surrounding card
35
+ * lends (`useContentTitleBar`), or into a frame of the patch's own.
36
+ */
37
+ export const patchContent = {
38
+ name: "patch",
39
+ accepts,
40
+ display: "block",
41
+ Component: Patch,
42
+ };
43
+ //# sourceMappingURL=patch-content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patch-content.js","sourceRoot":"","sources":["../src/patch-content.tsx"],"names":[],"mappings":";AAAA,OAAO,EAIL,WAAW,EACX,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAkB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAiB,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAkB,CAAC;AAE7C,SAAS,OAAO,CAAC,MAAqB;IACpC,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC;QACxC,OAAO,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,OAAO,CAAC;IAC7C,CAAC;IACD,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC;AAC7B,CAAC;AAED,SAAS,KAAK,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAgB;IAC3D,MAAM,QAAQ,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC5C,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,CACL,cAAK,SAAS,EAAE,SAAS,YACvB,KAAC,SAAS,IACR,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,EACpC,IAAI,EAAE,MAAM,CAAC,IAAI,EACjB,QAAQ,EAAE,QAAQ,GAClB,GACE,CACP,CAAC;IACJ,CAAC;IACD,OAAO,CACL,KAAC,QAAQ,IAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,YACjE,CAAC,IAAI,EAAE,EAAE,CAAC,CACT,KAAC,SAAS,IACR,QAAQ,EAAE,MAAM,CAAC,IAAI,EACrB,IAAI,EAAE,IAAI,EACV,WAAW,QACX,WAAW;YACX,kEAAkE;YAClE,gCAAgC;YAChC,GAAG,EACD,SAAS,KAAK,QAAQ;gBACpB,CAAC,CAAC,MAAM;gBACR,CAAC,CAAC,QAAQ,KAAK,SAAS;oBACtB,CAAC,CAAC,SAAS;oBACX,CAAC,CAAC,MAAM,EAEd,QAAQ,EAAE,QAAQ,GAClB,CACH,GACQ,CACZ,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,YAAY,GAAoB;IAC3C,IAAI,EAAE,OAAO;IACb,OAAO;IACP,OAAO,EAAE,OAAO;IAChB,SAAS,EAAE,KAAK;CACjB,CAAC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Changed lines past which a file's diff waits behind "Load diff". Not a speed
3
+ * limit — a 40,000-line file drew in 0.1 s — but a reading one: a generated
4
+ * file that size buries the files around it.
5
+ */
6
+ export declare const LARGE_DIFF_LINES = 2000;
7
+ /** How the diffs' box is capped; see `PatchView`'s `fit`. */
8
+ declare const FIT_CLASS: {
9
+ readonly flow: "max-h-[70vh] overflow-auto";
10
+ readonly pane: "max-h-[calc(75vh-3.5rem)] overflow-auto";
11
+ readonly clipped: "max-h-screen overflow-hidden";
12
+ };
13
+ export type PatchViewProps = {
14
+ /** Names the raw view's highlighting. */
15
+ filename: string;
16
+ text: string;
17
+ /** Line numbers on the raw view, as whole files have them. */
18
+ lineNumbers?: boolean;
19
+ /**
20
+ * Say so when the text is not a patch. A file named .patch promised one; a
21
+ * fence tagged `diff` holding a bare +/- snippet never did.
22
+ */
23
+ invalidNote?: boolean;
24
+ /**
25
+ * The box the diffs scroll in, which has to be capped for the view to
26
+ * virtualize. `flow` (default): within a document, up to 70vh. `pane`: the
27
+ * attachment viewer, within its 75vh pane. `clipped`: inside a card that
28
+ * hides its overflow below one screen, so the diffs do not scroll and the
29
+ * file list does not jump, since nothing the reader can do would scroll
30
+ * back.
31
+ */
32
+ fit?: keyof typeof FIT_CLASS;
33
+ /**
34
+ * Where the surrounding title bar takes the controls (`useContentTitleBar`);
35
+ * null until it has mounted. Undefined, the patch draws a bar of its own.
36
+ */
37
+ titleBar?: HTMLElement | null;
38
+ };
39
+ /**
40
+ * A unified diff drawn as one diff per file, each commit's subject, author and
41
+ * message above its files. The file list and the way back to the text as
42
+ * written are controls of the surface around it: a card or viewer lends a spot
43
+ * in its title bar, and a fence, which has none, gets a frame with one.
44
+ * Text that does not parse cleanly stays that text: see `parsePatch` for why a
45
+ * half-parsed patch is never drawn.
46
+ */
47
+ export declare function PatchView({ filename, text, lineNumbers, invalidNote, fit, titleBar, }: PatchViewProps): import("react").JSX.Element;
48
+ export {};
49
+ //# sourceMappingURL=patch-view.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patch-view.d.ts","sourceRoot":"","sources":["../src/patch-view.tsx"],"names":[],"mappings":"AAmGA;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,OAAO,CAAC;AAsIrC,6DAA6D;AAC7D,QAAA,MAAM,SAAS;aACb,IAAI,EAAE,4BAA4B;aAKlC,IAAI,EAAE,yCAAyC;aAI/C,OAAO,EAAE,8BAA8B;CAC/B,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG;IAC3B,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,8DAA8D;IAC9D,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;;;OAOG;IACH,GAAG,CAAC,EAAE,MAAM,OAAO,SAAS,CAAC;IAC7B;;;OAGG;IACH,QAAQ,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;CAC/B,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,EACxB,QAAQ,EACR,IAAI,EACJ,WAAmB,EACnB,WAAmB,EACnB,GAAY,EACZ,QAAQ,GACT,EAAE,cAAc,+BA0KhB"}
@@ -0,0 +1,167 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button } from "@orz/ui/components/button";
3
+ import { Popover, PopoverContent, PopoverTrigger, } from "@orz/ui/components/popover";
4
+ import { cn } from "@orz/ui/lib/utils";
5
+ import { ChevronDownIcon, CodeIcon, FileDiffIcon, GitCommitHorizontalIcon, } from "lucide-react";
6
+ import { useEffect, useMemo, useRef, useState } from "react";
7
+ import { createPortal } from "react-dom";
8
+ import { CappedCodeBlock } from "./capped-code-block.js";
9
+ import { PATCH_HEADER_HEIGHT, PatchFiles, PlainCodeFallback, parsePatch, patchCommitId, patchFileId, } from "./code-block.js";
10
+ import { formatCommitDate, parsePatchCommit, } from "./patch-commit.js";
11
+ function countLines(file) {
12
+ let plus = 0;
13
+ let minus = 0;
14
+ for (const hunk of file.hunks) {
15
+ plus += hunk.additionLines;
16
+ minus += hunk.deletionLines;
17
+ }
18
+ return { plus, minus };
19
+ }
20
+ function Counts({ plus, minus }) {
21
+ return (_jsxs("span", { className: "shrink-0 space-x-1 font-mono text-xs tabular-nums", children: [plus > 0 && _jsxs("span", { className: "diff-addition-text", children: ["+", plus] }), minus > 0 && _jsxs("span", { className: "diff-deletion-text", children: ["\u2212", minus] })] }));
22
+ }
23
+ function fileLabel(file) {
24
+ return file.prevName !== undefined && file.prevName !== file.name
25
+ ? `${file.prevName} → ${file.name}`
26
+ : file.name;
27
+ }
28
+ const HEADER_ROW = "flex min-w-0 items-center gap-2 px-3 text-sm";
29
+ function CommitHeader({ commit }) {
30
+ const date = commit.date === undefined ? undefined : formatCommitDate(commit.date);
31
+ return (_jsxs("div", { className: HEADER_ROW, style: { height: PATCH_HEADER_HEIGHT }, children: [_jsx(GitCommitHorizontalIcon, { className: "size-4 shrink-0 text-muted-foreground" }), commit.series !== undefined && (_jsx("span", { className: "shrink-0 rounded-full border px-1.5 text-[11px] leading-4 text-muted-foreground tabular-nums", children: commit.series })), _jsx("span", { className: "min-w-0 truncate font-medium", title: commit.subject, children: commit.subject === "" ? "Message" : commit.subject }), _jsxs("span", { className: "ml-auto shrink-0 text-xs text-muted-foreground", children: [commit.author, commit.author && date ? " · " : null, date && _jsx("time", { children: date }), commit.hash !== undefined && (_jsx("span", { className: "ml-2 font-mono", children: commit.hash.slice(0, 7) }))] })] }));
32
+ }
33
+ /**
34
+ * Changed lines past which a file's diff waits behind "Load diff". Not a speed
35
+ * limit — a 40,000-line file drew in 0.1 s — but a reading one: a generated
36
+ * file that size buries the files around it.
37
+ */
38
+ export const LARGE_DIFF_LINES = 2000;
39
+ function FileHeader({ file, stat, onLoad, }) {
40
+ const label = fileLabel(file);
41
+ return (_jsxs("div", { className: HEADER_ROW, style: { height: PATCH_HEADER_HEIGHT }, children: [_jsx(FileDiffIcon, { className: "size-4 shrink-0 text-muted-foreground" }), _jsx("span", { className: "min-w-0 truncate font-mono text-[0.8rem]", title: label, children: label }), _jsxs("span", { className: "ml-auto flex shrink-0 items-center gap-2", children: [onLoad !== undefined && (_jsx(Button, { type: "button", size: "xs", variant: "outline", onClick: onLoad, children: "Load diff" })), _jsx(Counts, { ...stat })] })] }));
42
+ }
43
+ function FileList({ files, stats, onJump, }) {
44
+ return (_jsx("ul", { className: "divide-y text-xs", children: files.map((file, index) => {
45
+ // A long path gives up its directories, never the file's own name.
46
+ const slash = file.name.lastIndexOf("/");
47
+ const row = (_jsxs(_Fragment, { children: [_jsxs("span", { className: "flex min-w-0 font-mono", children: [_jsx("span", { className: "min-w-0 truncate text-muted-foreground", children: file.name.slice(0, slash + 1) }), _jsx("span", { className: "shrink-0", children: file.name.slice(slash + 1) })] }), _jsx(Counts, { ...(stats[index] ?? { plus: 0, minus: 0 }) })] }));
48
+ const rowClass = "flex w-full items-center justify-between gap-3 px-2.5 py-1.5";
49
+ return (_jsx("li", { title: fileLabel(file), children: onJump !== undefined ? (_jsx("button", { type: "button", onClick: () => onJump(index), className: cn(rowClass, "cursor-pointer text-left hover:bg-muted"), children: row })) : (_jsx("div", { className: rowClass, children: row })) }, index));
50
+ }) }));
51
+ }
52
+ function FilesMenu({ files, stats, onJump, }) {
53
+ const [open, setOpen] = useState(false);
54
+ const total = stats.reduce((sum, s) => ({ plus: sum.plus + s.plus, minus: sum.minus + s.minus }), { plus: 0, minus: 0 });
55
+ return (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { type: "button", size: "xs", variant: "ghost", className: "font-normal text-muted-foreground", children: [_jsxs("span", { className: "tabular-nums", children: [files.length, " files"] }), _jsx(Counts, { ...total }), _jsx(ChevronDownIcon, {})] }) }), _jsx(PopoverContent, { align: "end", className: "max-h-[55vh] w-96 max-w-[calc(100vw-2rem)] overflow-y-auto p-0", children: _jsx(FileList, { files: files, stats: stats, onJump: onJump === undefined
56
+ ? undefined
57
+ : (index) => {
58
+ setOpen(false);
59
+ onJump(index);
60
+ } }) })] }));
61
+ }
62
+ /** How the diffs' box is capped; see `PatchView`'s `fit`. */
63
+ const FIT_CLASS = {
64
+ flow: "max-h-[70vh] overflow-auto",
65
+ // Not --attachment-pane-height: maximized, that is 100%, which resolves
66
+ // against the auto-height wrappers in between to no cap at all, and the
67
+ // view lays out every line. The 3.5rem leaves room for a frame's own bar
68
+ // inside the 75vh pane.
69
+ pane: "max-h-[calc(75vh-3.5rem)] overflow-auto",
70
+ // Any cap past the card's own works: the card hides the rest, and the
71
+ // reader expands the card rather than scrolling inside it. A card capped
72
+ // taller than the screen, or not at all, cuts the patch at one screen.
73
+ clipped: "max-h-screen overflow-hidden",
74
+ };
75
+ /**
76
+ * A unified diff drawn as one diff per file, each commit's subject, author and
77
+ * message above its files. The file list and the way back to the text as
78
+ * written are controls of the surface around it: a card or viewer lends a spot
79
+ * in its title bar, and a fence, which has none, gets a frame with one.
80
+ * Text that does not parse cleanly stays that text: see `parsePatch` for why a
81
+ * half-parsed patch is never drawn.
82
+ */
83
+ export function PatchView({ filename, text, lineNumbers = false, invalidNote = false, fit = "flow", titleBar, }) {
84
+ const [parsed, setParsed] = useState({ kind: "pending" });
85
+ const [raw, setRaw] = useState(false);
86
+ const [loaded, setLoaded] = useState(() => new Set());
87
+ const view = useRef(null);
88
+ useEffect(() => {
89
+ let live = true;
90
+ setParsed({ kind: "pending" });
91
+ setLoaded(new Set());
92
+ // A fence body arrives without its last newline. The patch's own
93
+ // "" markers carry that fact, not this one.
94
+ parsePatch(text.endsWith("\n") ? text : `${text}\n`).then((patches) => {
95
+ if (live) {
96
+ setParsed(patches === null ? { kind: "invalid" } : { kind: "patch", patches });
97
+ }
98
+ }, () => {
99
+ if (live)
100
+ setParsed({ kind: "unavailable" });
101
+ });
102
+ return () => {
103
+ live = false;
104
+ };
105
+ }, [text]);
106
+ const patches = parsed.kind === "patch" ? parsed.patches : null;
107
+ const drawn = useMemo(() => {
108
+ if (patches === null)
109
+ return null;
110
+ const files = patches.flatMap((patch) => patch.files);
111
+ const stats = files.map(countLines);
112
+ const commits = patches.map((patch) => parsePatchCommit(patch.patchMetadata ?? ""));
113
+ const messages = commits.map((commit) => commit?.body ?? null);
114
+ // A lone file is what the reader opened the patch for.
115
+ const large = new Set();
116
+ if (files.length > 1) {
117
+ stats.forEach((stat, index) => {
118
+ if (stat.plus + stat.minus > LARGE_DIFF_LINES)
119
+ large.add(index);
120
+ });
121
+ }
122
+ return { files, stats, commits, messages, large };
123
+ }, [patches]);
124
+ const collapsed = useMemo(() => {
125
+ const held = new Set();
126
+ for (const index of drawn?.large ?? []) {
127
+ if (!loaded.has(index))
128
+ held.add(index);
129
+ }
130
+ return held;
131
+ }, [drawn, loaded]);
132
+ const headers = useMemo(() => {
133
+ const rows = new Map();
134
+ if (drawn === null)
135
+ return rows;
136
+ drawn.commits.forEach((commit, index) => {
137
+ if (commit !== null) {
138
+ rows.set(patchCommitId(index), _jsx(CommitHeader, { commit: commit }));
139
+ }
140
+ });
141
+ drawn.files.forEach((file, index) => {
142
+ rows.set(patchFileId(index), _jsx(FileHeader, { file: file, stat: drawn.stats[index] ?? { plus: 0, minus: 0 }, onLoad: collapsed.has(index)
143
+ ? () => setLoaded((shown) => new Set(shown).add(index))
144
+ : undefined }));
145
+ });
146
+ return rows;
147
+ }, [drawn, collapsed]);
148
+ if (parsed.kind === "pending")
149
+ return _jsx(PlainCodeFallback, { contents: text });
150
+ if (patches === null || drawn === null) {
151
+ return (_jsxs(_Fragment, { children: [parsed.kind === "invalid" && invalidNote && (_jsx("p", { className: "mb-2 text-xs text-muted-foreground", children: "Not a valid patch \u2014 showing the text." })), _jsx(CappedCodeBlock, { filename: filename, contents: text, lineNumbers: lineNumbers })] }));
152
+ }
153
+ const { files, stats, messages } = drawn;
154
+ const controls = (_jsxs("span", { className: "inline-flex shrink-0 items-center gap-0.5", children: [files.length > 1 && !raw && (_jsx(FilesMenu, { files: files, stats: stats, onJump: fit === "clipped"
155
+ ? undefined
156
+ : (index) => view.current?.scrollTo({
157
+ type: "item",
158
+ id: patchFileId(index),
159
+ align: "start",
160
+ }) })), _jsxs(Button, { type: "button", size: "xs", variant: "ghost", "aria-pressed": raw, title: raw ? "Back to the diff" : "The patch as written", className: cn("font-normal text-muted-foreground", raw && "bg-muted text-foreground"), onClick: () => setRaw((shown) => !shown), children: [_jsx(CodeIcon, {}), "raw"] })] }));
161
+ const body = raw ? (_jsx(CappedCodeBlock, { filename: filename, contents: text, lineNumbers: lineNumbers })) : (_jsx(PatchFiles, { patches: patches, messages: messages, collapsedFiles: collapsed, text: text, viewRef: view, renderHeader: (item) => headers.get(item.id), className: FIT_CLASS[fit] }));
162
+ if (titleBar !== undefined) {
163
+ return (_jsxs(_Fragment, { children: [titleBar !== null && createPortal(controls, titleBar), body] }));
164
+ }
165
+ return (_jsxs("div", { className: "overflow-hidden rounded-lg border", children: [_jsxs("div", { className: "flex items-center gap-2 border-b bg-muted/40 py-1 pr-1.5 pl-3 text-xs text-muted-foreground", children: [_jsx(FileDiffIcon, { className: "size-3.5" }), _jsx("span", { children: "patch" }), _jsx("span", { className: "ml-auto" }), controls] }), _jsx("div", { className: "p-2", children: body })] }));
166
+ }
167
+ //# sourceMappingURL=patch-view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patch-view.js","sourceRoot":"","sources":["../src/patch-view.tsx"],"names":[],"mappings":"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"}