@tuidom/elements 0.1.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.
- package/dist/body/bodyElement.d.ts +33 -0
- package/dist/body/bodyElement.js +87 -0
- package/dist/button/buttonElement.d.ts +18 -0
- package/dist/button/buttonElement.js +68 -0
- package/dist/completionlist/completionDetailsElement.d.ts +49 -0
- package/dist/completionlist/completionDetailsElement.js +165 -0
- package/dist/completionlist/completionItemKindIcon.d.ts +2 -0
- package/dist/completionlist/completionItemKindIcon.js +43 -0
- package/dist/completionlist/completionListElement.d.ts +102 -0
- package/dist/completionlist/completionListElement.js +309 -0
- package/dist/completionlist/completionWidgetElement.d.ts +41 -0
- package/dist/completionlist/completionWidgetElement.js +102 -0
- package/dist/contextview/contextMenuController.d.ts +23 -0
- package/dist/contextview/contextMenuController.js +75 -0
- package/dist/contextview/overlayHostElement.d.ts +23 -0
- package/dist/contextview/overlayHostElement.js +47 -0
- package/dist/editorgroup/editorTabItemElement.d.ts +41 -0
- package/dist/editorgroup/editorTabItemElement.js +186 -0
- package/dist/editorgroup/editorTabStripElement.d.ts +33 -0
- package/dist/editorgroup/editorTabStripElement.js +118 -0
- package/dist/editorpart/editorPartElement.d.ts +95 -0
- package/dist/editorpart/editorPartElement.js +285 -0
- package/dist/inputbox/inputElement.d.ts +34 -0
- package/dist/inputbox/inputElement.js +207 -0
- package/dist/inputbox/inputState.d.ts +69 -0
- package/dist/inputbox/inputState.js +326 -0
- package/dist/layout/boxContainerElement.d.ts +27 -0
- package/dist/layout/boxContainerElement.js +121 -0
- package/dist/layout/boxElement.d.ts +4 -0
- package/dist/layout/boxElement.js +30 -0
- package/dist/layout/fillerElement.d.ts +12 -0
- package/dist/layout/fillerElement.js +16 -0
- package/dist/layout/fitContentElement.d.ts +18 -0
- package/dist/layout/fitContentElement.js +46 -0
- package/dist/layout/hFlexElement.d.ts +26 -0
- package/dist/layout/hFlexElement.js +134 -0
- package/dist/layout/paddingContainerElement.d.ts +30 -0
- package/dist/layout/paddingContainerElement.js +88 -0
- package/dist/layout/sizedBoxElement.d.ts +30 -0
- package/dist/layout/sizedBoxElement.js +74 -0
- package/dist/layout/vFlexElement.d.ts +32 -0
- package/dist/layout/vFlexElement.js +136 -0
- package/dist/layout/vStackElement.d.ts +18 -0
- package/dist/layout/vStackElement.js +74 -0
- package/dist/list/listViewElement.d.ts +232 -0
- package/dist/list/listViewElement.js +944 -0
- package/dist/menu/menuBarElement.d.ts +47 -0
- package/dist/menu/menuBarElement.js +285 -0
- package/dist/menu/menuBarItemElement.d.ts +20 -0
- package/dist/menu/menuBarItemElement.js +68 -0
- package/dist/menu/popupMenuElement.d.ts +81 -0
- package/dist/menu/popupMenuElement.js +318 -0
- package/dist/menu/popupMenuItemElement.d.ts +24 -0
- package/dist/menu/popupMenuItemElement.js +89 -0
- package/dist/panel/panelContainerElement.d.ts +64 -0
- package/dist/panel/panelContainerElement.js +219 -0
- package/dist/quickpick/quickPickElement.d.ts +161 -0
- package/dist/quickpick/quickPickElement.js +561 -0
- package/dist/sash/sashElement.d.ts +30 -0
- package/dist/sash/sashElement.js +78 -0
- package/dist/scrollbar/iScrollable.d.ts +8 -0
- package/dist/scrollbar/iScrollable.js +1 -0
- package/dist/scrollbar/scrollBarRenderer.d.ts +36 -0
- package/dist/scrollbar/scrollBarRenderer.js +76 -0
- package/dist/scrollbar/scrollContainerElement.d.ts +39 -0
- package/dist/scrollbar/scrollContainerElement.js +91 -0
- package/dist/scrollbar/scrollViewport.d.ts +28 -0
- package/dist/scrollbar/scrollViewport.js +65 -0
- package/dist/scrollbar/scrollableElement.d.ts +22 -0
- package/dist/scrollbar/scrollableElement.js +42 -0
- package/dist/selectbox/selectBoxElement.d.ts +48 -0
- package/dist/selectbox/selectBoxElement.js +161 -0
- package/dist/terminal/encodeKeyForPty.d.ts +3 -0
- package/dist/terminal/encodeKeyForPty.js +56 -0
- package/dist/terminal/terminalViewElement.d.ts +17 -0
- package/dist/terminal/terminalViewElement.js +172 -0
- package/dist/text/textBlockElement.d.ts +13 -0
- package/dist/text/textBlockElement.js +35 -0
- package/dist/text/textLabelElement.d.ts +28 -0
- package/dist/text/textLabelElement.js +77 -0
- package/dist/titledpanel/titledPanelElement.d.ts +14 -0
- package/dist/titledpanel/titledPanelElement.js +40 -0
- package/dist/tree/iTreeDataProvider.d.ts +19 -0
- package/dist/tree/iTreeDataProvider.js +1 -0
- package/dist/tree/treeViewElement.d.ts +116 -0
- package/dist/tree/treeViewElement.js +748 -0
- package/dist/workbenchlayout/workbenchLayoutElement.d.ts +60 -0
- package/dist/workbenchlayout/workbenchLayoutElement.js +203 -0
- package/package.json +33 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { BoxConstraints, Size } from "@tuidom/core/common/geometryPromitives";
|
|
2
|
+
import { StyleFlags } from "@tuidom/core/common/styleFlags";
|
|
3
|
+
import { RenderContext, TUIElement } from "@tuidom/core/dom/tuiElement";
|
|
4
|
+
const CLOSE_CHAR = "×";
|
|
5
|
+
const MODIFIED_CHAR = "●";
|
|
6
|
+
// Codicon-замок — тот же глиф, которым VS Code метит read-only вкладку.
|
|
7
|
+
// Пишется escape'ом, а не литералом: глиф из Private Use Area не переживает
|
|
8
|
+
// копирование через инструменты и тихо превращается в пустую строку.
|
|
9
|
+
const READONLY_CHAR = "\uea75"; // nf-cod-lock
|
|
10
|
+
export class EditorTabItemElement extends TUIElement {
|
|
11
|
+
label;
|
|
12
|
+
icon;
|
|
13
|
+
iconColor;
|
|
14
|
+
modified;
|
|
15
|
+
readOnly;
|
|
16
|
+
paddingLeft;
|
|
17
|
+
paddingRight;
|
|
18
|
+
hovered = false;
|
|
19
|
+
onActivate = null;
|
|
20
|
+
onClose = null;
|
|
21
|
+
constructor(label, icon, iconColor, options) {
|
|
22
|
+
super();
|
|
23
|
+
this.label = label;
|
|
24
|
+
this.icon = icon;
|
|
25
|
+
this.iconColor = iconColor;
|
|
26
|
+
this.modified = options?.modified ?? false;
|
|
27
|
+
this.readOnly = options?.readOnly ?? false;
|
|
28
|
+
this.paddingLeft = options?.paddingLeft ?? 1;
|
|
29
|
+
this.paddingRight = options?.paddingRight ?? 1;
|
|
30
|
+
this.addEventListener("click", (event) => {
|
|
31
|
+
const mouseEvent = event;
|
|
32
|
+
// Middle click closes the tab regardless of where it lands (VSCode behaviour).
|
|
33
|
+
if (mouseEvent.button === "middle") {
|
|
34
|
+
this.onClose?.();
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const closeStart = this.getCloseButtonStart();
|
|
38
|
+
if (mouseEvent.localX >= closeStart && mouseEvent.localX < closeStart + CLOSE_CHAR.length) {
|
|
39
|
+
this.onClose?.();
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
this.onActivate?.();
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
this.addEventListener("mouseenter", () => {
|
|
46
|
+
if (this.hovered)
|
|
47
|
+
return;
|
|
48
|
+
this.hovered = true;
|
|
49
|
+
this.markDirty();
|
|
50
|
+
});
|
|
51
|
+
this.addEventListener("mouseleave", () => {
|
|
52
|
+
if (!this.hovered)
|
|
53
|
+
return;
|
|
54
|
+
this.hovered = false;
|
|
55
|
+
this.markDirty();
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
getLabel() {
|
|
59
|
+
return this.label;
|
|
60
|
+
}
|
|
61
|
+
setLabel(label) {
|
|
62
|
+
this.label = label;
|
|
63
|
+
this.markDirty();
|
|
64
|
+
}
|
|
65
|
+
getIcon() {
|
|
66
|
+
return this.icon;
|
|
67
|
+
}
|
|
68
|
+
setIcon(icon, color) {
|
|
69
|
+
this.icon = icon;
|
|
70
|
+
this.iconColor = color;
|
|
71
|
+
this.markDirty();
|
|
72
|
+
}
|
|
73
|
+
getModified() {
|
|
74
|
+
return this.modified;
|
|
75
|
+
}
|
|
76
|
+
setModified(modified) {
|
|
77
|
+
if (this.modified === modified)
|
|
78
|
+
return;
|
|
79
|
+
this.modified = modified;
|
|
80
|
+
this.markDirty();
|
|
81
|
+
}
|
|
82
|
+
getReadOnly() {
|
|
83
|
+
return this.readOnly;
|
|
84
|
+
}
|
|
85
|
+
/** Показывает/прячет метку-замок перед именем файла (VS Code read-only tab). */
|
|
86
|
+
setReadOnly(readOnly) {
|
|
87
|
+
if (this.readOnly === readOnly)
|
|
88
|
+
return;
|
|
89
|
+
this.readOnly = readOnly;
|
|
90
|
+
this.markDirty();
|
|
91
|
+
}
|
|
92
|
+
getPaddingLeft() {
|
|
93
|
+
return this.paddingLeft;
|
|
94
|
+
}
|
|
95
|
+
setPaddingLeft(value) {
|
|
96
|
+
this.paddingLeft = value;
|
|
97
|
+
this.markDirty();
|
|
98
|
+
}
|
|
99
|
+
getPaddingRight() {
|
|
100
|
+
return this.paddingRight;
|
|
101
|
+
}
|
|
102
|
+
setPaddingRight(value) {
|
|
103
|
+
this.paddingRight = value;
|
|
104
|
+
this.markDirty();
|
|
105
|
+
}
|
|
106
|
+
// ─── Content Layout ───
|
|
107
|
+
getContentWidth() {
|
|
108
|
+
// [paddingLeft][icon " "][lock " "][label][" ●/×"][paddingRight]
|
|
109
|
+
// The trailing slot shows the modified dot OR the close cross — never both —
|
|
110
|
+
// so the tab width stays stable regardless of modified/hover state. The lock
|
|
111
|
+
// is the one part that does change the width: read-only is a rare, sticky
|
|
112
|
+
// state, and squeezing it into an existing slot would hide the file icon.
|
|
113
|
+
const iconPart = this.icon.length > 0 ? this.icon.length + 1 : 0; // icon + space
|
|
114
|
+
const lockPart = this.readOnly ? READONLY_CHAR.length + 1 : 0; // lock + space
|
|
115
|
+
const trailingPart = 2; // " ●" or " ×"
|
|
116
|
+
return this.paddingLeft + iconPart + lockPart + this.label.length + trailingPart + this.paddingRight;
|
|
117
|
+
}
|
|
118
|
+
getCloseButtonStart() {
|
|
119
|
+
return this.getContentWidth() - this.paddingRight - CLOSE_CHAR.length;
|
|
120
|
+
}
|
|
121
|
+
// ─── Intrinsic Size ───
|
|
122
|
+
getMinIntrinsicWidth(_height) {
|
|
123
|
+
return this.getContentWidth();
|
|
124
|
+
}
|
|
125
|
+
getMaxIntrinsicWidth(_height) {
|
|
126
|
+
return this.getContentWidth();
|
|
127
|
+
}
|
|
128
|
+
getMinIntrinsicHeight(_width) {
|
|
129
|
+
return 1;
|
|
130
|
+
}
|
|
131
|
+
getMaxIntrinsicHeight(_width) {
|
|
132
|
+
return 1;
|
|
133
|
+
}
|
|
134
|
+
performLayout(constraints) {
|
|
135
|
+
const natural = new Size(this.getMaxIntrinsicWidth(1), this.getMaxIntrinsicHeight(0));
|
|
136
|
+
return super.performLayout(BoxConstraints.tight(constraints.constrain(natural)));
|
|
137
|
+
}
|
|
138
|
+
// ─── Render ───
|
|
139
|
+
render(context) {
|
|
140
|
+
const width = this.layoutSize.width;
|
|
141
|
+
const resolved = this.resolvedStyle;
|
|
142
|
+
let x = 0;
|
|
143
|
+
// Fill background for the whole width first
|
|
144
|
+
for (let i = 0; i < width; i++) {
|
|
145
|
+
context.setCell(i, 0, { char: " ", fg: resolved.fg, bg: resolved.bg });
|
|
146
|
+
}
|
|
147
|
+
// Padding left (already filled with spaces)
|
|
148
|
+
x += this.paddingLeft;
|
|
149
|
+
// Icon
|
|
150
|
+
if (this.icon.length > 0 && x < width) {
|
|
151
|
+
context.setCell(x, 0, { char: this.icon, fg: this.iconColor, bg: resolved.bg });
|
|
152
|
+
x += this.icon.length;
|
|
153
|
+
if (x < width) {
|
|
154
|
+
context.setCell(x, 0, { char: " ", fg: resolved.fg, bg: resolved.bg });
|
|
155
|
+
x += 1;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// Read-only lock, between the file icon and the label.
|
|
159
|
+
if (this.readOnly && x < width) {
|
|
160
|
+
context.setCell(x, 0, { char: READONLY_CHAR, fg: resolved.fg, bg: resolved.bg });
|
|
161
|
+
x += READONLY_CHAR.length;
|
|
162
|
+
if (x < width) {
|
|
163
|
+
context.setCell(x, 0, { char: " ", fg: resolved.fg, bg: resolved.bg });
|
|
164
|
+
x += 1;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// Label
|
|
168
|
+
for (let i = 0; i < this.label.length && x < width; i++) {
|
|
169
|
+
context.setCell(x, 0, { char: this.label[i], fg: resolved.fg, bg: resolved.bg });
|
|
170
|
+
x += 1;
|
|
171
|
+
}
|
|
172
|
+
// Trailing indicator: the modified dot until the tab is hovered, then
|
|
173
|
+
// the close cross (VSCode behaviour). Clicking the slot always closes.
|
|
174
|
+
const trailingChar = this.modified && !this.hovered ? MODIFIED_CHAR : CLOSE_CHAR;
|
|
175
|
+
if (x + 1 < width) {
|
|
176
|
+
context.setCell(x, 0, { char: " ", fg: resolved.fg, bg: resolved.bg });
|
|
177
|
+
x += 1;
|
|
178
|
+
context.setCell(x, 0, {
|
|
179
|
+
char: trailingChar,
|
|
180
|
+
fg: resolved.fg,
|
|
181
|
+
bg: resolved.bg,
|
|
182
|
+
style: StyleFlags.None,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { BoxConstraints, Size } from "@tuidom/core/common/geometryPromitives";
|
|
2
|
+
import { TUIElement } from "@tuidom/core/dom/tuiElement";
|
|
3
|
+
import { EditorTabItemElement } from "./editorTabItemElement.js";
|
|
4
|
+
export interface TabInfo {
|
|
5
|
+
label: string;
|
|
6
|
+
icon: string;
|
|
7
|
+
iconColor: number;
|
|
8
|
+
isModified: boolean;
|
|
9
|
+
/** Read-only буфер — вкладка получает метку-замок. */
|
|
10
|
+
isReadOnly: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare class EditorTabStripElement extends TUIElement {
|
|
13
|
+
private hflex;
|
|
14
|
+
private itemElements;
|
|
15
|
+
private filler;
|
|
16
|
+
private activeIndexValue;
|
|
17
|
+
onTabActivate: ((index: number) => void) | null;
|
|
18
|
+
onTabClose: ((index: number) => void) | null;
|
|
19
|
+
constructor();
|
|
20
|
+
get activeIndex(): number;
|
|
21
|
+
set activeIndex(value: number);
|
|
22
|
+
/** Observable state: tab labels with active/modified/readonly flags. */
|
|
23
|
+
inspectState(): Record<string, unknown>;
|
|
24
|
+
getItemElements(): readonly EditorTabItemElement[];
|
|
25
|
+
setTabs(tabs: TabInfo[]): void;
|
|
26
|
+
private rebuildHFlex;
|
|
27
|
+
private updateItemStyles;
|
|
28
|
+
getMinIntrinsicWidth(height: number): number;
|
|
29
|
+
getMaxIntrinsicWidth(height: number): number;
|
|
30
|
+
getMinIntrinsicHeight(_width: number): number;
|
|
31
|
+
getMaxIntrinsicHeight(_width: number): number;
|
|
32
|
+
protected performLayout(constraints: BoxConstraints): Size;
|
|
33
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { BoxConstraints, Size } from "@tuidom/core/common/geometryPromitives";
|
|
2
|
+
import { TUIElement } from "@tuidom/core/dom/tuiElement";
|
|
3
|
+
import { FillerElement } from "../layout/fillerElement.js";
|
|
4
|
+
import { HFlexElement, hflexFill, hflexFit } from "../layout/hFlexElement.js";
|
|
5
|
+
import { EditorTabItemElement } from "./editorTabItemElement.js";
|
|
6
|
+
// ─── EditorTabStripElement ───
|
|
7
|
+
export class EditorTabStripElement extends TUIElement {
|
|
8
|
+
hflex;
|
|
9
|
+
itemElements = [];
|
|
10
|
+
filler;
|
|
11
|
+
activeIndexValue = -1;
|
|
12
|
+
onTabActivate = null;
|
|
13
|
+
onTabClose = null;
|
|
14
|
+
constructor() {
|
|
15
|
+
super();
|
|
16
|
+
this.hflex = new HFlexElement();
|
|
17
|
+
this.filler = new FillerElement();
|
|
18
|
+
this.filler.style = { bg: "editorGroupHeader.tabsBackground" };
|
|
19
|
+
this.hflex.addChild(this.filler, { width: hflexFill(), height: 1 });
|
|
20
|
+
this.appendChild(this.hflex);
|
|
21
|
+
}
|
|
22
|
+
get activeIndex() {
|
|
23
|
+
return this.activeIndexValue;
|
|
24
|
+
}
|
|
25
|
+
set activeIndex(value) {
|
|
26
|
+
if (this.activeIndexValue === value)
|
|
27
|
+
return;
|
|
28
|
+
this.activeIndexValue = value;
|
|
29
|
+
this.updateItemStyles();
|
|
30
|
+
this.markDirty();
|
|
31
|
+
}
|
|
32
|
+
/** Observable state: tab labels with active/modified/readonly flags. */
|
|
33
|
+
inspectState() {
|
|
34
|
+
return {
|
|
35
|
+
activeIndex: this.activeIndexValue,
|
|
36
|
+
tabs: this.itemElements.map((item, i) => ({
|
|
37
|
+
label: item.getLabel(),
|
|
38
|
+
active: i === this.activeIndexValue,
|
|
39
|
+
modified: item.getModified(),
|
|
40
|
+
readOnly: item.getReadOnly(),
|
|
41
|
+
})),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
getItemElements() {
|
|
45
|
+
return this.itemElements;
|
|
46
|
+
}
|
|
47
|
+
setTabs(tabs) {
|
|
48
|
+
const newItems = [];
|
|
49
|
+
for (let i = 0; i < tabs.length; i++) {
|
|
50
|
+
const tab = tabs[i];
|
|
51
|
+
let item;
|
|
52
|
+
if (i < this.itemElements.length) {
|
|
53
|
+
item = this.itemElements[i];
|
|
54
|
+
item.setLabel(tab.label);
|
|
55
|
+
item.setIcon(tab.icon, tab.iconColor);
|
|
56
|
+
item.setModified(tab.isModified);
|
|
57
|
+
item.setReadOnly(tab.isReadOnly);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
item = new EditorTabItemElement(tab.label, tab.icon, tab.iconColor, {
|
|
61
|
+
modified: tab.isModified,
|
|
62
|
+
readOnly: tab.isReadOnly,
|
|
63
|
+
paddingLeft: 2,
|
|
64
|
+
paddingRight: 2,
|
|
65
|
+
});
|
|
66
|
+
// Вкладка декларирует оба вида токенами; активность — состояние.
|
|
67
|
+
item.style = {
|
|
68
|
+
fg: "tab.inactiveForeground",
|
|
69
|
+
bg: "tab.inactiveBackground",
|
|
70
|
+
when: [{ states: ["active"], fg: "tab.activeForeground", bg: "tab.activeBackground" }],
|
|
71
|
+
};
|
|
72
|
+
const index = i;
|
|
73
|
+
item.onActivate = () => this.onTabActivate?.(index);
|
|
74
|
+
item.onClose = () => this.onTabClose?.(index);
|
|
75
|
+
}
|
|
76
|
+
newItems.push(item);
|
|
77
|
+
}
|
|
78
|
+
this.itemElements = newItems;
|
|
79
|
+
this.rebuildHFlex();
|
|
80
|
+
this.updateItemStyles();
|
|
81
|
+
this.markDirty();
|
|
82
|
+
}
|
|
83
|
+
rebuildHFlex() {
|
|
84
|
+
const children = [];
|
|
85
|
+
for (const item of this.itemElements) {
|
|
86
|
+
item.layoutStyle = { width: hflexFit(), height: 1 };
|
|
87
|
+
children.push(item);
|
|
88
|
+
}
|
|
89
|
+
this.filler.layoutStyle = { width: hflexFill(), height: 1 };
|
|
90
|
+
children.push(this.filler);
|
|
91
|
+
this.hflex.replaceChildren(children);
|
|
92
|
+
}
|
|
93
|
+
updateItemStyles() {
|
|
94
|
+
for (let i = 0; i < this.itemElements.length; i++) {
|
|
95
|
+
this.itemElements[i].setStyleState("active", i === this.activeIndexValue);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// ─── Children ───
|
|
99
|
+
// ─── Intrinsic Size ───
|
|
100
|
+
getMinIntrinsicWidth(height) {
|
|
101
|
+
return this.hflex.getMinIntrinsicWidth(height);
|
|
102
|
+
}
|
|
103
|
+
getMaxIntrinsicWidth(height) {
|
|
104
|
+
return this.hflex.getMaxIntrinsicWidth(height);
|
|
105
|
+
}
|
|
106
|
+
getMinIntrinsicHeight(_width) {
|
|
107
|
+
return 1;
|
|
108
|
+
}
|
|
109
|
+
getMaxIntrinsicHeight(_width) {
|
|
110
|
+
return 1;
|
|
111
|
+
}
|
|
112
|
+
// ─── Layout ───
|
|
113
|
+
performLayout(constraints) {
|
|
114
|
+
const containerSize = super.performLayout(constraints);
|
|
115
|
+
this.layoutChild(this.hflex, 0, 0, BoxConstraints.tight(new Size(containerSize.width, 1)));
|
|
116
|
+
return containerSize;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { BoxConstraints, Size } from "@tuidom/core/common/geometryPromitives";
|
|
2
|
+
import { TUIElement } from "@tuidom/core/dom/tuiElement";
|
|
3
|
+
/** Ось полосы групп: колонки (сплиты слева-направо) или ряды (сверху-вниз). */
|
|
4
|
+
export type EditorPartOrientation = "columns" | "rows";
|
|
5
|
+
/** Минимальная ширина группы в колонках — узже таб-стрип и код нечитаемы. */
|
|
6
|
+
export declare const MIN_GROUP_MAIN_COLS = 20;
|
|
7
|
+
/** Минимальная высота группы в рядах — таб-стрип + пара строк кода. */
|
|
8
|
+
export declare const MIN_GROUP_MAIN_ROWS = 5;
|
|
9
|
+
/**
|
|
10
|
+
* Полоса групп редакторов по одной оси (аналог grid-вью `EditorPart` VS Code,
|
|
11
|
+
* сведённого к одному ряду/колонке): N вью групп + N−1 сашей между ними.
|
|
12
|
+
* Пропорции — нормированные веса, переживают ресайз терминала; политику весов
|
|
13
|
+
* при сплите/схлопывании задаёт владелец (`EditorPartComponent`) через
|
|
14
|
+
* {@link setViews}. Саши лежат ПОВЕРХ граничной ячейки (пуш последними —
|
|
15
|
+
* hit-test): в columns — поверх первой колонки следующей группы, в rows —
|
|
16
|
+
* поверх ПОСЛЕДНЕЙ строки предыдущей: первая строка нижней группы это её
|
|
17
|
+
* табы, и наложение отняло бы у них мышь, а нижняя строка редактора менее
|
|
18
|
+
* ценна. Каждый саш укладывается явно в каждом layout.
|
|
19
|
+
*
|
|
20
|
+
* Деградация «не влезаем»: контейнер уже, чем N×минимум, — display-only равное
|
|
21
|
+
* деление без мутации весов; при возврате размера пропорции восстанавливаются.
|
|
22
|
+
* Отказ в НОВОМ сплите при нехватке места — {@link canFit}, решает владелец.
|
|
23
|
+
*/
|
|
24
|
+
export declare class EditorPartElement extends TUIElement {
|
|
25
|
+
private views;
|
|
26
|
+
/** Нормированные доли групп; длина всегда равна `views.length`. */
|
|
27
|
+
private weightsValue;
|
|
28
|
+
private sashes;
|
|
29
|
+
private orientationValue;
|
|
30
|
+
private maximizedIndexValue;
|
|
31
|
+
/** Основные размеры групп из последнего layout — база для drag-математики. */
|
|
32
|
+
private lastSizes;
|
|
33
|
+
/**
|
|
34
|
+
* Смена весов действием пользователя (drag саша, nudge/even команды) — для
|
|
35
|
+
* персиста. Плейн-колбэк (TUIDom без DI); НЕ вызывается из performLayout.
|
|
36
|
+
*/
|
|
37
|
+
onDidChangeWeights?: () => void;
|
|
38
|
+
/** Ось полосы. Смена сохраняет веса (US-19: тумблер не теряет пропорций). */
|
|
39
|
+
get orientation(): EditorPartOrientation;
|
|
40
|
+
set orientation(value: EditorPartOrientation);
|
|
41
|
+
/** Нормированные доли групп (копия). */
|
|
42
|
+
get weights(): readonly number[];
|
|
43
|
+
/** Индекс максимизированной группы, либо `null` (обычная полоса). */
|
|
44
|
+
get maximizedIndex(): number | null;
|
|
45
|
+
set maximizedIndex(value: number | null);
|
|
46
|
+
/**
|
|
47
|
+
* Задаёт состав полосы и доли. Политика долей — у владельца (сплит делит
|
|
48
|
+
* долю активной группы пополам, join отдаёт долю соседу и т.п.); элемент
|
|
49
|
+
* лишь нормирует. Пустые/невалидные веса → равные доли. Максимизация
|
|
50
|
+
* сбрасывается: состав сменился, старый индекс — про другую полосу.
|
|
51
|
+
*/
|
|
52
|
+
setViews(views: TUIElement[], weights?: readonly number[]): void;
|
|
53
|
+
/** Выравнивает доли (Reset Editor Group Sizes). */
|
|
54
|
+
evenWeights(): void;
|
|
55
|
+
/**
|
|
56
|
+
* Задаёт доли программно (рестор персиста). Невалидные/чужой длины веса
|
|
57
|
+
* нормализуются в равные; событие не файрится — это не действие пользователя.
|
|
58
|
+
*/
|
|
59
|
+
setWeights(weights: readonly number[]): void;
|
|
60
|
+
/**
|
|
61
|
+
* Меняет основной размер группы `index` на `deltaCells` ячеек за счёт соседа
|
|
62
|
+
* справа/снизу (последняя группа растёт за счёт соседа слева/сверху) —
|
|
63
|
+
* increase/decreaseEditorWidth/Height. Кламп по минимуму обеих.
|
|
64
|
+
*/
|
|
65
|
+
nudgeWeight(index: number, deltaCells: number): void;
|
|
66
|
+
/** Влезет ли полоса из `count` групп в текущий основной размер. */
|
|
67
|
+
canFit(count: number): boolean;
|
|
68
|
+
inspectState(): Record<string, unknown>;
|
|
69
|
+
/** Основной размер полосы по текущей оси (из последнего layout). */
|
|
70
|
+
private mainAxisSize;
|
|
71
|
+
private minMainSize;
|
|
72
|
+
/** Текущие основные размеры групп; `null` до первого layout. */
|
|
73
|
+
private currentSizes;
|
|
74
|
+
/** Нормирует произвольные положительные величины в доли; пусто/мусор → равные. */
|
|
75
|
+
private normalizeWeights;
|
|
76
|
+
/** Пересоздаёт N−1 сашей под текущие состав и ось; вешает drag-обработчики. */
|
|
77
|
+
private rebuildSashes;
|
|
78
|
+
/** Дети: вью групп, затем саши (поверх границ — hit-test); максимизация прячет прочее. */
|
|
79
|
+
private syncChildren;
|
|
80
|
+
/**
|
|
81
|
+
* Drag саша `index` (граница групп index/index+1): абсолютная координата →
|
|
82
|
+
* новый размер левой/верхней группы, кламп по минимуму пары, веса — из
|
|
83
|
+
* фактических размеров. Веса остальных групп не трогаются.
|
|
84
|
+
*/
|
|
85
|
+
private handleSashDrag;
|
|
86
|
+
/**
|
|
87
|
+
* Целочисленные основные размеры из долей: floor + остатки самым большим
|
|
88
|
+
* дробным частям (сумма всегда равна `mainSize`), затем min-клампы за счёт
|
|
89
|
+
* самых широких. Полоса уже N×минимума — display-only равное деление, веса
|
|
90
|
+
* не мутируются (US-25: пропорции восстановятся при возврате размера).
|
|
91
|
+
*/
|
|
92
|
+
private computeSizes;
|
|
93
|
+
private distributeEvenly;
|
|
94
|
+
protected performLayout(constraints: BoxConstraints): Size;
|
|
95
|
+
}
|