@effect-tui/core 0.1.0-alpha.1
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 +21 -0
- package/README.md +93 -0
- package/dist/anim.d.ts +4 -0
- package/dist/anim.d.ts.map +1 -0
- package/dist/anim.js +5 -0
- package/dist/anim.js.map +1 -0
- package/dist/ansi.d.ts +69 -0
- package/dist/ansi.d.ts.map +1 -0
- package/dist/ansi.js +72 -0
- package/dist/ansi.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/keys.d.ts +18 -0
- package/dist/keys.d.ts.map +1 -0
- package/dist/keys.js +247 -0
- package/dist/keys.js.map +1 -0
- package/dist/layout/linearStack.d.ts +17 -0
- package/dist/layout/linearStack.d.ts.map +1 -0
- package/dist/layout/linearStack.js +86 -0
- package/dist/layout/linearStack.js.map +1 -0
- package/dist/motion-value.d.ts +58 -0
- package/dist/motion-value.d.ts.map +1 -0
- package/dist/motion-value.js +250 -0
- package/dist/motion-value.js.map +1 -0
- package/dist/present/display.d.ts +58 -0
- package/dist/present/display.d.ts.map +1 -0
- package/dist/present/display.js +168 -0
- package/dist/present/display.js.map +1 -0
- package/dist/present/writers/fullscreen.d.ts +19 -0
- package/dist/present/writers/fullscreen.d.ts.map +1 -0
- package/dist/present/writers/fullscreen.js +55 -0
- package/dist/present/writers/fullscreen.js.map +1 -0
- package/dist/present/writers/inline.d.ts +20 -0
- package/dist/present/writers/inline.d.ts.map +1 -0
- package/dist/present/writers/inline.js +92 -0
- package/dist/present/writers/inline.js.map +1 -0
- package/dist/render/buffer.d.ts +31 -0
- package/dist/render/buffer.d.ts.map +1 -0
- package/dist/render/buffer.js +183 -0
- package/dist/render/buffer.js.map +1 -0
- package/dist/render/color-utils.d.ts +18 -0
- package/dist/render/color-utils.d.ts.map +1 -0
- package/dist/render/color-utils.js +58 -0
- package/dist/render/color-utils.js.map +1 -0
- package/dist/render/diff.d.ts +30 -0
- package/dist/render/diff.d.ts.map +1 -0
- package/dist/render/diff.js +83 -0
- package/dist/render/diff.js.map +1 -0
- package/dist/render/measure.d.ts +15 -0
- package/dist/render/measure.d.ts.map +1 -0
- package/dist/render/measure.js +65 -0
- package/dist/render/measure.js.map +1 -0
- package/dist/render/palette.d.ts +46 -0
- package/dist/render/palette.d.ts.map +1 -0
- package/dist/render/palette.js +108 -0
- package/dist/render/palette.js.map +1 -0
- package/dist/render/surface.d.ts +77 -0
- package/dist/render/surface.d.ts.map +1 -0
- package/dist/render/surface.js +198 -0
- package/dist/render/surface.js.map +1 -0
- package/dist/runtime/backend_node.d.ts +36 -0
- package/dist/runtime/backend_node.d.ts.map +1 -0
- package/dist/runtime/backend_node.js +66 -0
- package/dist/runtime/backend_node.js.map +1 -0
- package/dist/spring-physics.d.ts +36 -0
- package/dist/spring-physics.d.ts.map +1 -0
- package/dist/spring-physics.js +113 -0
- package/dist/spring-physics.js.map +1 -0
- package/dist/spring.d.ts +73 -0
- package/dist/spring.d.ts.map +1 -0
- package/dist/spring.js +136 -0
- package/dist/spring.js.map +1 -0
- package/dist/ui/containers/canvas.d.ts +13 -0
- package/dist/ui/containers/canvas.d.ts.map +1 -0
- package/dist/ui/containers/canvas.js +16 -0
- package/dist/ui/containers/canvas.js.map +1 -0
- package/dist/ui/containers/geometry-reader.d.ts +17 -0
- package/dist/ui/containers/geometry-reader.d.ts.map +1 -0
- package/dist/ui/containers/geometry-reader.js +24 -0
- package/dist/ui/containers/geometry-reader.js.map +1 -0
- package/dist/ui/containers/hstack.d.ts +12 -0
- package/dist/ui/containers/hstack.d.ts.map +1 -0
- package/dist/ui/containers/hstack.js +28 -0
- package/dist/ui/containers/hstack.js.map +1 -0
- package/dist/ui/containers/scroll.d.ts +28 -0
- package/dist/ui/containers/scroll.d.ts.map +1 -0
- package/dist/ui/containers/scroll.js +97 -0
- package/dist/ui/containers/scroll.js.map +1 -0
- package/dist/ui/containers/shared.d.ts +12 -0
- package/dist/ui/containers/shared.d.ts.map +1 -0
- package/dist/ui/containers/shared.js +19 -0
- package/dist/ui/containers/shared.js.map +1 -0
- package/dist/ui/containers/vstack.d.ts +12 -0
- package/dist/ui/containers/vstack.d.ts.map +1 -0
- package/dist/ui/containers/vstack.js +28 -0
- package/dist/ui/containers/vstack.js.map +1 -0
- package/dist/ui/containers/zstack.d.ts +14 -0
- package/dist/ui/containers/zstack.d.ts.map +1 -0
- package/dist/ui/containers/zstack.js +36 -0
- package/dist/ui/containers/zstack.js.map +1 -0
- package/dist/ui/core/geometry-store.d.ts +22 -0
- package/dist/ui/core/geometry-store.d.ts.map +1 -0
- package/dist/ui/core/geometry-store.js +29 -0
- package/dist/ui/core/geometry-store.js.map +1 -0
- package/dist/ui/core/geometry.d.ts +34 -0
- package/dist/ui/core/geometry.d.ts.map +1 -0
- package/dist/ui/core/geometry.js +14 -0
- package/dist/ui/core/geometry.js.map +1 -0
- package/dist/ui/core/view.d.ts +25 -0
- package/dist/ui/core/view.d.ts.map +1 -0
- package/dist/ui/core/view.js +34 -0
- package/dist/ui/core/view.js.map +1 -0
- package/dist/ui/index.d.ts +44 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +39 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/inlinetext.d.ts +24 -0
- package/dist/ui/inlinetext.d.ts.map +1 -0
- package/dist/ui/inlinetext.js +131 -0
- package/dist/ui/inlinetext.js.map +1 -0
- package/dist/ui/install.d.ts +22 -0
- package/dist/ui/install.d.ts.map +1 -0
- package/dist/ui/install.js +66 -0
- package/dist/ui/install.js.map +1 -0
- package/dist/ui/markdown.d.ts +40 -0
- package/dist/ui/markdown.d.ts.map +1 -0
- package/dist/ui/markdown.js +351 -0
- package/dist/ui/markdown.js.map +1 -0
- package/dist/ui/modifiers/border.d.ts +33 -0
- package/dist/ui/modifiers/border.d.ts.map +1 -0
- package/dist/ui/modifiers/border.js +82 -0
- package/dist/ui/modifiers/border.js.map +1 -0
- package/dist/ui/modifiers/fill.d.ts +14 -0
- package/dist/ui/modifiers/fill.d.ts.map +1 -0
- package/dist/ui/modifiers/fill.js +25 -0
- package/dist/ui/modifiers/fill.js.map +1 -0
- package/dist/ui/modifiers/frame.d.ts +23 -0
- package/dist/ui/modifiers/frame.d.ts.map +1 -0
- package/dist/ui/modifiers/frame.js +54 -0
- package/dist/ui/modifiers/frame.js.map +1 -0
- package/dist/ui/modifiers/offset.d.ts +15 -0
- package/dist/ui/modifiers/offset.d.ts.map +1 -0
- package/dist/ui/modifiers/offset.js +21 -0
- package/dist/ui/modifiers/offset.js.map +1 -0
- package/dist/ui/modifiers/opacity.d.ts +15 -0
- package/dist/ui/modifiers/opacity.d.ts.map +1 -0
- package/dist/ui/modifiers/opacity.js +95 -0
- package/dist/ui/modifiers/opacity.js.map +1 -0
- package/dist/ui/modifiers/padding.d.ts +20 -0
- package/dist/ui/modifiers/padding.d.ts.map +1 -0
- package/dist/ui/modifiers/padding.js +36 -0
- package/dist/ui/modifiers/padding.js.map +1 -0
- package/dist/ui/modifiers/styled.d.ts +14 -0
- package/dist/ui/modifiers/styled.d.ts.map +1 -0
- package/dist/ui/modifiers/styled.js +26 -0
- package/dist/ui/modifiers/styled.js.map +1 -0
- package/dist/ui/primitives/rectangle.d.ts +15 -0
- package/dist/ui/primitives/rectangle.d.ts.map +1 -0
- package/dist/ui/primitives/rectangle.js +23 -0
- package/dist/ui/primitives/rectangle.js.map +1 -0
- package/dist/ui/primitives/spacer.d.ts +13 -0
- package/dist/ui/primitives/spacer.d.ts.map +1 -0
- package/dist/ui/primitives/spacer.js +16 -0
- package/dist/ui/primitives/spacer.js.map +1 -0
- package/dist/ui/primitives/text.d.ts +15 -0
- package/dist/ui/primitives/text.d.ts.map +1 -0
- package/dist/ui/primitives/text.js +79 -0
- package/dist/ui/primitives/text.js.map +1 -0
- package/dist/ui/primitives/wrapped-text.d.ts +30 -0
- package/dist/ui/primitives/wrapped-text.d.ts.map +1 -0
- package/dist/ui/primitives/wrapped-text.js +117 -0
- package/dist/ui/primitives/wrapped-text.js.map +1 -0
- package/dist/ui/shinytext.d.ts +66 -0
- package/dist/ui/shinytext.d.ts.map +1 -0
- package/dist/ui/shinytext.js +99 -0
- package/dist/ui/shinytext.js.map +1 -0
- package/dist/ui/text/layout.d.ts +35 -0
- package/dist/ui/text/layout.d.ts.map +1 -0
- package/dist/ui/text/layout.js +102 -0
- package/dist/ui/text/layout.js.map +1 -0
- package/dist/ui/textinput.d.ts +140 -0
- package/dist/ui/textinput.d.ts.map +1 -0
- package/dist/ui/textinput.js +402 -0
- package/dist/ui/textinput.js.map +1 -0
- package/dist/ui/view-constructors.d.ts +72 -0
- package/dist/ui/view-constructors.d.ts.map +1 -0
- package/dist/ui/view-constructors.js +74 -0
- package/dist/ui/view-constructors.js.map +1 -0
- package/package.json +57 -0
- package/src/anim.ts +5 -0
- package/src/ansi.ts +83 -0
- package/src/index.ts +21 -0
- package/src/keys.ts +302 -0
- package/src/layout/linearStack.ts +115 -0
- package/src/motion-value.ts +335 -0
- package/src/present/display.ts +206 -0
- package/src/present/writers/fullscreen.ts +58 -0
- package/src/present/writers/inline.ts +101 -0
- package/src/render/buffer.ts +200 -0
- package/src/render/color-utils.ts +60 -0
- package/src/render/diff.ts +95 -0
- package/src/render/measure.ts +74 -0
- package/src/render/palette.ts +113 -0
- package/src/render/surface.ts +238 -0
- package/src/runtime/backend_node.ts +80 -0
- package/src/spring-physics.ts +151 -0
- package/src/spring.ts +234 -0
- package/src/ui/__snapshots__/wrappedtext.test.ts.snap +57 -0
- package/src/ui/containers/canvas.ts +18 -0
- package/src/ui/containers/geometry-reader.ts +32 -0
- package/src/ui/containers/hstack.ts +33 -0
- package/src/ui/containers/scroll.ts +106 -0
- package/src/ui/containers/shared.ts +27 -0
- package/src/ui/containers/vstack.ts +34 -0
- package/src/ui/containers/zstack.ts +37 -0
- package/src/ui/core/geometry-store.ts +42 -0
- package/src/ui/core/geometry.ts +30 -0
- package/src/ui/core/view.ts +49 -0
- package/src/ui/index.ts +84 -0
- package/src/ui/inlinetext.ts +135 -0
- package/src/ui/install.ts +110 -0
- package/src/ui/markdown.test.ts +74 -0
- package/src/ui/markdown.ts +388 -0
- package/src/ui/modifiers/border.ts +100 -0
- package/src/ui/modifiers/fill.ts +28 -0
- package/src/ui/modifiers/frame.ts +74 -0
- package/src/ui/modifiers/offset.ts +23 -0
- package/src/ui/modifiers/opacity.ts +93 -0
- package/src/ui/modifiers/padding.ts +53 -0
- package/src/ui/modifiers/styled.ts +31 -0
- package/src/ui/primitives/rectangle.ts +25 -0
- package/src/ui/primitives/spacer.ts +18 -0
- package/src/ui/primitives/text.ts +85 -0
- package/src/ui/primitives/wrapped-text.ts +131 -0
- package/src/ui/shinytext.ts +159 -0
- package/src/ui/text/layout.ts +119 -0
- package/src/ui/textinput.ts +496 -0
- package/src/ui/view-constructors.ts +96 -0
- package/src/ui/wrappedtext.test.ts +138 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { View } from "../core/view.js";
|
|
2
|
+
// Spacer (flexible in stacks)
|
|
3
|
+
export class Spacer extends View {
|
|
4
|
+
minLength;
|
|
5
|
+
constructor(minLength = 0) {
|
|
6
|
+
super();
|
|
7
|
+
this.minLength = minLength;
|
|
8
|
+
}
|
|
9
|
+
measureContent(_maxW, _maxH) {
|
|
10
|
+
return { w: 0, h: 0 };
|
|
11
|
+
}
|
|
12
|
+
renderContent(_s, _pal, _rect) {
|
|
13
|
+
// Spacers render nothing
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=spacer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spacer.js","sourceRoot":"","sources":["../../../src/ui/primitives/spacer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAGtC,8BAA8B;AAC9B,MAAM,OAAO,MAAO,SAAQ,IAAI;IACT;IAArB,YAAqB,YAAY,CAAC;QAChC,KAAK,EAAE,CAAA;QADY,cAAS,GAAT,SAAS,CAAI;IAElC,CAAC;IAES,cAAc,CAAC,KAAa,EAAE,KAAa;QACnD,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAA;IACvB,CAAC;IAES,aAAa,CAAC,EAAW,EAAE,IAAa,EAAE,KAAW;QAC7D,yBAAyB;IAC3B,CAAC;CACF"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Palette, Surface } from "../../render/surface.js";
|
|
2
|
+
import { View } from "../core/view.js";
|
|
3
|
+
import type { Rect } from "../core/geometry.js";
|
|
4
|
+
export declare class Text extends View {
|
|
5
|
+
readonly text: string;
|
|
6
|
+
readonly wrap?: boolean | undefined;
|
|
7
|
+
constructor(text: string, wrap?: boolean | undefined);
|
|
8
|
+
protected measureContent(maxW: number, maxH: number): {
|
|
9
|
+
w: number;
|
|
10
|
+
h: number;
|
|
11
|
+
};
|
|
12
|
+
protected renderContent(s: Surface, pal: Palette, rect: Rect): void;
|
|
13
|
+
private wrapText;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=text.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/ui/primitives/text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AAE/D,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AACtC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAE/C,qBAAa,IAAK,SAAQ,IAAI;IAE1B,QAAQ,CAAC,IAAI,EAAE,MAAM;IACrB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO;gBADd,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,OAAO,YAAA;IAKzB,SAAS,CAAC,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;;;;IAgBnD,SAAS,CAAC,aAAa,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI;IAgB5D,OAAO,CAAC,QAAQ;CAuCjB"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { displayWidth } from "../../render/measure.js";
|
|
2
|
+
import { View } from "../core/view.js";
|
|
3
|
+
export class Text extends View {
|
|
4
|
+
text;
|
|
5
|
+
wrap;
|
|
6
|
+
constructor(text, wrap) {
|
|
7
|
+
super();
|
|
8
|
+
this.text = text;
|
|
9
|
+
this.wrap = wrap;
|
|
10
|
+
}
|
|
11
|
+
measureContent(maxW, maxH) {
|
|
12
|
+
if (!this.wrap) {
|
|
13
|
+
const w = Math.min(maxW, displayWidth(this.text));
|
|
14
|
+
return { w, h: 1 };
|
|
15
|
+
}
|
|
16
|
+
// Wrapped text measurement
|
|
17
|
+
const lines = this.wrapText(maxW);
|
|
18
|
+
const height = Math.min(maxH, lines.length);
|
|
19
|
+
let width = 0;
|
|
20
|
+
for (let i = 0; i < height; i++) {
|
|
21
|
+
width = Math.max(width, Math.min(maxW, displayWidth(lines[i])));
|
|
22
|
+
}
|
|
23
|
+
return { w: width, h: height };
|
|
24
|
+
}
|
|
25
|
+
renderContent(s, pal, rect) {
|
|
26
|
+
const id = pal.id();
|
|
27
|
+
if (this.wrap) {
|
|
28
|
+
// Use wrapping logic for rendering
|
|
29
|
+
const lines = this.wrapText(rect.w);
|
|
30
|
+
for (let i = 0; i < Math.min(lines.length, rect.h); i++) {
|
|
31
|
+
const line = lines[i];
|
|
32
|
+
if (line.length > 0) {
|
|
33
|
+
s.drawText(rect.x, rect.y + i, line, id, rect.w);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
s.drawText(rect.x, rect.y, this.text, id, rect.w);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
wrapText(maxWidth) {
|
|
42
|
+
if (maxWidth <= 0)
|
|
43
|
+
return [""];
|
|
44
|
+
if (!this.text)
|
|
45
|
+
return [""];
|
|
46
|
+
const lines = this.text.split("\n");
|
|
47
|
+
const result = [];
|
|
48
|
+
for (const line of lines) {
|
|
49
|
+
if (line.length === 0) {
|
|
50
|
+
result.push("");
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const words = line.split(" ");
|
|
54
|
+
let currentLine = "";
|
|
55
|
+
for (const word of words) {
|
|
56
|
+
const testLine = currentLine + (currentLine ? " " : "") + word;
|
|
57
|
+
if (displayWidth(testLine) <= maxWidth) {
|
|
58
|
+
currentLine = testLine;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
if (currentLine) {
|
|
62
|
+
result.push(currentLine);
|
|
63
|
+
currentLine = word;
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
// Single word longer than maxWidth
|
|
67
|
+
result.push(word.slice(0, maxWidth));
|
|
68
|
+
currentLine = word.slice(maxWidth);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (currentLine) {
|
|
73
|
+
result.push(currentLine);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return result.length > 0 ? result : [""];
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../../src/ui/primitives/text.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Palette, Surface } from "../../render/surface.js";
|
|
2
|
+
import type { Rect } from "../core/geometry.js";
|
|
3
|
+
import { View } from "../core/view.js";
|
|
4
|
+
export type WrappingOptions = {
|
|
5
|
+
wordWrap?: boolean;
|
|
6
|
+
breakWords?: boolean;
|
|
7
|
+
};
|
|
8
|
+
export declare class WrappedText extends View {
|
|
9
|
+
readonly text: string;
|
|
10
|
+
readonly options: WrappingOptions;
|
|
11
|
+
constructor(text: string, options?: WrappingOptions);
|
|
12
|
+
/**
|
|
13
|
+
* Split text into lines, respecting wrapping rules
|
|
14
|
+
*/
|
|
15
|
+
private wrapText;
|
|
16
|
+
/**
|
|
17
|
+
* Wrap a line by word boundaries
|
|
18
|
+
*/
|
|
19
|
+
private wrapLineByWords;
|
|
20
|
+
/**
|
|
21
|
+
* Wrap a line by character boundaries
|
|
22
|
+
*/
|
|
23
|
+
private wrapLineByCharacters;
|
|
24
|
+
protected measureContent(maxW: number, maxH: number): {
|
|
25
|
+
w: number;
|
|
26
|
+
h: number;
|
|
27
|
+
};
|
|
28
|
+
protected renderContent(s: Surface, pal: Palette, rect: Rect): void;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=wrapped-text.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrapped-text.d.ts","sourceRoot":"","sources":["../../../src/ui/primitives/wrapped-text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AAC/D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAGtC,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB,CAAA;AAED,qBAAa,WAAY,SAAQ,IAAI;IAEjC,QAAQ,CAAC,IAAI,EAAE,MAAM;IACrB,QAAQ,CAAC,OAAO,EAAE,eAAe;gBADxB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,eAAoB;IAKxC;;OAEG;IACH,OAAO,CAAC,QAAQ;IAgChB;;OAEG;IACH,OAAO,CAAC,eAAe;IA0CvB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAU5B,SAAS,CAAC,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE;IAQ9E,SAAS,CAAC,aAAa,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI;CAWpE"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { View } from "../core/view.js";
|
|
2
|
+
import { displayWidth, sliceByWidth } from "../../render/measure.js";
|
|
3
|
+
export class WrappedText extends View {
|
|
4
|
+
text;
|
|
5
|
+
options;
|
|
6
|
+
constructor(text, options = {}) {
|
|
7
|
+
super();
|
|
8
|
+
this.text = text;
|
|
9
|
+
this.options = options;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Split text into lines, respecting wrapping rules
|
|
13
|
+
*/
|
|
14
|
+
wrapText(maxWidth) {
|
|
15
|
+
if (maxWidth <= 0)
|
|
16
|
+
return [""];
|
|
17
|
+
if (!this.text)
|
|
18
|
+
return [];
|
|
19
|
+
const { wordWrap = true, breakWords = false } = this.options;
|
|
20
|
+
// First split on explicit line breaks
|
|
21
|
+
const inputLines = this.text.split("\n");
|
|
22
|
+
const wrappedLines = [];
|
|
23
|
+
for (const line of inputLines) {
|
|
24
|
+
if (line.length === 0) {
|
|
25
|
+
wrappedLines.push("");
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if (line.length <= maxWidth) {
|
|
29
|
+
wrappedLines.push(line);
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
// Line needs wrapping
|
|
33
|
+
if (wordWrap) {
|
|
34
|
+
this.wrapLineByWords(line, maxWidth, breakWords, wrappedLines);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
this.wrapLineByCharacters(line, maxWidth, wrappedLines);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return wrappedLines;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Wrap a line by word boundaries
|
|
44
|
+
*/
|
|
45
|
+
wrapLineByWords(line, maxWidth, breakWords, output) {
|
|
46
|
+
const words = line.split(/(\s+)/); // Keep whitespace in results
|
|
47
|
+
let currentLine = "";
|
|
48
|
+
for (const word of words) {
|
|
49
|
+
// Skip empty strings
|
|
50
|
+
if (word.length === 0)
|
|
51
|
+
continue;
|
|
52
|
+
// If this is whitespace and we're at the start of a line, skip it
|
|
53
|
+
if (/^\s+$/.test(word) && currentLine.length === 0)
|
|
54
|
+
continue;
|
|
55
|
+
// If adding this word would exceed width
|
|
56
|
+
if (displayWidth(currentLine + word) > maxWidth) {
|
|
57
|
+
// If we have content on current line, save it and start new line
|
|
58
|
+
if (currentLine.length > 0) {
|
|
59
|
+
output.push(currentLine.trimEnd());
|
|
60
|
+
currentLine = "";
|
|
61
|
+
}
|
|
62
|
+
// Handle long words
|
|
63
|
+
if (displayWidth(word.trim()) > maxWidth) {
|
|
64
|
+
if (breakWords) {
|
|
65
|
+
this.wrapLineByCharacters(word.trim(), maxWidth, output);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
// Don't break the word, just put it on its own line (may overflow)
|
|
69
|
+
output.push(word.trim());
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else if (word.trim().length > 0) {
|
|
73
|
+
// Start new line with this word (skip leading whitespace)
|
|
74
|
+
currentLine = word.trim();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
currentLine += word;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Add remaining content
|
|
82
|
+
if (currentLine.length > 0) {
|
|
83
|
+
output.push(currentLine.trimEnd());
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Wrap a line by character boundaries
|
|
88
|
+
*/
|
|
89
|
+
wrapLineByCharacters(line, maxWidth, output) {
|
|
90
|
+
let rest = line;
|
|
91
|
+
while (rest.length > 0) {
|
|
92
|
+
const { text } = sliceByWidth(rest, maxWidth);
|
|
93
|
+
if (text.length === 0)
|
|
94
|
+
break;
|
|
95
|
+
output.push(text);
|
|
96
|
+
rest = rest.slice(text.length);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
measureContent(maxW, maxH) {
|
|
100
|
+
const lines = this.wrapText(maxW);
|
|
101
|
+
const h = Math.min(maxH, Math.max(1, lines.length));
|
|
102
|
+
// WrappedText is greedy horizontally - takes full available width when content exists
|
|
103
|
+
const w = maxW;
|
|
104
|
+
return { w, h };
|
|
105
|
+
}
|
|
106
|
+
renderContent(s, pal, rect) {
|
|
107
|
+
const lines = this.wrapText(rect.w);
|
|
108
|
+
const styleId = pal.id();
|
|
109
|
+
for (let i = 0; i < Math.min(lines.length, rect.h); i++) {
|
|
110
|
+
const line = lines[i];
|
|
111
|
+
if (line.length > 0) {
|
|
112
|
+
s.drawText(rect.x, rect.y + i, line, styleId, rect.w);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=wrapped-text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrapped-text.js","sourceRoot":"","sources":["../../../src/ui/primitives/wrapped-text.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { Palette, Surface } from "../render/surface.js";
|
|
2
|
+
import type { Rect } from "./core/geometry.js";
|
|
3
|
+
import { type Stepper } from "../anim.js";
|
|
4
|
+
import { View } from "./core/view.js";
|
|
5
|
+
export type ShineTextOptions = {
|
|
6
|
+
/**
|
|
7
|
+
* Center position of the shine in character coordinates (can be fractional).
|
|
8
|
+
* 0 = before first char, length-1 = last char. Values outside are fine for overscan.
|
|
9
|
+
*/
|
|
10
|
+
center?: number;
|
|
11
|
+
/**
|
|
12
|
+
* Alternative to center: normalized progress 0..1 across the text.
|
|
13
|
+
* If provided, takes precedence and maps to center internally.
|
|
14
|
+
*/
|
|
15
|
+
progress?: number;
|
|
16
|
+
/** Gaussian falloff spread; larger = wider shine. Default 2.25 */
|
|
17
|
+
spread?: number;
|
|
18
|
+
/** Base gray level (0..23). Default 12 */
|
|
19
|
+
baseGray?: number;
|
|
20
|
+
/** Max additional gray levels added at peak (0..23). Default 8 */
|
|
21
|
+
boost?: number;
|
|
22
|
+
/** Bold threshold on intensity (0..1). Default 0.75 */
|
|
23
|
+
boldThreshold?: number;
|
|
24
|
+
};
|
|
25
|
+
export declare class ShinyText extends View {
|
|
26
|
+
readonly text: string;
|
|
27
|
+
readonly opts?: ShineTextOptions | undefined;
|
|
28
|
+
constructor(text: string, opts?: ShineTextOptions | undefined);
|
|
29
|
+
private getChars;
|
|
30
|
+
protected measureContent(maxW: number, _maxH: number): {
|
|
31
|
+
w: number;
|
|
32
|
+
h: number;
|
|
33
|
+
};
|
|
34
|
+
protected renderContent(s: Surface, pal: Palette, rect: Rect): void;
|
|
35
|
+
}
|
|
36
|
+
export type ViewShinyTextExt = {
|
|
37
|
+
shineText(text: string, opts?: ShineTextOptions): View;
|
|
38
|
+
};
|
|
39
|
+
export declare const viewShinyText: ViewShinyTextExt;
|
|
40
|
+
export type ShinyTextModel = {
|
|
41
|
+
text: string;
|
|
42
|
+
step: Stepper;
|
|
43
|
+
speedMs: number;
|
|
44
|
+
overscan: number;
|
|
45
|
+
shine?: Omit<ShineTextOptions, "center" | "progress">;
|
|
46
|
+
};
|
|
47
|
+
export type InitShinyOptions = {
|
|
48
|
+
speedMs?: number;
|
|
49
|
+
overscan?: number;
|
|
50
|
+
shine?: Omit<ShineTextOptions, "center" | "progress">;
|
|
51
|
+
};
|
|
52
|
+
export declare function initShinyText(text: string, opts?: InitShinyOptions): ShinyTextModel;
|
|
53
|
+
export declare function tickShinyText(state: ShinyTextModel, nowMs: number): ShinyTextModel;
|
|
54
|
+
export declare function setShinySpeed(state: ShinyTextModel, speedMs: number): ShinyTextModel;
|
|
55
|
+
/** Create a ShinyText node from state. Use with chainers like .frame/.padding. */
|
|
56
|
+
export declare function shinyText(state: ShinyTextModel): View;
|
|
57
|
+
export declare namespace ShinyText {
|
|
58
|
+
type Model = ShinyTextModel;
|
|
59
|
+
type Options = ShineTextOptions;
|
|
60
|
+
type MakeOptions = InitShinyOptions;
|
|
61
|
+
const make: typeof initShinyText;
|
|
62
|
+
const tick: typeof tickShinyText;
|
|
63
|
+
const setSpeed: typeof setShinySpeed;
|
|
64
|
+
const view: typeof shinyText;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=shinytext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shinytext.d.ts","sourceRoot":"","sources":["../../src/ui/shinytext.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAA;AAE5D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAQ,KAAK,OAAO,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAA;AAErC,MAAM,MAAM,gBAAgB,GAAG;IAC7B;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,uDAAuD;IACvD,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,CAAA;AAED,qBAAa,SAAU,SAAQ,IAAI;IAE/B,QAAQ,CAAC,IAAI,EAAE,MAAM;IACrB,QAAQ,CAAC,IAAI,CAAC,EAAE,gBAAgB;gBADvB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,gBAAgB,YAAA;IAKlC,OAAO,CAAC,QAAQ;IAIhB,SAAS,CAAC,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;;;;IAKpD,SAAS,CAAC,aAAa,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI;CA+C7D;AAGD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAA;CACvD,CAAA;AACD,eAAO,MAAM,aAAa,EAAE,gBAI3B,CAAA;AAMD,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,OAAO,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,QAAQ,GAAG,UAAU,CAAC,CAAA;CACtD,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,QAAQ,GAAG,UAAU,CAAC,CAAA;CACtD,CAAA;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,gBAAgB,GAAG,cAAc,CAMnF;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,cAAc,CAGlF;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,GAAG,cAAc,CAIpF;AAED,kFAAkF;AAClF,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAGrD;AAGD,yBAAiB,SAAS,CAAC;IACzB,KAAY,KAAK,GAAG,cAAc,CAAA;IAClC,KAAY,OAAO,GAAG,gBAAgB,CAAA;IACtC,KAAY,WAAW,GAAG,gBAAgB,CAAA;IAEnC,MAAM,IAAI,sBAAgB,CAAA;IAC1B,MAAM,IAAI,sBAAgB,CAAA;IAC1B,MAAM,QAAQ,sBAAgB,CAAA;IAC9B,MAAM,IAAI,kBAAY,CAAA;CAC9B"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/* shinytext.ts — reusable shining text component */
|
|
2
|
+
import { Colors } from "../render/surface.js";
|
|
3
|
+
import { Step } from "../anim.js";
|
|
4
|
+
import { View } from "./core/view.js";
|
|
5
|
+
export class ShinyText extends View {
|
|
6
|
+
text;
|
|
7
|
+
opts;
|
|
8
|
+
constructor(text, opts) {
|
|
9
|
+
super();
|
|
10
|
+
this.text = text;
|
|
11
|
+
this.opts = opts;
|
|
12
|
+
}
|
|
13
|
+
getChars() {
|
|
14
|
+
return [...this.text];
|
|
15
|
+
}
|
|
16
|
+
measureContent(maxW, _maxH) {
|
|
17
|
+
const w = Math.min(maxW, this.getChars().length);
|
|
18
|
+
return { w, h: 1 };
|
|
19
|
+
}
|
|
20
|
+
renderContent(s, pal, rect) {
|
|
21
|
+
const chars = this.getChars();
|
|
22
|
+
const n = Math.min(rect.w, chars.length);
|
|
23
|
+
if (rect.h <= 0 || n <= 0)
|
|
24
|
+
return;
|
|
25
|
+
const spread = this.opts?.spread ?? 2.25;
|
|
26
|
+
const base = Math.max(0, Math.min(23, (this.opts?.baseGray ?? 12) | 0));
|
|
27
|
+
const boost = Math.max(0, Math.min(23, (this.opts?.boost ?? 8) | 0));
|
|
28
|
+
const boldTh = this.opts?.boldThreshold ?? 0.75;
|
|
29
|
+
const progress = this.opts?.progress;
|
|
30
|
+
const center = progress != null ? progress * (chars.length - 1) : (this.opts?.center ?? 0);
|
|
31
|
+
const styleFor = (i) => {
|
|
32
|
+
const d = (i - center) / Math.max(1e-3, spread);
|
|
33
|
+
const intensity = Math.exp(-d * d);
|
|
34
|
+
const level = Math.max(0, Math.min(23, base + Math.round(intensity * boost)));
|
|
35
|
+
const bold = intensity > boldTh;
|
|
36
|
+
return pal.id({ fg: Colors.gray(level), bold });
|
|
37
|
+
};
|
|
38
|
+
// Emit minimal runs per style id
|
|
39
|
+
const y = rect.y;
|
|
40
|
+
let x = rect.x;
|
|
41
|
+
let runStyle = -1;
|
|
42
|
+
let runStart = x;
|
|
43
|
+
let runText = "";
|
|
44
|
+
const flush = () => {
|
|
45
|
+
if (runText.length > 0) {
|
|
46
|
+
const maxW = Math.max(0, rect.x + rect.w - runStart);
|
|
47
|
+
if (maxW > 0)
|
|
48
|
+
s.drawText(runStart, y, runText, runStyle, maxW);
|
|
49
|
+
runText = "";
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
for (let i = 0; i < n; i++) {
|
|
53
|
+
const ch = chars[i];
|
|
54
|
+
const id = styleFor(i);
|
|
55
|
+
if (id !== runStyle) {
|
|
56
|
+
flush();
|
|
57
|
+
runStyle = id;
|
|
58
|
+
runStart = x;
|
|
59
|
+
}
|
|
60
|
+
runText += ch;
|
|
61
|
+
x++;
|
|
62
|
+
}
|
|
63
|
+
flush();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export const viewShinyText = {
|
|
67
|
+
shineText(text, opts) {
|
|
68
|
+
return new ShinyText(text, opts);
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
export function initShinyText(text, opts) {
|
|
72
|
+
const speedMs = Math.max(1, (opts?.speedMs ?? 40) | 0);
|
|
73
|
+
const overscan = Math.max(0, (opts?.overscan ?? 6) | 0);
|
|
74
|
+
const width = [...text].length;
|
|
75
|
+
const step = Step.init(width + overscan * 2, speedMs, 0);
|
|
76
|
+
return { text, step, speedMs, overscan, shine: opts?.shine };
|
|
77
|
+
}
|
|
78
|
+
export function tickShinyText(state, nowMs) {
|
|
79
|
+
const step = Step.tick(state.step, nowMs);
|
|
80
|
+
return { ...state, step };
|
|
81
|
+
}
|
|
82
|
+
export function setShinySpeed(state, speedMs) {
|
|
83
|
+
const ms = Math.max(1, speedMs | 0);
|
|
84
|
+
const step = { ...state.step, intervalMs: ms };
|
|
85
|
+
return { ...state, speedMs: ms, step };
|
|
86
|
+
}
|
|
87
|
+
/** Create a ShinyText node from state. Use with chainers like .frame/.padding. */
|
|
88
|
+
export function shinyText(state) {
|
|
89
|
+
const center = state.step.index - state.overscan;
|
|
90
|
+
return new ShinyText(state.text, { ...state.shine, center });
|
|
91
|
+
}
|
|
92
|
+
// Merged namespace to expose a cohesive API: ShinyText.make(), ShinyText.tick(), ShinyText.setSpeed(), ShinyText.view()
|
|
93
|
+
(function (ShinyText) {
|
|
94
|
+
ShinyText.make = initShinyText;
|
|
95
|
+
ShinyText.tick = tickShinyText;
|
|
96
|
+
ShinyText.setSpeed = setShinySpeed;
|
|
97
|
+
ShinyText.view = shinyText;
|
|
98
|
+
})(ShinyText || (ShinyText = {}));
|
|
99
|
+
//# sourceMappingURL=shinytext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shinytext.js","sourceRoot":"","sources":["../../src/ui/shinytext.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export type WrappedLine = {
|
|
2
|
+
text: string;
|
|
3
|
+
graphemes: string[];
|
|
4
|
+
start: number;
|
|
5
|
+
width: number;
|
|
6
|
+
};
|
|
7
|
+
export type Wrapped = {
|
|
8
|
+
lines: Array<WrappedLine>;
|
|
9
|
+
};
|
|
10
|
+
export type WrapOptions = {
|
|
11
|
+
widthFirst: number;
|
|
12
|
+
widthOther: number;
|
|
13
|
+
wordWrap: boolean;
|
|
14
|
+
breakWords: boolean;
|
|
15
|
+
};
|
|
16
|
+
/** Compute wrapped lines with widths and grapheme start offsets (soft + hard breaks). */
|
|
17
|
+
export declare function wrapText(value: string, opts: WrapOptions): Wrapped;
|
|
18
|
+
/** Locate the visual line and column within that line for a grapheme cursor. */
|
|
19
|
+
export declare function findVisualPos(wrap: Wrapped, cursor: number): {
|
|
20
|
+
lineIdx: number;
|
|
21
|
+
colInLine: number;
|
|
22
|
+
};
|
|
23
|
+
/** Sum display widths of graphemes up to a column to get visual cell X. */
|
|
24
|
+
export declare function cellXWithinLine(wrap: Wrapped, lineIdx: number, colInLine: number): number;
|
|
25
|
+
/** Map a visual cell X back to a cursor index on a given line (nearest-left by centers). */
|
|
26
|
+
export declare function cursorFromCellX(wrap: Wrapped, lineIdx: number, x: number): number;
|
|
27
|
+
/** Map cursor index to absolute caret coordinates using provided anchors. */
|
|
28
|
+
export declare function caretXYFromCursor(wrap: Wrapped, cursor: number, anchors: {
|
|
29
|
+
xFirst: number;
|
|
30
|
+
xOther: number;
|
|
31
|
+
}): {
|
|
32
|
+
x: number;
|
|
33
|
+
y: number;
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../src/ui/text/layout.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,WAAW,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAC7F,MAAM,MAAM,OAAO,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC,WAAW,CAAC,CAAA;CAAE,CAAA;AAEnD,MAAM,MAAM,WAAW,GAAG;IACxB,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,OAAO,CAAA;IACjB,UAAU,EAAE,OAAO,CAAA;CACpB,CAAA;AAED,yFAAyF;AACzF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAkClE;AAED,gFAAgF;AAChF,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAoBnG;AAED,2EAA2E;AAC3E,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAMzF;AAED,4FAA4F;AAC5F,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAWjF;AAED,6EAA6E;AAC7E,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAM1B"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/* text/layout.ts — Shared text layout utilities for wrapping and caret mapping
|
|
2
|
+
*
|
|
3
|
+
* Single source of truth for:
|
|
4
|
+
* - Computing wrapped visual lines (first-line width vs subsequent)
|
|
5
|
+
* - Mapping between grapheme cursor index and visual caret coordinates
|
|
6
|
+
* - Mapping from visual cell X back to cursor index (for vertical nav)
|
|
7
|
+
*
|
|
8
|
+
* These helpers mirror renderer behavior by delegating to render/measure.ts
|
|
9
|
+
* (displayWidth, graphemes, sliceByWidth), ensuring edit-time and render-time
|
|
10
|
+
* wrapping boundaries are identical.
|
|
11
|
+
*/
|
|
12
|
+
import { displayWidth, graphemes, sliceByWidth } from "../../render/measure.js";
|
|
13
|
+
/** Compute wrapped lines with widths and grapheme start offsets (soft + hard breaks). */
|
|
14
|
+
export function wrapText(value, opts) {
|
|
15
|
+
const lines = [];
|
|
16
|
+
const widthFor = (isFirstVisual) => Math.max(0, isFirstVisual ? opts.widthFirst : opts.widthOther);
|
|
17
|
+
let gOffset = 0; // grapheme index from start of whole value
|
|
18
|
+
let isFirstVisual = true;
|
|
19
|
+
// Split logical lines by explicit newlines
|
|
20
|
+
const logicals = value.split("\n");
|
|
21
|
+
for (let li = 0; li < logicals.length; li++) {
|
|
22
|
+
const logical = logicals[li];
|
|
23
|
+
let rest = logical;
|
|
24
|
+
// Even for empty logical lines, emit one visual line (empty)
|
|
25
|
+
if (rest.length === 0) {
|
|
26
|
+
lines.push({ graphemes: [], start: gOffset, width: 0 });
|
|
27
|
+
if (li < logicals.length - 1)
|
|
28
|
+
gOffset += 1; // the "\n" grapheme
|
|
29
|
+
isFirstVisual = false;
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
while (rest.length > 0) {
|
|
33
|
+
const maxW = widthFor(isFirstVisual);
|
|
34
|
+
const { text } = sliceByWidth(rest, maxW);
|
|
35
|
+
const used = text.length > 0 ? text : rest.slice(0, 1); // ensure progress even when maxW == 0
|
|
36
|
+
const usedGs = graphemes(used);
|
|
37
|
+
const w = displayWidth(used);
|
|
38
|
+
lines.push({ graphemes: usedGs, start: gOffset, width: w });
|
|
39
|
+
gOffset += usedGs.length;
|
|
40
|
+
rest = rest.slice(used.length);
|
|
41
|
+
isFirstVisual = false;
|
|
42
|
+
if (used.length === 0)
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
if (li < logicals.length - 1)
|
|
46
|
+
gOffset += 1; // account for newline between logical segments
|
|
47
|
+
}
|
|
48
|
+
return { lines: lines.map((l) => ({ ...l, text: l.graphemes.join("") })) };
|
|
49
|
+
}
|
|
50
|
+
/** Locate the visual line and column within that line for a grapheme cursor. */
|
|
51
|
+
export function findVisualPos(wrap, cursor) {
|
|
52
|
+
for (let i = 0; i < wrap.lines.length; i++) {
|
|
53
|
+
const ln = wrap.lines[i];
|
|
54
|
+
const start = ln.start;
|
|
55
|
+
// Use next line's start as upper bound (accounts for newline gaps)
|
|
56
|
+
const nextStart = i + 1 < wrap.lines.length ? wrap.lines[i + 1].start : Infinity;
|
|
57
|
+
// Cursor in range [start, nextStart) belongs to this line
|
|
58
|
+
if (cursor >= start && cursor < nextStart) {
|
|
59
|
+
// For empty lines, cursor must be exactly at start
|
|
60
|
+
if (ln.graphemes.length === 0) {
|
|
61
|
+
return { lineIdx: i, colInLine: 0 };
|
|
62
|
+
}
|
|
63
|
+
const col = Math.min(cursor - start, ln.graphemes.length);
|
|
64
|
+
return { lineIdx: i, colInLine: col };
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Fallback: end of last line
|
|
68
|
+
const last = wrap.lines[wrap.lines.length - 1];
|
|
69
|
+
return { lineIdx: wrap.lines.length - 1, colInLine: last.graphemes.length };
|
|
70
|
+
}
|
|
71
|
+
/** Sum display widths of graphemes up to a column to get visual cell X. */
|
|
72
|
+
export function cellXWithinLine(wrap, lineIdx, colInLine) {
|
|
73
|
+
const ln = wrap.lines[lineIdx];
|
|
74
|
+
const gs = ln.graphemes;
|
|
75
|
+
let x = 0;
|
|
76
|
+
for (let i = 0; i < Math.min(colInLine, gs.length); i++)
|
|
77
|
+
x += displayWidth(gs[i]);
|
|
78
|
+
return x;
|
|
79
|
+
}
|
|
80
|
+
/** Map a visual cell X back to a cursor index on a given line (nearest-left by centers). */
|
|
81
|
+
export function cursorFromCellX(wrap, lineIdx, x) {
|
|
82
|
+
const ln = wrap.lines[lineIdx];
|
|
83
|
+
const gs = ln.graphemes;
|
|
84
|
+
let acc = 0;
|
|
85
|
+
for (let i = 0; i < gs.length; i++) {
|
|
86
|
+
const w = displayWidth(gs[i]);
|
|
87
|
+
const center = acc + w / 2;
|
|
88
|
+
if (x < center)
|
|
89
|
+
return ln.start + i;
|
|
90
|
+
acc += w;
|
|
91
|
+
}
|
|
92
|
+
return ln.start + gs.length;
|
|
93
|
+
}
|
|
94
|
+
/** Map cursor index to absolute caret coordinates using provided anchors. */
|
|
95
|
+
export function caretXYFromCursor(wrap, cursor, anchors) {
|
|
96
|
+
const { lineIdx, colInLine } = findVisualPos(wrap, cursor);
|
|
97
|
+
const baseX = lineIdx === 0 ? anchors.xFirst : anchors.xOther;
|
|
98
|
+
const x = baseX + cellXWithinLine(wrap, lineIdx, colInLine);
|
|
99
|
+
const y = lineIdx;
|
|
100
|
+
return { x, y };
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=layout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.js","sourceRoot":"","sources":["../../../src/ui/text/layout.ts"],"names":[],"mappings":"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"}
|