ranuts 0.4.1-alpha.1 → 0.4.1-alpha.2

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 (38) hide show
  1. package/CLAUDE.md +156 -11
  2. package/README.md +2 -0
  3. package/README.zh-CN.md +2 -0
  4. package/dist/{color-B_KMM8UX.js → color-BTvZUuf-.js} +1 -1
  5. package/dist/i18n-DW21b_DJ.js +1 -0
  6. package/dist/index.js +1 -1
  7. package/dist/src/conversation/engine.d.ts +109 -0
  8. package/dist/src/conversation/index.d.ts +12 -0
  9. package/dist/src/conversation/index.js +1 -0
  10. package/dist/src/conversation/types.d.ts +99 -0
  11. package/dist/src/node/index.js +1 -1
  12. package/dist/src/stream/accumulator.d.ts +51 -0
  13. package/dist/src/stream/budget.d.ts +89 -0
  14. package/dist/src/stream/index.d.ts +25 -0
  15. package/dist/src/stream/index.js +1 -0
  16. package/dist/src/stream/sse.d.ts +51 -0
  17. package/dist/src/stream/types.d.ts +106 -0
  18. package/dist/src/utils/canvas.d.ts +1 -0
  19. package/dist/src/utils/diff.d.ts +51 -0
  20. package/dist/src/utils/i18n/index.js +1 -1
  21. package/dist/src/utils/index.d.ts +9 -5
  22. package/dist/src/utils/index.js +1 -1
  23. package/dist/src/utils/number.d.ts +20 -0
  24. package/dist/src/utils/placement.d.ts +42 -5
  25. package/dist/src/utils/scroll.d.ts +93 -0
  26. package/dist/test/budget.test.d.ts +1 -0
  27. package/dist/test/conversation.test.d.ts +1 -0
  28. package/dist/test/diff.test.d.ts +1 -0
  29. package/dist/test/formatBytes.test.d.ts +1 -0
  30. package/dist/test/scroll.test.d.ts +1 -0
  31. package/dist/test/stream.test.d.ts +1 -0
  32. package/dist/umd/index.umd.cjs +1 -1
  33. package/dist/umd/utils/utils.umd.cjs +1 -1
  34. package/dist/utils-B4FnyUzW.js +1 -0
  35. package/docs/API.md +80 -3
  36. package/package.json +11 -2
  37. package/dist/i18n-BJIS1fR1.js +0 -1
  38. package/dist/utils-BNwhohXq.js +0 -1
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Provider-neutral vocabulary for one streamed model response.
3
+ *
4
+ * Every mainstream chat completion API streams the same four things — assistant text,
5
+ * separately-billed reasoning text, tool calls, and a token count — but each names them
6
+ * differently and interleaves them differently. Normalizing to one union at the edge means
7
+ * a renderer, an accumulator, and a test fixture never learn a vendor's wire format.
8
+ *
9
+ * The union is the contract; the shape below is what makes it usable:
10
+ *
11
+ * - **`index` correlates interleaved deltas.** Reasoning and text can arrive interleaved,
12
+ * and a response can open several tool calls at once. Consumers group by `index` rather
13
+ * than assuming a delta belongs to whatever arrived last.
14
+ * - **`block-end` carries the assembled block.** A consumer that accumulated the deltas
15
+ * itself can adopt or verify it; a consumer that only wants finished blocks can ignore
16
+ * every delta.
17
+ * - **Tool arguments stay raw JSON text.** `argumentsDelta` is never parsed mid-stream:
18
+ * half a JSON document is not a value, and pretending otherwise is where streaming tool
19
+ * calls usually break.
20
+ * - **`finish` terminates.** `usage` arrives before it, and nothing follows it. A consumer
21
+ * can treat `finish` as the point where its state is complete.
22
+ *
23
+ * @module ranuts/stream
24
+ */
25
+ /** Discriminator for the content a block accumulates. */
26
+ export type ContentBlockType = 'text' | 'reasoning' | 'tool-call';
27
+ /** Assistant prose addressed to the user. */
28
+ export interface TextBlock {
29
+ type: 'text';
30
+ text: string;
31
+ }
32
+ /**
33
+ * Model reasoning, when the provider exposes it. Kept separate from {@link TextBlock}
34
+ * because it is billed, displayed, and retained differently — a UI usually collapses it,
35
+ * and it is normally dropped from the history sent back on the next request.
36
+ */
37
+ export interface ReasoningBlock {
38
+ type: 'reasoning';
39
+ text: string;
40
+ }
41
+ /** One tool invocation requested by the model. */
42
+ export interface ToolCallBlock {
43
+ type: 'tool-call';
44
+ /** Provider-assigned call id, echoed back with the result. */
45
+ id: string;
46
+ /** Tool name; empty until the provider has sent it. */
47
+ name: string;
48
+ /** Raw JSON text of the arguments — deliberately unparsed. */
49
+ arguments: string;
50
+ }
51
+ /** One completed unit of assistant output. */
52
+ export type ContentBlock = TextBlock | ReasoningBlock | ToolCallBlock;
53
+ /**
54
+ * Why the response ended.
55
+ *
56
+ * `tool-calls` is not a failure: the model finished its turn by asking for tools, and the
57
+ * caller is expected to run them and continue. `aborted` means the consumer stopped the
58
+ * stream, which is why it is distinct from `error`.
59
+ */
60
+ export type FinishReason = 'stop' | 'length' | 'tool-calls' | 'content-filter' | 'error' | 'aborted';
61
+ /** Token counts reported for one response. Every field is optional: providers differ. */
62
+ export interface TokenUsage {
63
+ inputTokens?: number;
64
+ outputTokens?: number;
65
+ /** Reasoning tokens, where the provider bills them separately from output. */
66
+ reasoningTokens?: number;
67
+ /** Input tokens served from a provider-side cache, where reported. */
68
+ cachedInputTokens?: number;
69
+ totalTokens?: number;
70
+ }
71
+ /**
72
+ * One normalized event from a streamed response.
73
+ *
74
+ * `block-start` is optional in practice — several providers begin a block with its first
75
+ * delta — so consumers must tolerate a delta for an index they have not seen.
76
+ * {@link createStreamAccumulator} does.
77
+ */
78
+ export type StreamChunk = {
79
+ type: 'block-start';
80
+ index: number;
81
+ blockType: ContentBlockType;
82
+ } | {
83
+ type: 'text-delta';
84
+ index: number;
85
+ text: string;
86
+ } | {
87
+ type: 'reasoning-delta';
88
+ index: number;
89
+ text: string;
90
+ } | {
91
+ type: 'tool-call-delta';
92
+ index: number;
93
+ id: string;
94
+ name?: string;
95
+ argumentsDelta: string;
96
+ } | {
97
+ type: 'block-end';
98
+ index: number;
99
+ block: ContentBlock;
100
+ } | {
101
+ type: 'usage';
102
+ usage: TokenUsage;
103
+ } | {
104
+ type: 'finish';
105
+ reason: FinishReason;
106
+ };
@@ -50,5 +50,6 @@ export declare const roundRectByArc: (ctx: CanvasRenderingContext2D, ...[x, y, w
50
50
  * @param {number} h rectangle height
51
51
  * @param {string} background a string such as `linear-gradient(90deg, red, blue)`
52
52
  * @return {CanvasGradient} assignable straight to fillStyle / strokeStyle
53
+ * @throws {TypeError} when `background` is not a `linear-gradient(...)` value
53
54
  */
54
55
  export declare const getLinearGradient: (ctx: CanvasRenderingContext2D, x: number, y: number, w: number, h: number, background: string) => CanvasGradient;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Line-level text diff.
3
+ *
4
+ * Enough to render "what changed in this file" — a review card, a tool result, a config
5
+ * preview — without a diff library. It is deliberately line-level: word- and
6
+ * character-level diffing is a different problem with different trade-offs, and a
7
+ * component that renders lines gains nothing from it.
8
+ *
9
+ * The shape is the familiar unified-diff one, because that is what consumers already know
10
+ * how to render and because it is what a server-side producer would send.
11
+ */
12
+ /** What happened to one line. */
13
+ export type DiffLineKind = 'context' | 'added' | 'removed';
14
+ /** One line of a diff, carrying both line numbers so a gutter can show either side. */
15
+ export interface DiffLine {
16
+ kind: DiffLineKind;
17
+ text: string;
18
+ /** 1-based line number on the old side, or null for an added line. */
19
+ oldLine: number | null;
20
+ /** 1-based line number on the new side, or null for a removed line. */
21
+ newLine: number | null;
22
+ }
23
+ /** A run of changed lines plus the context around it. */
24
+ export interface DiffHunk {
25
+ /** 1-based first old-side line in this hunk; 0 when the old side is empty. */
26
+ oldStart: number;
27
+ oldLines: number;
28
+ /** 1-based first new-side line in this hunk; 0 when the new side is empty. */
29
+ newStart: number;
30
+ newLines: number;
31
+ lines: DiffLine[];
32
+ }
33
+ /** How to compute a diff. */
34
+ export interface DiffOptions {
35
+ /** Unchanged lines kept either side of a change. Defaults to 3. */
36
+ context?: number;
37
+ }
38
+ /**
39
+ * Diffs two texts by line.
40
+ *
41
+ * A common prefix and suffix are matched directly, so a one-line edit in a large file
42
+ * costs almost nothing; only the differing middle goes through the quadratic table. Past
43
+ * {@link MAX_TABLE_CELLS} that middle degrades to a wholesale replacement rather than
44
+ * allocating an unbounded table.
45
+ *
46
+ * @param oldText The text before. Pass `''` for a file being created.
47
+ * @param newText The text after. Pass `''` for a file being deleted.
48
+ * @param options Context size.
49
+ * @returns Hunks in order; empty when the texts are identical.
50
+ */
51
+ export declare function diffLines(oldText: string, newText: string, options?: DiffOptions): DiffHunk[];
@@ -1 +1 @@
1
- import{n as r,r as s,t as a}from"../../../i18n-BJIS1fR1.js";export{a as I18nCore,r as createI18n,s as useI18n};
1
+ import{n as r,r as s,t as a}from"../../../i18n-DW21b_DJ.js";export{a as I18nCore,r as createI18n,s as useI18n};
@@ -1,6 +1,10 @@
1
+ import { createBottomFollower } from './scroll';
2
+ import { diffLines } from './diff';
1
3
  import { SyncHook } from './subscribe';
2
- import { Mathjs, addNumSym, clamp, fit, inverseLerp, lerp, linearstep, mathjs, parseChineseNumber, parseEnglishNumber, parseRomanNumber, perToNum, range, remap, smoothstep, transformNumber } from './number';
4
+ import { Mathjs, addNumSym, formatBytes, clamp, fit, inverseLerp, lerp, linearstep, mathjs, parseChineseNumber, parseEnglishNumber, parseRomanNumber, perToNum, range, remap, smoothstep, transformNumber } from './number';
3
5
  import { MessageCodec, arrayBufferToString, checkEncoding, clearBr, clearStr, getMatchingSentences, getRandomString, isString, md5, randomString, strParse, toFullWidth, toHalfWidth, toString, transformText, truncate, truncateWithMarker, fenceCode, slugify, csvEscape } from './str';
6
+ import type { BottomFollower, BottomFollowerOptions } from './scroll';
7
+ import type { DiffHunk, DiffLine, DiffLineKind, DiffOptions } from './diff';
4
8
  import type { TransformText, TruncateOptions, TruncatePosition } from './str';
5
9
  import { createSpeechRecognizer, isSpeechRecognitionSupported } from './speech';
6
10
  import type { SpeechError, SpeechErrorKind, SpeechRecognizer, SpeechRecognizerOptions } from './speech';
@@ -41,8 +45,8 @@ import { I18nCore, createI18n, useI18n } from './i18n';
41
45
  import type { I18nConfig, LocaleChangeHandler, LocaleMessages, MessageDict, StringValues, TranslateParams } from './i18n';
42
46
  import { createLocalePath } from './localePath';
43
47
  import type { LocalePath, LocalePathConfig, LocaleRoute } from './localePath';
44
- import { computePlacement } from './placement';
45
- import type { ComputePlacementOptions, ComputedPlacement, Placement, PlacementRect } from './placement';
48
+ import { alignCrossAxis, computePlacement } from './placement';
49
+ import type { ComputePlacementOptions, ComputedPlacement, Placement, PlacementAlign, PlacementRect, PlacementSide } from './placement';
46
50
  import type { ResolveLocaleOptions, TextLanguage } from './lang';
47
51
  import { readFileAsArrayBuffer, readFileAsDataURL, readFileAsText, readFileAsUint8Array } from './file';
48
52
  import { base64ToBytes, bytesToBase64, decodeTextBytes, fetchMaybeGzip, gunzipMaybe, isGzip, isHtmlDocument, isZipContainer, saveFileToDisk, bytesToBase64Url, base64UrlToBytes, concatBytes } from './binary';
@@ -73,5 +77,5 @@ import type { CurrentDevice } from './device';
73
77
  import { MOBILE_MEDIA_QUERY, currentDevice, isClient, isMobile, isWeiXin, matchMediaQuery, watchMediaQuery } from './device';
74
78
  import { Color, ColorScheme, FMT, HEX_COLOR_REGEX, Hsl, Hsla, RGBA_REGEX, RGB_REGEX, Rgb, Rgba, blendMultiply, blendOverlay, blendScreen, brightnessContrast, componentToHex, cosinePalette, hexToAlpha, hexToHsb, hexToHsv, hexToRgb, hsbToHsl, hsbToRgb, hslToHsb, hslToHsv, hslToRgb, hsvToHsl, hsvToRgb, hue2rgb, linearToSrgb, luma, randomColor, rgbToHex, rgbToHsb, rgbToHsl, rgbToHsv, rgbaString, rgbaToHex, rgbaToRgb, saturation, srgbToLinear, vibrance } from '@/utils/color';
75
79
  import type { RGB } from '@/utils/color';
76
- export { performanceTime, timeFormat, timestampToTime, throttle, SyncHook, clearBr, clearStr, isString, randomString, strParse, scriptOnLoad, handleFetchHook, createData, report, QuestQueue, noop, getPerformance, querystring, formatJson, filterObj, merge, replaceOld, mergeExports, perToNum, range, clamp, lerp, inverseLerp, remap, fit, linearstep, smoothstep, Mathjs, mathjs, getStatus, status, Monitor, MimeType, getExtensions, setMime, getMime, memoize, once, isImageSize, convertImageToBase64, handleError, addClassToElement, removeClassToElement, createDocumentFragment, escapeHtml, isClient, isWeiXin, isMobile, debounce, currentDevice, handleConsole, compose, Color, FMT, Hsl, Hsla, Rgb, Rgba, randomColor, hexToRgb, componentToHex, rgbToHex, rgbToHsl, hue2rgb, hslToRgb, rgbToHsb, hsbToRgb, hsvToRgb, hsvToHsl, ColorScheme, AudioRecorder, getCookie, requestUrlToBuffer, getPixelRatio, createObjectURL, getFrame, getAllQueryString, queryFlag, isInIframe, appendUrl, getCookieByName, getWindow, connection, encodeUrl, imageRequest, durationHandler, networkSpeed, TOTP, localStorageGetItem, localStorageSetItem, localStorageRemoveItem, createStore, setFontSize2html, autosizeTextarea, createSpeechRecognizer, isSpeechRecognitionSupported, Chain, create, isEqual, cloneDeep, createSignal, subscribers, getMatchingSentences, transformNumber, toString, addNumSym, checkEncoding, transformText, isSafari, md5, getRandomString, bridgeManager, Client, BridgeManager, PostMessageBridge, MessageCodec, Platform, openPortBridge, acceptPortBridge, createPortBridge, BRIDGE_MARKER, DEFAULT_CHANNEL, singleFlight, WebDB, createHandoff, buildOffsets, paginateText, indexForOffset, segmentByRanges, detectLanguage, navigatorLanguage, resolveLocale, readFileAsArrayBuffer, readFileAsUint8Array, base64ToBytes, bytesToBase64, decodeTextBytes, fetchMaybeGzip, gunzipMaybe, isGzip, isHtmlDocument, isZipContainer, saveFileToDisk, readFileAsText, readFileAsDataURL, WorkerClient, serveWorker, whenIdle, networkAllowsDownload, isUrlCached, prefetchUrl, prefetchUrls, prefetchWhenIdle, deferred, withTimeout, withTimeoutFallback, delay, TimeoutError, createRaceGuard, crc32, inflateRaw, readZipEntries, readZipEntry, zipHasEntry, rewriteZip, createZip, ZIP_STORED, ZIP_DEFLATE, arrayBufferToString, toHalfWidth, toFullWidth, truncate, parseChineseNumber, parseRomanNumber, parseEnglishNumber, MOBILE_MEDIA_QUERY, matchMediaQuery, watchMediaQuery, createLocalePath, setReportUrl, getReportUrl, formatDate, formatDuration, formatRelative, parseVttCueTiming, parseVttTimestamp, handleXhrHook, EventManager, createDoubleTapDetector, quad, cubic, quart, quint, sine, expo, circ, getImage, cutRound, opacity, getMatrix, getAngle, getArcPointerByDeg, getTangentByPointer, fanShapedByArc, roundRectByArc, getLinearGradient, adoptStyles, adoptSheetText, ADOPTED_STYLE_MARKER, ADOPTED_SHEET_MARKER, rgbToHsv, hexToHsb, hexToHsv, hsbToHsl, hslToHsb, hslToHsv, hexToAlpha, rgbaString, rgbaToRgb, rgbaToHex, srgbToLinear, linearToSrgb, luma, blendScreen, blendMultiply, blendOverlay, brightnessContrast, saturation, vibrance, cosinePalette, HEX_COLOR_REGEX, RGB_REGEX, RGBA_REGEX, loadScript, I18nCore, createI18n, useI18n, computePlacement, safeEqual, secureRandomString, secureToken, UNAMBIGUOUS_ALPHABET, bytesToBase64Url, base64UrlToBytes, concatBytes, truncateWithMarker, fenceCode, slugify, csvEscape, };
77
- export type { RGB, DateInput, FormatRelativeOptions, RelativeStyle, TruncateOptions, TruncatePosition, SpeechError, SpeechErrorKind, SpeechRecognizer, SpeechRecognizerOptions, EasingFn, SpeedType, ImgSource, LoadScriptOptions, I18nConfig, MessageDict, StringValues, LocaleMessages, TranslateParams, LocaleChangeHandler, Debounced, Throttled, BeaconPayload, ReportConfig, LocalePath, LocalePathConfig, LocaleRoute, SingleFlight, IDBCollection, IDBResult, IDBStoreSchema, WebDBOptions, Handoff, HandoffOptions, JsonStore, Deferred, RaceGuard, DoubleTapDetector, DoubleTapDetectorOptions, ZipEntry, RewriteZipOptions, ResolveLocaleOptions, OffsetRange, PaginateOptions, PaginateResult, TextBox, TextGridMetrics, TextPage, Segment, TextLanguage, ServeWorkerOptions, WorkerClientOptions, WorkerHandlerContext, WorkerRequestBase, WorkerResponseBase, WhenIdleOptions, NetworkAllowanceOptions, PrefetchOptions, CurrentDevice, TransformText, MessageHandler, MessageData, PendingRequest, BridgeManagerOptions, BroadcastPayload, CallToPayload, PortBridge, OpenPortBridgeOptions, AcceptPortBridgeOptions, ComputePlacementOptions, ComputedPlacement, Placement, PlacementRect, };
80
+ export { createBottomFollower, diffLines, formatBytes, performanceTime, timeFormat, timestampToTime, throttle, SyncHook, clearBr, clearStr, isString, randomString, strParse, scriptOnLoad, handleFetchHook, createData, report, QuestQueue, noop, getPerformance, querystring, formatJson, filterObj, merge, replaceOld, mergeExports, perToNum, range, clamp, lerp, inverseLerp, remap, fit, linearstep, smoothstep, Mathjs, mathjs, getStatus, status, Monitor, MimeType, getExtensions, setMime, getMime, memoize, once, isImageSize, convertImageToBase64, handleError, addClassToElement, removeClassToElement, createDocumentFragment, escapeHtml, isClient, isWeiXin, isMobile, debounce, currentDevice, handleConsole, compose, Color, FMT, Hsl, Hsla, Rgb, Rgba, randomColor, hexToRgb, componentToHex, rgbToHex, rgbToHsl, hue2rgb, hslToRgb, rgbToHsb, hsbToRgb, hsvToRgb, hsvToHsl, ColorScheme, AudioRecorder, getCookie, requestUrlToBuffer, getPixelRatio, createObjectURL, getFrame, getAllQueryString, queryFlag, isInIframe, appendUrl, getCookieByName, getWindow, connection, encodeUrl, imageRequest, durationHandler, networkSpeed, TOTP, localStorageGetItem, localStorageSetItem, localStorageRemoveItem, createStore, setFontSize2html, autosizeTextarea, createSpeechRecognizer, isSpeechRecognitionSupported, Chain, create, isEqual, cloneDeep, createSignal, subscribers, getMatchingSentences, transformNumber, toString, addNumSym, checkEncoding, transformText, isSafari, md5, getRandomString, bridgeManager, Client, BridgeManager, PostMessageBridge, MessageCodec, Platform, openPortBridge, acceptPortBridge, createPortBridge, BRIDGE_MARKER, DEFAULT_CHANNEL, singleFlight, WebDB, createHandoff, buildOffsets, paginateText, indexForOffset, segmentByRanges, detectLanguage, navigatorLanguage, resolveLocale, readFileAsArrayBuffer, readFileAsUint8Array, base64ToBytes, bytesToBase64, decodeTextBytes, fetchMaybeGzip, gunzipMaybe, isGzip, isHtmlDocument, isZipContainer, saveFileToDisk, readFileAsText, readFileAsDataURL, WorkerClient, serveWorker, whenIdle, networkAllowsDownload, isUrlCached, prefetchUrl, prefetchUrls, prefetchWhenIdle, deferred, withTimeout, withTimeoutFallback, delay, TimeoutError, createRaceGuard, crc32, inflateRaw, readZipEntries, readZipEntry, zipHasEntry, rewriteZip, createZip, ZIP_STORED, ZIP_DEFLATE, arrayBufferToString, toHalfWidth, toFullWidth, truncate, parseChineseNumber, parseRomanNumber, parseEnglishNumber, MOBILE_MEDIA_QUERY, matchMediaQuery, watchMediaQuery, createLocalePath, setReportUrl, getReportUrl, formatDate, formatDuration, formatRelative, parseVttCueTiming, parseVttTimestamp, handleXhrHook, EventManager, createDoubleTapDetector, quad, cubic, quart, quint, sine, expo, circ, getImage, cutRound, opacity, getMatrix, getAngle, getArcPointerByDeg, getTangentByPointer, fanShapedByArc, roundRectByArc, getLinearGradient, adoptStyles, adoptSheetText, ADOPTED_STYLE_MARKER, ADOPTED_SHEET_MARKER, rgbToHsv, hexToHsb, hexToHsv, hsbToHsl, hslToHsb, hslToHsv, hexToAlpha, rgbaString, rgbaToRgb, rgbaToHex, srgbToLinear, linearToSrgb, luma, blendScreen, blendMultiply, blendOverlay, brightnessContrast, saturation, vibrance, cosinePalette, HEX_COLOR_REGEX, RGB_REGEX, RGBA_REGEX, loadScript, I18nCore, createI18n, useI18n, alignCrossAxis, computePlacement, safeEqual, secureRandomString, secureToken, UNAMBIGUOUS_ALPHABET, bytesToBase64Url, base64UrlToBytes, concatBytes, truncateWithMarker, fenceCode, slugify, csvEscape, };
81
+ export type { RGB, DateInput, FormatRelativeOptions, RelativeStyle, TruncateOptions, TruncatePosition, SpeechError, SpeechErrorKind, SpeechRecognizer, SpeechRecognizerOptions, EasingFn, SpeedType, ImgSource, LoadScriptOptions, I18nConfig, MessageDict, StringValues, LocaleMessages, TranslateParams, LocaleChangeHandler, Debounced, Throttled, BeaconPayload, ReportConfig, LocalePath, LocalePathConfig, LocaleRoute, SingleFlight, IDBCollection, IDBResult, IDBStoreSchema, WebDBOptions, Handoff, HandoffOptions, JsonStore, Deferred, RaceGuard, DoubleTapDetector, DoubleTapDetectorOptions, ZipEntry, RewriteZipOptions, ResolveLocaleOptions, OffsetRange, PaginateOptions, PaginateResult, TextBox, TextGridMetrics, TextPage, Segment, TextLanguage, ServeWorkerOptions, WorkerClientOptions, WorkerHandlerContext, WorkerRequestBase, WorkerResponseBase, WhenIdleOptions, NetworkAllowanceOptions, PrefetchOptions, CurrentDevice, TransformText, MessageHandler, MessageData, PendingRequest, BridgeManagerOptions, BroadcastPayload, CallToPayload, PortBridge, OpenPortBridgeOptions, AcceptPortBridgeOptions, ComputePlacementOptions, ComputedPlacement, Placement, PlacementAlign, PlacementRect, PlacementSide, BottomFollower, BottomFollowerOptions, DiffHunk, DiffLine, DiffLineKind, DiffOptions, };
@@ -1 +1 @@
1
- import{i as s}from"../../enums-BAgbyGdH.js";import{$ as a,A as t,B as n,C as o,D as r,E as m,F as i,G as p,H as f,I as j,J as c,K as l,L as u,M as d,N as h,O as x,P as b,Q as e,R as g,S as k,T as v,U as w,V as y,W as A,X as C,Y as D,Z as E,_ as F,a as M,at as N,b as O,c as P,ct as S,d as T,dt as _,et as z,f as B,g as H,h as I,i as L,it as R,j as U,k as V,l as q,lt as G,m as J,n as K,nt as Q,o as W,ot as X,p as Y,q as Z,r as $,rt as ss,s as as,st as ts,t as ns,tt as os,u as rs,ut as ms,v as is,w as ps,x as fs,y as js,z as cs}from"../../color-B_KMM8UX.js";import{$ as ls,$t as us,A as ds,An as hs,At as xs,B as bs,Bn as es,Bt as gs,C as ks,Cn as vs,Ct as ws,D as ys,Dn as As,Dt as Cs,E as Ds,En as Es,Et as Fs,F as Ms,Fn as Ns,Ft as Os,G as Ps,Gt as Ss,H as Ts,Hn as _s,Ht as zs,I as Bs,In as Hs,It as Is,J as Ls,Jt as Rs,K as Us,Kt as Vs,L as qs,Ln as Gs,Lt as Js,M as Ks,Mn as Qs,Mt as Ws,N as Xs,Nn as Ys,Nt as Zs,O as $s,On as sa,Ot as aa,P as ta,Pn as na,Pt as oa,Q as ra,Qt as ma,R as ia,Rn as pa,Rt as fa,S as ja,Sn as ca,St as la,T as ua,Tn as da,Tt as ha,U as xa,Un as ba,Ut as ea,V as ga,Vn as ka,Vt as va,W as wa,Wt as ya,X as Aa,Xt as Ca,Y as Da,Yt as Ea,Z as Fa,Zt as Ma,_ as Na,_n as Oa,_t as Pa,a as Sa,an as Ta,at as _a,b as za,bn as Ba,bt as Ha,c as Ia,cn as La,ct as Ra,d as Ua,dn as Va,dt as qa,en as Ga,et as Ja,f as Ka,fn as Qa,ft as Wa,g as Xa,gn as Ya,gt as Za,h as $a,hn as st,ht as at,i as tt,in as nt,it as ot,j as rt,jn as mt,jt as it,k as pt,kn as ft,kt as jt,l as ct,ln as lt,lt as ut,m as dt,mn as ht,mt as xt,n as bt,nn as et,nt as gt,o as kt,on as vt,ot as wt,p as yt,pn as At,pt as Ct,q as Dt,qt as Et,r as Ft,rn as Mt,rt as Nt,s as Ot,sn as Pt,st as St,t as Tt,tn as _t,tt as zt,u as Bt,un as Ht,ut as It,v as Lt,vn as Rt,vt as Ut,w as Vt,wn as qt,wt as Gt,x as Jt,xn as Kt,xt as Qt,y as Wt,yn as Xt,yt as Yt,z as Zt,zn as $t,zt as sn}from"../../utils-BNwhohXq.js";import{A as an,C as tn,D as nn,E as on,F as rn,M as mn,N as pn,O as fn,P as jn,S as cn,T as ln,_ as un,a as dn,b as hn,c as xn,d as bn,f as en,g as gn,h as kn,i as vn,j as wn,k as yn,l as An,m as Cn,n as Dn,o as En,p as Fn,r as Mn,s as Nn,t as On,u as Pn,v as Sn,w as Tn,x as _n,y as zn}from"../../i18n-BJIS1fR1.js";import{n as Bn,t as Hn}from"../../chain-CTywmh_H.js";export{Wa as ADOPTED_SHEET_MARKER,Ct as ADOPTED_STYLE_MARKER,Mt as AudioRecorder,Ya as BRIDGE_MARKER,Oa as BridgeManager,Hn as Chain,Rt as Client,ns as Color,K as ColorScheme,Xt as DEFAULT_CHANNEL,Os as EventManager,$ as FMT,L as HEX_COLOR_REGEX,M as Hsl,W as Hsla,On as I18nCore,ya as MOBILE_MEDIA_QUERY,sa as Mathjs,l as MessageCodec,f as MimeType,kt as Monitor,Ba as Platform,Kt as PostMessageBridge,Ft as QuestQueue,as as RGBA_REGEX,P as RGB_REGEX,q as Rgb,rs as Rgba,s as SyncHook,Ga as TOTP,Vt as TimeoutError,ia as UNAMBIGUOUS_ALPHABET,It as WebDB,Bs as WorkerClient,$a as ZIP_DEFLATE,Xa as ZIP_STORED,ca as acceptPortBridge,fa as addClassToElement,ft as addNumSym,xt as adoptSheetText,at as adoptStyles,bn as appendUrl,Z as arrayBufferToString,sn as autosizeTextarea,Ts as base64ToBytes,xa as base64UrlToBytes,T as blendMultiply,B as blendOverlay,Y as blendScreen,vs as bridgeManager,J as brightnessContrast,St as buildOffsets,wa as bytesToBase64,Ps as bytesToBase64Url,c as checkEncoding,aa as circ,hs as clamp,D as clearBr,C as clearStr,nt as cloneDeep,I as componentToHex,us as compose,ot as computePlacement,Us as concatBytes,en as connection,Za as convertImageToBase64,H as cosinePalette,Na as crc32,Bn as create,Bt as createData,gs as createDocumentFragment,Is as createDoubleTapDetector,qa as createHandoff,Dn as createI18n,_a as createLocalePath,Fn as createObjectURL,qt as createPortBridge,ua as createRaceGuard,_t as createSignal,Es as createSpeechRecognizer,Nn as createStore,Lt as createZip,E as csvEscape,jt as cubic,Ss as currentDevice,Pa as cutRound,Ma as debounce,Dt as decodeTextBytes,Ds as deferred,ys as delay,vn as detectLanguage,Cn as durationHandler,kn as encodeUrl,va as escapeHtml,xs as expo,la as fanShapedByArc,e as fenceCode,Ls as fetchMaybeGzip,Ta as filterObj,mt as fit,fn as formatDate,yn as formatDuration,vt as formatJson,an as formatRelative,gn as getAllQueryString,ws as getAngle,Gt as getArcPointerByDeg,un as getCookie,Sn as getCookieByName,w as getExtensions,zn as getFrame,Ut as getImage,ha as getLinearGradient,a as getMatchingSentences,Yt as getMatrix,A as getMime,dt as getPerformance,hn as getPixelRatio,z as getRandomString,Ua as getReportUrl,tt as getStatus,Fs as getTangentByPointer,_n as getWindow,Da as gunzipMaybe,ma as handleConsole,Js as handleError,Ia as handleFetchHook,ct as handleXhrHook,F as hexToAlpha,is as hexToHsb,js as hexToHsv,O as hexToRgb,fs as hsbToHsl,k as hsbToRgb,o as hslToHsb,ps as hslToHsv,v as hslToRgb,m as hsvToHsl,r as hsvToRgb,x as hue2rgb,cn as imageRequest,Ra as indexForOffset,Wt as inflateRaw,Qs as inverseLerp,Vs as isClient,Pt as isEqual,Aa as isGzip,Fa as isHtmlDocument,Ha as isImageSize,tn as isInIframe,Et as isMobile,Tn as isSafari,As as isSpeechRecognitionSupported,os as isString,ds as isUrlCached,Rs as isWeiXin,ra as isZipContainer,Ys as lerp,V as linearToSrgb,na as linearstep,Tt as loadScript,xn as localStorageGetItem,An as localStorageRemoveItem,Pn as localStorageSetItem,t as luma,Ea as matchMediaQuery,Ns as mathjs,Q as md5,At as memoize,La as merge,lt as mergeExports,dn as navigatorLanguage,rt as networkAllowsDownload,ln as networkSpeed,Qa as noop,ht as once,Qt as opacity,da as openPortBridge,wt as paginateText,Hs as parseChineseNumber,Gs as parseEnglishNumber,pa as parseRomanNumber,wn as parseVttCueTiming,mn as parseVttTimestamp,$t as perToNum,pn as performanceTime,Ks as prefetchUrl,Xs as prefetchUrls,ta as prefetchWhenIdle,it as quad,Ws as quart,on as queryFlag,Ht as querystring,Zs as quint,U as randomColor,ss as randomString,es as range,Ja as readFileAsArrayBuffer,zt as readFileAsDataURL,gt as readFileAsText,Nt as readFileAsUint8Array,za as readZipEntries,Jt as readZipEntry,ka as remap,zs as removeClassToElement,Va as replaceOld,Ka as report,nn as requestUrlToBuffer,En as resolveLocale,ja as rewriteZip,d as rgbToHex,h as rgbToHsb,b as rgbToHsl,i as rgbToHsv,j as rgbaString,u as rgbaToHex,g as rgbaToRgb,Cs as roundRectByArc,Zt as safeEqual,cs as saturation,ls as saveFileToDisk,bt as scriptOnLoad,bs as secureRandomString,ga as secureToken,ut as segmentByRanges,qs as serveWorker,ea as setFontSize2html,p as setMime,yt as setReportUrl,oa as sine,st as singleFlight,R as slugify,_s as smoothstep,n as srgbToLinear,Sa as status,N as strParse,et as subscribers,Ot as throttle,jn as timeFormat,rn as timestampToTime,X as toFullWidth,ts as toHalfWidth,S as toString,ba as transformNumber,G as transformText,ms as truncate,_ as truncateWithMarker,Mn as useI18n,y as vibrance,Ca as watchMediaQuery,Ms as whenIdle,$s as withTimeout,pt as withTimeoutFallback,ks as zipHasEntry};
1
+ import{$ as s,$t as a,A as t,An as n,At as o,B as r,Bn as m,Bt as i,C as p,Cn as f,Ct as j,D as c,Dn as l,Dt as u,E as d,En as h,Et as x,F as b,Fn as e,Ft as g,G as k,Gn as v,Gt as w,H as y,Hn as A,Ht as C,I as D,In as E,It as F,J as M,Jt as N,K as O,Kn as P,Kt as S,L as T,Ln as _,Lt as q,M as z,Mn as B,Mt as G,N as H,Nn as I,Nt as K,O as L,On as R,Ot as U,P as V,Pn as W,Pt as J,Q,Qt as X,R as Y,Rn as Z,Rt as $,S as ss,Sn as as,St as ts,T as ns,Tn as os,Tt as rs,U as ms,Un as is,Ut as ps,V as fs,Vn as js,Vt as cs,W as ls,Wn as us,Wt as ds,X as hs,Xt as xs,Y as bs,Yt as es,Z as gs,Zt as ks,_ as vs,_n as ws,_t as ys,a as As,an as Cs,at as Ds,b as Es,bn as Fs,bt as Ms,c as Ns,cn as Os,ct as Ps,d as Ss,dn as Ts,dt as _s,en as qs,et as zs,f as Bs,fn as Gs,ft as Hs,g as Is,gn as Ks,gt as Ls,h as Rs,hn as Us,ht as Vs,i as Ws,in as Js,it as Qs,j as Xs,jn as Ys,jt as Zs,k as $s,kn as sa,kt as aa,l as ta,ln as na,lt as oa,m as ra,mn as ma,mt as ia,n as pa,nn as fa,nt as ja,o as ca,on as la,ot as ua,p as da,pn as ha,pt as xa,q as ba,qn as ea,qt as ga,r as ka,rn as va,rt as wa,s as ya,sn as Aa,st as Ca,t as Da,tn as Ea,tt as Fa,u as Ma,un as Na,ut as Oa,v as Pa,vn as Sa,vt as Ta,w as _a,wn as qa,wt as za,x as Ba,xn as Ga,xt as Ha,y as Ia,yn as Ka,yt as La,z as Ra,zn as Ua,zt as Va}from"../../utils-B4FnyUzW.js";import{i as Wa}from"../../enums-BAgbyGdH.js";import{$ as Ja,A as Qa,B as Xa,C as Ya,D as Za,E as $a,F as st,G as at,H as tt,I as nt,J as ot,K as rt,L as mt,M as it,N as pt,O as ft,P as jt,Q as ct,R as lt,S as ut,T as dt,U as ht,V as xt,W as bt,X as et,Y as gt,Z as kt,_ as vt,a as wt,at as yt,b as At,c as Ct,ct as Dt,d as Et,dt as Ft,et as Mt,f as Nt,g as Ot,h as Pt,i as St,it as Tt,j as _t,k as qt,l as zt,lt as Bt,m as Gt,n as Ht,nt as It,o as Kt,ot as Lt,p as Rt,q as Ut,r as Vt,rt as Wt,s as Jt,st as Qt,t as Xt,tt as Yt,u as Zt,ut as $t,v as sn,w as an,x as tn,y as nn,z as on}from"../../color-BTvZUuf-.js";import{A as rn,C as mn,D as pn,E as fn,F as jn,M as cn,N as ln,O as un,P as dn,S as hn,T as xn,_ as bn,a as en,b as gn,c as kn,d as vn,f as wn,g as yn,h as An,i as Cn,j as Dn,k as En,l as Fn,m as Mn,n as Nn,o as On,p as Pn,r as Sn,s as Tn,t as _n,u as qn,v as zn,w as Bn,x as Gn,y as Hn}from"../../i18n-DW21b_DJ.js";import{n as In,t as Kn}from"../../chain-CTywmh_H.js";export{xa as ADOPTED_SHEET_MARKER,ia as ADOPTED_STYLE_MARKER,Js as AudioRecorder,ws as BRIDGE_MARKER,Sa as BridgeManager,Kn as Chain,Ka as Client,Xt as Color,Ht as ColorScheme,Fs as DEFAULT_CHANNEL,F as EventManager,Vt as FMT,St as HEX_COLOR_REGEX,wt as Hsl,Kt as Hsla,_n as I18nCore,w as MOBILE_MEDIA_QUERY,sa as Mathjs,rt as MessageCodec,tt as MimeType,ca as Monitor,Ga as Platform,as as PostMessageBridge,ka as QuestQueue,Jt as RGBA_REGEX,Ct as RGB_REGEX,zt as Rgb,Zt as Rgba,Wa as SyncHook,Ea as TOTP,_a as TimeoutError,Y as UNAMBIGUOUS_ALPHABET,_s as WebDB,D as WorkerClient,Rs as ZIP_DEFLATE,Is as ZIP_STORED,f as acceptPortBridge,Va as addClassToElement,n as addNumSym,Vs as adoptSheetText,Ls as adoptStyles,Qs as alignCrossAxis,vn as appendUrl,Ut as arrayBufferToString,i as autosizeTextarea,y as base64ToBytes,ms as base64UrlToBytes,Et as blendMultiply,Nt as blendOverlay,Rt as blendScreen,qa as bridgeManager,Gt as brightnessContrast,Ps as buildOffsets,ls as bytesToBase64,k as bytesToBase64Url,ot as checkEncoding,aa as circ,Ys as clamp,gt as clearBr,et as clearStr,Cs as cloneDeep,Pt as componentToHex,qs as compose,Ds as computePlacement,O as concatBytes,wn as connection,ys as convertImageToBase64,Ot as cosinePalette,vs as crc32,In as create,ea as createBottomFollower,Ma as createData,cs as createDocumentFragment,q as createDoubleTapDetector,Hs as createHandoff,Nn as createI18n,ua as createLocalePath,Pn as createObjectURL,os as createPortBridge,ns as createRaceGuard,fa as createSignal,l as createSpeechRecognizer,Tn as createStore,Pa as createZip,kt as csvEscape,o as cubic,S as currentDevice,Ta as cutRound,X as debounce,ba as decodeTextBytes,d as deferred,c as delay,Cn as detectLanguage,P as diffLines,Mn as durationHandler,An as encodeUrl,C as escapeHtml,Zs as expo,j as fanShapedByArc,ct as fenceCode,M as fetchMaybeGzip,la as filterObj,B as fit,I as formatBytes,un as formatDate,En as formatDuration,Aa as formatJson,rn as formatRelative,yn as getAllQueryString,za as getAngle,rs as getArcPointerByDeg,bn as getCookie,zn as getCookieByName,ht as getExtensions,Hn as getFrame,La as getImage,x as getLinearGradient,Ja as getMatchingSentences,Ms as getMatrix,bt as getMime,ra as getPerformance,gn as getPixelRatio,Mt as getRandomString,Ss as getReportUrl,Ws as getStatus,u as getTangentByPointer,Gn as getWindow,bs as gunzipMaybe,a as handleConsole,$ as handleError,Ns as handleFetchHook,ta as handleXhrHook,vt as hexToAlpha,sn as hexToHsb,nn as hexToHsv,At as hexToRgb,tn as hsbToHsl,ut as hsbToRgb,Ya as hslToHsb,an as hslToHsv,dt as hslToRgb,$a as hsvToHsl,Za as hsvToRgb,ft as hue2rgb,hn as imageRequest,oa as indexForOffset,Ia as inflateRaw,W as inverseLerp,ga as isClient,Os as isEqual,hs as isGzip,gs as isHtmlDocument,Ha as isImageSize,mn as isInIframe,N as isMobile,Bn as isSafari,R as isSpeechRecognitionSupported,Yt as isString,t as isUrlCached,es as isWeiXin,Q as isZipContainer,e as lerp,qt as linearToSrgb,E as linearstep,Da as loadScript,kn as localStorageGetItem,Fn as localStorageRemoveItem,qn as localStorageSetItem,Qa as luma,xs as matchMediaQuery,_ as mathjs,It as md5,ma as memoize,na as merge,Na as mergeExports,en as navigatorLanguage,Xs as networkAllowsDownload,xn as networkSpeed,ha as noop,Us as once,ts as opacity,h as openPortBridge,Ca as paginateText,Z as parseChineseNumber,Ua as parseEnglishNumber,m as parseRomanNumber,Dn as parseVttCueTiming,cn as parseVttTimestamp,js as perToNum,ln as performanceTime,z as prefetchUrl,H as prefetchUrls,V as prefetchWhenIdle,G as quad,K as quart,fn as queryFlag,Ts as querystring,J as quint,_t as randomColor,Wt as randomString,A as range,zs as readFileAsArrayBuffer,Fa as readFileAsDataURL,ja as readFileAsText,wa as readFileAsUint8Array,Es as readZipEntries,Ba as readZipEntry,is as remap,ps as removeClassToElement,Gs as replaceOld,Bs as report,pn as requestUrlToBuffer,On as resolveLocale,ss as rewriteZip,it as rgbToHex,pt as rgbToHsb,jt as rgbToHsl,st as rgbToHsv,nt as rgbaString,mt as rgbaToHex,lt as rgbaToRgb,U as roundRectByArc,Ra as safeEqual,on as saturation,s as saveFileToDisk,pa as scriptOnLoad,r as secureRandomString,fs as secureToken,Oa as segmentByRanges,T as serveWorker,ds as setFontSize2html,at as setMime,da as setReportUrl,g as sine,Ks as singleFlight,Tt as slugify,us as smoothstep,Xa as srgbToLinear,As as status,yt as strParse,va as subscribers,ya as throttle,dn as timeFormat,jn as timestampToTime,Lt as toFullWidth,Qt as toHalfWidth,Dt as toString,v as transformNumber,Bt as transformText,$t as truncate,Ft as truncateWithMarker,Sn as useI18n,xt as vibrance,ks as watchMediaQuery,b as whenIdle,L as withTimeout,$s as withTimeoutFallback,p as zipHasEntry};
@@ -139,4 +139,24 @@ export declare const linearstep: (edge0: number, edge1: number, x: number) => nu
139
139
  * @return {number}
140
140
  */
141
141
  export declare const smoothstep: (edge0: number, edge1: number, x: number) => number;
142
+ /**
143
+ * @description: Format a byte count for a person to read.
144
+ *
145
+ * Steps in units of 1024 and keeps one decimal from KB up, because "1.4 MB" is the number a
146
+ * file manager shows for the same file and a reader comparing the two should not have to
147
+ * wonder. Bytes get no decimal — a fraction of a byte is not a thing.
148
+ *
149
+ * @param {number} bytes Byte count. Negative or non-finite input yields `'0 B'`, since there
150
+ * is no honest reading of a file with a negative size.
151
+ * @return {string}
152
+ * @example
153
+ * ```ts
154
+ * formatBytes(0); // '0 B'
155
+ * formatBytes(999); // '999 B'
156
+ * formatBytes(1024); // '1.0 KB'
157
+ * formatBytes(1536); // '1.5 KB'
158
+ * formatBytes(1048576); // '1.0 MB'
159
+ * ```
160
+ */
161
+ export declare const formatBytes: (bytes: number) => string;
142
162
  export {};
@@ -1,4 +1,18 @@
1
- export type Placement = 'top' | 'bottom' | 'left' | 'right';
1
+ /** The side of the anchor a floating panel sits on. */
2
+ export type PlacementSide = 'top' | 'bottom' | 'left' | 'right';
3
+ /**
4
+ * Where the panel lines up along the cross axis: with the anchor's leading
5
+ * edge, its centre, or its trailing edge. For a `top`/`bottom` placement that
6
+ * is horizontal (left edge / centre / right edge); for `left`/`right` it is
7
+ * vertical (top edge / centre / bottom edge).
8
+ */
9
+ export type PlacementAlign = 'start' | 'center' | 'end';
10
+ /**
11
+ * A side, optionally suffixed with a cross-axis alignment — the same grammar
12
+ * Floating UI and Popper use (`bottom`, `bottom-end`, `right-center`, …).
13
+ * A bare side means `-start`, which is what this module has always done.
14
+ */
15
+ export type Placement = PlacementSide | `${PlacementSide}-${PlacementAlign}`;
2
16
  export interface PlacementRect {
3
17
  top: number;
4
18
  left: number;
@@ -13,7 +27,7 @@ export interface ComputePlacementOptions {
13
27
  width: number;
14
28
  height: number;
15
29
  };
16
- /** Preferred side. Flips to the opposite side when it lacks room and the opposite side has more. */
30
+ /** Preferred side, optionally with a cross-axis alignment. Flips to the opposite side when it lacks room and the opposite side has more; the alignment is carried across the flip. */
17
31
  placement: Placement;
18
32
  /** Gap kept between the anchor and the floating panel, in px. */
19
33
  offset?: number;
@@ -25,14 +39,37 @@ export interface ComputePlacementOptions {
25
39
  export interface ComputedPlacement {
26
40
  top: number;
27
41
  left: number;
28
- /** The side actually used, after flip. */
42
+ /**
43
+ * The placement actually used, after flip, in the form the caller asked for:
44
+ * a bare side stays bare, a suffixed one keeps its suffix. Callers that key a
45
+ * lookup table off four sides therefore keep working unchanged.
46
+ */
29
47
  placement: Placement;
48
+ /** The side actually used, after flip — always bare, whatever form `placement` took. */
49
+ side: PlacementSide;
50
+ /** The cross-axis alignment actually used. `start` when the caller named none. */
51
+ align: PlacementAlign;
30
52
  }
53
+ /**
54
+ * @description: Where a floating panel starts along the cross axis, given how
55
+ * it should line up with its anchor. `start` pins the leading edges together,
56
+ * `end` the trailing ones, `center` splits the difference. Exported because a
57
+ * caller that computes its own coordinates -- a panel positioned inside a
58
+ * custom container rather than the viewport -- still has to align the same way
59
+ * `computePlacement` does, and two implementations of that would drift.
60
+ * @param align cross-axis alignment
61
+ * @param anchorStart anchor's leading edge on that axis (`left` or `top`)
62
+ * @param anchorSize anchor's size on that axis (`width` or `height`)
63
+ * @param floatingSize the panel's size on that axis
64
+ * @return the panel's leading edge on that axis
65
+ */
66
+ export declare const alignCrossAxis: (align: PlacementAlign, anchorStart: number, anchorSize: number, floatingSize: number) => number;
31
67
  /**
32
68
  * Position a floating panel relative to an anchor rect: flips to the opposite
33
69
  * side when the preferred side doesn't have room and the opposite side has
34
- * more, then shifts along the cross axis to stay within `boundary`. Mirrors
35
- * Floating UI's `flip`/`shift` middleware, minus the dependency.
70
+ * more, aligns along the cross axis as asked, then shifts to stay within
71
+ * `boundary`. Mirrors Floating UI's `flip`/`shift` middleware, minus the
72
+ * dependency.
36
73
  *
37
74
  * Coordinates are viewport-relative throughout (same space as `anchor`); the
38
75
  * caller adds `scrollX`/`scrollY` when writing `position: absolute` styles.
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Bottom-follow for append-only scrollers — a streaming chat transcript, a log tail, a
3
+ * terminal pane.
4
+ *
5
+ * The requirement sounds trivial and is not: stay pinned to the floor as content arrives,
6
+ * but the instant the reader scrolls up to read something, stop — and re-pin only when
7
+ * they come back down themselves. Naive implementations fight the reader, because they
8
+ * cannot tell their own scroll writes apart from the reader's.
9
+ *
10
+ * The mechanism here is an **observed-top ledger**. Every programmatic write records the
11
+ * `scrollTop` it produced. When a scroll event arrives, a position that matches the ledger
12
+ * is this module's own write echoing back; a position that deviates is the reader. That
13
+ * covers wheel, touch, scrollbar drag, keyboard, and `scrollIntoView` from unrelated code
14
+ * uniformly, without listening for any input device — which matters because no set of
15
+ * device listeners is ever complete.
16
+ *
17
+ * Two cases the ledger has to survive:
18
+ *
19
+ * - **Shrink-clamp.** When content shrinks, the browser clamps `scrollTop` to the new
20
+ * floor without any reader involvement. Comparing against `min(ledger, floor)` treats
21
+ * that clamp as the ledger's own value rather than as a reader scroll, so a clamp
22
+ * never changes who owns the scroll position — a reader who had scrolled up stays
23
+ * unpinned even when the clamp happens to leave them at the floor, and re-pins on
24
+ * their next scroll. Re-pinning on a clamp would take control back without input.
25
+ * - **Growth while pinned.** Appended content moves the floor away. A scroll event that
26
+ * the reader did not cause, while pinned, re-snaps to the new floor.
27
+ *
28
+ * Scrolling is always instant. Smooth scrolling animates over a moving target, so during
29
+ * streaming it visibly lags the content and, worse, its own intermediate positions read as
30
+ * reader input on the next event.
31
+ */
32
+ /** How to construct a follower. */
33
+ export interface BottomFollowerOptions {
34
+ /** The element that scrolls. */
35
+ scrollport: HTMLElement;
36
+ /**
37
+ * Elements whose size changes should re-follow the floor while pinned — the content
38
+ * column, and any sticky footer that resizes outside it. Streaming text grows an
39
+ * existing node rather than appending one, so growth is observed rather than announced.
40
+ */
41
+ observe?: readonly HTMLElement[];
42
+ /** Distance from the floor still counted as pinned. Defaults to 24. */
43
+ threshold?: number;
44
+ /**
45
+ * Called when the pinned state flips, so a caller can show or hide a "jump to latest"
46
+ * affordance. Never called for a change the caller itself just made synchronously.
47
+ */
48
+ onPinnedChange?: (pinned: boolean) => void;
49
+ }
50
+ /** Imperative bottom-follow controller. */
51
+ export interface BottomFollower {
52
+ /** Whether new content is currently being followed. */
53
+ readonly pinned: boolean;
54
+ /** Scrolls to the floor and pins, regardless of the current state. */
55
+ toBottom(): void;
56
+ /**
57
+ * Follows the floor only if currently pinned. Safe to call on every content change —
58
+ * a reader who has scrolled up is left alone.
59
+ */
60
+ follow(): void;
61
+ /**
62
+ * Remembers a row's current offset from the scrollport top, before content is prepended
63
+ * above it. Capture a row that is actually on screen, so the restore keeps what the
64
+ * reader is looking at exactly where it was.
65
+ *
66
+ * @param row The row to keep still.
67
+ */
68
+ captureAnchor(row: HTMLElement): void;
69
+ /**
70
+ * Restores the captured row to its captured offset, then forgets it.
71
+ *
72
+ * @param resolve Re-resolves the row after the prepend, for callers that replace nodes
73
+ * rather than reuse them. Omit when the captured element is still in the document.
74
+ * @returns Whether an anchor was restored.
75
+ */
76
+ restoreAnchor(resolve?: () => HTMLElement | null): boolean;
77
+ /** Discards any captured anchor without restoring it. */
78
+ releaseAnchor(): void;
79
+ /** Removes the scroll listener and disconnects the resize observer. */
80
+ destroy(): void;
81
+ }
82
+ /**
83
+ * Creates a bottom-follow controller for one scrollport.
84
+ *
85
+ * The controller starts pinned, which is what an append-only view wants on first paint and
86
+ * after a reload. To restore a remembered position instead, set `scrollTop` before or
87
+ * after construction and the first scroll event will settle the pinned state from the
88
+ * geometry.
89
+ *
90
+ * @param options Scrollport, elements to observe, and threshold.
91
+ * @returns The controller; call `destroy` to release its listeners.
92
+ */
93
+ export declare function createBottomFollower(options: BottomFollowerOptions): BottomFollower;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};