@tuidom/core 0.2.0 → 0.2.3
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", "
|
|
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", "
|
|
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),
|
|
@@ -158,8 +158,14 @@ export class TuiApplication {
|
|
|
158
158
|
target.dispatchEvent(contextMenuEvent);
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
|
-
// Tab focus cycling (default behavior if not prevented, only on keydown)
|
|
162
|
-
|
|
161
|
+
// Tab focus cycling (default behavior if not prevented, only on keydown).
|
|
162
|
+
// Обход фокуса — только у голого Tab и Shift+Tab: Ctrl+Tab, Alt+Tab и Meta+Tab
|
|
163
|
+
// это отдельные аккорды, и приложение вправе повесить на них своё. Если бы
|
|
164
|
+
// мы крутили кольцо и на них, то нерезолвнувшийся аккорд приложения (его
|
|
165
|
+
// `when` не прошёл — значит preventDefault никто не позвал) уводил бы фокус
|
|
166
|
+
// на случайный элемент. Shift здесь не модификатор аккорда, а направление.
|
|
167
|
+
const plainTab = !event.ctrlKey && !event.altKey && !event.metaKey;
|
|
168
|
+
if (notPrevented && event.key === "Tab" && event.type === "keydown" && plainTab && this.focusManager) {
|
|
163
169
|
const direction = event.shiftKey ? "backward" : "forward";
|
|
164
170
|
this.focusManager.cycleFocus(direction);
|
|
165
171
|
}
|
package/dist/dom/tuiElement.d.ts
CHANGED
|
@@ -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}). */
|
package/dist/dom/tuiElement.js
CHANGED
|
@@ -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
|
|
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:
|
|
131
|
-
this.setCell(right, y, { char:
|
|
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:
|
|
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:
|
|
138
|
-
this.setCell(right, yy, { char:
|
|
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:
|
|
160
|
+
this.setCell(xx, yy, { char: border.horizontal, fg, bg, style });
|
|
141
161
|
}
|
|
142
162
|
else {
|
|
143
|
-
this.setCell(x, yy, { char:
|
|
144
|
-
this.setCell(right, yy, { char:
|
|
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:
|
|
149
|
-
this.setCell(right, bottom, { char:
|
|
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:
|
|
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