@orz/ui-ansi 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.
- package/LICENSE +29 -0
- package/README.md +232 -2
- package/dist/content.d.ts +20 -0
- package/dist/content.d.ts.map +1 -0
- package/dist/content.js +90 -0
- package/dist/content.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/parse/index.d.ts +6 -0
- package/dist/parse/index.d.ts.map +1 -0
- package/dist/parse/index.js +5 -0
- package/dist/parse/index.js.map +1 -0
- package/dist/parse/level-tracker.d.ts +14 -0
- package/dist/parse/level-tracker.d.ts.map +1 -0
- package/dist/parse/level-tracker.js +87 -0
- package/dist/parse/level-tracker.js.map +1 -0
- package/dist/parse/levels.d.ts +19 -0
- package/dist/parse/levels.d.ts.map +1 -0
- package/dist/parse/levels.js +167 -0
- package/dist/parse/levels.js.map +1 -0
- package/dist/parse/line.d.ts +49 -0
- package/dist/parse/line.d.ts.map +1 -0
- package/dist/parse/line.js +289 -0
- package/dist/parse/line.js.map +1 -0
- package/dist/parse/palette.d.ts +12 -0
- package/dist/parse/palette.d.ts.map +1 -0
- package/dist/parse/palette.js +40 -0
- package/dist/parse/palette.js.map +1 -0
- package/dist/parse/parser.d.ts +18 -0
- package/dist/parse/parser.d.ts.map +1 -0
- package/dist/parse/parser.js +178 -0
- package/dist/parse/parser.js.map +1 -0
- package/dist/parse/sgr.d.ts +7 -0
- package/dist/parse/sgr.d.ts.map +1 -0
- package/dist/parse/sgr.js +179 -0
- package/dist/parse/sgr.js.map +1 -0
- package/dist/parse/styles.d.ts +15 -0
- package/dist/parse/styles.d.ts.map +1 -0
- package/dist/parse/styles.js +75 -0
- package/dist/parse/styles.js.map +1 -0
- package/dist/parse/tokenizer.d.ts +36 -0
- package/dist/parse/tokenizer.d.ts.map +1 -0
- package/dist/parse/tokenizer.js +287 -0
- package/dist/parse/tokenizer.js.map +1 -0
- package/dist/parse/types.d.ts +50 -0
- package/dist/parse/types.d.ts.map +1 -0
- package/dist/parse/types.js +2 -0
- package/dist/parse/types.js.map +1 -0
- package/dist/view/ansi-view.d.ts +27 -0
- package/dist/view/ansi-view.d.ts.map +1 -0
- package/dist/view/ansi-view.js +675 -0
- package/dist/view/ansi-view.js.map +1 -0
- package/dist/view/geometry.d.ts +30 -0
- package/dist/view/geometry.d.ts.map +1 -0
- package/dist/view/geometry.js +125 -0
- package/dist/view/geometry.js.map +1 -0
- package/dist/view/metrics.d.ts +17 -0
- package/dist/view/metrics.d.ts.map +1 -0
- package/dist/view/metrics.js +69 -0
- package/dist/view/metrics.js.map +1 -0
- package/dist/view/row.d.ts +41 -0
- package/dist/view/row.d.ts.map +1 -0
- package/dist/view/row.js +113 -0
- package/dist/view/row.js.map +1 -0
- package/dist/view/run-style.d.ts +11 -0
- package/dist/view/run-style.d.ts.map +1 -0
- package/dist/view/run-style.js +87 -0
- package/dist/view/run-style.js.map +1 -0
- package/dist/view/search.d.ts +28 -0
- package/dist/view/search.d.ts.map +1 -0
- package/dist/view/search.js +76 -0
- package/dist/view/search.js.map +1 -0
- package/dist/view/shown-lines.d.ts +15 -0
- package/dist/view/shown-lines.d.ts.map +1 -0
- package/dist/view/shown-lines.js +50 -0
- package/dist/view/shown-lines.js.map +1 -0
- package/dist/view/time-slices.d.ts +9 -0
- package/dist/view/time-slices.d.ts.map +1 -0
- package/dist/view/time-slices.js +35 -0
- package/dist/view/time-slices.js.map +1 -0
- package/dist/view/toolbar.d.ts +47 -0
- package/dist/view/toolbar.d.ts.map +1 -0
- package/dist/view/toolbar.js +58 -0
- package/dist/view/toolbar.js.map +1 -0
- package/dist/view/use-ansi-lines.d.ts +28 -0
- package/dist/view/use-ansi-lines.d.ts.map +1 -0
- package/dist/view/use-ansi-lines.js +103 -0
- package/dist/view/use-ansi-lines.js.map +1 -0
- package/dist/view/use-search.d.ts +37 -0
- package/dist/view/use-search.d.ts.map +1 -0
- package/dist/view/use-search.js +205 -0
- package/dist/view/use-search.js.map +1 -0
- package/dist/view/virtual-rows.d.ts +36 -0
- package/dist/view/virtual-rows.d.ts.map +1 -0
- package/dist/view/virtual-rows.js +156 -0
- package/dist/view/virtual-rows.js.map +1 -0
- package/package.json +58 -3
- package/styles.css +110 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { useEffect, useState, useSyncExternalStore } from "react";
|
|
2
|
+
import { compileQuery, createMatchSink, growMatchLines, scanLines, } from "./search.js";
|
|
3
|
+
import { runSlices } from "./time-slices.js";
|
|
4
|
+
/** How long the query and flags must stay unchanged before a scan starts. */
|
|
5
|
+
export const SEARCH_DEBOUNCE_MS = 150;
|
|
6
|
+
// Lines scanned between deadline checks.
|
|
7
|
+
const CHUNK = 256;
|
|
8
|
+
/**
|
|
9
|
+
* True when `next` keeps the first `scanned` ids of `prev`, so the scan can
|
|
10
|
+
* carry on. `appendShownLines` writes into its spare capacity, so a shared
|
|
11
|
+
* buffer settles it at once; otherwise the scanned prefix is compared.
|
|
12
|
+
*/
|
|
13
|
+
function extendsShown(prev, next, scanned) {
|
|
14
|
+
if (!prev || !next)
|
|
15
|
+
return prev === next;
|
|
16
|
+
if (next.length < scanned)
|
|
17
|
+
return false;
|
|
18
|
+
if (next.buffer === prev.buffer && next.byteOffset === prev.byteOffset) {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
for (let i = 0; i < scanned; i++)
|
|
22
|
+
if (next[i] !== prev[i])
|
|
23
|
+
return false;
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
class SearchStore {
|
|
27
|
+
listeners = new Set();
|
|
28
|
+
input = null;
|
|
29
|
+
re = null;
|
|
30
|
+
error = null;
|
|
31
|
+
sink = createMatchSink();
|
|
32
|
+
// The lines and shown list the scan has read from; `cursor` positions in them.
|
|
33
|
+
lines = [];
|
|
34
|
+
shown = null;
|
|
35
|
+
cursor = 0;
|
|
36
|
+
timer;
|
|
37
|
+
stopSlices = null;
|
|
38
|
+
generation = 0;
|
|
39
|
+
snapshot = {
|
|
40
|
+
matches: new Uint32Array(0),
|
|
41
|
+
count: 0,
|
|
42
|
+
capped: false,
|
|
43
|
+
scanning: false,
|
|
44
|
+
matchLines: this.sink.matchLines,
|
|
45
|
+
error: null,
|
|
46
|
+
generation: 0,
|
|
47
|
+
};
|
|
48
|
+
subscribe = (listener) => {
|
|
49
|
+
this.listeners.add(listener);
|
|
50
|
+
return () => {
|
|
51
|
+
this.listeners.delete(listener);
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
getSnapshot = () => this.snapshot;
|
|
55
|
+
update(next) {
|
|
56
|
+
const prev = this.input;
|
|
57
|
+
this.input = next;
|
|
58
|
+
if (next.query === "") {
|
|
59
|
+
this.halt();
|
|
60
|
+
this.re = null;
|
|
61
|
+
this.error = null;
|
|
62
|
+
if (this.sink.count > 0 || this.sink.capped) {
|
|
63
|
+
this.sink = createMatchSink(next.count);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
const retyped = !prev ||
|
|
68
|
+
prev.query !== next.query ||
|
|
69
|
+
prev.caseSensitive !== next.caseSensitive ||
|
|
70
|
+
prev.regex !== next.regex;
|
|
71
|
+
// Results scanned from other text, or from lines the filter now hides,
|
|
72
|
+
// must not outlive the wait: their ids no longer point where they did.
|
|
73
|
+
const stale = this.re !== null &&
|
|
74
|
+
(next.lines !== this.lines ||
|
|
75
|
+
!extendsShown(this.shown, next.shown, this.cursor));
|
|
76
|
+
if (retyped || (stale && this.timer !== undefined)) {
|
|
77
|
+
// Typing restarts the wait; the last results stay up until it ends.
|
|
78
|
+
if (retyped)
|
|
79
|
+
this.halt();
|
|
80
|
+
if (stale)
|
|
81
|
+
this.drop(next);
|
|
82
|
+
if (retyped) {
|
|
83
|
+
this.timer = setTimeout(() => {
|
|
84
|
+
this.timer = undefined;
|
|
85
|
+
this.begin();
|
|
86
|
+
}, SEARCH_DEBOUNCE_MS);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
else if (stale) {
|
|
90
|
+
this.begin();
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
else if (this.re) {
|
|
94
|
+
this.shown = next.shown;
|
|
95
|
+
if (this.timer === undefined)
|
|
96
|
+
this.kick();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
this.publish();
|
|
100
|
+
}
|
|
101
|
+
/** Stops the wait and the scan; the next {@link update} starts afresh. */
|
|
102
|
+
stop() {
|
|
103
|
+
this.halt();
|
|
104
|
+
this.input = null;
|
|
105
|
+
}
|
|
106
|
+
halt() {
|
|
107
|
+
clearTimeout(this.timer);
|
|
108
|
+
this.timer = undefined;
|
|
109
|
+
this.stopSlices?.();
|
|
110
|
+
this.stopSlices = null;
|
|
111
|
+
}
|
|
112
|
+
drop(next) {
|
|
113
|
+
this.generation++;
|
|
114
|
+
this.sink = createMatchSink(next.count);
|
|
115
|
+
this.lines = next.lines;
|
|
116
|
+
this.shown = next.shown;
|
|
117
|
+
this.cursor = 0;
|
|
118
|
+
}
|
|
119
|
+
total() {
|
|
120
|
+
return this.shown ? this.shown.length : (this.input?.count ?? 0);
|
|
121
|
+
}
|
|
122
|
+
begin() {
|
|
123
|
+
const input = this.input;
|
|
124
|
+
if (!input)
|
|
125
|
+
return;
|
|
126
|
+
this.halt();
|
|
127
|
+
const re = compileQuery(input.query, input);
|
|
128
|
+
this.re = re instanceof RegExp ? re : null;
|
|
129
|
+
this.generation++;
|
|
130
|
+
this.error = re === "invalid" ? "invalid" : null;
|
|
131
|
+
this.sink = createMatchSink(input.count);
|
|
132
|
+
this.lines = input.lines;
|
|
133
|
+
this.shown = input.shown;
|
|
134
|
+
this.cursor = 0;
|
|
135
|
+
this.kick();
|
|
136
|
+
this.publish();
|
|
137
|
+
}
|
|
138
|
+
kick() {
|
|
139
|
+
const re = this.re;
|
|
140
|
+
if (!re || this.stopSlices || this.sink.capped)
|
|
141
|
+
return;
|
|
142
|
+
if (this.cursor >= this.total())
|
|
143
|
+
return;
|
|
144
|
+
const sink = this.sink;
|
|
145
|
+
const step = (deadline) => {
|
|
146
|
+
for (;;) {
|
|
147
|
+
const end = Math.min(this.cursor + CHUNK, this.total());
|
|
148
|
+
scanLines(re, this.lines, this.shown, this.cursor, end, sink);
|
|
149
|
+
this.cursor = end;
|
|
150
|
+
if (sink.capped || end >= this.total()) {
|
|
151
|
+
this.stopSlices = null;
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
if (performance.now() >= deadline)
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
this.stopSlices = runSlices(step, () => this.publish());
|
|
159
|
+
}
|
|
160
|
+
publish() {
|
|
161
|
+
const sink = this.sink;
|
|
162
|
+
growMatchLines(sink, this.input?.count ?? 0);
|
|
163
|
+
const scanning = this.timer !== undefined ||
|
|
164
|
+
(this.re !== null &&
|
|
165
|
+
!sink.capped &&
|
|
166
|
+
(this.cursor < this.total() || !this.input?.done));
|
|
167
|
+
const prev = this.snapshot;
|
|
168
|
+
if (prev.count === sink.count &&
|
|
169
|
+
prev.capped === sink.capped &&
|
|
170
|
+
prev.scanning === scanning &&
|
|
171
|
+
prev.matchLines === sink.matchLines &&
|
|
172
|
+
prev.error === this.error &&
|
|
173
|
+
prev.generation === this.generation &&
|
|
174
|
+
prev.matches.buffer === sink.matches.buffer) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
this.snapshot = {
|
|
178
|
+
matches: sink.matches.subarray(0, sink.count * 3),
|
|
179
|
+
count: sink.count,
|
|
180
|
+
capped: sink.capped,
|
|
181
|
+
scanning,
|
|
182
|
+
matchLines: sink.matchLines,
|
|
183
|
+
error: this.error,
|
|
184
|
+
generation: this.generation,
|
|
185
|
+
};
|
|
186
|
+
for (const listener of this.listeners)
|
|
187
|
+
listener();
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Every match of `query` in the lines `shown` lists, found in time slices
|
|
192
|
+
* {@link SEARCH_DEBOUNCE_MS} after the query or flags last changed. Lines that
|
|
193
|
+
* arrive while parsing, and ids appended to `shown`, are scanned as they come;
|
|
194
|
+
* any other change to `lines` or `shown` starts the scan over.
|
|
195
|
+
*/
|
|
196
|
+
export function useSearch(input) {
|
|
197
|
+
const [store] = useState(() => new SearchStore());
|
|
198
|
+
const { query, caseSensitive, regex, lines, count, done, shown } = input;
|
|
199
|
+
useEffect(() => {
|
|
200
|
+
store.update({ query, caseSensitive, regex, lines, count, done, shown });
|
|
201
|
+
}, [store, query, caseSensitive, regex, lines, count, done, shown]);
|
|
202
|
+
useEffect(() => () => store.stop(), [store]);
|
|
203
|
+
return useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=use-search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-search.js","sourceRoot":"","sources":["../../src/view/use-search.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type CSSProperties, type ReactNode, type RefObject } from "react";
|
|
2
|
+
/** Rows mounted beyond each edge of the viewport. */
|
|
3
|
+
export declare const OVERSCAN = 20;
|
|
4
|
+
/** Scrolling driven from outside, e.g. going to a search match. */
|
|
5
|
+
export interface VirtualRowsHandle {
|
|
6
|
+
/** The row at the top of the viewport. */
|
|
7
|
+
topRow(): number;
|
|
8
|
+
/** Scrolls so that `row` sits at the top of the viewport, or mid-way down it. */
|
|
9
|
+
scrollToRow(row: number, align: "top" | "center"): void;
|
|
10
|
+
}
|
|
11
|
+
export interface VirtualRowsProps<L> {
|
|
12
|
+
/** The element that scrolls; the rows mount inside it. */
|
|
13
|
+
scrollRef: RefObject<HTMLElement | null>;
|
|
14
|
+
totalRows: number;
|
|
15
|
+
rowHeight: number;
|
|
16
|
+
viewportHeight: number;
|
|
17
|
+
/** The rows' layout width; omitted, the scroll container's. */
|
|
18
|
+
width?: number;
|
|
19
|
+
renderRow: (row: number) => ReactNode;
|
|
20
|
+
/** What the rows are laid out by; a new value may move a line to new rows. */
|
|
21
|
+
layout: L;
|
|
22
|
+
/** Where the content at `row` of layout `from` sits in layout `to`. */
|
|
23
|
+
carryRow: (row: number, from: L, to: L) => number;
|
|
24
|
+
/** Empty space above the first row and below the last, in px. */
|
|
25
|
+
padding?: number;
|
|
26
|
+
/** Merged into the spacer's style, e.g. a background drawn along the rows. */
|
|
27
|
+
style?: CSSProperties;
|
|
28
|
+
handle?: RefObject<VirtualRowsHandle | null>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Fixed-height rows of which only the visible ones, plus {@link OVERSCAN},
|
|
32
|
+
* are mounted, under a spacer sized by `scroll-map`. Past its pixel cap the
|
|
33
|
+
* scroll position maps to rows proportionally.
|
|
34
|
+
*/
|
|
35
|
+
export declare function VirtualRows<L>({ scrollRef, totalRows, rowHeight, viewportHeight, width, renderRow, layout, carryRow, padding, style, handle, }: VirtualRowsProps<L>): import("react").JSX.Element;
|
|
36
|
+
//# sourceMappingURL=virtual-rows.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"virtual-rows.d.ts","sourceRoot":"","sources":["../../src/view/virtual-rows.tsx"],"names":[],"mappings":"AAOA,OAAO,EACL,KAAK,aAAa,EAElB,KAAK,SAAS,EACd,KAAK,SAAS,EAOf,MAAM,OAAO,CAAC;AAEf,qDAAqD;AACrD,eAAO,MAAM,QAAQ,KAAK,CAAC;AAE3B,mEAAmE;AACnE,MAAM,WAAW,iBAAiB;IAChC,0CAA0C;IAC1C,MAAM,IAAI,MAAM,CAAC;IACjB,iFAAiF;IACjF,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,QAAQ,GAAG,IAAI,CAAC;CACzD;AAED,MAAM,WAAW,gBAAgB,CAAC,CAAC;IACjC,0DAA0D;IAC1D,SAAS,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,SAAS,CAAC;IACtC,8EAA8E;IAC9E,MAAM,EAAE,CAAC,CAAC;IACV,uEAAuE;IACvE,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,MAAM,CAAC;IAClD,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,MAAM,CAAC,EAAE,SAAS,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;CAC9C;AAqBD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,EAC7B,SAAS,EACT,SAAS,EACT,SAAS,EACT,cAAc,EACd,KAAK,EACL,SAAS,EACT,MAAM,EACN,QAAQ,EACR,OAAW,EACX,KAAK,EACL,MAAM,GACP,EAAE,gBAAgB,CAAC,CAAC,CAAC,+BAyJrB"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { clampTopRow, scrollFromTopRow, scrollGeometry, topRowFromScroll, } from "@orz/ui/lib/scroll-map";
|
|
3
|
+
import { Fragment, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, } from "react";
|
|
4
|
+
/** Rows mounted beyond each edge of the viewport. */
|
|
5
|
+
export const OVERSCAN = 20;
|
|
6
|
+
/**
|
|
7
|
+
* `scroll-map` knows only the rows; the padding sits outside them, so the
|
|
8
|
+
* scroll position is shifted by the top padding before it is mapped.
|
|
9
|
+
*/
|
|
10
|
+
function rowFromScroll(scrollTop, g, padding) {
|
|
11
|
+
return topRowFromScroll(scrollTop - padding, g);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The first and last rows map to the very ends, so reaching either shows its
|
|
15
|
+
* padding too.
|
|
16
|
+
*/
|
|
17
|
+
function scrollFromRow(row, g, padding) {
|
|
18
|
+
const top = clampTopRow(row, g);
|
|
19
|
+
if (top === 0)
|
|
20
|
+
return 0;
|
|
21
|
+
const scrollTop = scrollFromTopRow(top, g);
|
|
22
|
+
return top === g.maxTopRow ? scrollTop + 2 * padding : scrollTop + padding;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Fixed-height rows of which only the visible ones, plus {@link OVERSCAN},
|
|
26
|
+
* are mounted, under a spacer sized by `scroll-map`. Past its pixel cap the
|
|
27
|
+
* scroll position maps to rows proportionally.
|
|
28
|
+
*/
|
|
29
|
+
export function VirtualRows({ scrollRef, totalRows, rowHeight, viewportHeight, width, renderRow, layout, carryRow, padding = 0, style, handle, }) {
|
|
30
|
+
const geometry = useMemo(() => scrollGeometry(totalRows, rowHeight, viewportHeight), [totalRows, rowHeight, viewportHeight]);
|
|
31
|
+
const geometryRef = useRef(geometry);
|
|
32
|
+
geometryRef.current = geometry;
|
|
33
|
+
const layoutRef = useRef(layout);
|
|
34
|
+
layoutRef.current = layout;
|
|
35
|
+
const paddingRef = useRef(padding);
|
|
36
|
+
paddingRef.current = padding;
|
|
37
|
+
// The top row is kept with the layout it was read in, so a re-wrap keeps
|
|
38
|
+
// the reader on the same line rather than the same row number. Mounted once
|
|
39
|
+
// a streamed log passes the threshold, it keeps the place already scrolled to.
|
|
40
|
+
const [top, setTop] = useState(() => {
|
|
41
|
+
const el = scrollRef.current;
|
|
42
|
+
return {
|
|
43
|
+
row: el ? rowFromScroll(el.scrollTop, geometry, padding) : 0,
|
|
44
|
+
layout,
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
const topRow = clampTopRow(top.layout === layout ? top.row : carryRow(top.row, top.layout, layout), geometry);
|
|
48
|
+
const topRowRef = useRef(topRow);
|
|
49
|
+
topRowRef.current = topRow;
|
|
50
|
+
// Scaled, the element's own scrollTop after a write is rounded; a scroll
|
|
51
|
+
// event echoing it must not move the top row again.
|
|
52
|
+
const lastWritten = useRef(-1);
|
|
53
|
+
const wheelRows = useRef(0);
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
const el = scrollRef.current;
|
|
56
|
+
if (!el)
|
|
57
|
+
return;
|
|
58
|
+
const onScroll = () => {
|
|
59
|
+
const g = geometryRef.current;
|
|
60
|
+
const scrollTop = el.scrollTop;
|
|
61
|
+
if (g.scaled && Math.abs(scrollTop - lastWritten.current) <= 1)
|
|
62
|
+
return;
|
|
63
|
+
lastWritten.current = scrollTop;
|
|
64
|
+
const next = rowFromScroll(scrollTop, g, paddingRef.current);
|
|
65
|
+
topRowRef.current = next;
|
|
66
|
+
setTop({ row: next, layout: layoutRef.current });
|
|
67
|
+
};
|
|
68
|
+
el.addEventListener("scroll", onScroll, { passive: true });
|
|
69
|
+
return () => el.removeEventListener("scroll", onScroll);
|
|
70
|
+
}, [scrollRef]);
|
|
71
|
+
// Scaled, one wheel notch would otherwise cross megabytes of rows.
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
const el = scrollRef.current;
|
|
74
|
+
if (!el || !geometry.scaled)
|
|
75
|
+
return;
|
|
76
|
+
const onWheel = (event) => {
|
|
77
|
+
if (event.ctrlKey || event.deltaY === 0)
|
|
78
|
+
return;
|
|
79
|
+
event.preventDefault();
|
|
80
|
+
const g = geometryRef.current;
|
|
81
|
+
const unit = event.deltaMode === 1
|
|
82
|
+
? g.rowHeight
|
|
83
|
+
: event.deltaMode === 2
|
|
84
|
+
? g.viewportRows * g.rowHeight
|
|
85
|
+
: 1;
|
|
86
|
+
// Trackpads send a few pixels at a time; they add up to whole rows.
|
|
87
|
+
wheelRows.current += (event.deltaY * unit) / g.rowHeight;
|
|
88
|
+
const step = Math.trunc(wheelRows.current);
|
|
89
|
+
wheelRows.current -= step;
|
|
90
|
+
if (step) {
|
|
91
|
+
const next = clampTopRow(topRowRef.current + step, g);
|
|
92
|
+
topRowRef.current = next;
|
|
93
|
+
setTop({ row: next, layout: layoutRef.current });
|
|
94
|
+
const scrollTop = scrollFromRow(next, g, paddingRef.current);
|
|
95
|
+
lastWritten.current = scrollTop;
|
|
96
|
+
el.scrollTop = scrollTop;
|
|
97
|
+
}
|
|
98
|
+
if (event.deltaX)
|
|
99
|
+
el.scrollLeft += event.deltaX * unit;
|
|
100
|
+
};
|
|
101
|
+
el.addEventListener("wheel", onWheel, { passive: false });
|
|
102
|
+
return () => el.removeEventListener("wheel", onWheel);
|
|
103
|
+
}, [geometry.scaled, scrollRef]);
|
|
104
|
+
useImperativeHandle(handle, () => ({
|
|
105
|
+
topRow: () => topRowRef.current,
|
|
106
|
+
scrollToRow(row, align) {
|
|
107
|
+
const el = scrollRef.current;
|
|
108
|
+
const g = geometryRef.current;
|
|
109
|
+
const next = clampTopRow(align === "top" ? row : row - Math.floor((g.viewportRows - 1) / 2), g);
|
|
110
|
+
topRowRef.current = next;
|
|
111
|
+
setTop({ row: next, layout: layoutRef.current });
|
|
112
|
+
if (!el)
|
|
113
|
+
return;
|
|
114
|
+
const scrollTop = scrollFromRow(next, g, paddingRef.current);
|
|
115
|
+
lastWritten.current = scrollTop;
|
|
116
|
+
el.scrollTop = scrollTop;
|
|
117
|
+
},
|
|
118
|
+
}), [scrollRef]);
|
|
119
|
+
// A resize, more rows, a re-wrap or a switch between 1:1 and scaled moves
|
|
120
|
+
// the mapping under the top row; the element keeps its old scrollTop.
|
|
121
|
+
useLayoutEffect(() => {
|
|
122
|
+
const el = scrollRef.current;
|
|
123
|
+
if (!el)
|
|
124
|
+
return;
|
|
125
|
+
const current = el.scrollTop;
|
|
126
|
+
if (rowFromScroll(current, geometry, padding) === topRow)
|
|
127
|
+
return;
|
|
128
|
+
// 1:1 the rows never move in the spacer. Left at the old bottom, where
|
|
129
|
+
// the top row sits a padding higher than its mapped place, the view stays
|
|
130
|
+
// put rather than jump when more rows extend the range.
|
|
131
|
+
if (!geometry.scaled &&
|
|
132
|
+
Math.abs(current - scrollFromTopRow(topRow, geometry) - 2 * padding) < 1) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const scrollTop = scrollFromRow(topRow, geometry, padding);
|
|
136
|
+
lastWritten.current = scrollTop;
|
|
137
|
+
el.scrollTop = scrollTop;
|
|
138
|
+
}, [geometry, topRow, scrollRef, padding]);
|
|
139
|
+
const first = Math.max(0, topRow - OVERSCAN);
|
|
140
|
+
const end = Math.min(totalRows, topRow + geometry.viewportRows + OVERSCAN);
|
|
141
|
+
// 1:1 this is padding + first × rowHeight, so the browser scrolls the rows
|
|
142
|
+
// smoothly; scaled, the top row is pinned to the viewport's top edge.
|
|
143
|
+
const offset = padding + scrollFromTopRow(topRow, geometry) - (topRow - first) * rowHeight;
|
|
144
|
+
const rows = [];
|
|
145
|
+
for (let row = first; row < end; row++) {
|
|
146
|
+
rows.push(_jsx(Fragment, { children: renderRow(row) }, row));
|
|
147
|
+
}
|
|
148
|
+
return (_jsx("div", { className: "relative min-w-full", style: {
|
|
149
|
+
...style,
|
|
150
|
+
height: geometry.spacerHeight + 2 * padding,
|
|
151
|
+
width,
|
|
152
|
+
// The overscan below the last rows must not extend the scroll range.
|
|
153
|
+
overflowY: "clip",
|
|
154
|
+
}, children: _jsx("div", { className: "absolute top-0 left-0 w-full", style: { transform: `translateY(${offset}px)` }, children: rows }) }));
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=virtual-rows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"virtual-rows.js","sourceRoot":"","sources":["../../src/view/virtual-rows.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,61 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orz/ui-ansi",
|
|
3
|
-
"version": "0.0.0
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "Text with ANSI escape sequences drawn in the active @orz/ui terminal colours, contributed to the @orz/ui-content registry",
|
|
5
|
+
"license": "BSD-3-Clause",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/orzFly/ui.git",
|
|
9
|
+
"directory": "packages/ui-ansi"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"sideEffects": [
|
|
13
|
+
"**/*.css"
|
|
14
|
+
],
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"@orz/source": "./src/index.ts",
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"default": "./dist/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./parse": {
|
|
22
|
+
"@orz/source": "./src/parse/index.ts",
|
|
23
|
+
"types": "./dist/parse/index.d.ts",
|
|
24
|
+
"default": "./dist/parse/index.js"
|
|
25
|
+
},
|
|
26
|
+
"./styles.css": "./styles.css"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"styles.css"
|
|
31
|
+
],
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public"
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"lucide-react": "^1",
|
|
37
|
+
"react": "^19",
|
|
38
|
+
"react-dom": "^19",
|
|
39
|
+
"@orz/ui": "^0.0.0",
|
|
40
|
+
"@orz/ui-content": "^0.0.0"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@testing-library/react": "^16.3.2",
|
|
44
|
+
"@types/react": "^19.2.18",
|
|
45
|
+
"@types/react-dom": "^19.2.4",
|
|
46
|
+
"happy-dom": "^21.0.3",
|
|
47
|
+
"lucide-react": "^1.31.0",
|
|
48
|
+
"radix-ui": "^1.6.7",
|
|
49
|
+
"react": "^19.2.8",
|
|
50
|
+
"react-dom": "^19.2.8",
|
|
51
|
+
"vitest": "^5.0.5",
|
|
52
|
+
"@orz/themes": "0.0.0",
|
|
53
|
+
"@orz/ui-content": "0.0.0",
|
|
54
|
+
"@orz/ui": "0.0.0"
|
|
55
|
+
},
|
|
56
|
+
"scripts": {
|
|
57
|
+
"build": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.build.json",
|
|
58
|
+
"typecheck": "tsc --noEmit",
|
|
59
|
+
"test": "vitest run"
|
|
60
|
+
}
|
|
6
61
|
}
|
package/styles.css
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/* Tailwind resolves an imported file's @source against that file, so a
|
|
2
|
+
consumer importing this stylesheet scans the classes in the package's
|
|
3
|
+
shipped JS without writing an @source of its own. */
|
|
4
|
+
@source "./dist";
|
|
5
|
+
|
|
6
|
+
@layer components {
|
|
7
|
+
.ansi-view ::selection {
|
|
8
|
+
background: var(--terminal-selection);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.ansi-view [data-level="fatal"] {
|
|
12
|
+
--log-level: var(--ansi-bright-red);
|
|
13
|
+
}
|
|
14
|
+
.ansi-view [data-level="error"] {
|
|
15
|
+
--log-level: var(--ansi-red);
|
|
16
|
+
}
|
|
17
|
+
.ansi-view [data-level="warn"] {
|
|
18
|
+
--log-level: var(--ansi-yellow);
|
|
19
|
+
}
|
|
20
|
+
.ansi-view [data-level="info"] {
|
|
21
|
+
--log-level: var(--ansi-green);
|
|
22
|
+
}
|
|
23
|
+
.ansi-view [data-level="debug"] {
|
|
24
|
+
--log-level: var(--ansi-blue);
|
|
25
|
+
}
|
|
26
|
+
.ansi-view [data-level="trace"] {
|
|
27
|
+
--log-level: var(--ansi-bright-black);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* A background, so the text and run backgrounds paint over it. */
|
|
31
|
+
.ansi-view
|
|
32
|
+
[data-line]:is(
|
|
33
|
+
[data-level="fatal"],
|
|
34
|
+
[data-level="error"],
|
|
35
|
+
[data-level="warn"]
|
|
36
|
+
) {
|
|
37
|
+
--log-stripe: var(--log-level);
|
|
38
|
+
background-color: color-mix(in srgb, var(--log-level) 12%, transparent);
|
|
39
|
+
}
|
|
40
|
+
/* In the scroll container's left padding (its px-3): on the row itself it
|
|
41
|
+
would cover the first glyph of a pane, or of a one-digit gutter. */
|
|
42
|
+
.ansi-view
|
|
43
|
+
[data-line]:is(
|
|
44
|
+
[data-level="fatal"],
|
|
45
|
+
[data-level="error"],
|
|
46
|
+
[data-level="warn"]
|
|
47
|
+
)::after {
|
|
48
|
+
content: "";
|
|
49
|
+
position: absolute;
|
|
50
|
+
inset-block: 0;
|
|
51
|
+
left: -0.75rem;
|
|
52
|
+
width: 3px;
|
|
53
|
+
background: var(--log-stripe);
|
|
54
|
+
pointer-events: none;
|
|
55
|
+
}
|
|
56
|
+
.ansi-view [data-line][data-level="warn"] {
|
|
57
|
+
background-color: color-mix(in srgb, var(--log-level) 10%, transparent);
|
|
58
|
+
}
|
|
59
|
+
.ansi-view [data-line][data-inherited] {
|
|
60
|
+
--log-stripe: color-mix(in srgb, var(--log-level) 50%, transparent);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* On the row, so that only runs without a colour of their own take it. */
|
|
64
|
+
.ansi-view
|
|
65
|
+
[data-line]:is([data-level="debug"], [data-level="trace"]):not(
|
|
66
|
+
[data-coloured]
|
|
67
|
+
) {
|
|
68
|
+
color: color-mix(
|
|
69
|
+
in oklab,
|
|
70
|
+
var(--terminal-foreground) 60%,
|
|
71
|
+
var(--terminal-background)
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.ansi-view [data-level-word] {
|
|
76
|
+
color: var(--log-level);
|
|
77
|
+
font-weight: 600;
|
|
78
|
+
}
|
|
79
|
+
.ansi-view [data-level="fatal"] [data-level-word] {
|
|
80
|
+
background-color: var(--log-level);
|
|
81
|
+
color: var(--terminal-background);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* biome-ignore-start lint/complexity/noImportantStyles: run colours are inline styles, which only !important overrides */
|
|
85
|
+
.ansi-view [data-match] {
|
|
86
|
+
background-color: color-mix(
|
|
87
|
+
in srgb,
|
|
88
|
+
var(--ansi-yellow) 40%,
|
|
89
|
+
transparent
|
|
90
|
+
) !important;
|
|
91
|
+
}
|
|
92
|
+
.ansi-view [data-match][data-level-word] {
|
|
93
|
+
color: inherit;
|
|
94
|
+
}
|
|
95
|
+
.ansi-view [data-match="current"] {
|
|
96
|
+
background-color: var(--ansi-yellow) !important;
|
|
97
|
+
color: var(--terminal-background) !important;
|
|
98
|
+
}
|
|
99
|
+
/* biome-ignore-end lint/complexity/noImportantStyles: run colours are inline styles */
|
|
100
|
+
|
|
101
|
+
/* A pseudo-element, so the fixed row height is unchanged. */
|
|
102
|
+
.ansi-view [data-gap]::before {
|
|
103
|
+
content: "";
|
|
104
|
+
position: absolute;
|
|
105
|
+
inset-inline: 0;
|
|
106
|
+
top: 0;
|
|
107
|
+
border-top: 1px dashed var(--ansi-bright-black);
|
|
108
|
+
pointer-events: none;
|
|
109
|
+
}
|
|
110
|
+
}
|