@teammates/consolonia 0.3.0 → 0.3.2

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/README.md CHANGED
@@ -1,48 +1,48 @@
1
- # @teammates/consolonia
2
-
3
- > Part of the [teammates](https://github.com/Stevenic/teammates) monorepo.
4
-
5
- Terminal UI rendering engine inspired by Consolonia. Pixel-level compositing with ANSI output.
6
-
7
- ## Quick Start
8
-
9
- ```bash
10
- npm install @teammates/consolonia
11
- ```
12
-
13
- ## Features
14
-
15
- - Pixel-level terminal buffer with foreground/background compositing
16
- - Box-drawing character merging (single, double, mixed)
17
- - Layout system: Box, Row, Column, Stack with constraint-based sizing
18
- - Clipping regions for nested drawing contexts
19
- - Widget library: Border, Panel, Text, TextInput, ScrollView, ChatView, Markdown, Syntax
20
- - Styled text with inline markup (`*bold*`, `_italic_`, `` `code` ``, `~dim~`)
21
- - Input processing: keyboard, mouse, paste detection, escape sequences
22
- - ANSI output with dirty-region rendering (only redraws what changed)
23
-
24
- ## Architecture
25
-
26
- ```
27
- src/
28
- pixel/ # Buffer, Pixel, Color, Symbol, Foreground, Background
29
- layout/ # Box, Row, Column, Stack, Control (constraint solver)
30
- drawing/ # DrawingContext, Clip
31
- render/ # RenderTarget, Regions (dirty tracking)
32
- widgets/ # Border, Panel, Text, TextInput, ScrollView, ChatView, Markdown, Syntax
33
- input/ # Processor, Matchers (text, escape, mouse, paste)
34
- ansi/ # Escape codes, Output, Strip
35
- styled.ts # Inline markup parser
36
- app.ts # Application lifecycle
37
- index.ts # Public API
38
- ```
39
-
40
- ## Testing
41
-
42
- ```bash
43
- npm test
44
- ```
45
-
46
- ## Requirements
47
-
48
- - Node.js >= 20
1
+ # @teammates/consolonia
2
+
3
+ > Part of the [teammates](https://github.com/Stevenic/teammates) monorepo.
4
+
5
+ Terminal UI rendering engine inspired by Consolonia. Pixel-level compositing with ANSI output.
6
+
7
+ ## Quick Start
8
+
9
+ ```bash
10
+ npm install @teammates/consolonia
11
+ ```
12
+
13
+ ## Features
14
+
15
+ - Pixel-level terminal buffer with foreground/background compositing
16
+ - Box-drawing character merging (single, double, mixed)
17
+ - Layout system: Box, Row, Column, Stack with constraint-based sizing
18
+ - Clipping regions for nested drawing contexts
19
+ - Widget library: Border, Panel, Text, TextInput, ScrollView, ChatView, Markdown, Syntax
20
+ - Styled text with inline markup (`*bold*`, `_italic_`, `` `code` ``, `~dim~`)
21
+ - Input processing: keyboard, mouse, paste detection, escape sequences
22
+ - ANSI output with dirty-region rendering (only redraws what changed)
23
+
24
+ ## Architecture
25
+
26
+ ```
27
+ src/
28
+ pixel/ # Buffer, Pixel, Color, Symbol, Foreground, Background
29
+ layout/ # Box, Row, Column, Stack, Control (constraint solver)
30
+ drawing/ # DrawingContext, Clip
31
+ render/ # RenderTarget, Regions (dirty tracking)
32
+ widgets/ # Border, Panel, Text, TextInput, ScrollView, ChatView, Markdown, Syntax
33
+ input/ # Processor, Matchers (text, escape, mouse, paste)
34
+ ansi/ # Escape codes, Output, Strip
35
+ styled.ts # Inline markup parser
36
+ app.ts # Application lifecycle
37
+ index.ts # Public API
38
+ ```
39
+
40
+ ## Testing
41
+
42
+ ```bash
43
+ npm test
44
+ ```
45
+
46
+ ## Requirements
47
+
48
+ - Node.js >= 20
@@ -145,6 +145,10 @@ export declare class ChatView extends Control {
145
145
  private _selAnchor;
146
146
  private _selEnd;
147
147
  private _selecting;
148
+ /** Timer for auto-scrolling the feed during drag-to-select. */
149
+ private _selScrollTimer;
150
+ /** Direction of auto-scroll: -1 = up, 1 = down, 0 = none. */
151
+ private _selScrollDir;
148
152
  /** DrawingContext reference from the last render (for text extraction). */
149
153
  private _ctx;
150
154
  /** Optional widget that replaces the input area (e.g. Interview). */
@@ -250,5 +254,9 @@ export declare class ChatView extends Control {
250
254
  private _renderSelection;
251
255
  /** Clear any active text selection. */
252
256
  clearSelection(): void;
257
+ /** Start interval-based scroll during drag-to-select at feed edges. */
258
+ private _startSelScroll;
259
+ /** Stop auto-scroll timer. */
260
+ private _stopSelScroll;
253
261
  private _autoScrollToBottom;
254
262
  }
@@ -89,6 +89,10 @@ export class ChatView extends Control {
89
89
  _selAnchor = null;
90
90
  _selEnd = null;
91
91
  _selecting = false;
92
+ /** Timer for auto-scrolling the feed during drag-to-select. */
93
+ _selScrollTimer = null;
94
+ /** Direction of auto-scroll: -1 = up, 1 = down, 0 = none. */
95
+ _selScrollDir = 0;
92
96
  /** DrawingContext reference from the last render (for text extraction). */
93
97
  _ctx = null;
94
98
  /** Optional widget that replaces the input area (e.g. Interview). */
@@ -606,15 +610,27 @@ export class ChatView extends Control {
606
610
  return true;
607
611
  }
608
612
  }
609
- // Text selection: extend on move
613
+ // Text selection: extend on move (with auto-scroll at edges)
610
614
  if (me.type === "move" && this._selecting) {
611
615
  this._selEnd = { x: me.x, y: me.y };
616
+ const feedTop = this._feedY;
617
+ const feedBot = this._feedY + this._feedH;
618
+ if (me.y < feedTop) {
619
+ this._startSelScroll(-1);
620
+ }
621
+ else if (me.y >= feedBot) {
622
+ this._startSelScroll(1);
623
+ }
624
+ else {
625
+ this._stopSelScroll();
626
+ }
612
627
  this.invalidate();
613
628
  return true;
614
629
  }
615
630
  // Text selection: finalize on release
616
631
  if (me.type === "release" && this._selecting) {
617
632
  this._selecting = false;
633
+ this._stopSelScroll();
618
634
  // If anchor == end (just a click, no drag), clear selection
619
635
  if (this._selAnchor &&
620
636
  this._selEnd &&
@@ -1082,9 +1098,37 @@ export class ChatView extends Control {
1082
1098
  this._selAnchor = null;
1083
1099
  this._selEnd = null;
1084
1100
  this._selecting = false;
1101
+ this._stopSelScroll();
1085
1102
  this.invalidate();
1086
1103
  }
1087
1104
  // ── Auto-scroll ────────────────────────────────────────────────
1105
+ /** Start interval-based scroll during drag-to-select at feed edges. */
1106
+ _startSelScroll(dir) {
1107
+ if (this._selScrollDir === dir && this._selScrollTimer)
1108
+ return;
1109
+ this._stopSelScroll();
1110
+ this._selScrollDir = dir;
1111
+ this._selScrollTimer = setInterval(() => {
1112
+ this.scrollFeed(this._selScrollDir * 3);
1113
+ // Move selEnd to keep extending the selection while scrolling
1114
+ if (this._selEnd) {
1115
+ this._selEnd = {
1116
+ x: this._selEnd.x,
1117
+ y: this._selScrollDir < 0
1118
+ ? this._feedY
1119
+ : this._feedY + this._feedH - 1,
1120
+ };
1121
+ }
1122
+ }, 80);
1123
+ }
1124
+ /** Stop auto-scroll timer. */
1125
+ _stopSelScroll() {
1126
+ if (this._selScrollTimer) {
1127
+ clearInterval(this._selScrollTimer);
1128
+ this._selScrollTimer = null;
1129
+ }
1130
+ this._selScrollDir = 0;
1131
+ }
1088
1132
  _autoScrollToBottom() {
1089
1133
  // Set scroll to a very large value; it will be clamped during render
1090
1134
  this._feedScrollOffset = Number.MAX_SAFE_INTEGER;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teammates/consolonia",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Terminal UI rendering engine inspired by Consolonia. Pixel-level compositing with ANSI output.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",