@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.
Files changed (241) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +93 -0
  3. package/dist/anim.d.ts +4 -0
  4. package/dist/anim.d.ts.map +1 -0
  5. package/dist/anim.js +5 -0
  6. package/dist/anim.js.map +1 -0
  7. package/dist/ansi.d.ts +69 -0
  8. package/dist/ansi.d.ts.map +1 -0
  9. package/dist/ansi.js +72 -0
  10. package/dist/ansi.js.map +1 -0
  11. package/dist/index.d.ts +16 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +16 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/keys.d.ts +18 -0
  16. package/dist/keys.d.ts.map +1 -0
  17. package/dist/keys.js +247 -0
  18. package/dist/keys.js.map +1 -0
  19. package/dist/layout/linearStack.d.ts +17 -0
  20. package/dist/layout/linearStack.d.ts.map +1 -0
  21. package/dist/layout/linearStack.js +86 -0
  22. package/dist/layout/linearStack.js.map +1 -0
  23. package/dist/motion-value.d.ts +58 -0
  24. package/dist/motion-value.d.ts.map +1 -0
  25. package/dist/motion-value.js +250 -0
  26. package/dist/motion-value.js.map +1 -0
  27. package/dist/present/display.d.ts +58 -0
  28. package/dist/present/display.d.ts.map +1 -0
  29. package/dist/present/display.js +168 -0
  30. package/dist/present/display.js.map +1 -0
  31. package/dist/present/writers/fullscreen.d.ts +19 -0
  32. package/dist/present/writers/fullscreen.d.ts.map +1 -0
  33. package/dist/present/writers/fullscreen.js +55 -0
  34. package/dist/present/writers/fullscreen.js.map +1 -0
  35. package/dist/present/writers/inline.d.ts +20 -0
  36. package/dist/present/writers/inline.d.ts.map +1 -0
  37. package/dist/present/writers/inline.js +92 -0
  38. package/dist/present/writers/inline.js.map +1 -0
  39. package/dist/render/buffer.d.ts +31 -0
  40. package/dist/render/buffer.d.ts.map +1 -0
  41. package/dist/render/buffer.js +183 -0
  42. package/dist/render/buffer.js.map +1 -0
  43. package/dist/render/color-utils.d.ts +18 -0
  44. package/dist/render/color-utils.d.ts.map +1 -0
  45. package/dist/render/color-utils.js +58 -0
  46. package/dist/render/color-utils.js.map +1 -0
  47. package/dist/render/diff.d.ts +30 -0
  48. package/dist/render/diff.d.ts.map +1 -0
  49. package/dist/render/diff.js +83 -0
  50. package/dist/render/diff.js.map +1 -0
  51. package/dist/render/measure.d.ts +15 -0
  52. package/dist/render/measure.d.ts.map +1 -0
  53. package/dist/render/measure.js +65 -0
  54. package/dist/render/measure.js.map +1 -0
  55. package/dist/render/palette.d.ts +46 -0
  56. package/dist/render/palette.d.ts.map +1 -0
  57. package/dist/render/palette.js +108 -0
  58. package/dist/render/palette.js.map +1 -0
  59. package/dist/render/surface.d.ts +77 -0
  60. package/dist/render/surface.d.ts.map +1 -0
  61. package/dist/render/surface.js +198 -0
  62. package/dist/render/surface.js.map +1 -0
  63. package/dist/runtime/backend_node.d.ts +36 -0
  64. package/dist/runtime/backend_node.d.ts.map +1 -0
  65. package/dist/runtime/backend_node.js +66 -0
  66. package/dist/runtime/backend_node.js.map +1 -0
  67. package/dist/spring-physics.d.ts +36 -0
  68. package/dist/spring-physics.d.ts.map +1 -0
  69. package/dist/spring-physics.js +113 -0
  70. package/dist/spring-physics.js.map +1 -0
  71. package/dist/spring.d.ts +73 -0
  72. package/dist/spring.d.ts.map +1 -0
  73. package/dist/spring.js +136 -0
  74. package/dist/spring.js.map +1 -0
  75. package/dist/ui/containers/canvas.d.ts +13 -0
  76. package/dist/ui/containers/canvas.d.ts.map +1 -0
  77. package/dist/ui/containers/canvas.js +16 -0
  78. package/dist/ui/containers/canvas.js.map +1 -0
  79. package/dist/ui/containers/geometry-reader.d.ts +17 -0
  80. package/dist/ui/containers/geometry-reader.d.ts.map +1 -0
  81. package/dist/ui/containers/geometry-reader.js +24 -0
  82. package/dist/ui/containers/geometry-reader.js.map +1 -0
  83. package/dist/ui/containers/hstack.d.ts +12 -0
  84. package/dist/ui/containers/hstack.d.ts.map +1 -0
  85. package/dist/ui/containers/hstack.js +28 -0
  86. package/dist/ui/containers/hstack.js.map +1 -0
  87. package/dist/ui/containers/scroll.d.ts +28 -0
  88. package/dist/ui/containers/scroll.d.ts.map +1 -0
  89. package/dist/ui/containers/scroll.js +97 -0
  90. package/dist/ui/containers/scroll.js.map +1 -0
  91. package/dist/ui/containers/shared.d.ts +12 -0
  92. package/dist/ui/containers/shared.d.ts.map +1 -0
  93. package/dist/ui/containers/shared.js +19 -0
  94. package/dist/ui/containers/shared.js.map +1 -0
  95. package/dist/ui/containers/vstack.d.ts +12 -0
  96. package/dist/ui/containers/vstack.d.ts.map +1 -0
  97. package/dist/ui/containers/vstack.js +28 -0
  98. package/dist/ui/containers/vstack.js.map +1 -0
  99. package/dist/ui/containers/zstack.d.ts +14 -0
  100. package/dist/ui/containers/zstack.d.ts.map +1 -0
  101. package/dist/ui/containers/zstack.js +36 -0
  102. package/dist/ui/containers/zstack.js.map +1 -0
  103. package/dist/ui/core/geometry-store.d.ts +22 -0
  104. package/dist/ui/core/geometry-store.d.ts.map +1 -0
  105. package/dist/ui/core/geometry-store.js +29 -0
  106. package/dist/ui/core/geometry-store.js.map +1 -0
  107. package/dist/ui/core/geometry.d.ts +34 -0
  108. package/dist/ui/core/geometry.d.ts.map +1 -0
  109. package/dist/ui/core/geometry.js +14 -0
  110. package/dist/ui/core/geometry.js.map +1 -0
  111. package/dist/ui/core/view.d.ts +25 -0
  112. package/dist/ui/core/view.d.ts.map +1 -0
  113. package/dist/ui/core/view.js +34 -0
  114. package/dist/ui/core/view.js.map +1 -0
  115. package/dist/ui/index.d.ts +44 -0
  116. package/dist/ui/index.d.ts.map +1 -0
  117. package/dist/ui/index.js +39 -0
  118. package/dist/ui/index.js.map +1 -0
  119. package/dist/ui/inlinetext.d.ts +24 -0
  120. package/dist/ui/inlinetext.d.ts.map +1 -0
  121. package/dist/ui/inlinetext.js +131 -0
  122. package/dist/ui/inlinetext.js.map +1 -0
  123. package/dist/ui/install.d.ts +22 -0
  124. package/dist/ui/install.d.ts.map +1 -0
  125. package/dist/ui/install.js +66 -0
  126. package/dist/ui/install.js.map +1 -0
  127. package/dist/ui/markdown.d.ts +40 -0
  128. package/dist/ui/markdown.d.ts.map +1 -0
  129. package/dist/ui/markdown.js +351 -0
  130. package/dist/ui/markdown.js.map +1 -0
  131. package/dist/ui/modifiers/border.d.ts +33 -0
  132. package/dist/ui/modifiers/border.d.ts.map +1 -0
  133. package/dist/ui/modifiers/border.js +82 -0
  134. package/dist/ui/modifiers/border.js.map +1 -0
  135. package/dist/ui/modifiers/fill.d.ts +14 -0
  136. package/dist/ui/modifiers/fill.d.ts.map +1 -0
  137. package/dist/ui/modifiers/fill.js +25 -0
  138. package/dist/ui/modifiers/fill.js.map +1 -0
  139. package/dist/ui/modifiers/frame.d.ts +23 -0
  140. package/dist/ui/modifiers/frame.d.ts.map +1 -0
  141. package/dist/ui/modifiers/frame.js +54 -0
  142. package/dist/ui/modifiers/frame.js.map +1 -0
  143. package/dist/ui/modifiers/offset.d.ts +15 -0
  144. package/dist/ui/modifiers/offset.d.ts.map +1 -0
  145. package/dist/ui/modifiers/offset.js +21 -0
  146. package/dist/ui/modifiers/offset.js.map +1 -0
  147. package/dist/ui/modifiers/opacity.d.ts +15 -0
  148. package/dist/ui/modifiers/opacity.d.ts.map +1 -0
  149. package/dist/ui/modifiers/opacity.js +95 -0
  150. package/dist/ui/modifiers/opacity.js.map +1 -0
  151. package/dist/ui/modifiers/padding.d.ts +20 -0
  152. package/dist/ui/modifiers/padding.d.ts.map +1 -0
  153. package/dist/ui/modifiers/padding.js +36 -0
  154. package/dist/ui/modifiers/padding.js.map +1 -0
  155. package/dist/ui/modifiers/styled.d.ts +14 -0
  156. package/dist/ui/modifiers/styled.d.ts.map +1 -0
  157. package/dist/ui/modifiers/styled.js +26 -0
  158. package/dist/ui/modifiers/styled.js.map +1 -0
  159. package/dist/ui/primitives/rectangle.d.ts +15 -0
  160. package/dist/ui/primitives/rectangle.d.ts.map +1 -0
  161. package/dist/ui/primitives/rectangle.js +23 -0
  162. package/dist/ui/primitives/rectangle.js.map +1 -0
  163. package/dist/ui/primitives/spacer.d.ts +13 -0
  164. package/dist/ui/primitives/spacer.d.ts.map +1 -0
  165. package/dist/ui/primitives/spacer.js +16 -0
  166. package/dist/ui/primitives/spacer.js.map +1 -0
  167. package/dist/ui/primitives/text.d.ts +15 -0
  168. package/dist/ui/primitives/text.d.ts.map +1 -0
  169. package/dist/ui/primitives/text.js +79 -0
  170. package/dist/ui/primitives/text.js.map +1 -0
  171. package/dist/ui/primitives/wrapped-text.d.ts +30 -0
  172. package/dist/ui/primitives/wrapped-text.d.ts.map +1 -0
  173. package/dist/ui/primitives/wrapped-text.js +117 -0
  174. package/dist/ui/primitives/wrapped-text.js.map +1 -0
  175. package/dist/ui/shinytext.d.ts +66 -0
  176. package/dist/ui/shinytext.d.ts.map +1 -0
  177. package/dist/ui/shinytext.js +99 -0
  178. package/dist/ui/shinytext.js.map +1 -0
  179. package/dist/ui/text/layout.d.ts +35 -0
  180. package/dist/ui/text/layout.d.ts.map +1 -0
  181. package/dist/ui/text/layout.js +102 -0
  182. package/dist/ui/text/layout.js.map +1 -0
  183. package/dist/ui/textinput.d.ts +140 -0
  184. package/dist/ui/textinput.d.ts.map +1 -0
  185. package/dist/ui/textinput.js +402 -0
  186. package/dist/ui/textinput.js.map +1 -0
  187. package/dist/ui/view-constructors.d.ts +72 -0
  188. package/dist/ui/view-constructors.d.ts.map +1 -0
  189. package/dist/ui/view-constructors.js +74 -0
  190. package/dist/ui/view-constructors.js.map +1 -0
  191. package/package.json +57 -0
  192. package/src/anim.ts +5 -0
  193. package/src/ansi.ts +83 -0
  194. package/src/index.ts +21 -0
  195. package/src/keys.ts +302 -0
  196. package/src/layout/linearStack.ts +115 -0
  197. package/src/motion-value.ts +335 -0
  198. package/src/present/display.ts +206 -0
  199. package/src/present/writers/fullscreen.ts +58 -0
  200. package/src/present/writers/inline.ts +101 -0
  201. package/src/render/buffer.ts +200 -0
  202. package/src/render/color-utils.ts +60 -0
  203. package/src/render/diff.ts +95 -0
  204. package/src/render/measure.ts +74 -0
  205. package/src/render/palette.ts +113 -0
  206. package/src/render/surface.ts +238 -0
  207. package/src/runtime/backend_node.ts +80 -0
  208. package/src/spring-physics.ts +151 -0
  209. package/src/spring.ts +234 -0
  210. package/src/ui/__snapshots__/wrappedtext.test.ts.snap +57 -0
  211. package/src/ui/containers/canvas.ts +18 -0
  212. package/src/ui/containers/geometry-reader.ts +32 -0
  213. package/src/ui/containers/hstack.ts +33 -0
  214. package/src/ui/containers/scroll.ts +106 -0
  215. package/src/ui/containers/shared.ts +27 -0
  216. package/src/ui/containers/vstack.ts +34 -0
  217. package/src/ui/containers/zstack.ts +37 -0
  218. package/src/ui/core/geometry-store.ts +42 -0
  219. package/src/ui/core/geometry.ts +30 -0
  220. package/src/ui/core/view.ts +49 -0
  221. package/src/ui/index.ts +84 -0
  222. package/src/ui/inlinetext.ts +135 -0
  223. package/src/ui/install.ts +110 -0
  224. package/src/ui/markdown.test.ts +74 -0
  225. package/src/ui/markdown.ts +388 -0
  226. package/src/ui/modifiers/border.ts +100 -0
  227. package/src/ui/modifiers/fill.ts +28 -0
  228. package/src/ui/modifiers/frame.ts +74 -0
  229. package/src/ui/modifiers/offset.ts +23 -0
  230. package/src/ui/modifiers/opacity.ts +93 -0
  231. package/src/ui/modifiers/padding.ts +53 -0
  232. package/src/ui/modifiers/styled.ts +31 -0
  233. package/src/ui/primitives/rectangle.ts +25 -0
  234. package/src/ui/primitives/spacer.ts +18 -0
  235. package/src/ui/primitives/text.ts +85 -0
  236. package/src/ui/primitives/wrapped-text.ts +131 -0
  237. package/src/ui/shinytext.ts +159 -0
  238. package/src/ui/text/layout.ts +119 -0
  239. package/src/ui/textinput.ts +496 -0
  240. package/src/ui/view-constructors.ts +96 -0
  241. 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":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AACtC,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAOpE,MAAM,OAAO,WAAY,SAAQ,IAAI;IAExB;IACA;IAFX,YACW,IAAY,EACZ,UAA2B,EAAE;QAEtC,KAAK,EAAE,CAAA;QAHE,SAAI,GAAJ,IAAI,CAAQ;QACZ,YAAO,GAAP,OAAO,CAAsB;IAGxC,CAAC;IAED;;OAEG;IACK,QAAQ,CAAC,QAAgB;QAC/B,IAAI,QAAQ,IAAI,CAAC;YAAE,OAAO,CAAC,EAAE,CAAC,CAAA;QAC9B,IAAI,CAAC,IAAI,CAAC,IAAI;YAAE,OAAO,EAAE,CAAA;QAEzB,MAAM,EAAE,QAAQ,GAAG,IAAI,EAAE,UAAU,GAAG,KAAK,EAAE,GAAG,IAAI,CAAC,OAAO,CAAA;QAE5D,sCAAsC;QACtC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACxC,MAAM,YAAY,GAAa,EAAE,CAAA;QAEjC,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;YAC9B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACtB,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;gBACrB,SAAQ;YACV,CAAC;YAED,IAAI,IAAI,CAAC,MAAM,IAAI,QAAQ,EAAE,CAAC;gBAC5B,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;gBACvB,SAAQ;YACV,CAAC;YAED,sBAAsB;YACtB,IAAI,QAAQ,EAAE,CAAC;gBACb,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,CAAC,CAAA;YAChE,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,oBAAoB,CAAC,IAAI,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAA;YACzD,CAAC;QACH,CAAC;QAED,OAAO,YAAY,CAAA;IACrB,CAAC;IAED;;OAEG;IACK,eAAe,CAAC,IAAY,EAAE,QAAgB,EAAE,UAAmB,EAAE,MAAgB;QAC3F,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA,CAAC,6BAA6B;QAC/D,IAAI,WAAW,GAAG,EAAE,CAAA;QAEpB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,qBAAqB;YACrB,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;gBAAE,SAAQ;YAE/B,kEAAkE;YAClE,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;gBAAE,SAAQ;YAE5D,yCAAyC;YACzC,IAAI,YAAY,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,QAAQ,EAAE,CAAC;gBAChD,iEAAiE;gBACjE,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC3B,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC,CAAA;oBAClC,WAAW,GAAG,EAAE,CAAA;gBAClB,CAAC;gBAED,oBAAoB;gBACpB,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC;oBACzC,IAAI,UAAU,EAAE,CAAC;wBACf,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAA;oBAC1D,CAAC;yBAAM,CAAC;wBACN,mEAAmE;wBACnE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;oBAC1B,CAAC;gBACH,CAAC;qBAAM,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAClC,0DAA0D;oBAC1D,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;gBAC3B,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,WAAW,IAAI,IAAI,CAAA;YACrB,CAAC;QACH,CAAC;QAED,wBAAwB;QACxB,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC,CAAA;QACpC,CAAC;IACH,CAAC;IAED;;OAEG;IACK,oBAAoB,CAAC,IAAY,EAAE,QAAgB,EAAE,MAAgB;QAC3E,IAAI,IAAI,GAAG,IAAI,CAAA;QACf,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,EAAE,IAAI,EAAE,GAAG,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;YAC7C,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;gBAAE,MAAK;YAC5B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACjB,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAChC,CAAC;IACH,CAAC;IAES,cAAc,CAAC,IAAY,EAAE,IAAY;QACjD,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;QACjC,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAA;QACnD,sFAAsF;QACtF,MAAM,CAAC,GAAG,IAAI,CAAA;QACd,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAA;IACjB,CAAC;IAES,aAAa,CAAC,CAAU,EAAE,GAAY,EAAE,IAAU;QAC1D,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACnC,MAAM,OAAO,GAAG,GAAG,CAAC,EAAE,EAAE,CAAA;QAExB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YACxD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;YACrB,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACpB,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;YACvD,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
@@ -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":"AAAA,oDAAoD;AAGpD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAE7C,OAAO,EAAE,IAAI,EAAgB,MAAM,YAAY,CAAA;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAA;AAuBrC,MAAM,OAAO,SAAU,SAAQ,IAAI;IAEtB;IACA;IAFX,YACW,IAAY,EACZ,IAAuB;QAEhC,KAAK,EAAE,CAAA;QAHE,SAAI,GAAJ,IAAI,CAAQ;QACZ,SAAI,GAAJ,IAAI,CAAmB;IAGlC,CAAC;IAEO,QAAQ;QACd,OAAO,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAA;IACvB,CAAC;IAES,cAAc,CAAC,IAAY,EAAE,KAAa;QAClD,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAA;QAChD,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAA;IACpB,CAAC;IAES,aAAa,CAAC,CAAU,EAAE,GAAY,EAAE,IAAU;QAC1D,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAA;QAC7B,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;QACxC,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAM;QAEjC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,MAAM,IAAI,IAAI,CAAA;QACxC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;QACvE,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;QACpE,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,aAAa,IAAI,IAAI,CAAA;QAE/C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAA;QACpC,MAAM,MAAM,GAAG,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC,CAAC,CAAA;QAE1F,MAAM,QAAQ,GAAG,CAAC,CAAS,EAAE,EAAE;YAC7B,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;YAC/C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;YAClC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;YAC7E,MAAM,IAAI,GAAG,SAAS,GAAG,MAAM,CAAA;YAC/B,OAAO,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC,CAAA;QACjD,CAAC,CAAA;QAED,iCAAiC;QACjC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAA;QAChB,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,CAAA;QACd,IAAI,QAAQ,GAAG,CAAC,CAAC,CAAA;QACjB,IAAI,QAAQ,GAAG,CAAC,CAAA;QAChB,IAAI,OAAO,GAAG,EAAE,CAAA;QAChB,MAAM,KAAK,GAAG,GAAG,EAAE;YACjB,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAA;gBACpD,IAAI,IAAI,GAAG,CAAC;oBAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAA;gBAC9D,OAAO,GAAG,EAAE,CAAA;YACd,CAAC;QACH,CAAC,CAAA;QACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3B,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;YACnB,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAA;YACtB,IAAI,EAAE,KAAK,QAAQ,EAAE,CAAC;gBACpB,KAAK,EAAE,CAAA;gBACP,QAAQ,GAAG,EAAE,CAAA;gBACb,QAAQ,GAAG,CAAC,CAAA;YACd,CAAC;YACD,OAAO,IAAI,EAAE,CAAA;YACb,CAAC,EAAE,CAAA;QACL,CAAC;QACD,KAAK,EAAE,CAAA;IACT,CAAC;CACF;AAMD,MAAM,CAAC,MAAM,aAAa,GAAqB;IAC7C,SAAS,CAAC,IAAY,EAAE,IAAuB;QAC7C,OAAO,IAAI,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;IAClC,CAAC;CACF,CAAA;AAoBD,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,IAAuB;IACjE,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;IACtD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IACvD,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,MAAM,CAAA;IAC9B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,QAAQ,GAAG,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAA;IACxD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAA;AAC9D,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAqB,EAAE,KAAa;IAChE,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IACzC,OAAO,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,CAAA;AAC3B,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAqB,EAAE,OAAe;IAClE,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,CAAA;IACnC,MAAM,IAAI,GAAG,EAAE,GAAG,KAAK,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,CAAA;IAC9C,OAAO,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAA;AACxC,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,SAAS,CAAC,KAAqB;IAC7C,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAA;IAChD,OAAO,IAAI,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;AAC9D,CAAC;AAED,wHAAwH;AACxH,WAAiB,SAAS;IAKX,cAAI,GAAG,aAAa,CAAA;IACpB,cAAI,GAAG,aAAa,CAAA;IACpB,kBAAQ,GAAG,aAAa,CAAA;IACxB,cAAI,GAAG,SAAS,CAAA;AAC/B,CAAC,EATgB,SAAS,KAAT,SAAS,QASzB"}
@@ -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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"}