@tuidom/core 0.2.0 → 0.2.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.
@@ -8,7 +8,7 @@ import type { StyleVarScope } from "./tuiStyle.js";
8
8
  * Имена — в конвенции color id VS Code ("list.activeSelectionBackground"),
9
9
  * чтобы хост перекрывал дефолты ключами своей темы без функций-мостов;
10
10
  * tuidom-специфика без темного эквивалента — под собственным именем
11
- * ("menu.shortcutForeground", "quickPick.*", "titledPanel.*", "menuBar.*").
11
+ * ("menu.shortcutForeground", "titledPanel.*", "menuBar.*").
12
12
  * Значения — только конкретные числа (packed RGB | DEFAULT_COLOR); сентинелы
13
13
  * INHERITED_* в таблицах запрещены (проверяется в setStyleVars).
14
14
  *
@@ -64,14 +64,6 @@ export declare const STYLE_TOKEN_DEFAULTS: {
64
64
  "input.selectionBackground": number;
65
65
  focusBorder: number;
66
66
  "sash.hoverBorder": number;
67
- "quickInput.foreground": number;
68
- "quickInput.background": number;
69
- "quickPick.border": number;
70
- "quickPick.badgeForeground": number;
71
- "quickPick.shortcutForeground": number;
72
- "quickPick.hintForeground": number;
73
- "quickPick.titleForeground": number;
74
- "quickPick.promptForeground": number;
75
67
  descriptionForeground: number;
76
68
  "editorSuggestWidget.border": number;
77
69
  "editorSuggestWidget.background": number;
@@ -8,7 +8,7 @@ import { DEFAULT_COLOR, packRgb } from "../../common/colorUtils.js";
8
8
  * Имена — в конвенции color id VS Code ("list.activeSelectionBackground"),
9
9
  * чтобы хост перекрывал дефолты ключами своей темы без функций-мостов;
10
10
  * tuidom-специфика без темного эквивалента — под собственным именем
11
- * ("menu.shortcutForeground", "quickPick.*", "titledPanel.*", "menuBar.*").
11
+ * ("menu.shortcutForeground", "titledPanel.*", "menuBar.*").
12
12
  * Значения — только конкретные числа (packed RGB | DEFAULT_COLOR); сентинелы
13
13
  * INHERITED_* в таблицах запрещены (проверяется в setStyleVars).
14
14
  *
@@ -76,14 +76,6 @@ export const STYLE_TOKEN_DEFAULTS = {
76
76
  // ── Sash ──
77
77
  "sash.hoverBorder": packRgb(0, 120, 215),
78
78
  // ── Квик-пик ──
79
- "quickInput.foreground": packRgb(204, 204, 204),
80
- "quickInput.background": packRgb(37, 37, 38),
81
- "quickPick.border": packRgb(83, 83, 83),
82
- "quickPick.badgeForeground": packRgb(150, 190, 100),
83
- "quickPick.shortcutForeground": packRgb(128, 128, 128),
84
- "quickPick.hintForeground": packRgb(100, 150, 200),
85
- "quickPick.titleForeground": packRgb(230, 230, 230),
86
- "quickPick.promptForeground": packRgb(140, 140, 140),
87
79
  descriptionForeground: packRgb(125, 125, 125),
88
80
  // ── Автодополнение ──
89
81
  "editorSuggestWidget.border": packRgb(83, 83, 83),
@@ -20,6 +20,16 @@ export declare class RenderContext {
20
20
  constructor(canvas: TerminalScreen, offset?: Offset, clipRect?: Rect);
21
21
  withOffset(extra: Offset): RenderContext;
22
22
  withClip(rect: Rect): RenderContext;
23
+ /**
24
+ * Патчит ячейку: заданные поля перезаписываются, опущенные остаются
25
+ * прежними (так проходы-подсветки кладут один `bg`, не трогая глиф).
26
+ *
27
+ * Непрозрачная запись ячейки — та, что кладёт свой `char`, — обязана
28
+ * задавать и `style`: иначе ячейка донашивает атрибуты того, кто рисовал
29
+ * здесь раньше в этом же кадре, и оверлей поверх подчёркнутого текста
30
+ * получает чужую волну (`drawText`/`drawBox`/{@link TUIElement.paintOwnBackground}
31
+ * так и делают).
32
+ */
23
33
  setCell(x: number, y: number, cell: CellPatch): void;
24
34
  /**
25
35
  * Читает уже отрисованную ячейку в локальных координатах (тот же оффсет и
@@ -33,6 +43,9 @@ export declare class RenderContext {
33
43
  * Render a text string at (x, y), handling wide chars, tabs, combining marks and emoji.
34
44
  * Each column within [startCol, startCol + maxWidth) is rendered.
35
45
  *
46
+ * Каждая записанная ячейка получает ПОЛНЫЙ стиль: не переданные флаги —
47
+ * {@link StyleFlags.None}, а не то, что лежало в ячейке до текста.
48
+ *
36
49
  * @param x Left screen column (local coordinates)
37
50
  * @param y Screen row (local coordinates)
38
51
  * @param text Raw text to render
@@ -73,6 +86,10 @@ export declare class RenderContext {
73
86
  * @param options fg/bg, пресет `style` (по умолчанию {@link BORDER_ROUNDED} —
74
87
  * канонический стиль оверлеев Vexx), `fill` (залить фон внутри
75
88
  * рамки), `separators` (ряды-разделители)
89
+ *
90
+ * Как и {@link drawText}, кладёт ячейки целиком: флаги стиля сбрасываются в
91
+ * {@link StyleFlags.None}. Рамка — непрозрачная поверхность (обычно оверлей),
92
+ * и подчёркивание текста под ней сквозь неё проступать не должно.
76
93
  */
77
94
  drawBox(x: number, y: number, width: number, height: number, options?: {
78
95
  fg?: number;
@@ -481,6 +498,11 @@ export declare class TUIElement {
481
498
  * считаются «задан»: это намеренная перезаливка цветом родителя (INHERITED_BG)
482
499
  * или инверсия (INHERITED_FG). Выход за границы невозможен — контекст
483
500
  * элемента уже клипован родителем.
501
+ *
502
+ * Заливка непрозрачна, поэтому кладёт ячейку целиком, вместе со сбросом
503
+ * флагов стиля: собственный фон — это новая поверхность, и атрибуты того,
504
+ * что нарисовано под ней раньше в этом кадре (подчёркивание диагностики под
505
+ * попапом, жирный токен под диалогом), на ней проступать не должны.
484
506
  */
485
507
  protected paintOwnBackground(context: RenderContext): void;
486
508
  /** true, если фон задан собственным стилем (см. {@link paintOwnBackground}). */
@@ -1,6 +1,7 @@
1
1
  import { DEFAULT_COLOR } from "../common/colorUtils.js";
2
2
  import { DisplayLine } from "../common/displayLine.js";
3
3
  import { BoxConstraints, Offset, Point, Rect, Size } from "../common/geometryPromitives.js";
4
+ import { StyleFlags } from "../common/styleFlags.js";
4
5
  import { TerminalScreen } from "../rendering/terminalScreen.js";
5
6
  import { BORDER_ROUNDED } from "./borderStyle.js";
6
7
  import { EventPhase, TUIEventBase } from "./events/tuiEventBase.js";
@@ -25,6 +26,16 @@ export class RenderContext {
25
26
  withClip(rect) {
26
27
  return new RenderContext(this.canvas, this.offset, this.clipRect.intersect(rect));
27
28
  }
29
+ /**
30
+ * Патчит ячейку: заданные поля перезаписываются, опущенные остаются
31
+ * прежними (так проходы-подсветки кладут один `bg`, не трогая глиф).
32
+ *
33
+ * Непрозрачная запись ячейки — та, что кладёт свой `char`, — обязана
34
+ * задавать и `style`: иначе ячейка донашивает атрибуты того, кто рисовал
35
+ * здесь раньше в этом же кадре, и оверлей поверх подчёркнутого текста
36
+ * получает чужую волну (`drawText`/`drawBox`/{@link TUIElement.paintOwnBackground}
37
+ * так и делают).
38
+ */
28
39
  setCell(x, y, cell) {
29
40
  const screenX = x + this.offset.dx;
30
41
  const screenY = y + this.offset.dy;
@@ -58,6 +69,9 @@ export class RenderContext {
58
69
  * Render a text string at (x, y), handling wide chars, tabs, combining marks and emoji.
59
70
  * Each column within [startCol, startCol + maxWidth) is rendered.
60
71
  *
72
+ * Каждая записанная ячейка получает ПОЛНЫЙ стиль: не переданные флаги —
73
+ * {@link StyleFlags.None}, а не то, что лежало в ячейке до текста.
74
+ *
61
75
  * @param x Left screen column (local coordinates)
62
76
  * @param y Screen row (local coordinates)
63
77
  * @param text Raw text to render
@@ -84,12 +98,13 @@ export class RenderContext {
84
98
  const w = slot ? slot.displayWidth : 1;
85
99
  const slotStyle = slot && options?.getStyle ? options.getStyle(slot.offset) : undefined;
86
100
  const resolvedStyle = slotStyle !== undefined ? { ...style, ...slotStyle } : style;
101
+ const cellStyle = resolvedStyle?.style ?? StyleFlags.None;
87
102
  if (w === 2 && col + 1 >= maxWidth) {
88
- this.setCell(x + col, y, { char: " ", width: 1, ...resolvedStyle });
103
+ this.setCell(x + col, y, { char: " ", width: 1, ...resolvedStyle, style: cellStyle });
89
104
  col++;
90
105
  }
91
106
  else {
92
- this.setCell(x + col, y, { char, width: w, ...resolvedStyle });
107
+ this.setCell(x + col, y, { char, width: w, ...resolvedStyle, style: cellStyle });
93
108
  col += w;
94
109
  }
95
110
  }
@@ -111,44 +126,49 @@ export class RenderContext {
111
126
  * @param options fg/bg, пресет `style` (по умолчанию {@link BORDER_ROUNDED} —
112
127
  * канонический стиль оверлеев Vexx), `fill` (залить фон внутри
113
128
  * рамки), `separators` (ряды-разделители)
129
+ *
130
+ * Как и {@link drawText}, кладёт ячейки целиком: флаги стиля сбрасываются в
131
+ * {@link StyleFlags.None}. Рамка — непрозрачная поверхность (обычно оверлей),
132
+ * и подчёркивание текста под ней сквозь неё проступать не должно.
114
133
  */
115
134
  drawBox(x, y, width, height, options = {}) {
116
- const style = options.style ?? BORDER_ROUNDED;
135
+ const border = options.style ?? BORDER_ROUNDED;
117
136
  const fg = options.fg;
118
137
  const bg = options.bg;
138
+ const style = StyleFlags.None;
119
139
  const right = x + width - 1;
120
140
  const bottom = y + height - 1;
121
141
  if (options.fill === true) {
122
142
  for (let yy = y; yy <= bottom; yy++) {
123
143
  for (let xx = x; xx <= right; xx++) {
124
- this.setCell(xx, yy, { char: " ", fg, bg });
144
+ this.setCell(xx, yy, { char: " ", fg, bg, style });
125
145
  }
126
146
  }
127
147
  }
128
148
  const separators = new Set(options.separators);
129
149
  // Top border.
130
- this.setCell(x, y, { char: style.topLeft, fg, bg });
131
- this.setCell(right, y, { char: style.topRight, fg, bg });
150
+ this.setCell(x, y, { char: border.topLeft, fg, bg, style });
151
+ this.setCell(right, y, { char: border.topRight, fg, bg, style });
132
152
  for (let xx = x + 1; xx < right; xx++)
133
- this.setCell(xx, y, { char: style.horizontal, fg, bg });
153
+ this.setCell(xx, y, { char: border.horizontal, fg, bg, style });
134
154
  // Side borders (+ separator T-connectors).
135
155
  for (let yy = y + 1; yy < bottom; yy++) {
136
156
  if (separators.has(yy - y)) {
137
- this.setCell(x, yy, { char: style.leftJoint, fg, bg });
138
- this.setCell(right, yy, { char: style.rightJoint, fg, bg });
157
+ this.setCell(x, yy, { char: border.leftJoint, fg, bg, style });
158
+ this.setCell(right, yy, { char: border.rightJoint, fg, bg, style });
139
159
  for (let xx = x + 1; xx < right; xx++)
140
- this.setCell(xx, yy, { char: style.horizontal, fg, bg });
160
+ this.setCell(xx, yy, { char: border.horizontal, fg, bg, style });
141
161
  }
142
162
  else {
143
- this.setCell(x, yy, { char: style.vertical, fg, bg });
144
- this.setCell(right, yy, { char: style.vertical, fg, bg });
163
+ this.setCell(x, yy, { char: border.vertical, fg, bg, style });
164
+ this.setCell(right, yy, { char: border.vertical, fg, bg, style });
145
165
  }
146
166
  }
147
167
  // Bottom border.
148
- this.setCell(x, bottom, { char: style.bottomLeft, fg, bg });
149
- this.setCell(right, bottom, { char: style.bottomRight, fg, bg });
168
+ this.setCell(x, bottom, { char: border.bottomLeft, fg, bg, style });
169
+ this.setCell(right, bottom, { char: border.bottomRight, fg, bg, style });
150
170
  for (let xx = x + 1; xx < right; xx++)
151
- this.setCell(xx, bottom, { char: style.horizontal, fg, bg });
171
+ this.setCell(xx, bottom, { char: border.horizontal, fg, bg, style });
152
172
  }
153
173
  }
154
174
  export class TUIElement {
@@ -1065,6 +1085,11 @@ export class TUIElement {
1065
1085
  * считаются «задан»: это намеренная перезаливка цветом родителя (INHERITED_BG)
1066
1086
  * или инверсия (INHERITED_FG). Выход за границы невозможен — контекст
1067
1087
  * элемента уже клипован родителем.
1088
+ *
1089
+ * Заливка непрозрачна, поэтому кладёт ячейку целиком, вместе со сбросом
1090
+ * флагов стиля: собственный фон — это новая поверхность, и атрибуты того,
1091
+ * что нарисовано под ней раньше в этом кадре (подчёркивание диагностики под
1092
+ * попапом, жирный токен под диалогом), на ней проступать не должны.
1068
1093
  */
1069
1094
  paintOwnBackground(context) {
1070
1095
  if (this.appliedBgValue === undefined)
@@ -1073,7 +1098,7 @@ export class TUIElement {
1073
1098
  const { width, height } = this.layoutSize;
1074
1099
  for (let y = 0; y < height; y++) {
1075
1100
  for (let x = 0; x < width; x++) {
1076
- context.setCell(x, y, { char: " ", fg, bg });
1101
+ context.setCell(x, y, { char: " ", fg, bg, style: StyleFlags.None });
1077
1102
  }
1078
1103
  }
1079
1104
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tuidom/core",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "type": "module",
5
5
  "description": "Experimental terminal UI DOM — core: element tree, flex layout, grid rendering, input parsing. API is unstable.",
6
6
  "license": "MIT",