@teammates/consolonia 0.3.4 → 0.4.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.
|
@@ -33,7 +33,7 @@ import type { DrawingContext, TextStyle } from "../drawing/context.js";
|
|
|
33
33
|
import type { InputEvent } from "../input/events.js";
|
|
34
34
|
import { Control } from "../layout/control.js";
|
|
35
35
|
import type { Constraint, Rect, Size } from "../layout/types.js";
|
|
36
|
-
import type
|
|
36
|
+
import { type StyledSpan } from "../styled.js";
|
|
37
37
|
import { type StyledLine } from "./styled-text.js";
|
|
38
38
|
import { type DeleteSizer, type InputColorizer, TextInput } from "./text-input.js";
|
|
39
39
|
export interface DropdownItem {
|
|
@@ -93,8 +93,10 @@ export interface ChatViewOptions {
|
|
|
93
93
|
dropdownLabelStyle?: TextStyle;
|
|
94
94
|
/** Maximum number of lines the input box can grow to (default 1). */
|
|
95
95
|
maxInputHeight?: number;
|
|
96
|
-
/** Footer content shown below the input (StyledLine for mixed colors). */
|
|
96
|
+
/** Footer content shown below the input (StyledLine for mixed colors). Sets the left side. */
|
|
97
97
|
footer?: StyledLine;
|
|
98
|
+
/** Right-aligned footer content. */
|
|
99
|
+
footerRight?: StyledLine;
|
|
98
100
|
/** Style for footer text (used as default when footer is a plain string). */
|
|
99
101
|
footerStyle?: TextStyle;
|
|
100
102
|
/** Command history entries. */
|
|
@@ -117,6 +119,7 @@ export declare class ChatView extends Control {
|
|
|
117
119
|
private _input;
|
|
118
120
|
private _inputSeparator;
|
|
119
121
|
private _footer;
|
|
122
|
+
private _footerRight;
|
|
120
123
|
private _dropdownItems;
|
|
121
124
|
private _dropdownIndex;
|
|
122
125
|
private _feedStyle;
|
|
@@ -166,8 +169,10 @@ export declare class ChatView extends Control {
|
|
|
166
169
|
set bannerWidget(widget: Control);
|
|
167
170
|
/** Get the current banner widget. */
|
|
168
171
|
get bannerWidget(): Control;
|
|
169
|
-
/** Set footer content (plain string or StyledSpan for mixed colors). */
|
|
172
|
+
/** Set left-side footer content (plain string or StyledSpan for mixed colors). */
|
|
170
173
|
setFooter(content: StyledLine): void;
|
|
174
|
+
/** Set right-side footer content (plain string or StyledSpan for mixed colors). */
|
|
175
|
+
setFooterRight(content: StyledLine): void;
|
|
171
176
|
/** Append a line of plain text to the feed. Auto-scrolls to bottom. */
|
|
172
177
|
appendToFeed(text: string, style?: TextStyle): void;
|
|
173
178
|
/** Append a styled line (StyledSpan) to the feed. */
|
|
@@ -57,6 +57,7 @@ export class ChatView extends Control {
|
|
|
57
57
|
_input;
|
|
58
58
|
_inputSeparator;
|
|
59
59
|
_footer;
|
|
60
|
+
_footerRight;
|
|
60
61
|
_dropdownItems = [];
|
|
61
62
|
_dropdownIndex = -1;
|
|
62
63
|
// ── Configuration ──────────────────────────────────────────────
|
|
@@ -163,6 +164,13 @@ export class ChatView extends Control {
|
|
|
163
164
|
wrap: false,
|
|
164
165
|
});
|
|
165
166
|
this.addChild(this._footer);
|
|
167
|
+
const footerRightLine = options.footerRight ?? "";
|
|
168
|
+
this._footerRight = new StyledText({
|
|
169
|
+
lines: [footerRightLine],
|
|
170
|
+
defaultStyle: this._footerStyle,
|
|
171
|
+
wrap: false,
|
|
172
|
+
});
|
|
173
|
+
this.addChild(this._footerRight);
|
|
166
174
|
// Wire input events to ChatView events
|
|
167
175
|
this._input.on("submit", (text) => this.emit("submit", text));
|
|
168
176
|
this._input.on("change", (text) => this.emit("change", text));
|
|
@@ -221,11 +229,16 @@ export class ChatView extends Control {
|
|
|
221
229
|
return this._banner;
|
|
222
230
|
}
|
|
223
231
|
// ── Public API: Footer ─────────────────────────────────────────
|
|
224
|
-
/** Set footer content (plain string or StyledSpan for mixed colors). */
|
|
232
|
+
/** Set left-side footer content (plain string or StyledSpan for mixed colors). */
|
|
225
233
|
setFooter(content) {
|
|
226
234
|
this._footer.lines = [content];
|
|
227
235
|
this.invalidate();
|
|
228
236
|
}
|
|
237
|
+
/** Set right-side footer content (plain string or StyledSpan for mixed colors). */
|
|
238
|
+
setFooterRight(content) {
|
|
239
|
+
this._footerRight.lines = [content];
|
|
240
|
+
this.invalidate();
|
|
241
|
+
}
|
|
229
242
|
// ── Public API: Feed ───────────────────────────────────────────
|
|
230
243
|
/** Append a line of plain text to the feed. Auto-scrolls to bottom. */
|
|
231
244
|
appendToFeed(text, style) {
|
|
@@ -446,6 +459,7 @@ export class ChatView extends Control {
|
|
|
446
459
|
this._input.focusable = false;
|
|
447
460
|
this._inputSeparator.visible = false;
|
|
448
461
|
this._footer.visible = false;
|
|
462
|
+
this._footerRight.visible = false;
|
|
449
463
|
}
|
|
450
464
|
else {
|
|
451
465
|
// Restore normal input chrome
|
|
@@ -454,6 +468,7 @@ export class ChatView extends Control {
|
|
|
454
468
|
this._input.onFocus();
|
|
455
469
|
this._inputSeparator.visible = true;
|
|
456
470
|
this._footer.visible = true;
|
|
471
|
+
this._footerRight.visible = true;
|
|
457
472
|
}
|
|
458
473
|
this.invalidate();
|
|
459
474
|
}
|
|
@@ -631,6 +646,7 @@ export class ChatView extends Control {
|
|
|
631
646
|
if (me.type === "release" && this._selecting) {
|
|
632
647
|
this._selecting = false;
|
|
633
648
|
this._stopSelScroll();
|
|
649
|
+
this._selEnd = { x: me.x, y: me.y };
|
|
634
650
|
// If anchor == end (just a click, no drag), clear selection
|
|
635
651
|
if (this._selAnchor &&
|
|
636
652
|
this._selEnd &&
|
|
@@ -881,6 +897,7 @@ export class ChatView extends Control {
|
|
|
881
897
|
this._renderDropdown(ctx, b.x, y, W, totalDropdownH);
|
|
882
898
|
}
|
|
883
899
|
else {
|
|
900
|
+
// Left footer
|
|
884
901
|
this._footer.measure({
|
|
885
902
|
minWidth: 0,
|
|
886
903
|
maxWidth: W,
|
|
@@ -889,6 +906,23 @@ export class ChatView extends Control {
|
|
|
889
906
|
});
|
|
890
907
|
this._footer.arrange({ x: b.x, y, width: W, height: footerH });
|
|
891
908
|
this._footer.render(ctx);
|
|
909
|
+
// Right footer (right-aligned on the same row)
|
|
910
|
+
const rightSize = this._footerRight.measure({
|
|
911
|
+
minWidth: 0,
|
|
912
|
+
maxWidth: W,
|
|
913
|
+
minHeight: 0,
|
|
914
|
+
maxHeight: 1,
|
|
915
|
+
});
|
|
916
|
+
if (rightSize.width > 0) {
|
|
917
|
+
const rightX = b.x + W - rightSize.width;
|
|
918
|
+
this._footerRight.arrange({
|
|
919
|
+
x: rightX,
|
|
920
|
+
y,
|
|
921
|
+
width: rightSize.width,
|
|
922
|
+
height: footerH,
|
|
923
|
+
});
|
|
924
|
+
this._footerRight.render(ctx);
|
|
925
|
+
}
|
|
892
926
|
}
|
|
893
927
|
}
|
|
894
928
|
// ── Feed rendering ─────────────────────────────────────────────
|
|
@@ -983,6 +1017,9 @@ export class ChatView extends Control {
|
|
|
983
1017
|
}
|
|
984
1018
|
cy += item.height;
|
|
985
1019
|
}
|
|
1020
|
+
// Always cache feed geometry for selection edge-detection
|
|
1021
|
+
this._feedY = y;
|
|
1022
|
+
this._feedH = height;
|
|
986
1023
|
// Render scrollbar and cache geometry for hit-testing
|
|
987
1024
|
if (height > 0 && totalContentH > height) {
|
|
988
1025
|
const scrollX = x + width - 1;
|
|
@@ -994,8 +1031,6 @@ export class ChatView extends Control {
|
|
|
994
1031
|
const thumbStyle = this._feedStyle;
|
|
995
1032
|
// Cache for mouse interaction
|
|
996
1033
|
this._scrollbarX = scrollX;
|
|
997
|
-
this._feedY = y;
|
|
998
|
-
this._feedH = height;
|
|
999
1034
|
this._thumbPos = thumbPos;
|
|
1000
1035
|
this._thumbSize = thumbSize;
|
|
1001
1036
|
this._maxScroll = maxScroll;
|
package/package.json
CHANGED