@chengchenccc/tui 0.1.1-rc.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 (226) hide show
  1. package/dist/autocomplete.d.ts +56 -0
  2. package/dist/autocomplete.d.ts.map +1 -0
  3. package/dist/autocomplete.js +647 -0
  4. package/dist/components/box.d.ts +22 -0
  5. package/dist/components/box.d.ts.map +1 -0
  6. package/dist/components/box.js +103 -0
  7. package/dist/components/card.d.ts +33 -0
  8. package/dist/components/card.d.ts.map +1 -0
  9. package/dist/components/card.js +49 -0
  10. package/dist/components/editor.d.ts +257 -0
  11. package/dist/components/editor.d.ts.map +1 -0
  12. package/dist/components/editor.js +1980 -0
  13. package/dist/components/input.d.ts +37 -0
  14. package/dist/components/input.d.ts.map +1 -0
  15. package/dist/components/input.js +389 -0
  16. package/dist/components/loader.d.ts +33 -0
  17. package/dist/components/loader.d.ts.map +1 -0
  18. package/dist/components/loader.js +100 -0
  19. package/dist/components/markdown.d.ts +108 -0
  20. package/dist/components/markdown.d.ts.map +1 -0
  21. package/dist/components/markdown.js +847 -0
  22. package/dist/components/markdown.test.d.ts +2 -0
  23. package/dist/components/markdown.test.d.ts.map +1 -0
  24. package/dist/components/markdown.test.js +81 -0
  25. package/dist/components/output-block.d.ts +44 -0
  26. package/dist/components/output-block.d.ts.map +1 -0
  27. package/dist/components/output-block.js +131 -0
  28. package/dist/components/select-list.d.ts +50 -0
  29. package/dist/components/select-list.d.ts.map +1 -0
  30. package/dist/components/select-list.js +166 -0
  31. package/dist/components/spacer.d.ts +12 -0
  32. package/dist/components/spacer.d.ts.map +1 -0
  33. package/dist/components/spacer.js +22 -0
  34. package/dist/components/statusline.d.ts +30 -0
  35. package/dist/components/statusline.d.ts.map +1 -0
  36. package/dist/components/statusline.js +46 -0
  37. package/dist/components/text.d.ts +19 -0
  38. package/dist/components/text.d.ts.map +1 -0
  39. package/dist/components/text.js +90 -0
  40. package/dist/components/truncated-text.d.ts +13 -0
  41. package/dist/components/truncated-text.d.ts.map +1 -0
  42. package/dist/components/truncated-text.js +50 -0
  43. package/dist/editor-component.d.ts +39 -0
  44. package/dist/editor-component.d.ts.map +1 -0
  45. package/dist/editor-component.js +1 -0
  46. package/dist/fuzzy.d.ts +16 -0
  47. package/dist/fuzzy.d.ts.map +1 -0
  48. package/dist/fuzzy.js +109 -0
  49. package/dist/index.d.ts +25 -0
  50. package/dist/index.d.ts.map +1 -0
  51. package/dist/index.js +36 -0
  52. package/dist/keybindings.d.ts +193 -0
  53. package/dist/keybindings.d.ts.map +1 -0
  54. package/dist/keybindings.js +191 -0
  55. package/dist/keys.d.ts +184 -0
  56. package/dist/keys.d.ts.map +1 -0
  57. package/dist/keys.js +1191 -0
  58. package/dist/kill-ring.d.ts +28 -0
  59. package/dist/kill-ring.d.ts.map +1 -0
  60. package/dist/kill-ring.js +43 -0
  61. package/dist/mermaid.d.ts +23 -0
  62. package/dist/mermaid.d.ts.map +1 -0
  63. package/dist/mermaid.js +77 -0
  64. package/dist/mouse.d.ts +40 -0
  65. package/dist/mouse.d.ts.map +1 -0
  66. package/dist/mouse.js +39 -0
  67. package/dist/mouse.test.d.ts +2 -0
  68. package/dist/mouse.test.d.ts.map +1 -0
  69. package/dist/mouse.test.js +36 -0
  70. package/dist/native-modifiers.d.ts +3 -0
  71. package/dist/native-modifiers.d.ts.map +1 -0
  72. package/dist/native-modifiers.js +52 -0
  73. package/dist/stdin-buffer.d.ts +50 -0
  74. package/dist/stdin-buffer.d.ts.map +1 -0
  75. package/dist/stdin-buffer.js +360 -0
  76. package/dist/terminal-colors.d.ts +10 -0
  77. package/dist/terminal-colors.d.ts.map +1 -0
  78. package/dist/terminal-colors.js +58 -0
  79. package/dist/terminal-image.d.ts +90 -0
  80. package/dist/terminal-image.d.ts.map +1 -0
  81. package/dist/terminal-image.js +375 -0
  82. package/dist/terminal.d.ts +110 -0
  83. package/dist/terminal.d.ts.map +1 -0
  84. package/dist/terminal.js +432 -0
  85. package/dist/tui-scrollback.test.d.ts +2 -0
  86. package/dist/tui-scrollback.test.d.ts.map +1 -0
  87. package/dist/tui-scrollback.test.js +51 -0
  88. package/dist/tui.d.ts +330 -0
  89. package/dist/tui.d.ts.map +1 -0
  90. package/dist/tui.js +1568 -0
  91. package/dist/undo-stack.d.ts +17 -0
  92. package/dist/undo-stack.d.ts.map +1 -0
  93. package/dist/undo-stack.js +24 -0
  94. package/dist/utils.d.ts +85 -0
  95. package/dist/utils.d.ts.map +1 -0
  96. package/dist/utils.js +1066 -0
  97. package/dist/vendor/mermaid-ascii/ascii/ansi.d.ts +42 -0
  98. package/dist/vendor/mermaid-ascii/ascii/ansi.d.ts.map +1 -0
  99. package/dist/vendor/mermaid-ascii/ascii/ansi.js +361 -0
  100. package/dist/vendor/mermaid-ascii/ascii/canvas.d.ts +90 -0
  101. package/dist/vendor/mermaid-ascii/ascii/canvas.d.ts.map +1 -0
  102. package/dist/vendor/mermaid-ascii/ascii/canvas.js +414 -0
  103. package/dist/vendor/mermaid-ascii/ascii/class-diagram.d.ts +8 -0
  104. package/dist/vendor/mermaid-ascii/ascii/class-diagram.d.ts.map +1 -0
  105. package/dist/vendor/mermaid-ascii/ascii/class-diagram.js +623 -0
  106. package/dist/vendor/mermaid-ascii/ascii/converter.d.ts +13 -0
  107. package/dist/vendor/mermaid-ascii/ascii/converter.d.ts.map +1 -0
  108. package/dist/vendor/mermaid-ascii/ascii/converter.js +233 -0
  109. package/dist/vendor/mermaid-ascii/ascii/draw.d.ts +67 -0
  110. package/dist/vendor/mermaid-ascii/ascii/draw.d.ts.map +1 -0
  111. package/dist/vendor/mermaid-ascii/ascii/draw.js +1313 -0
  112. package/dist/vendor/mermaid-ascii/ascii/edge-bundling.d.ts +49 -0
  113. package/dist/vendor/mermaid-ascii/ascii/edge-bundling.d.ts.map +1 -0
  114. package/dist/vendor/mermaid-ascii/ascii/edge-bundling.js +289 -0
  115. package/dist/vendor/mermaid-ascii/ascii/edge-routing.d.ts +44 -0
  116. package/dist/vendor/mermaid-ascii/ascii/edge-routing.d.ts.map +1 -0
  117. package/dist/vendor/mermaid-ascii/ascii/edge-routing.js +302 -0
  118. package/dist/vendor/mermaid-ascii/ascii/er-diagram.d.ts +8 -0
  119. package/dist/vendor/mermaid-ascii/ascii/er-diagram.d.ts.map +1 -0
  120. package/dist/vendor/mermaid-ascii/ascii/er-diagram.js +380 -0
  121. package/dist/vendor/mermaid-ascii/ascii/grid.d.ts +57 -0
  122. package/dist/vendor/mermaid-ascii/ascii/grid.d.ts.map +1 -0
  123. package/dist/vendor/mermaid-ascii/ascii/grid.js +516 -0
  124. package/dist/vendor/mermaid-ascii/ascii/index.d.ts +66 -0
  125. package/dist/vendor/mermaid-ascii/ascii/index.d.ts.map +1 -0
  126. package/dist/vendor/mermaid-ascii/ascii/index.js +133 -0
  127. package/dist/vendor/mermaid-ascii/ascii/multiline-utils.d.ts +28 -0
  128. package/dist/vendor/mermaid-ascii/ascii/multiline-utils.d.ts.map +1 -0
  129. package/dist/vendor/mermaid-ascii/ascii/multiline-utils.js +60 -0
  130. package/dist/vendor/mermaid-ascii/ascii/pathfinder.d.ts +18 -0
  131. package/dist/vendor/mermaid-ascii/ascii/pathfinder.d.ts.map +1 -0
  132. package/dist/vendor/mermaid-ascii/ascii/pathfinder.js +224 -0
  133. package/dist/vendor/mermaid-ascii/ascii/sequence.d.ts +8 -0
  134. package/dist/vendor/mermaid-ascii/ascii/sequence.d.ts.map +1 -0
  135. package/dist/vendor/mermaid-ascii/ascii/sequence.js +416 -0
  136. package/dist/vendor/mermaid-ascii/ascii/shapes/circle.d.ts +12 -0
  137. package/dist/vendor/mermaid-ascii/ascii/shapes/circle.d.ts.map +1 -0
  138. package/dist/vendor/mermaid-ascii/ascii/shapes/circle.js +22 -0
  139. package/dist/vendor/mermaid-ascii/ascii/shapes/corners.d.ts +35 -0
  140. package/dist/vendor/mermaid-ascii/ascii/shapes/corners.d.ts.map +1 -0
  141. package/dist/vendor/mermaid-ascii/ascii/shapes/corners.js +91 -0
  142. package/dist/vendor/mermaid-ascii/ascii/shapes/diamond.d.ts +12 -0
  143. package/dist/vendor/mermaid-ascii/ascii/shapes/diamond.d.ts.map +1 -0
  144. package/dist/vendor/mermaid-ascii/ascii/shapes/diamond.js +22 -0
  145. package/dist/vendor/mermaid-ascii/ascii/shapes/hexagon.d.ts +12 -0
  146. package/dist/vendor/mermaid-ascii/ascii/shapes/hexagon.d.ts.map +1 -0
  147. package/dist/vendor/mermaid-ascii/ascii/shapes/hexagon.js +22 -0
  148. package/dist/vendor/mermaid-ascii/ascii/shapes/index.d.ts +27 -0
  149. package/dist/vendor/mermaid-ascii/ascii/shapes/index.d.ts.map +1 -0
  150. package/dist/vendor/mermaid-ascii/ascii/shapes/index.js +66 -0
  151. package/dist/vendor/mermaid-ascii/ascii/shapes/rectangle.d.ts +32 -0
  152. package/dist/vendor/mermaid-ascii/ascii/shapes/rectangle.d.ts.map +1 -0
  153. package/dist/vendor/mermaid-ascii/ascii/shapes/rectangle.js +149 -0
  154. package/dist/vendor/mermaid-ascii/ascii/shapes/rounded.d.ts +12 -0
  155. package/dist/vendor/mermaid-ascii/ascii/shapes/rounded.d.ts.map +1 -0
  156. package/dist/vendor/mermaid-ascii/ascii/shapes/rounded.js +22 -0
  157. package/dist/vendor/mermaid-ascii/ascii/shapes/special.d.ts +60 -0
  158. package/dist/vendor/mermaid-ascii/ascii/shapes/special.d.ts.map +1 -0
  159. package/dist/vendor/mermaid-ascii/ascii/shapes/special.js +253 -0
  160. package/dist/vendor/mermaid-ascii/ascii/shapes/stadium.d.ts +18 -0
  161. package/dist/vendor/mermaid-ascii/ascii/shapes/stadium.d.ts.map +1 -0
  162. package/dist/vendor/mermaid-ascii/ascii/shapes/stadium.js +103 -0
  163. package/dist/vendor/mermaid-ascii/ascii/shapes/state.d.ts +31 -0
  164. package/dist/vendor/mermaid-ascii/ascii/shapes/state.d.ts.map +1 -0
  165. package/dist/vendor/mermaid-ascii/ascii/shapes/state.js +167 -0
  166. package/dist/vendor/mermaid-ascii/ascii/shapes/types.d.ts +56 -0
  167. package/dist/vendor/mermaid-ascii/ascii/shapes/types.d.ts.map +1 -0
  168. package/dist/vendor/mermaid-ascii/ascii/shapes/types.js +4 -0
  169. package/dist/vendor/mermaid-ascii/ascii/types.d.ts +207 -0
  170. package/dist/vendor/mermaid-ascii/ascii/types.d.ts.map +1 -0
  171. package/dist/vendor/mermaid-ascii/ascii/types.js +39 -0
  172. package/dist/vendor/mermaid-ascii/ascii/validate.d.ts +52 -0
  173. package/dist/vendor/mermaid-ascii/ascii/validate.d.ts.map +1 -0
  174. package/dist/vendor/mermaid-ascii/ascii/validate.js +97 -0
  175. package/dist/vendor/mermaid-ascii/ascii/xychart.d.ts +3 -0
  176. package/dist/vendor/mermaid-ascii/ascii/xychart.d.ts.map +1 -0
  177. package/dist/vendor/mermaid-ascii/ascii/xychart.js +719 -0
  178. package/dist/vendor/mermaid-ascii/class/parser.d.ts +7 -0
  179. package/dist/vendor/mermaid-ascii/class/parser.d.ts.map +1 -0
  180. package/dist/vendor/mermaid-ascii/class/parser.js +265 -0
  181. package/dist/vendor/mermaid-ascii/class/types.d.ts +103 -0
  182. package/dist/vendor/mermaid-ascii/class/types.d.ts.map +1 -0
  183. package/dist/vendor/mermaid-ascii/class/types.js +7 -0
  184. package/dist/vendor/mermaid-ascii/er/parser.d.ts +7 -0
  185. package/dist/vendor/mermaid-ascii/er/parser.d.ts.map +1 -0
  186. package/dist/vendor/mermaid-ascii/er/parser.js +162 -0
  187. package/dist/vendor/mermaid-ascii/er/types.d.ts +77 -0
  188. package/dist/vendor/mermaid-ascii/er/types.d.ts.map +1 -0
  189. package/dist/vendor/mermaid-ascii/er/types.js +7 -0
  190. package/dist/vendor/mermaid-ascii/index.d.ts +2 -0
  191. package/dist/vendor/mermaid-ascii/index.d.ts.map +1 -0
  192. package/dist/vendor/mermaid-ascii/index.js +13 -0
  193. package/dist/vendor/mermaid-ascii/multiline-utils.d.ts +10 -0
  194. package/dist/vendor/mermaid-ascii/multiline-utils.d.ts.map +1 -0
  195. package/dist/vendor/mermaid-ascii/multiline-utils.js +29 -0
  196. package/dist/vendor/mermaid-ascii/parser.d.ts +8 -0
  197. package/dist/vendor/mermaid-ascii/parser.d.ts.map +1 -0
  198. package/dist/vendor/mermaid-ascii/parser.js +558 -0
  199. package/dist/vendor/mermaid-ascii/sequence/parser.d.ts +7 -0
  200. package/dist/vendor/mermaid-ascii/sequence/parser.d.ts.map +1 -0
  201. package/dist/vendor/mermaid-ascii/sequence/parser.js +182 -0
  202. package/dist/vendor/mermaid-ascii/sequence/types.d.ts +131 -0
  203. package/dist/vendor/mermaid-ascii/sequence/types.d.ts.map +1 -0
  204. package/dist/vendor/mermaid-ascii/sequence/types.js +7 -0
  205. package/dist/vendor/mermaid-ascii/text-metrics.d.ts +24 -0
  206. package/dist/vendor/mermaid-ascii/text-metrics.d.ts.map +1 -0
  207. package/dist/vendor/mermaid-ascii/text-metrics.js +69 -0
  208. package/dist/vendor/mermaid-ascii/types.d.ts +115 -0
  209. package/dist/vendor/mermaid-ascii/types.d.ts.map +1 -0
  210. package/dist/vendor/mermaid-ascii/types.js +4 -0
  211. package/dist/vendor/mermaid-ascii/xychart/colors.d.ts +26 -0
  212. package/dist/vendor/mermaid-ascii/xychart/colors.d.ts.map +1 -0
  213. package/dist/vendor/mermaid-ascii/xychart/colors.js +145 -0
  214. package/dist/vendor/mermaid-ascii/xychart/parser.d.ts +7 -0
  215. package/dist/vendor/mermaid-ascii/xychart/parser.d.ts.map +1 -0
  216. package/dist/vendor/mermaid-ascii/xychart/parser.js +105 -0
  217. package/dist/vendor/mermaid-ascii/xychart/types.d.ts +146 -0
  218. package/dist/vendor/mermaid-ascii/xychart/types.d.ts.map +1 -0
  219. package/dist/vendor/mermaid-ascii/xychart/types.js +8 -0
  220. package/dist/virtual-terminal.d.ts +80 -0
  221. package/dist/virtual-terminal.d.ts.map +1 -0
  222. package/dist/virtual-terminal.js +284 -0
  223. package/dist/word-navigation.d.ts +25 -0
  224. package/dist/word-navigation.d.ts.map +1 -0
  225. package/dist/word-navigation.js +97 -0
  226. package/package.json +38 -0
@@ -0,0 +1,414 @@
1
+ // ============================================================================
2
+ // ASCII renderer — 2D text canvas
3
+ //
4
+ // Ported from AlexanderGrooff/mermaid-ascii cmd/draw.go.
5
+ // The canvas is a column-major 2D array of single-character strings.
6
+ // canvas[x][y] gives the character at column x, row y.
7
+ // ============================================================================
8
+ import { colorizeLine, DEFAULT_ASCII_THEME } from "./ansi.js";
9
+ import { displayWidth, LABEL_SPACE, toCells, WIDE_PAD } from "../text-metrics.js";
10
+ /**
11
+ * Create a blank canvas filled with spaces.
12
+ * Dimensions are inclusive: mkCanvas(3, 2) creates a 4x3 grid (indices 0..3, 0..2).
13
+ */
14
+ export function mkCanvas(x, y) {
15
+ const canvas = [];
16
+ for (let i = 0; i <= x; i++) {
17
+ const col = [];
18
+ for (let j = 0; j <= y; j++) {
19
+ col.push(' ');
20
+ }
21
+ canvas.push(col);
22
+ }
23
+ return canvas;
24
+ }
25
+ /** Create a blank canvas with the same dimensions as the given canvas. */
26
+ export function copyCanvas(source) {
27
+ const [maxX, maxY] = getCanvasSize(source);
28
+ return mkCanvas(maxX, maxY);
29
+ }
30
+ // ============================================================================
31
+ // Role canvas creation and management
32
+ // ============================================================================
33
+ /**
34
+ * Create a blank role canvas filled with nulls.
35
+ * Same dimensions as mkCanvas — column-major, roleCanvas[x][y].
36
+ */
37
+ export function mkRoleCanvas(x, y) {
38
+ const roleCanvas = [];
39
+ for (let i = 0; i <= x; i++) {
40
+ const col = [];
41
+ for (let j = 0; j <= y; j++) {
42
+ col.push(null);
43
+ }
44
+ roleCanvas.push(col);
45
+ }
46
+ return roleCanvas;
47
+ }
48
+ /** Create a blank role canvas with the same dimensions as the given role canvas. */
49
+ export function copyRoleCanvas(source) {
50
+ const maxX = source.length - 1;
51
+ const maxY = (source[0]?.length ?? 1) - 1;
52
+ return mkRoleCanvas(maxX, maxY);
53
+ }
54
+ /**
55
+ * Grow the role canvas to fit at least (newX, newY), preserving existing roles.
56
+ * Mutates the role canvas in place and returns it.
57
+ */
58
+ export function increaseRoleCanvasSize(roleCanvas, newX, newY) {
59
+ const currX = roleCanvas.length - 1;
60
+ const currY = (roleCanvas[0]?.length ?? 1) - 1;
61
+ const targetX = Math.max(newX, currX);
62
+ const targetY = Math.max(newY, currY);
63
+ const grown = mkRoleCanvas(targetX, targetY);
64
+ for (let x = 0; x < grown.length; x++) {
65
+ for (let y = 0; y < grown[0].length; y++) {
66
+ if (x < roleCanvas.length && y < roleCanvas[0].length) {
67
+ grown[x][y] = roleCanvas[x][y];
68
+ }
69
+ }
70
+ }
71
+ roleCanvas.length = 0;
72
+ roleCanvas.push(...grown);
73
+ return roleCanvas;
74
+ }
75
+ /**
76
+ * Set a role at a specific coordinate.
77
+ * Expands the role canvas if necessary.
78
+ */
79
+ export function setRole(roleCanvas, x, y, role) {
80
+ if (x >= roleCanvas.length || y >= (roleCanvas[0]?.length ?? 0)) {
81
+ increaseRoleCanvasSize(roleCanvas, x, y);
82
+ }
83
+ roleCanvas[x][y] = role;
84
+ }
85
+ /**
86
+ * Merge role canvases — same logic as mergeCanvases but for roles.
87
+ * Non-null roles in overlays overwrite null roles in base.
88
+ */
89
+ export function mergeRoleCanvases(base, offset, ...overlays) {
90
+ let maxX = base.length - 1;
91
+ let maxY = (base[0]?.length ?? 1) - 1;
92
+ for (const overlay of overlays) {
93
+ const oX = overlay.length - 1;
94
+ const oY = (overlay[0]?.length ?? 1) - 1;
95
+ maxX = Math.max(maxX, oX + offset.x);
96
+ maxY = Math.max(maxY, oY + offset.y);
97
+ }
98
+ const merged = mkRoleCanvas(maxX, maxY);
99
+ // Copy base
100
+ for (let x = 0; x <= maxX; x++) {
101
+ for (let y = 0; y <= maxY; y++) {
102
+ if (x < base.length && y < base[0].length) {
103
+ merged[x][y] = base[x][y];
104
+ }
105
+ }
106
+ }
107
+ // Apply overlays
108
+ for (const overlay of overlays) {
109
+ for (let x = 0; x < overlay.length; x++) {
110
+ for (let y = 0; y < overlay[0].length; y++) {
111
+ const role = overlay[x]?.[y];
112
+ if (role !== null && role !== undefined) {
113
+ const mx = x + offset.x;
114
+ const my = y + offset.y;
115
+ merged[mx][my] = role;
116
+ }
117
+ }
118
+ }
119
+ }
120
+ return merged;
121
+ }
122
+ /** Returns [maxX, maxY] — the highest valid indices in each dimension. */
123
+ export function getCanvasSize(canvas) {
124
+ return [canvas.length - 1, (canvas[0]?.length ?? 1) - 1];
125
+ }
126
+ /**
127
+ * Grow the canvas to fit at least (newX, newY), preserving existing content.
128
+ * Mutates the canvas in place and returns it.
129
+ */
130
+ export function increaseSize(canvas, newX, newY) {
131
+ const [currX, currY] = getCanvasSize(canvas);
132
+ const targetX = Math.max(newX, currX);
133
+ const targetY = Math.max(newY, currY);
134
+ const grown = mkCanvas(targetX, targetY);
135
+ for (let x = 0; x < grown.length; x++) {
136
+ for (let y = 0; y < grown[0].length; y++) {
137
+ if (x < canvas.length && y < canvas[0].length) {
138
+ grown[x][y] = canvas[x][y];
139
+ }
140
+ }
141
+ }
142
+ // Mutate in place: splice old contents and replace with grown
143
+ canvas.length = 0;
144
+ canvas.push(...grown);
145
+ return canvas;
146
+ }
147
+ // ============================================================================
148
+ // Junction merging — Unicode box-drawing character compositing
149
+ // ============================================================================
150
+ /** All Unicode box-drawing characters that participate in junction merging. */
151
+ const JUNCTION_CHARS = new Set([
152
+ '─', '│', '┌', '┐', '└', '┘', '├', '┤', '┬', '┴', '┼', '╴', '╵', '╶', '╷',
153
+ ]);
154
+ export function isJunctionChar(c) {
155
+ return JUNCTION_CHARS.has(c);
156
+ }
157
+ /**
158
+ * Check if a cell holds label content for first-label-wins collision
159
+ * handling during merges: letters/digits in any script, the continuation
160
+ * cell of a wide glyph, or any 2-column glyph. Wide glyphs are only ever
161
+ * produced by labels (CJK ideographs, Hangul, emoji) — the renderer's own
162
+ * structural glyphs (borders, the narrow arrowheads ◀▶) are 1 column — so
163
+ * width 2 is a sufficient signal for emoji labels (🚀, 🇨🇳, 👍🏽) that the
164
+ * letter/digit test misses.
165
+ */
166
+ function isLabelChar(c) {
167
+ return c === LABEL_SPACE || c === WIDE_PAD || displayWidth(c) === 2 || /[\p{L}\p{N}]/u.test(c);
168
+ }
169
+ /**
170
+ * Write one cell, dissolving any wide-glyph pair the write would split:
171
+ * overwriting a WIDE_PAD orphans its lead, and overwriting a lead orphans
172
+ * its pad — the orphaned half becomes a space so serialized rows keep
173
+ * exactly one column per cell.
174
+ */
175
+ function writeCell(canvas, x, y, c) {
176
+ const current = canvas[x][y];
177
+ if (current === WIDE_PAD && x > 0 && c !== WIDE_PAD) {
178
+ canvas[x - 1][y] = ' ';
179
+ }
180
+ else if (current !== WIDE_PAD && canvas[x + 1]?.[y] === WIDE_PAD && c !== current) {
181
+ canvas[x + 1][y] = ' ';
182
+ }
183
+ canvas[x][y] = c;
184
+ }
185
+ /**
186
+ * When two junction characters overlap during canvas merging,
187
+ * resolve them to the correct combined junction.
188
+ * E.g., '─' overlapping '│' becomes '┼'.
189
+ */
190
+ const JUNCTION_MAP = {
191
+ '─': { '│': '┼', '┌': '┬', '┐': '┬', '└': '┴', '┘': '┴', '├': '┼', '┤': '┼', '┬': '┬', '┴': '┴' },
192
+ '│': { '─': '┼', '┌': '├', '┐': '┤', '└': '├', '┘': '┤', '├': '├', '┤': '┤', '┬': '┼', '┴': '┼' },
193
+ '┌': { '─': '┬', '│': '├', '┐': '┬', '└': '├', '┘': '┼', '├': '├', '┤': '┼', '┬': '┬', '┴': '┼' },
194
+ '┐': { '─': '┬', '│': '┤', '┌': '┬', '└': '┼', '┘': '┤', '├': '┼', '┤': '┤', '┬': '┬', '┴': '┼' },
195
+ '└': { '─': '┴', '│': '├', '┌': '├', '┐': '┼', '┘': '┴', '├': '├', '┤': '┼', '┬': '┼', '┴': '┴' },
196
+ '┘': { '─': '┴', '│': '┤', '┌': '┼', '┐': '┤', '└': '┴', '├': '┼', '┤': '┤', '┬': '┼', '┴': '┴' },
197
+ '├': { '─': '┼', '│': '├', '┌': '├', '┐': '┼', '└': '├', '┘': '┼', '┤': '┼', '┬': '┼', '┴': '┼' },
198
+ '┤': { '─': '┼', '│': '┤', '┌': '┼', '┐': '┤', '└': '┼', '┘': '┤', '├': '┼', '┬': '┼', '┴': '┼' },
199
+ '┬': { '─': '┬', '│': '┼', '┌': '┬', '┐': '┬', '└': '┼', '┘': '┼', '├': '┼', '┤': '┼', '┴': '┼' },
200
+ '┴': { '─': '┴', '│': '┼', '┌': '┼', '┐': '┼', '└': '┴', '┘': '┴', '├': '┼', '┤': '┼', '┬': '┼' },
201
+ };
202
+ export function mergeJunctions(c1, c2) {
203
+ return JUNCTION_MAP[c1]?.[c2] ?? c1;
204
+ }
205
+ // ============================================================================
206
+ // Canvas merging — composite multiple canvases with offset
207
+ // ============================================================================
208
+ /**
209
+ * Merge overlay canvases onto a base canvas at the given offset.
210
+ * Non-space characters in overlays overwrite the base.
211
+ * When both characters are Unicode junction chars, they're merged intelligently.
212
+ */
213
+ export function mergeCanvases(base, offset, useAscii, ...overlays) {
214
+ let [maxX, maxY] = getCanvasSize(base);
215
+ for (const overlay of overlays) {
216
+ const [oX, oY] = getCanvasSize(overlay);
217
+ maxX = Math.max(maxX, oX + offset.x);
218
+ maxY = Math.max(maxY, oY + offset.y);
219
+ }
220
+ const merged = mkCanvas(maxX, maxY);
221
+ // Copy base
222
+ for (let x = 0; x <= maxX; x++) {
223
+ for (let y = 0; y <= maxY; y++) {
224
+ if (x < base.length && y < base[0].length) {
225
+ merged[x][y] = base[x][y];
226
+ }
227
+ }
228
+ }
229
+ // Apply overlays
230
+ for (const overlay of overlays) {
231
+ for (let x = 0; x < overlay.length; x++) {
232
+ for (let y = 0; y < overlay[0].length; y++) {
233
+ const c = overlay[x][y];
234
+ // Spaces are transparent; WIDE_PAD cells are written atomically with their lead below
235
+ if (c === ' ' || c === WIDE_PAD)
236
+ continue;
237
+ const mx = x + offset.x;
238
+ const my = y + offset.y;
239
+ const current = merged[mx][my];
240
+ const isWide = overlay[x + 1]?.[y] === WIDE_PAD;
241
+ if (!useAscii && isJunctionChar(c) && isJunctionChar(current)) {
242
+ merged[mx][my] = mergeJunctions(current, c);
243
+ }
244
+ else if (isWide) {
245
+ // Wide glyphs land or yield as a whole pair (first label wins)
246
+ if (!isLabelChar(current) && !isLabelChar(merged[mx + 1]?.[my] ?? ' ')) {
247
+ writeCell(merged, mx, my, c);
248
+ writeCell(merged, mx + 1, my, WIDE_PAD);
249
+ }
250
+ }
251
+ else if (isLabelChar(current) && isLabelChar(c)) {
252
+ // Don't overwrite existing label text with new label text
253
+ // This prevents label collisions (first label wins)
254
+ }
255
+ else {
256
+ writeCell(merged, mx, my, c);
257
+ }
258
+ }
259
+ }
260
+ }
261
+ return merged;
262
+ }
263
+ /**
264
+ * Convert the canvas to a multi-line string (row by row, left to right).
265
+ * Optionally applies ANSI color codes based on character roles.
266
+ */
267
+ export function canvasToString(canvas, options) {
268
+ const [maxX, maxY] = getCanvasSize(canvas);
269
+ const lines = [];
270
+ const roleCanvas = options?.roleCanvas;
271
+ const colorMode = options?.colorMode ?? 'none';
272
+ const theme = options?.theme ?? DEFAULT_ASCII_THEME;
273
+ for (let y = 0; y <= maxY; y++) {
274
+ if (colorMode === 'none' || !roleCanvas) {
275
+ // Plain text output — no colors
276
+ let line = '';
277
+ for (let x = 0; x <= maxX; x++) {
278
+ const c = canvas[x][y];
279
+ // Skip wide-glyph continuation cells and restore opaque label spaces.
280
+ if (c !== WIDE_PAD)
281
+ line += c === LABEL_SPACE ? ' ' : c;
282
+ }
283
+ lines.push(line);
284
+ }
285
+ else {
286
+ // Colored output — collect chars and roles for this row
287
+ const chars = [];
288
+ const roles = [];
289
+ for (let x = 0; x <= maxX; x++) {
290
+ const c = canvas[x][y];
291
+ if (c === WIDE_PAD)
292
+ continue;
293
+ chars.push(c === LABEL_SPACE ? ' ' : c);
294
+ roles.push(roleCanvas[x]?.[y] ?? null);
295
+ }
296
+ lines.push(colorizeLine(chars, roles, theme, colorMode));
297
+ }
298
+ }
299
+ return lines.join('\n');
300
+ }
301
+ // ============================================================================
302
+ // Canvas vertical flip — used for BT (bottom-to-top) direction support.
303
+ //
304
+ // The ASCII renderer lays out graphs top-down (TD). For BT direction, we
305
+ // flip the finished canvas vertically and remap directional characters so
306
+ // arrows point upward and corners are mirrored correctly.
307
+ // ============================================================================
308
+ /**
309
+ * Characters that change meaning when the Y-axis is flipped.
310
+ * Symmetric characters (─, │, ├, ┤, ┼) are unchanged.
311
+ */
312
+ const VERTICAL_FLIP_MAP = {
313
+ // Unicode arrows
314
+ '▲': '▼', '▼': '▲',
315
+ '◤': '◣', '◣': '◤',
316
+ '◥': '◢', '◢': '◥',
317
+ // ASCII arrows
318
+ '^': 'v', 'v': '^',
319
+ // Unicode corners
320
+ '┌': '└', '└': '┌',
321
+ '┐': '┘', '┘': '┐',
322
+ '╭': '╰', '╰': '╭',
323
+ '╮': '╯', '╯': '╮',
324
+ // Unicode junctions (T-pieces flip vertically)
325
+ '┬': '┴', '┴': '┬',
326
+ // Box-start junctions (exit points from node boxes)
327
+ '╵': '╷', '╷': '╵',
328
+ };
329
+ /**
330
+ * Flip the canvas vertically (mirror across the horizontal center).
331
+ * Reverses row order within each column and remaps directional characters
332
+ * (arrows, corners, junctions) so they point the correct way after flip.
333
+ *
334
+ * Used to transform a TD-rendered canvas into BT output.
335
+ * Mutates the canvas in place and returns it.
336
+ */
337
+ export function flipCanvasVertically(canvas) {
338
+ // Reverse each column array (Y-axis flip in column-major layout)
339
+ for (const col of canvas) {
340
+ col.reverse();
341
+ }
342
+ // Remap directional characters that change meaning after vertical flip
343
+ for (const col of canvas) {
344
+ for (let y = 0; y < col.length; y++) {
345
+ const flipped = VERTICAL_FLIP_MAP[col[y]];
346
+ if (flipped)
347
+ col[y] = flipped;
348
+ }
349
+ }
350
+ return canvas;
351
+ }
352
+ /**
353
+ * Flip the role canvas vertically to match flipCanvasVertically.
354
+ * Mutates the role canvas in place and returns it.
355
+ */
356
+ export function flipRoleCanvasVertically(roleCanvas) {
357
+ for (const col of roleCanvas) {
358
+ col.reverse();
359
+ }
360
+ return roleCanvas;
361
+ }
362
+ /**
363
+ * Draw text string onto the canvas starting at the given coordinate.
364
+ * By default, preserves existing non-space characters (labels don't overwrite each other).
365
+ * Set forceOverwrite=true to always overwrite (for box content).
366
+ */
367
+ export function drawText(canvas, start, text, forceOverwrite = false) {
368
+ const cells = toCells(text);
369
+ increaseSize(canvas, start.x + cells.length, start.y);
370
+ for (let i = 0; i < cells.length; i++) {
371
+ const cell = cells[i];
372
+ // WIDE_PAD cells are written atomically with their lead below
373
+ if (cell === WIDE_PAD)
374
+ continue;
375
+ const x = start.x + i;
376
+ if (cells[i + 1] === WIDE_PAD) {
377
+ // Wide glyph: needs both its cells free (or forced) to land
378
+ const pairFree = canvas[x][start.y] === ' ' && canvas[x + 1][start.y] === ' ';
379
+ if (forceOverwrite || pairFree) {
380
+ writeCell(canvas, x, start.y, cell);
381
+ writeCell(canvas, x + 1, start.y, WIDE_PAD);
382
+ }
383
+ }
384
+ else if (forceOverwrite || canvas[x][start.y] === ' ') {
385
+ writeCell(canvas, x, start.y, cell);
386
+ }
387
+ }
388
+ }
389
+ /**
390
+ * Set the canvas size to fit all grid columns and rows.
391
+ * Called after layout to ensure the canvas covers the full drawing area.
392
+ */
393
+ export function setCanvasSizeToGrid(canvas, columnWidth, rowHeight) {
394
+ let maxX = 0;
395
+ let maxY = 0;
396
+ for (const w of columnWidth.values())
397
+ maxX += w;
398
+ for (const h of rowHeight.values())
399
+ maxY += h;
400
+ increaseSize(canvas, maxX - 1, maxY - 1);
401
+ }
402
+ /**
403
+ * Set the role canvas size to match the grid dimensions.
404
+ * Should be called alongside setCanvasSizeToGrid.
405
+ */
406
+ export function setRoleCanvasSizeToGrid(roleCanvas, columnWidth, rowHeight) {
407
+ let maxX = 0;
408
+ let maxY = 0;
409
+ for (const w of columnWidth.values())
410
+ maxX += w;
411
+ for (const h of rowHeight.values())
412
+ maxY += h;
413
+ increaseRoleCanvasSize(roleCanvas, maxX - 1, maxY - 1);
414
+ }
@@ -0,0 +1,8 @@
1
+ import type { AsciiConfig, AsciiTheme, ColorMode } from './types.ts';
2
+ /**
3
+ * Render a Mermaid class diagram to ASCII/Unicode text.
4
+ *
5
+ * Pipeline: parse → build boxes → level-based layout → draw boxes → draw relationships → string.
6
+ */
7
+ export declare function renderClassAscii(text: string, config: AsciiConfig, colorMode?: ColorMode, theme?: AsciiTheme): string;
8
+ //# sourceMappingURL=class-diagram.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"class-diagram.d.ts","sourceRoot":"","sources":["../../../../src/vendor/mermaid-ascii/ascii/class-diagram.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAU,WAAW,EAAwB,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAoIlG;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE,UAAU,GAAG,MAAM,CAmiBrH"}