@promptctl/rich-js 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/README.md +13 -26
  2. package/package.json +7 -3
  3. package/dist/core/box.d.ts +0 -144
  4. package/dist/core/box.js +0 -391
  5. package/dist/core/cells.d.ts +0 -148
  6. package/dist/core/cells.js +0 -266
  7. package/dist/core/color.d.ts +0 -250
  8. package/dist/core/color.js +0 -1029
  9. package/dist/core/console.d.ts +0 -156
  10. package/dist/core/console.js +0 -472
  11. package/dist/core/emoji.d.ts +0 -24
  12. package/dist/core/emoji.js +0 -391
  13. package/dist/core/export-html.d.ts +0 -24
  14. package/dist/core/export-html.js +0 -106
  15. package/dist/core/export-lines.d.ts +0 -121
  16. package/dist/core/export-lines.js +0 -141
  17. package/dist/core/highlighter.d.ts +0 -33
  18. package/dist/core/highlighter.js +0 -124
  19. package/dist/core/json.d.ts +0 -27
  20. package/dist/core/json.js +0 -53
  21. package/dist/core/markup.d.ts +0 -97
  22. package/dist/core/markup.js +0 -619
  23. package/dist/core/measure.d.ts +0 -27
  24. package/dist/core/measure.js +0 -61
  25. package/dist/core/oklch.d.ts +0 -161
  26. package/dist/core/oklch.js +0 -312
  27. package/dist/core/osc8.d.ts +0 -68
  28. package/dist/core/osc8.js +0 -90
  29. package/dist/core/pretty.d.ts +0 -141
  30. package/dist/core/pretty.js +0 -472
  31. package/dist/core/protocol.d.ts +0 -137
  32. package/dist/core/protocol.js +0 -101
  33. package/dist/core/render.d.ts +0 -84
  34. package/dist/core/render.js +0 -145
  35. package/dist/core/segment.d.ts +0 -142
  36. package/dist/core/segment.js +0 -433
  37. package/dist/core/spinnerData.d.ts +0 -10
  38. package/dist/core/spinnerData.js +0 -115
  39. package/dist/core/strip.d.ts +0 -145
  40. package/dist/core/strip.js +0 -308
  41. package/dist/core/style.d.ts +0 -144
  42. package/dist/core/style.js +0 -723
  43. package/dist/core/subscription.d.ts +0 -12
  44. package/dist/core/subscription.js +0 -12
  45. package/dist/core/text.d.ts +0 -255
  46. package/dist/core/text.js +0 -990
  47. package/dist/core/wrap.d.ts +0 -41
  48. package/dist/core/wrap.js +0 -127
  49. package/dist/host/host-stream.d.ts +0 -30
  50. package/dist/host/host-stream.js +0 -35
  51. package/dist/host/index.d.ts +0 -3
  52. package/dist/host/index.js +0 -2
  53. package/dist/host/terminal-host.d.ts +0 -143
  54. package/dist/host/terminal-host.js +0 -132
  55. package/dist/index.d.ts +0 -87
  56. package/dist/index.js +0 -104
  57. package/dist/node/prompt.d.ts +0 -21
  58. package/dist/node/prompt.js +0 -30
  59. package/dist/node/save.d.ts +0 -17
  60. package/dist/node/save.js +0 -21
  61. package/dist/node/terminal-host.d.ts +0 -84
  62. package/dist/node/terminal-host.js +0 -160
  63. package/dist/node/traceback.d.ts +0 -27
  64. package/dist/node/traceback.js +0 -112
  65. package/dist/renderables/align.d.ts +0 -16
  66. package/dist/renderables/align.js +0 -46
  67. package/dist/renderables/columns.d.ts +0 -61
  68. package/dist/renderables/columns.js +0 -168
  69. package/dist/renderables/constrain.d.ts +0 -15
  70. package/dist/renderables/constrain.js +0 -37
  71. package/dist/renderables/flexStrip.d.ts +0 -41
  72. package/dist/renderables/flexStrip.js +0 -200
  73. package/dist/renderables/group.d.ts +0 -11
  74. package/dist/renderables/group.js +0 -15
  75. package/dist/renderables/layout.d.ts +0 -92
  76. package/dist/renderables/layout.js +0 -315
  77. package/dist/renderables/live.d.ts +0 -47
  78. package/dist/renderables/live.js +0 -131
  79. package/dist/renderables/markdown.d.ts +0 -24
  80. package/dist/renderables/markdown.js +0 -182
  81. package/dist/renderables/padding.d.ts +0 -38
  82. package/dist/renderables/padding.js +0 -140
  83. package/dist/renderables/panel.d.ts +0 -116
  84. package/dist/renderables/panel.js +0 -322
  85. package/dist/renderables/progress.d.ts +0 -90
  86. package/dist/renderables/progress.js +0 -241
  87. package/dist/renderables/progressBar.d.ts +0 -31
  88. package/dist/renderables/progressBar.js +0 -52
  89. package/dist/renderables/prompt.d.ts +0 -49
  90. package/dist/renderables/prompt.js +0 -125
  91. package/dist/renderables/rule.d.ts +0 -24
  92. package/dist/renderables/rule.js +0 -90
  93. package/dist/renderables/spinner.d.ts +0 -29
  94. package/dist/renderables/spinner.js +0 -64
  95. package/dist/renderables/status.d.ts +0 -23
  96. package/dist/renderables/status.js +0 -60
  97. package/dist/renderables/syntax.d.ts +0 -35
  98. package/dist/renderables/syntax.js +0 -114
  99. package/dist/renderables/table.d.ts +0 -182
  100. package/dist/renderables/table.js +0 -697
  101. package/dist/renderables/traceback.d.ts +0 -31
  102. package/dist/renderables/traceback.js +0 -109
  103. package/dist/renderables/tree.d.ts +0 -54
  104. package/dist/renderables/tree.js +0 -159
  105. package/dist/template-bindings/color-funcs.d.ts +0 -87
  106. package/dist/template-bindings/color-funcs.js +0 -219
  107. package/dist/template-bindings/helpers.d.ts +0 -24
  108. package/dist/template-bindings/helpers.js +0 -48
  109. package/dist/template-bindings/index.d.ts +0 -107
  110. package/dist/template-bindings/index.js +0 -144
  111. package/dist/template-bindings/palette-funcs.d.ts +0 -94
  112. package/dist/template-bindings/palette-funcs.js +0 -151
  113. package/dist/template-bindings/style-funcs.d.ts +0 -28
  114. package/dist/template-bindings/style-funcs.js +0 -151
  115. package/dist/themes/buildPalette.d.ts +0 -36
  116. package/dist/themes/buildPalette.js +0 -56
  117. package/dist/themes/colorMath.d.ts +0 -82
  118. package/dist/themes/colorMath.js +0 -254
  119. package/dist/themes/colorRef.d.ts +0 -51
  120. package/dist/themes/colorRef.js +0 -96
  121. package/dist/themes/data/atom-one-dark.d.ts +0 -3
  122. package/dist/themes/data/atom-one-dark.js +0 -158
  123. package/dist/themes/data/atom-one-light.d.ts +0 -3
  124. package/dist/themes/data/atom-one-light.js +0 -158
  125. package/dist/themes/data/catppuccin-frappe.d.ts +0 -3
  126. package/dist/themes/data/catppuccin-frappe.js +0 -158
  127. package/dist/themes/data/catppuccin-latte.d.ts +0 -3
  128. package/dist/themes/data/catppuccin-latte.js +0 -158
  129. package/dist/themes/data/catppuccin-macchiato.d.ts +0 -3
  130. package/dist/themes/data/catppuccin-macchiato.js +0 -158
  131. package/dist/themes/data/catppuccin-mocha.d.ts +0 -3
  132. package/dist/themes/data/catppuccin-mocha.js +0 -158
  133. package/dist/themes/data/cyberpunk.d.ts +0 -17
  134. package/dist/themes/data/cyberpunk.js +0 -191
  135. package/dist/themes/data/default.d.ts +0 -3
  136. package/dist/themes/data/default.js +0 -158
  137. package/dist/themes/data/dracula.d.ts +0 -3
  138. package/dist/themes/data/dracula.js +0 -158
  139. package/dist/themes/data/flexoki.d.ts +0 -3
  140. package/dist/themes/data/flexoki.js +0 -158
  141. package/dist/themes/data/gruvbox.d.ts +0 -3
  142. package/dist/themes/data/gruvbox.js +0 -158
  143. package/dist/themes/data/index.d.ts +0 -35
  144. package/dist/themes/data/index.js +0 -64
  145. package/dist/themes/data/monokai.d.ts +0 -3
  146. package/dist/themes/data/monokai.js +0 -158
  147. package/dist/themes/data/nord.d.ts +0 -3
  148. package/dist/themes/data/nord.js +0 -158
  149. package/dist/themes/data/rose-pine-dawn.d.ts +0 -3
  150. package/dist/themes/data/rose-pine-dawn.js +0 -158
  151. package/dist/themes/data/rose-pine-moon.d.ts +0 -3
  152. package/dist/themes/data/rose-pine-moon.js +0 -158
  153. package/dist/themes/data/rose-pine.d.ts +0 -3
  154. package/dist/themes/data/rose-pine.js +0 -158
  155. package/dist/themes/data/solarized-dark.d.ts +0 -3
  156. package/dist/themes/data/solarized-dark.js +0 -158
  157. package/dist/themes/data/solarized-light.d.ts +0 -3
  158. package/dist/themes/data/solarized-light.js +0 -158
  159. package/dist/themes/data/svg-export.d.ts +0 -3
  160. package/dist/themes/data/svg-export.js +0 -158
  161. package/dist/themes/data/textual-ansi.d.ts +0 -3
  162. package/dist/themes/data/textual-ansi.js +0 -158
  163. package/dist/themes/data/textual-dark.d.ts +0 -3
  164. package/dist/themes/data/textual-dark.js +0 -158
  165. package/dist/themes/data/textual-light.d.ts +0 -3
  166. package/dist/themes/data/textual-light.js +0 -158
  167. package/dist/themes/data/tokyo-night.d.ts +0 -3
  168. package/dist/themes/data/tokyo-night.js +0 -158
  169. package/dist/themes/data/types.d.ts +0 -15
  170. package/dist/themes/data/types.js +0 -1
  171. package/dist/themes/palette.d.ts +0 -21
  172. package/dist/themes/palette.js +0 -28
  173. package/dist/themes/ramp.d.ts +0 -83
  174. package/dist/themes/ramp.js +0 -122
  175. package/dist/themes/registry.d.ts +0 -43
  176. package/dist/themes/registry.js +0 -82
  177. package/dist/themes/terminalThemes.d.ts +0 -54
  178. package/dist/themes/terminalThemes.js +0 -68
  179. package/dist/themes/transpose.d.ts +0 -87
  180. package/dist/themes/transpose.js +0 -138
  181. package/dist/widgets/button.d.ts +0 -49
  182. package/dist/widgets/button.js +0 -206
  183. package/dist/widgets/checkbox.d.ts +0 -41
  184. package/dist/widgets/checkbox.js +0 -155
  185. package/dist/widgets/dropdown.d.ts +0 -67
  186. package/dist/widgets/dropdown.js +0 -453
  187. package/dist/widgets/event-router.d.ts +0 -78
  188. package/dist/widgets/event-router.js +0 -622
  189. package/dist/widgets/focus-manager.d.ts +0 -26
  190. package/dist/widgets/focus-manager.js +0 -193
  191. package/dist/widgets/index.d.ts +0 -22
  192. package/dist/widgets/index.js +0 -15
  193. package/dist/widgets/screen.d.ts +0 -98
  194. package/dist/widgets/screen.js +0 -530
  195. package/dist/widgets/slider.d.ts +0 -57
  196. package/dist/widgets/slider.js +0 -270
  197. package/dist/widgets/static-item.d.ts +0 -40
  198. package/dist/widgets/static-item.js +0 -60
  199. package/dist/widgets/text-input.d.ts +0 -274
  200. package/dist/widgets/text-input.js +0 -1162
  201. package/dist/widgets/toggle.d.ts +0 -44
  202. package/dist/widgets/toggle.js +0 -179
  203. package/dist/widgets/types.d.ts +0 -108
  204. package/dist/widgets/types.js +0 -31
  205. package/dist/widgets/widget-base.d.ts +0 -42
  206. package/dist/widgets/widget-base.js +0 -173
@@ -1,182 +0,0 @@
1
- /**
2
- * Markdown — renders Markdown content to the terminal.
3
- * Uses built-in parsing (no external dependency).
4
- */
5
- import { Segment } from "../core/segment.js";
6
- import { Style } from "../core/style.js";
7
- import { RichText } from "../core/text.js";
8
- import { Rule } from "./rule.js";
9
- import { getStyle } from "../core/protocol.js";
10
- function tokenize(markdown) {
11
- const lines = markdown.split("\n");
12
- const tokens = [];
13
- let i = 0;
14
- while (i < lines.length) {
15
- const line = lines[i];
16
- // Blank line
17
- if (line.trim() === "") {
18
- tokens.push({ type: "blank" });
19
- i++;
20
- continue;
21
- }
22
- // Heading
23
- const headingMatch = /^(#{1,6})\s+(.+)$/.exec(line);
24
- if (headingMatch) {
25
- tokens.push({ type: "heading", level: headingMatch[1].length, text: headingMatch[2] });
26
- i++;
27
- continue;
28
- }
29
- // Horizontal rule
30
- if (/^(?:---+|===+|\*\*\*+)$/.test(line.trim())) {
31
- tokens.push({ type: "hr" });
32
- i++;
33
- continue;
34
- }
35
- // Fenced code block
36
- const codeMatch = /^```(\w*)/.exec(line);
37
- if (codeMatch) {
38
- const lang = codeMatch[1] ?? "";
39
- const codeLines = [];
40
- i++;
41
- while (i < lines.length && !lines[i].startsWith("```")) {
42
- codeLines.push(lines[i]);
43
- i++;
44
- }
45
- i++; // skip closing ```
46
- tokens.push({ type: "code_block", language: lang, code: codeLines.join("\n") });
47
- continue;
48
- }
49
- // Blockquote
50
- if (line.startsWith("> ")) {
51
- const quoteLines = [];
52
- while (i < lines.length && lines[i].startsWith("> ")) {
53
- quoteLines.push(lines[i].slice(2));
54
- i++;
55
- }
56
- tokens.push({ type: "blockquote", text: quoteLines.join("\n") });
57
- continue;
58
- }
59
- // Unordered list
60
- const ulMatch = /^([*\-+])\s+(.+)$/.exec(line);
61
- if (ulMatch) {
62
- tokens.push({ type: "list_item", ordered: false, index: 0, text: ulMatch[2] });
63
- i++;
64
- continue;
65
- }
66
- // Ordered list
67
- const olMatch = /^(\d+)\.\s+(.+)$/.exec(line);
68
- if (olMatch) {
69
- tokens.push({ type: "list_item", ordered: true, index: parseInt(olMatch[1], 10), text: olMatch[2] });
70
- i++;
71
- continue;
72
- }
73
- // Paragraph (collect consecutive non-blank lines)
74
- const paraLines = [];
75
- while (i < lines.length && lines[i].trim() !== "" && !/^#{1,6}\s/.test(lines[i]) && !/^```/.test(lines[i])) {
76
- paraLines.push(lines[i]);
77
- i++;
78
- }
79
- tokens.push({ type: "paragraph", text: paraLines.join(" ") });
80
- }
81
- return tokens;
82
- }
83
- function applyInlineStyles(text) {
84
- const result = new RichText("", { end: "" });
85
- // Process inline patterns
86
- const inlineRe = /(\*\*(.+?)\*\*|\*(.+?)\*|`(.+?)`|\[(.+?)\]\((.+?)\))/g;
87
- let lastIdx = 0;
88
- let match;
89
- while ((match = inlineRe.exec(text)) !== null) {
90
- // Add text before match
91
- if (match.index > lastIdx) {
92
- result.append(text.slice(lastIdx, match.index));
93
- }
94
- if (match[2]) {
95
- // Bold: **text**
96
- result.append(match[2], "bold");
97
- }
98
- else if (match[3]) {
99
- // Italic: *text*
100
- result.append(match[3], "italic");
101
- }
102
- else if (match[4]) {
103
- // Inline code: `text`
104
- result.append(match[4], "markdown.code");
105
- }
106
- else if (match[5] && match[6]) {
107
- // Link: [text](url)
108
- result.append(match[5], new Style({ link: match[6] }));
109
- }
110
- lastIdx = match.index + match[0].length;
111
- }
112
- // Remaining text
113
- if (lastIdx < text.length) {
114
- result.append(text.slice(lastIdx));
115
- }
116
- return result;
117
- }
118
- export class Markdown {
119
- markdown;
120
- inlineCodeStyle;
121
- hyperlinks;
122
- constructor(markdown, options) {
123
- this.markdown = markdown;
124
- this.inlineCodeStyle = options?.inlineCodeStyle ?? "markdown.code";
125
- this.hyperlinks = options?.hyperlinks !== false;
126
- }
127
- *render(options) {
128
- const tokens = tokenize(this.markdown);
129
- for (const token of tokens) {
130
- switch (token.type) {
131
- case "heading": {
132
- const style = getStyle(options, `markdown.h${Math.min(token.level, 4)}`);
133
- const text = applyInlineStyles(token.text);
134
- yield* Segment.applyStyle([...text.render(options)], style);
135
- yield Segment.line();
136
- break;
137
- }
138
- case "paragraph": {
139
- const text = applyInlineStyles(token.text);
140
- yield* text.render(options);
141
- yield Segment.line();
142
- break;
143
- }
144
- case "code_block": {
145
- const codeStyle = getStyle(options, "markdown.code");
146
- const lines = token.code.split("\n");
147
- for (const line of lines) {
148
- yield new Segment(line, codeStyle);
149
- yield Segment.line();
150
- }
151
- break;
152
- }
153
- case "hr": {
154
- const rule = new Rule(undefined, { style: "markdown.hr" });
155
- yield* rule.render(options);
156
- break;
157
- }
158
- case "list_item": {
159
- const bullet = token.ordered ? `${token.index}. ` : " • ";
160
- yield new Segment(bullet);
161
- const text = applyInlineStyles(token.text);
162
- yield* text.render({ ...options, maxWidth: options.maxWidth - bullet.length });
163
- break;
164
- }
165
- case "blockquote": {
166
- const quoteStyle = Style.parse("dim italic");
167
- yield new Segment("▎ ", getStyle(options, "markdown.hr"));
168
- const text = applyInlineStyles(token.text);
169
- yield* Segment.applyStyle([...text.render(options)], quoteStyle);
170
- yield Segment.line();
171
- break;
172
- }
173
- case "blank":
174
- yield Segment.line();
175
- break;
176
- }
177
- }
178
- }
179
- measure(options) {
180
- return { minimum: 1, maximum: options.maxWidth };
181
- }
182
- }
@@ -1,38 +0,0 @@
1
- /**
2
- * Padding — wraps a renderable with whitespace padding on all four sides.
3
- */
4
- import { Segment } from "../core/segment.js";
5
- import { Style } from "../core/style.js";
6
- import type { Renderable, Measurable, RenderOptions } from "../core/protocol.js";
7
- export type PaddingDimensions = number | [number, number] | [number, number, number, number];
8
- /**
9
- * Parses the shapes a caller may write padding in — one number, a vertical/
10
- * horizontal pair, or all four sides — into the four-sided form every
11
- * renderable indexes by, flooring each side at zero.
12
- *
13
- * [LAW:parse-dont-validate] This is the one crossing between the public
14
- * padding vocabulary and the internal tuple, which is why the floor lives
15
- * here and nowhere downstream: past this point `" ".repeat(left)` is safe in
16
- * any renderable without asking what the caller passed. A negative side used
17
- * to reach the renderers, where `Panel` drew content rows wider than its own
18
- * border and `Table` threw outright.
19
- */
20
- export declare function normalizePadding(padding: PaddingDimensions): [number, number, number, number];
21
- export declare class Padding implements Renderable, Measurable {
22
- readonly renderable: Renderable;
23
- readonly top: number;
24
- readonly right: number;
25
- readonly bottom: number;
26
- readonly left: number;
27
- readonly style: string | Style;
28
- readonly expand: boolean;
29
- constructor(renderable: Renderable, padding: PaddingDimensions, options?: {
30
- style?: string | Style;
31
- expand?: boolean;
32
- });
33
- render(rawOptions: RenderOptions): Iterable<Segment>;
34
- measure(rawOptions: RenderOptions): {
35
- minimum: number;
36
- maximum: number;
37
- };
38
- }
@@ -1,140 +0,0 @@
1
- /**
2
- * Padding — wraps a renderable with whitespace padding on all four sides.
3
- */
4
- import { Segment } from "../core/segment.js";
5
- import { cellCount } from "../core/cells.js";
6
- import { NULL_STYLE } from "../core/style.js";
7
- import { Measurement } from "../core/measure.js";
8
- import { getStyle, isMeasurable, withBoundedWidth, withCellWidth } from "../core/protocol.js";
9
- /**
10
- * Parses the shapes a caller may write padding in — one number, a vertical/
11
- * horizontal pair, or all four sides — into the four-sided form every
12
- * renderable indexes by, flooring each side at zero.
13
- *
14
- * [LAW:parse-dont-validate] This is the one crossing between the public
15
- * padding vocabulary and the internal tuple, which is why the floor lives
16
- * here and nowhere downstream: past this point `" ".repeat(left)` is safe in
17
- * any renderable without asking what the caller passed. A negative side used
18
- * to reach the renderers, where `Panel` drew content rows wider than its own
19
- * border and `Table` threw outright.
20
- */
21
- export function normalizePadding(padding) {
22
- // A padding side is a count of cells like any other, so it is parsed by the
23
- // same rule rather than by a second copy of it: a fractional side reaches
24
- // `" ".repeat`, which truncates, while the rows around it are measured
25
- // arithmetically — so the padding and the border disagree and the frame
26
- // breaks. `cellCount`'s header carries why the comparison, not `Math.max`.
27
- //
28
- // `Infinity` is where a side stops being an offer and the rule needs the one
29
- // addition. An unbounded *offer* is a question a renderable can answer, so
30
- // `cellCount` passes it through; an unbounded *side* is a quantity and there
31
- // is nothing to draw. Unparsed it reached `budget -= got` as
32
- // `Infinity - Infinity`, and `new Padding(text, Infinity).measure(...)`
33
- // handed back `{NaN, NaN}` from a public API.
34
- const side = (n) => (Number.isFinite(n) ? cellCount(n) : 0);
35
- const sides = typeof padding === "number"
36
- ? [padding, padding, padding, padding]
37
- : padding.length === 2
38
- ? [padding[0], padding[1], padding[0], padding[1]]
39
- : padding;
40
- return [side(sides[0]), side(sides[1]), side(sides[2]), side(sides[3])];
41
- }
42
- /**
43
- * Divides the requested width once into the three spans a padded row is made
44
- * of, in the order they are worth spending cells on.
45
- *
46
- * The three used to be derived separately and disagree where it matters:
47
- * `render` took the canvas as `Math.max(1, maxWidth - left - right)`, which
48
- * clamps *up*, so a padding of 1 inside a 2-cell request drew 3-cell content
49
- * rows beside 2-cell blank rows — an open frame the terminal then soft-wraps.
50
- * Content takes its first cell before padding takes any, for the reason
51
- * `layoutPanel` gives: a squeeze should cost you the decoration, not the thing
52
- * being decorated.
53
- */
54
- function layoutPadding(outerWidth, leftWanted, rightWanted) {
55
- let budget = cellCount(outerWidth);
56
- const take = (want) => {
57
- const got = Math.min(want, budget);
58
- budget -= got;
59
- return got;
60
- };
61
- const firstContentCell = take(1);
62
- const left = take(leftWanted);
63
- const right = take(rightWanted);
64
- return { left, contentWidth: firstContentCell + budget, right };
65
- }
66
- /** The full width of a padded row — the division, added back up. */
67
- function rowWidth(geometry) {
68
- return geometry.left + geometry.contentWidth + geometry.right;
69
- }
70
- export class Padding {
71
- renderable;
72
- top;
73
- right;
74
- bottom;
75
- left;
76
- style;
77
- expand;
78
- constructor(renderable, padding, options) {
79
- const [top, right, bottom, left] = normalizePadding(padding);
80
- this.renderable = renderable;
81
- this.top = top;
82
- this.right = right;
83
- this.bottom = bottom;
84
- this.left = left;
85
- this.style = options?.style ?? NULL_STYLE;
86
- this.expand = options?.expand !== false;
87
- }
88
- *render(rawOptions) {
89
- const options = withBoundedWidth(rawOptions, this);
90
- const geometry = layoutPadding(options.maxWidth, this.left, this.right);
91
- const innerOptions = {
92
- ...options,
93
- maxWidth: geometry.contentWidth,
94
- };
95
- const segments = [...this.renderable.render(innerOptions)];
96
- const lines = Segment.splitLines(segments);
97
- const resolved = getStyle(options, this.style);
98
- const style = resolved.isNull ? undefined : resolved;
99
- // Zero-length spans need no branch to suppress: the wire boundary drops
100
- // empty segments, so a padding the width could not afford emits nothing.
101
- const leftPad = new Segment(" ".repeat(geometry.left), style);
102
- const rightPad = new Segment(" ".repeat(geometry.right), style);
103
- const blankLine = new Segment(" ".repeat(rowWidth(geometry)), style);
104
- for (let i = 0; i < this.top; i++) {
105
- yield blankLine;
106
- yield Segment.line();
107
- }
108
- for (const line of lines) {
109
- yield leftPad;
110
- // `expand` is the pad half of this call; the crop half is unconditional,
111
- // because a child that ignored the canvas it was handed (a Table at its
112
- // natural width) would otherwise burst the padding around it.
113
- yield* Segment.adjustLineLength(line, geometry.contentWidth, style, this.expand);
114
- yield rightPad;
115
- yield Segment.line();
116
- }
117
- for (let i = 0; i < this.bottom; i++) {
118
- yield blankLine;
119
- yield Segment.line();
120
- }
121
- }
122
- measure(rawOptions) {
123
- const options = withCellWidth(rawOptions);
124
- const geometry = layoutPadding(options.maxWidth, this.left, this.right);
125
- const overhead = geometry.left + geometry.right;
126
- if (isMeasurable(this.renderable)) {
127
- const measurement = Measurement.get({ ...options, maxWidth: geometry.contentWidth }, this.renderable);
128
- // The ceiling is what was offered, and it wins over what the child asks
129
- // for: a range whose floor sits above its own ceiling — this returned
130
- // {8, 8} for three cells of padding inside a two-cell offer — is one no
131
- // parent layout can divide.
132
- const maximum = Math.min(options.maxWidth, measurement.maximum + overhead);
133
- return {
134
- minimum: Math.min(measurement.minimum + overhead, maximum),
135
- maximum,
136
- };
137
- }
138
- return { minimum: overhead, maximum: options.maxWidth };
139
- }
140
- }
@@ -1,116 +0,0 @@
1
- /**
2
- * Panel — a bordered box that wraps content, with optional title and subtitle.
3
- */
4
- import { Segment } from "../core/segment.js";
5
- import { Style } from "../core/style.js";
6
- import { Box } from "../core/box.js";
7
- import { RichText } from "../core/text.js";
8
- import type { PaddingDimensions } from "./padding.js";
9
- import type { Renderable, Measurable, RenderOptions } from "../core/protocol.js";
10
- /**
11
- * A lazily-resolved border accessory. Strings render inline in the
12
- * border style; a `RichText` accessory contributes ONLY its wrapping
13
- * `style` (per-range spans within the RichText are not preserved — the
14
- * accessory is a small status indicator, not an arbitrary span carrier).
15
- * A function form is evaluated at render time, *after* content has been
16
- * rendered for the current frame — use this when the accessory mirrors
17
- * state that the wrapped renderable populates during its own `render()`
18
- * (e.g. a widget's post-render scroll position).
19
- */
20
- export type BorderAccessory = string | RichText | (() => string | RichText | undefined);
21
- export interface PanelOptions {
22
- box?: Box;
23
- title?: string | RichText;
24
- subtitle?: string | RichText;
25
- /**
26
- * Right-aligned accessory in the bottom border, just left of the
27
- * `bottomRight` corner. Coexists with `subtitle` — the subtitle
28
- * remains centered in the remaining space. Padded with a leading/
29
- * trailing space like `title`/`subtitle`, so passing `"[14/102]"`
30
- * renders as `─ [14/102] ┘`.
31
- */
32
- bottomRightAccessory?: BorderAccessory;
33
- expand?: boolean;
34
- style?: string | Style;
35
- borderStyle?: string | Style;
36
- /**
37
- * Style for the title text in the top border. Defaults to `borderStyle`
38
- * (i.e. title inherits the border color). Set independently when the
39
- * title should pop relative to the border.
40
- */
41
- titleStyle?: string | Style;
42
- /**
43
- * Style for the subtitle text in the bottom border. Defaults to
44
- * `borderStyle`.
45
- */
46
- subtitleStyle?: string | Style;
47
- width?: number;
48
- padding?: PaddingDimensions;
49
- }
50
- export declare class Panel implements Renderable, Measurable {
51
- readonly renderable: Renderable;
52
- readonly box: Box;
53
- readonly title: string | RichText | undefined;
54
- readonly subtitle: string | RichText | undefined;
55
- readonly bottomRightAccessory: BorderAccessory | undefined;
56
- readonly expand: boolean;
57
- readonly style: string | Style;
58
- readonly borderStyle: string | Style;
59
- readonly titleStyle: string | Style | undefined;
60
- readonly subtitleStyle: string | Style | undefined;
61
- readonly width: number | undefined;
62
- readonly padding: [number, number, number, number];
63
- constructor(content: string | RichText | Renderable, options?: PanelOptions);
64
- render(rawOptions: RenderOptions): Iterable<Segment>;
65
- /**
66
- * The wrapped renderable's lines, laid out on a canvas `contentWidth` cells
67
- * wide. Below width 3 a panel is all frame and the canvas holds no lines —
68
- * but the render still happens, because a `bottomRightAccessory` thunk
69
- * fires at every width and reads state this render populates.
70
- */
71
- private _renderContent;
72
- /**
73
- * One row of the panel body: frame column, span, frame column.
74
- *
75
- * [LAW:single-enforcer] `adjustLineLength` is the one place a width is
76
- * decided here, and it runs twice against two different widths. The first
77
- * pass crops content that rendered wider than the canvas it was handed (a
78
- * `Table` at its natural width, say) back to the canvas, so an oversized
79
- * child is trimmed rather than allowed to eat the right-hand padding. The
80
- * second fills the rest of the span, which is the trailing padding and any
81
- * shortfall in one stroke.
82
- */
83
- private _renderRow;
84
- measure(rawOptions: RenderOptions): {
85
- minimum: number;
86
- maximum: number;
87
- };
88
- /**
89
- * The width this panel wants when nothing declared one for it: its content
90
- * plus its own frame, both read off the division it will render against.
91
- *
92
- * [LAW:one-source-of-truth] `measure` and `_getPanelWidth` ask this same
93
- * question, and each used to work it out itself — the same `layoutPanel`, the
94
- * same `frameOverhead`, the same `Math.min(maxWidth, maximum + overhead)`,
95
- * written twice. That is the pattern `_declaredWidth` below was extracted to
96
- * stop, left standing for the fit case; changing how overhead is derived in
97
- * one copy is all it would take to put `measure` and `render` back into the
98
- * disagreement this epic spent itself closing.
99
- */
100
- private _fitRange;
101
- /**
102
- * The width this panel was told to be, as a count of cells.
103
- *
104
- * [LAW:one-source-of-truth] `measure` and `_getPanelWidth` answer the same
105
- * question about the same field, so they read it from here. Answered
106
- * separately, `measure` reported nine cells of content while `render` drew the
107
- * declared twelve, and the parent that divided space from the range got a
108
- * panel three cells wider than the share it granted.
109
- */
110
- private get _declaredWidth();
111
- private _getPanelWidth;
112
- private _renderTopBorder;
113
- private _renderBottomBorder;
114
- private _resolveAccessory;
115
- static fit(content: string | RichText | Renderable, options?: Omit<PanelOptions, "expand">): Panel;
116
- }