@tuidom/core 0.5.0 → 0.5.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.
@@ -47,9 +47,6 @@ export declare const STYLE_TOKEN_DEFAULTS: {
47
47
  "tab.inactiveForeground": number;
48
48
  "tab.inactiveBackground": number;
49
49
  "editorGroupHeader.tabsBackground": number;
50
- "panel.background": number;
51
- "panelTitle.inactiveForeground": number;
52
- "panel.border": number;
53
50
  "titledPanel.titleForeground": number;
54
51
  "terminal.foreground": number;
55
52
  "terminal.background": number;
@@ -53,10 +53,10 @@ export const STYLE_TOKEN_DEFAULTS = {
53
53
  "tab.inactiveForeground": packRgb(150, 150, 150),
54
54
  "tab.inactiveBackground": packRgb(45, 45, 45),
55
55
  "editorGroupHeader.tabsBackground": packRgb(37, 37, 38),
56
- // ── Панель ──
57
- "panel.background": packRgb(24, 24, 24),
58
- "panelTitle.inactiveForeground": packRgb(142, 142, 142),
59
- "panel.border": packRgb(43, 43, 43),
56
+ // ── Панель с заголовком ──
57
+ // Дефолтов `panel.*` здесь больше нет: виджет нижней панели уехал в vexx
58
+ // (прикладной — его API оперировал понятиями панели IDE), и токены вместе с
59
+ // ним, в его реестр цветов.
60
60
  "titledPanel.titleForeground": packRgb(130, 130, 130),
61
61
  // ── Терминал ──
62
62
  "terminal.foreground": DEFAULT_COLOR,
@@ -35,8 +35,13 @@ export declare class TuiApplication {
35
35
  /**
36
36
  * Schedules a deferred render via setImmediate.
37
37
  * Batches multiple markDirty() calls into a single frame.
38
- * Skips rendering if layout is already clean (e.g. a synchronous
38
+ * Skips rendering if there is nothing to repaint (e.g. a synchronous
39
39
  * renderFrame from handleInput already ran).
40
+ *
41
+ * Гейт — {@link TUIElement.needsRepaint}, а не layout-грязь: layout снимает
42
+ * кто угодно (ленивый фоллбэк `layoutSize` у хит-теста мыши, инспектора,
43
+ * измеряющего виджета), и гейт по ней ронял уже запланированный кадр
44
+ * насовсем — экран ретейн-буфер, старые ячейки так и оставались на нём.
40
45
  */
41
46
  scheduleRender(): void;
42
47
  private handleInput;
@@ -50,6 +55,11 @@ export declare class TuiApplication {
50
55
  * жгли CPU впустую. Стилевые изменения гейт проходят: markStyleDirty
51
56
  * заканчивается markDirty. Синхронность оставлена намеренно: тесты и
52
57
  * обработчики читают экран/геометрию сразу после события.
58
+ *
59
+ * Гейт — {@link TUIElement.needsRepaint} (см. {@link scheduleRender}): сам
60
+ * хит-тест мыши читает `layoutSize` и гасит layout-грязь, так что гейт по
61
+ * ней терял кадр, помеченный ДО этого события (например ответ субпроцесса,
62
+ * пришедший между press и release одного клика).
53
63
  */
54
64
  private renderAfterInput;
55
65
  private handleResize;
@@ -109,8 +109,13 @@ export class TuiApplication {
109
109
  /**
110
110
  * Schedules a deferred render via setImmediate.
111
111
  * Batches multiple markDirty() calls into a single frame.
112
- * Skips rendering if layout is already clean (e.g. a synchronous
112
+ * Skips rendering if there is nothing to repaint (e.g. a synchronous
113
113
  * renderFrame from handleInput already ran).
114
+ *
115
+ * Гейт — {@link TUIElement.needsRepaint}, а не layout-грязь: layout снимает
116
+ * кто угодно (ленивый фоллбэк `layoutSize` у хит-теста мыши, инспектора,
117
+ * измеряющего виджета), и гейт по ней ронял уже запланированный кадр
118
+ * насовсем — экран ретейн-буфер, старые ячейки так и оставались на нём.
114
119
  */
115
120
  scheduleRender() {
116
121
  if (this.renderScheduled)
@@ -118,7 +123,7 @@ export class TuiApplication {
118
123
  this.renderScheduled = true;
119
124
  setImmediate(() => {
120
125
  this.renderScheduled = false;
121
- if (this.root?.isLayoutDirty) {
126
+ if (this.root?.needsRepaint === true) {
122
127
  this.renderFrame();
123
128
  }
124
129
  });
@@ -194,9 +199,14 @@ export class TuiApplication {
194
199
  * жгли CPU впустую. Стилевые изменения гейт проходят: markStyleDirty
195
200
  * заканчивается markDirty. Синхронность оставлена намеренно: тесты и
196
201
  * обработчики читают экран/геометрию сразу после события.
202
+ *
203
+ * Гейт — {@link TUIElement.needsRepaint} (см. {@link scheduleRender}): сам
204
+ * хит-тест мыши читает `layoutSize` и гасит layout-грязь, так что гейт по
205
+ * ней терял кадр, помеченный ДО этого события (например ответ субпроцесса,
206
+ * пришедший между press и release одного клика).
197
207
  */
198
208
  renderAfterInput() {
199
- if (this.root?.isLayoutDirty) {
209
+ if (this.root?.needsRepaint === true) {
200
210
  this.renderFrame();
201
211
  }
202
212
  }
@@ -133,6 +133,23 @@ export declare class TUIElement {
133
133
  private hasPaintDirtyDescendant;
134
134
  private lastPaintedRect;
135
135
  private pendingDetachDamage;
136
+ /**
137
+ * Есть ли что отдать следующему кадру в этом поддереве: кто-то просил
138
+ * перерисовку ({@link markDirty}) или отцепил поддерево, и кадра с тех пор
139
+ * не было.
140
+ *
141
+ * Это — и только это — гейт отложенного кадра (`TuiApplication`
142
+ * `scheduleRender`) и кадра после ввода. В отличие от
143
+ * {@link isLayoutDirty}, снимается ТОЛЬКО damage-обходом настоящего кадра
144
+ * ({@link collectDamage}): layout снимает кто угодно — ленивый фоллбэк
145
+ * геттера {@link layoutSize} зовут хит-тест мыши
146
+ * ({@link elementFromPoint}), инспектор и любой виджет, измеряющий соседа.
147
+ * Пока гейтом была layout-грязь, такой читатель гасил флаг посреди
148
+ * ожидания, и запланированный кадр не состоялся вовсе — а экран
149
+ * ретейн-буфер, так что старые ячейки оставались на нём до следующей
150
+ * несвязанной перерисовки.
151
+ */
152
+ get needsRepaint(): boolean;
136
153
  protected _parent: TUIElement | null;
137
154
  private isRootAnchor;
138
155
  private requestRenderCallback;
@@ -200,6 +200,28 @@ export class TUIElement {
200
200
  lastPaintedRect = null;
201
201
  // Только на корне: rect'ы поддеревьев, отцеплённых с последнего кадра.
202
202
  pendingDetachDamage = [];
203
+ /**
204
+ * Есть ли что отдать следующему кадру в этом поддереве: кто-то просил
205
+ * перерисовку ({@link markDirty}) или отцепил поддерево, и кадра с тех пор
206
+ * не было.
207
+ *
208
+ * Это — и только это — гейт отложенного кадра (`TuiApplication`
209
+ * `scheduleRender`) и кадра после ввода. В отличие от
210
+ * {@link isLayoutDirty}, снимается ТОЛЬКО damage-обходом настоящего кадра
211
+ * ({@link collectDamage}): layout снимает кто угодно — ленивый фоллбэк
212
+ * геттера {@link layoutSize} зовут хит-тест мыши
213
+ * ({@link elementFromPoint}), инспектор и любой виджет, измеряющий соседа.
214
+ * Пока гейтом была layout-грязь, такой читатель гасил флаг посреди
215
+ * ожидания, и запланированный кадр не состоялся вовсе — а экран
216
+ * ретейн-буфер, так что старые ячейки оставались на нём до следующей
217
+ * несвязанной перерисовки.
218
+ */
219
+ get needsRepaint() {
220
+ return (this.isPaintDirty ||
221
+ this.hasPaintDirtyDescendant ||
222
+ this.isLayoutDirty ||
223
+ this.pendingDetachDamage.length > 0);
224
+ }
203
225
  _parent = null;
204
226
  // Якорь дерева: выставляется setAsRoot() (BodyElement, тестовые корни).
205
227
  // Сам root НЕ кэшируется — getRoot() выводит его из цепочки родителей.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tuidom/core",
3
- "version": "0.5.0",
3
+ "version": "0.5.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",