@develemit/web-hooks 0.3.1 → 0.5.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/CHANGELOG.md +16 -0
- package/README.md +115 -0
- package/dist/chunk-IVLRQ23V.js +483 -0
- package/dist/chunk-JTLQQSLO.js +143 -0
- package/dist/index.cjs +639 -7
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +44 -0
- package/dist/log-helpers-rkbgYqZW.d.cts +25 -0
- package/dist/log-helpers-rkbgYqZW.d.ts +25 -0
- package/dist/terminal-output.cjs +660 -0
- package/dist/terminal-output.d.cts +163 -0
- package/dist/terminal-output.d.ts +163 -0
- package/dist/terminal-output.js +47 -0
- package/dist/virtual-list.cjs +499 -0
- package/dist/virtual-list.d.cts +116 -0
- package/dist/virtual-list.d.ts +116 -0
- package/dist/virtual-list.js +287 -0
- package/package.json +20 -2
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
import { Virtualizer } from '@tanstack/react-virtual';
|
|
3
|
+
import { a as Failure } from './log-helpers-rkbgYqZW.js';
|
|
4
|
+
|
|
5
|
+
type ScrollAlign = 'start' | 'center' | 'end' | 'auto';
|
|
6
|
+
declare const MAX_REALIGN_FRAMES = 3;
|
|
7
|
+
/** A 0 height means "not laid out yet" (jsdom, or a read before first paint), so fall back to the estimate. */
|
|
8
|
+
declare function measuredOrEstimate(measured: number | undefined, estimate: number): number;
|
|
9
|
+
interface RealignInput {
|
|
10
|
+
align: ScrollAlign;
|
|
11
|
+
itemStart: number;
|
|
12
|
+
itemSize: number;
|
|
13
|
+
scrollOffset: number;
|
|
14
|
+
viewportSize: number;
|
|
15
|
+
frame: number;
|
|
16
|
+
maxFrames?: number;
|
|
17
|
+
}
|
|
18
|
+
declare function targetOffset(align: ScrollAlign, itemStart: number, itemSize: number, viewportSize: number): number;
|
|
19
|
+
/** After rows above the target are measured the estimate can be off, so scroll again until the row sits where `align` says. */
|
|
20
|
+
declare function shouldRealign({ align, itemStart, itemSize, scrollOffset, viewportSize, frame, maxFrames }: RealignInput): boolean;
|
|
21
|
+
/** The first `initialCount` rows, used until the browser reports a viewport size. */
|
|
22
|
+
declare function initialVisibleCount(count: number, initialCount: number): number;
|
|
23
|
+
|
|
24
|
+
interface UseVirtualListOptions {
|
|
25
|
+
count: number;
|
|
26
|
+
estimateSize: (index: number) => number;
|
|
27
|
+
/** The overflow:auto element that scrolls. Omit with `windowScroll: true`. */
|
|
28
|
+
scrollRef?: RefObject<Element | null>;
|
|
29
|
+
/** Scroll with the page instead of an inner element. */
|
|
30
|
+
windowScroll?: boolean;
|
|
31
|
+
/** Distance from the top of the page to the list, for window scroll. */
|
|
32
|
+
scrollMargin?: number;
|
|
33
|
+
overscan?: number;
|
|
34
|
+
/** Measure each rendered row. Pass false when the app's own maths relies on `estimateSize`. */
|
|
35
|
+
measure?: boolean;
|
|
36
|
+
getItemKey?: (index: number) => string | number;
|
|
37
|
+
/** Rows rendered before the viewport size is known, so the server render isn't blank. */
|
|
38
|
+
initialCount?: number;
|
|
39
|
+
}
|
|
40
|
+
interface VirtualListItem {
|
|
41
|
+
index: number;
|
|
42
|
+
key: string | number | bigint;
|
|
43
|
+
start: number;
|
|
44
|
+
size: number;
|
|
45
|
+
}
|
|
46
|
+
interface ScrollToIndexOptions {
|
|
47
|
+
align?: ScrollAlign;
|
|
48
|
+
}
|
|
49
|
+
interface UseVirtualListResult {
|
|
50
|
+
items: VirtualListItem[];
|
|
51
|
+
totalSize: number;
|
|
52
|
+
/** Ref for each row element; the row also needs `data-index={item.index}`. */
|
|
53
|
+
measureRef: (el: Element | null) => void;
|
|
54
|
+
scrollToIndex: (index: number, options?: ScrollToIndexOptions) => void;
|
|
55
|
+
scrollToOffset: (offset: number) => void;
|
|
56
|
+
virtualizer: Virtualizer<Element, Element>;
|
|
57
|
+
}
|
|
58
|
+
declare function useVirtualList(options: UseVirtualListOptions): UseVirtualListResult;
|
|
59
|
+
|
|
60
|
+
interface UseVirtualLogOptions {
|
|
61
|
+
/** Plain or raw lines; the last one may still be growing. */
|
|
62
|
+
lines: readonly string[];
|
|
63
|
+
scrollRef: RefObject<HTMLElement | null>;
|
|
64
|
+
/** Show only lines containing this text. Typing stays responsive on large logs. */
|
|
65
|
+
query?: string;
|
|
66
|
+
estimateSize?: (index: number) => number;
|
|
67
|
+
overscan?: number;
|
|
68
|
+
/** Snap back to the end whenever this changes (switching logs). */
|
|
69
|
+
resetKey?: unknown;
|
|
70
|
+
/** Filename used by `download`. */
|
|
71
|
+
filename?: string;
|
|
72
|
+
}
|
|
73
|
+
interface VirtualLogRow {
|
|
74
|
+
/** Position in the shown list. */
|
|
75
|
+
index: number;
|
|
76
|
+
/** Index into `lines`. */
|
|
77
|
+
lineIndex: number;
|
|
78
|
+
key: string | number | bigint;
|
|
79
|
+
start: number;
|
|
80
|
+
size: number;
|
|
81
|
+
}
|
|
82
|
+
interface UseVirtualLogResult {
|
|
83
|
+
rows: VirtualLogRow[];
|
|
84
|
+
totalSize: number;
|
|
85
|
+
measureRef: UseVirtualListResult['measureRef'];
|
|
86
|
+
isFiltering: boolean;
|
|
87
|
+
/** Lines shown: all of them, or the matches. */
|
|
88
|
+
shownCount: number;
|
|
89
|
+
atBottom: boolean;
|
|
90
|
+
unread: number;
|
|
91
|
+
jumpToBottom: () => void;
|
|
92
|
+
failures: readonly Failure[];
|
|
93
|
+
/** Which failure the last jump landed on, or -1. */
|
|
94
|
+
failurePosition: number;
|
|
95
|
+
jumpToFailure: (n: number) => boolean;
|
|
96
|
+
nextFailure: () => boolean;
|
|
97
|
+
previousFailure: () => boolean;
|
|
98
|
+
/** The whole log as text, whatever is rendered. */
|
|
99
|
+
text: (options?: {
|
|
100
|
+
stripAnsi?: boolean;
|
|
101
|
+
}) => string;
|
|
102
|
+
copyText: () => string;
|
|
103
|
+
download: (filename?: string) => void;
|
|
104
|
+
list: UseVirtualListResult;
|
|
105
|
+
}
|
|
106
|
+
declare function useVirtualLog({ lines, scrollRef, query, estimateSize, overscan, resetKey, filename, }: UseVirtualLogOptions): UseVirtualLogResult;
|
|
107
|
+
|
|
108
|
+
interface LogToTextOptions {
|
|
109
|
+
/** Remove escape codes from each line. Default false: lines are joined as given. */
|
|
110
|
+
stripAnsi?: boolean;
|
|
111
|
+
}
|
|
112
|
+
declare function logToText(lines: readonly string[], options?: LogToTextOptions): string;
|
|
113
|
+
/** Saves text as a file. The Blob URL is revoked right after the click. */
|
|
114
|
+
declare function downloadText(filename: string, text: string): void;
|
|
115
|
+
|
|
116
|
+
export { type LogToTextOptions, MAX_REALIGN_FRAMES, type RealignInput, type ScrollAlign, type ScrollToIndexOptions, type UseVirtualListOptions, type UseVirtualListResult, type UseVirtualLogOptions, type UseVirtualLogResult, type VirtualListItem, type VirtualLogRow, downloadText, initialVisibleCount, logToText, measuredOrEstimate, shouldRealign, targetOffset, useVirtualList, useVirtualLog };
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
filterLines,
|
|
4
|
+
findFailures,
|
|
5
|
+
stripAnsi,
|
|
6
|
+
useFollowTail
|
|
7
|
+
} from "./chunk-IVLRQ23V.js";
|
|
8
|
+
|
|
9
|
+
// src/virtual-list/use-virtual-list.ts
|
|
10
|
+
import { useCallback, useEffect, useRef } from "react";
|
|
11
|
+
import {
|
|
12
|
+
observeWindowOffset,
|
|
13
|
+
observeWindowRect,
|
|
14
|
+
useVirtualizer,
|
|
15
|
+
windowScroll
|
|
16
|
+
} from "@tanstack/react-virtual";
|
|
17
|
+
|
|
18
|
+
// src/virtual-list/measure.ts
|
|
19
|
+
var MAX_REALIGN_FRAMES = 3;
|
|
20
|
+
function measuredOrEstimate(measured, estimate) {
|
|
21
|
+
return measured !== void 0 && measured > 0 ? measured : estimate;
|
|
22
|
+
}
|
|
23
|
+
function targetOffset(align, itemStart, itemSize, viewportSize) {
|
|
24
|
+
if (align === "end") return itemStart + itemSize - viewportSize;
|
|
25
|
+
if (align === "center") return itemStart + itemSize / 2 - viewportSize / 2;
|
|
26
|
+
return itemStart;
|
|
27
|
+
}
|
|
28
|
+
function shouldRealign({ align, itemStart, itemSize, scrollOffset, viewportSize, frame, maxFrames = MAX_REALIGN_FRAMES }) {
|
|
29
|
+
if (frame >= maxFrames) return false;
|
|
30
|
+
if (align === "auto") {
|
|
31
|
+
return itemStart < scrollOffset || itemStart + itemSize > scrollOffset + viewportSize;
|
|
32
|
+
}
|
|
33
|
+
const want = Math.max(0, targetOffset(align, itemStart, itemSize, viewportSize));
|
|
34
|
+
return Math.abs(scrollOffset - want) > 1;
|
|
35
|
+
}
|
|
36
|
+
function initialVisibleCount(count, initialCount) {
|
|
37
|
+
return Math.min(count, Math.max(0, initialCount));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// src/virtual-list/use-virtual-list.ts
|
|
41
|
+
var ESTIMATED_ROW_FOR_SSR = 30;
|
|
42
|
+
function useVirtualList(options) {
|
|
43
|
+
const {
|
|
44
|
+
count,
|
|
45
|
+
estimateSize,
|
|
46
|
+
scrollRef,
|
|
47
|
+
windowScroll: scrollsWindow = false,
|
|
48
|
+
scrollMargin = 0,
|
|
49
|
+
overscan = 10,
|
|
50
|
+
measure = true,
|
|
51
|
+
getItemKey,
|
|
52
|
+
initialCount = 30
|
|
53
|
+
} = options;
|
|
54
|
+
const frameRef = useRef(null);
|
|
55
|
+
const virtualizer = useVirtualizer({
|
|
56
|
+
count,
|
|
57
|
+
estimateSize,
|
|
58
|
+
overscan,
|
|
59
|
+
scrollMargin,
|
|
60
|
+
getScrollElement: () => scrollsWindow ? typeof window === "undefined" ? null : window : scrollRef?.current ?? null,
|
|
61
|
+
...scrollsWindow ? {
|
|
62
|
+
observeElementRect: observeWindowRect,
|
|
63
|
+
observeElementOffset: observeWindowOffset,
|
|
64
|
+
scrollToFn: windowScroll,
|
|
65
|
+
initialOffset: () => typeof window === "undefined" ? 0 : window.scrollY
|
|
66
|
+
} : {},
|
|
67
|
+
// Seeds a viewport so the server render and first paint include rows.
|
|
68
|
+
initialRect: { width: 0, height: initialCount * ESTIMATED_ROW_FOR_SSR },
|
|
69
|
+
...getItemKey ? { getItemKey } : {},
|
|
70
|
+
...measure ? {
|
|
71
|
+
measureElement: (el, entry, instance) => {
|
|
72
|
+
const height = entry?.borderBoxSize?.[0]?.blockSize ?? el.getBoundingClientRect().height;
|
|
73
|
+
const index = Number(el.dataset.index);
|
|
74
|
+
const estimate = Number.isNaN(index) ? 0 : instance.options.estimateSize(index);
|
|
75
|
+
return measuredOrEstimate(height, estimate);
|
|
76
|
+
}
|
|
77
|
+
} : {}
|
|
78
|
+
});
|
|
79
|
+
const cancelRealign = useCallback(() => {
|
|
80
|
+
if (frameRef.current !== null && typeof cancelAnimationFrame === "function") cancelAnimationFrame(frameRef.current);
|
|
81
|
+
frameRef.current = null;
|
|
82
|
+
}, []);
|
|
83
|
+
useEffect(() => cancelRealign, [cancelRealign]);
|
|
84
|
+
const scrollToIndex = useCallback(
|
|
85
|
+
(index, { align = "auto" } = {}) => {
|
|
86
|
+
cancelRealign();
|
|
87
|
+
const last = Math.max(0, count - 1);
|
|
88
|
+
const target = Math.max(0, Math.min(index, last));
|
|
89
|
+
virtualizer.scrollToIndex(target, { align });
|
|
90
|
+
if (typeof requestAnimationFrame !== "function") return;
|
|
91
|
+
let frame = 0;
|
|
92
|
+
const check = () => {
|
|
93
|
+
frameRef.current = null;
|
|
94
|
+
const item = virtualizer.measurementsCache[target];
|
|
95
|
+
const offset = virtualizer.scrollOffset;
|
|
96
|
+
const viewport = virtualizer.scrollRect?.height;
|
|
97
|
+
if (!item || offset === null || !viewport) return;
|
|
98
|
+
const input = { align, itemStart: item.start - scrollMargin, itemSize: item.size, scrollOffset: offset - scrollMargin, viewportSize: viewport, frame };
|
|
99
|
+
if (!shouldRealign(input)) return;
|
|
100
|
+
frame += 1;
|
|
101
|
+
virtualizer.scrollToIndex(target, { align });
|
|
102
|
+
frameRef.current = requestAnimationFrame(check);
|
|
103
|
+
};
|
|
104
|
+
frameRef.current = requestAnimationFrame(check);
|
|
105
|
+
},
|
|
106
|
+
[virtualizer, count, scrollMargin, cancelRealign]
|
|
107
|
+
);
|
|
108
|
+
const scrollToOffset = useCallback((offset) => virtualizer.scrollToOffset(offset), [virtualizer]);
|
|
109
|
+
const rendered = virtualizer.getVirtualItems();
|
|
110
|
+
const items = rendered.map((v) => ({ index: v.index, key: v.key, start: v.start - scrollMargin, size: v.size }));
|
|
111
|
+
const fallback = items.length === 0 && count > 0 ? initialVisibleCount(count, initialCount) : 0;
|
|
112
|
+
if (fallback > 0) {
|
|
113
|
+
let start = 0;
|
|
114
|
+
for (let i = 0; i < fallback; i++) {
|
|
115
|
+
const size = estimateSize(i);
|
|
116
|
+
items.push({ index: i, key: getItemKey ? getItemKey(i) : i, start, size });
|
|
117
|
+
start += size;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
items,
|
|
122
|
+
totalSize: virtualizer.getTotalSize(),
|
|
123
|
+
measureRef: measure ? virtualizer.measureElement : noopRef,
|
|
124
|
+
scrollToIndex,
|
|
125
|
+
scrollToOffset,
|
|
126
|
+
virtualizer
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function noopRef() {
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// src/virtual-list/use-virtual-log.ts
|
|
133
|
+
import { useCallback as useCallback2, useDeferredValue, useEffect as useEffect2, useMemo, useRef as useRef2, useState } from "react";
|
|
134
|
+
|
|
135
|
+
// src/virtual-list/log-index.ts
|
|
136
|
+
function emptyScan() {
|
|
137
|
+
return { lineCount: 0, firstLine: void 0, failures: [] };
|
|
138
|
+
}
|
|
139
|
+
function scanFailures(prev, lines) {
|
|
140
|
+
const appendOnly = prev.lineCount > 0 && lines.length >= prev.lineCount && lines[0] === prev.firstLine;
|
|
141
|
+
const from = appendOnly ? prev.lineCount - 1 : 0;
|
|
142
|
+
const kept = appendOnly ? prev.failures.filter((f) => f.index < from) : [];
|
|
143
|
+
const fresh = findFailures(lines.slice(from)).map((f) => ({ ...f, index: f.index + from }));
|
|
144
|
+
return { lineCount: lines.length, firstLine: lines[0], failures: [...kept, ...fresh] };
|
|
145
|
+
}
|
|
146
|
+
function visiblePosition(visible, lineIndex) {
|
|
147
|
+
if (!visible) return lineIndex;
|
|
148
|
+
let lo = 0;
|
|
149
|
+
let hi = visible.length - 1;
|
|
150
|
+
while (lo <= hi) {
|
|
151
|
+
const mid = lo + hi >> 1;
|
|
152
|
+
const value = visible[mid];
|
|
153
|
+
if (value === lineIndex) return mid;
|
|
154
|
+
if (value < lineIndex) lo = mid + 1;
|
|
155
|
+
else hi = mid - 1;
|
|
156
|
+
}
|
|
157
|
+
return -1;
|
|
158
|
+
}
|
|
159
|
+
function stepIndex(current, count, direction) {
|
|
160
|
+
if (count === 0) return -1;
|
|
161
|
+
if (current < 0) return direction === 1 ? 0 : count - 1;
|
|
162
|
+
return (current + direction + count) % count;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// src/virtual-list/log-text.ts
|
|
166
|
+
function logToText(lines, options = {}) {
|
|
167
|
+
const rows = options.stripAnsi ? lines.map((line) => stripAnsi(line)) : lines;
|
|
168
|
+
return rows.join("\n");
|
|
169
|
+
}
|
|
170
|
+
function downloadText(filename, text) {
|
|
171
|
+
const url = URL.createObjectURL(new Blob([text], { type: "text/plain" }));
|
|
172
|
+
const a = document.createElement("a");
|
|
173
|
+
a.href = url;
|
|
174
|
+
a.download = filename;
|
|
175
|
+
a.click();
|
|
176
|
+
URL.revokeObjectURL(url);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// src/virtual-list/use-virtual-log.ts
|
|
180
|
+
var DEFAULT_ROW = 18;
|
|
181
|
+
function useVirtualLog({
|
|
182
|
+
lines,
|
|
183
|
+
scrollRef,
|
|
184
|
+
query = "",
|
|
185
|
+
estimateSize,
|
|
186
|
+
overscan = 12,
|
|
187
|
+
resetKey,
|
|
188
|
+
filename = "log.txt"
|
|
189
|
+
}) {
|
|
190
|
+
const deferred = useDeferredValue(query);
|
|
191
|
+
const isFiltering = deferred.trim() !== "";
|
|
192
|
+
const visible = useMemo(() => isFiltering ? filterLines(lines, deferred) : null, [lines, deferred, isFiltering]);
|
|
193
|
+
const shownCount = visible ? visible.length : lines.length;
|
|
194
|
+
const scan = useRef2(emptyScan());
|
|
195
|
+
const failures = useMemo(() => {
|
|
196
|
+
scan.current = scanFailures(scan.current, lines);
|
|
197
|
+
return scan.current.failures;
|
|
198
|
+
}, [lines]);
|
|
199
|
+
const list = useVirtualList({
|
|
200
|
+
count: shownCount,
|
|
201
|
+
estimateSize: estimateSize ?? (() => DEFAULT_ROW),
|
|
202
|
+
scrollRef,
|
|
203
|
+
overscan
|
|
204
|
+
});
|
|
205
|
+
const lastIndex = shownCount - 1;
|
|
206
|
+
const follow = useFollowTail({
|
|
207
|
+
scrollRef,
|
|
208
|
+
itemCount: lines.length,
|
|
209
|
+
scrollToEnd: () => {
|
|
210
|
+
if (!isFiltering) list.scrollToIndex(lastIndex, { align: "end" });
|
|
211
|
+
},
|
|
212
|
+
resetKey
|
|
213
|
+
});
|
|
214
|
+
const baseline = useRef2(shownCount);
|
|
215
|
+
useEffect2(() => {
|
|
216
|
+
baseline.current = shownCount;
|
|
217
|
+
}, [deferred, resetKey]);
|
|
218
|
+
const unread = isFiltering ? Math.max(0, shownCount - baseline.current) : follow.unread;
|
|
219
|
+
useEffect2(() => {
|
|
220
|
+
if (isFiltering) list.scrollToOffset(0);
|
|
221
|
+
}, [deferred]);
|
|
222
|
+
const [failurePosition, setFailurePosition] = useState(-1);
|
|
223
|
+
const jumpToFailure = useCallback2(
|
|
224
|
+
(n) => {
|
|
225
|
+
const failure = failures[n];
|
|
226
|
+
if (!failure) return false;
|
|
227
|
+
const at = visiblePosition(visible, failure.index);
|
|
228
|
+
if (at < 0) return false;
|
|
229
|
+
setFailurePosition(n);
|
|
230
|
+
list.scrollToIndex(at, { align: "center" });
|
|
231
|
+
return true;
|
|
232
|
+
},
|
|
233
|
+
[failures, visible, list]
|
|
234
|
+
);
|
|
235
|
+
const step = useCallback2(
|
|
236
|
+
(direction) => {
|
|
237
|
+
for (let tries = 0, n = failurePosition; tries < failures.length; tries++) {
|
|
238
|
+
n = stepIndex(n, failures.length, direction);
|
|
239
|
+
if (jumpToFailure(n)) return true;
|
|
240
|
+
}
|
|
241
|
+
return false;
|
|
242
|
+
},
|
|
243
|
+
[failurePosition, failures.length, jumpToFailure]
|
|
244
|
+
);
|
|
245
|
+
const nextFailure = useCallback2(() => step(1), [step]);
|
|
246
|
+
const previousFailure = useCallback2(() => step(-1), [step]);
|
|
247
|
+
const text = useCallback2((options) => logToText(lines, options), [lines]);
|
|
248
|
+
const copyText = useCallback2(() => logToText(lines, { stripAnsi: true }), [lines]);
|
|
249
|
+
const download = useCallback2(
|
|
250
|
+
(name) => downloadText(name ?? filename, logToText(lines, { stripAnsi: true })),
|
|
251
|
+
[lines, filename]
|
|
252
|
+
);
|
|
253
|
+
const rows = list.items.map((item) => ({
|
|
254
|
+
...item,
|
|
255
|
+
lineIndex: visible ? visible[item.index] ?? item.index : item.index
|
|
256
|
+
}));
|
|
257
|
+
return {
|
|
258
|
+
rows,
|
|
259
|
+
totalSize: list.totalSize,
|
|
260
|
+
measureRef: list.measureRef,
|
|
261
|
+
isFiltering,
|
|
262
|
+
shownCount,
|
|
263
|
+
atBottom: follow.atBottom,
|
|
264
|
+
unread,
|
|
265
|
+
jumpToBottom: follow.jumpToBottom,
|
|
266
|
+
failures,
|
|
267
|
+
failurePosition,
|
|
268
|
+
jumpToFailure,
|
|
269
|
+
nextFailure,
|
|
270
|
+
previousFailure,
|
|
271
|
+
text,
|
|
272
|
+
copyText,
|
|
273
|
+
download,
|
|
274
|
+
list
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
export {
|
|
278
|
+
MAX_REALIGN_FRAMES,
|
|
279
|
+
downloadText,
|
|
280
|
+
initialVisibleCount,
|
|
281
|
+
logToText,
|
|
282
|
+
measuredOrEstimate,
|
|
283
|
+
shouldRealign,
|
|
284
|
+
targetOffset,
|
|
285
|
+
useVirtualList,
|
|
286
|
+
useVirtualLog
|
|
287
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@develemit/web-hooks",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Shared React behavior hooks for develemit web apps: drawer swipe, focus trap, escape key and clipboard.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Emit Dutcher",
|
|
@@ -109,6 +109,16 @@
|
|
|
109
109
|
"types": "./dist/push.d.ts",
|
|
110
110
|
"import": "./dist/push.js",
|
|
111
111
|
"require": "./dist/push.cjs"
|
|
112
|
+
},
|
|
113
|
+
"./terminal-output": {
|
|
114
|
+
"types": "./dist/terminal-output.d.ts",
|
|
115
|
+
"import": "./dist/terminal-output.js",
|
|
116
|
+
"require": "./dist/terminal-output.cjs"
|
|
117
|
+
},
|
|
118
|
+
"./virtual-list": {
|
|
119
|
+
"types": "./dist/virtual-list.d.ts",
|
|
120
|
+
"import": "./dist/virtual-list.js",
|
|
121
|
+
"require": "./dist/virtual-list.cjs"
|
|
112
122
|
}
|
|
113
123
|
},
|
|
114
124
|
"main": "./dist/index.cjs",
|
|
@@ -123,11 +133,14 @@
|
|
|
123
133
|
"access": "public"
|
|
124
134
|
},
|
|
125
135
|
"peerDependencies": {
|
|
126
|
-
"react": "^18.0.0 || ^19.0.0"
|
|
136
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
137
|
+
"@tanstack/react-virtual": "^3.13.0"
|
|
127
138
|
},
|
|
128
139
|
"devDependencies": {
|
|
129
140
|
"@eslint/js": "^9.0.0",
|
|
141
|
+
"@tanstack/react-virtual": "^3.14.26",
|
|
130
142
|
"@testing-library/react": "^16.0.0",
|
|
143
|
+
"@types/node": "^20.19.43",
|
|
131
144
|
"@types/react": "^19.0.0",
|
|
132
145
|
"@types/react-18": "npm:@types/react@^18.3.31",
|
|
133
146
|
"@types/react-dom": "^19.0.0",
|
|
@@ -145,6 +158,11 @@
|
|
|
145
158
|
"typescript-eslint": "^8.0.0",
|
|
146
159
|
"vitest": "^3.0.0"
|
|
147
160
|
},
|
|
161
|
+
"peerDependenciesMeta": {
|
|
162
|
+
"@tanstack/react-virtual": {
|
|
163
|
+
"optional": true
|
|
164
|
+
}
|
|
165
|
+
},
|
|
148
166
|
"scripts": {
|
|
149
167
|
"typecheck": "tsc --noEmit",
|
|
150
168
|
"lint": "eslint .",
|