tidepool 1.0.6 → 2.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/README.md +231 -71
- package/dist/effects/shadow.d.ts +9 -0
- package/dist/effects/shadow.d.ts.map +1 -0
- package/dist/effects/shadow.js +33 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -1
- package/dist/input.d.ts +33 -0
- package/dist/input.d.ts.map +1 -0
- package/dist/input.js +191 -0
- package/dist/interfaces.d.ts +40 -1
- package/dist/interfaces.d.ts.map +1 -1
- package/dist/objects/box.d.ts +9 -5
- package/dist/objects/box.d.ts.map +1 -1
- package/dist/objects/box.js +70 -32
- package/dist/objects/button.d.ts +29 -0
- package/dist/objects/button.d.ts.map +1 -0
- package/dist/objects/button.js +80 -0
- package/dist/objects/input.d.ts +38 -0
- package/dist/objects/input.d.ts.map +1 -0
- package/dist/objects/input.js +141 -0
- package/dist/objects/line.d.ts +2 -2
- package/dist/objects/line.d.ts.map +1 -1
- package/dist/objects/line.js +5 -7
- package/dist/objects/progress.d.ts +1 -0
- package/dist/objects/progress.d.ts.map +1 -0
- package/dist/objects/progress.js +1 -0
- package/dist/objects/text.d.ts +4 -2
- package/dist/objects/text.d.ts.map +1 -1
- package/dist/objects/text.js +16 -9
- package/dist/screen.d.ts +17 -7
- package/dist/screen.d.ts.map +1 -1
- package/dist/screen.js +118 -34
- package/dist/util.d.ts +3 -0
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +41 -11
- package/package.json +23 -5
- package/.github/workflows/eslint.yml +0 -50
- package/eslint.config.mjs +0 -38
package/dist/screen.js
CHANGED
|
@@ -2,59 +2,133 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.TideScreen = void 0;
|
|
4
4
|
class TideScreen {
|
|
5
|
-
constructor(width, height, backgroundColor =
|
|
5
|
+
constructor(width, height, backgroundColor = "transparent") {
|
|
6
6
|
this.fps = null;
|
|
7
7
|
this.updateFunction = null;
|
|
8
|
+
this.needsSort = true;
|
|
9
|
+
this.resizeListener = null;
|
|
10
|
+
this.didInitialClear = false;
|
|
8
11
|
this.width = width;
|
|
9
12
|
this.height = height;
|
|
10
|
-
this.
|
|
11
|
-
this.
|
|
13
|
+
this.frontBuffer = this.createBuffer(width, height);
|
|
14
|
+
this.backBuffer = this.createBuffer(width, height);
|
|
12
15
|
this.components = [];
|
|
13
16
|
this.backgroundColor = backgroundColor;
|
|
14
17
|
}
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
createBuffer(width, height) {
|
|
19
|
+
return Array.from({ length: height }, () => Array(width).fill(" "));
|
|
17
20
|
}
|
|
18
|
-
clearBuffer() {
|
|
19
|
-
|
|
21
|
+
clearBuffer(buffer, dirtyRows) {
|
|
22
|
+
for (let i = 0; i < this.height; i++) {
|
|
23
|
+
for (let j = 0; j < this.width; j++) {
|
|
24
|
+
buffer[i][j] = " ";
|
|
25
|
+
}
|
|
26
|
+
if (dirtyRows) {
|
|
27
|
+
dirtyRows.add(i);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
20
30
|
}
|
|
21
31
|
addComponent(component) {
|
|
22
32
|
this.components.push(component);
|
|
33
|
+
this.needsSort = true;
|
|
34
|
+
}
|
|
35
|
+
invalidateSort() {
|
|
36
|
+
this.needsSort = true;
|
|
23
37
|
}
|
|
24
38
|
getBackgroundColorCode(color) {
|
|
25
39
|
const colors = {
|
|
26
|
-
black:
|
|
27
|
-
red:
|
|
28
|
-
green:
|
|
29
|
-
yellow:
|
|
30
|
-
blue:
|
|
31
|
-
magenta:
|
|
32
|
-
cyan:
|
|
33
|
-
white:
|
|
34
|
-
transparent:
|
|
35
|
-
random:
|
|
40
|
+
black: "\x1b[40m",
|
|
41
|
+
red: "\x1b[41m",
|
|
42
|
+
green: "\x1b[42m",
|
|
43
|
+
yellow: "\x1b[43m",
|
|
44
|
+
blue: "\x1b[44m",
|
|
45
|
+
magenta: "\x1b[45m",
|
|
46
|
+
cyan: "\x1b[46m",
|
|
47
|
+
white: "\x1b[47m",
|
|
48
|
+
transparent: "\x1b[49m",
|
|
49
|
+
random: "\x1b[48;5;" + Math.floor(Math.random() * 256) + "m",
|
|
36
50
|
};
|
|
37
|
-
return colors[color.toLowerCase()] || colors[
|
|
51
|
+
return colors[color.toLowerCase()] || colors["black"];
|
|
38
52
|
}
|
|
39
53
|
renderBuffer() {
|
|
40
|
-
|
|
41
|
-
this.
|
|
42
|
-
|
|
54
|
+
const dirtyRows = new Set();
|
|
55
|
+
this.clearBuffer(this.backBuffer, dirtyRows);
|
|
56
|
+
if (this.needsSort) {
|
|
57
|
+
this.components.sort((a, b) => b.zIndex - a.zIndex);
|
|
58
|
+
this.needsSort = false;
|
|
59
|
+
}
|
|
60
|
+
const baseContext = {
|
|
61
|
+
buffer: this.backBuffer,
|
|
62
|
+
origin: { x: 0, y: 0 },
|
|
63
|
+
clip: { x: 0, y: 0, width: this.width, height: this.height },
|
|
64
|
+
screenSize: { width: this.width, height: this.height },
|
|
65
|
+
dirtyRows,
|
|
66
|
+
};
|
|
67
|
+
this.components.forEach((component) => component.draw(baseContext));
|
|
68
|
+
return dirtyRows;
|
|
43
69
|
}
|
|
44
|
-
applyBackgroundColor() {
|
|
70
|
+
applyBackgroundColor(dirtyRows) {
|
|
71
|
+
if (this.backgroundColor.toLowerCase() === "transparent") {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
45
74
|
const bgColorCode = this.getBackgroundColorCode(this.backgroundColor);
|
|
46
|
-
const resetCode =
|
|
75
|
+
const resetCode = "\x1b[0m";
|
|
47
76
|
for (let i = 0; i < this.height; i++) {
|
|
48
77
|
for (let j = 0; j < this.width; j++) {
|
|
49
|
-
this.
|
|
78
|
+
this.backBuffer[i][j] = `${bgColorCode}${this.backBuffer[i][j] || " "}${resetCode}`;
|
|
79
|
+
if (dirtyRows) {
|
|
80
|
+
dirtyRows.add(i);
|
|
81
|
+
}
|
|
50
82
|
}
|
|
51
83
|
}
|
|
52
84
|
}
|
|
53
|
-
|
|
54
|
-
this.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
85
|
+
resize(width, height) {
|
|
86
|
+
this.width = width;
|
|
87
|
+
this.height = height;
|
|
88
|
+
this.frontBuffer = this.createBuffer(width, height);
|
|
89
|
+
this.backBuffer = this.createBuffer(width, height);
|
|
90
|
+
}
|
|
91
|
+
enableAutoResize(getSize = () => ({
|
|
92
|
+
width: process.stdout.columns - 1,
|
|
93
|
+
height: process.stdout.rows - 1,
|
|
94
|
+
})) {
|
|
95
|
+
if (this.resizeListener) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
this.resizeListener = () => {
|
|
99
|
+
const size = getSize();
|
|
100
|
+
this.resize(size.width, size.height);
|
|
101
|
+
};
|
|
102
|
+
process.on("SIGWINCH", this.resizeListener);
|
|
103
|
+
}
|
|
104
|
+
disableAutoResize() {
|
|
105
|
+
if (!this.resizeListener) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
process.off("SIGWINCH", this.resizeListener);
|
|
109
|
+
this.resizeListener = null;
|
|
110
|
+
}
|
|
111
|
+
render(dirtyRows) {
|
|
112
|
+
if (!this.didInitialClear) {
|
|
113
|
+
process.stdout.write("\x1b[2J\x1b[H");
|
|
114
|
+
this.didInitialClear = true;
|
|
115
|
+
}
|
|
116
|
+
this.applyBackgroundColor(dirtyRows);
|
|
117
|
+
process.stdout.write("\x1b[H");
|
|
118
|
+
const rowsToRender = dirtyRows && dirtyRows.size > 0
|
|
119
|
+
? Array.from(dirtyRows)
|
|
120
|
+
: dirtyRows
|
|
121
|
+
? []
|
|
122
|
+
: Array.from({ length: this.height }, (_, i) => i);
|
|
123
|
+
for (const i of rowsToRender) {
|
|
124
|
+
for (let j = 0; j < this.width; j++) {
|
|
125
|
+
if (this.backBuffer[i][j] !== this.frontBuffer[i][j]) {
|
|
126
|
+
process.stdout.write(`\x1b[${i + 1};${j + 1}H`);
|
|
127
|
+
process.stdout.write(this.backBuffer[i][j]);
|
|
128
|
+
this.frontBuffer[i][j] = this.backBuffer[i][j];
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
58
132
|
}
|
|
59
133
|
setUpdateFunction(fn) {
|
|
60
134
|
this.updateFunction = fn;
|
|
@@ -66,10 +140,10 @@ class TideScreen {
|
|
|
66
140
|
if (this.updateFunction) {
|
|
67
141
|
this.updateFunction();
|
|
68
142
|
}
|
|
69
|
-
this.renderBuffer();
|
|
70
|
-
this.render();
|
|
143
|
+
const dirtyRows = this.renderBuffer();
|
|
144
|
+
this.render(dirtyRows);
|
|
71
145
|
}
|
|
72
|
-
renderCycle() {
|
|
146
|
+
renderCycle(beforeRender, afterRender) {
|
|
73
147
|
if (this.fps === null) {
|
|
74
148
|
throw new Error("FPS must be set before starting the render cycle.");
|
|
75
149
|
}
|
|
@@ -78,11 +152,21 @@ class TideScreen {
|
|
|
78
152
|
if (this.updateFunction) {
|
|
79
153
|
this.updateFunction();
|
|
80
154
|
}
|
|
81
|
-
|
|
82
|
-
|
|
155
|
+
if (beforeRender) {
|
|
156
|
+
beforeRender();
|
|
157
|
+
}
|
|
158
|
+
const dirtyRows = this.renderBuffer();
|
|
159
|
+
this.render(dirtyRows);
|
|
160
|
+
if (afterRender) {
|
|
161
|
+
afterRender();
|
|
162
|
+
}
|
|
83
163
|
setTimeout(loop, interval);
|
|
84
164
|
};
|
|
85
165
|
loop();
|
|
166
|
+
process.on("SIGINT", () => {
|
|
167
|
+
process.stdout.write("\x1b[?25h");
|
|
168
|
+
process.exit();
|
|
169
|
+
});
|
|
86
170
|
}
|
|
87
171
|
}
|
|
88
172
|
exports.TideScreen = TideScreen;
|
package/dist/util.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import type { Rect } from "./interfaces";
|
|
1
2
|
export declare function getColorCode(color: string): string;
|
|
2
3
|
export declare function wrapText(text: string, maxWidth: number): string[];
|
|
4
|
+
export declare function intersectRect(a: Rect, b: Rect): Rect | null;
|
|
5
|
+
export declare function setCell(buffer: string[][], x: number, y: number, value: string, clip?: Rect, dirtyRows?: Set<number>): void;
|
|
3
6
|
//# sourceMappingURL=util.d.ts.map
|
package/dist/util.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEzC,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,UAgBzC;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,YAetD;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAW3D;AAED,wBAAgB,OAAO,CACrB,MAAM,EAAE,MAAM,EAAE,EAAE,EAClB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,IAAI,EACX,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,QAmBxB"}
|
package/dist/util.js
CHANGED
|
@@ -2,20 +2,23 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getColorCode = getColorCode;
|
|
4
4
|
exports.wrapText = wrapText;
|
|
5
|
+
exports.intersectRect = intersectRect;
|
|
6
|
+
exports.setCell = setCell;
|
|
5
7
|
function getColorCode(color) {
|
|
6
8
|
const colors = {
|
|
7
|
-
reset:
|
|
8
|
-
black:
|
|
9
|
-
red:
|
|
10
|
-
green:
|
|
11
|
-
yellow:
|
|
12
|
-
blue:
|
|
13
|
-
magenta:
|
|
14
|
-
cyan:
|
|
15
|
-
white:
|
|
16
|
-
|
|
9
|
+
reset: "\x1b[0m",
|
|
10
|
+
black: "\x1b[30m",
|
|
11
|
+
red: "\x1b[31m",
|
|
12
|
+
green: "\x1b[32m",
|
|
13
|
+
yellow: "\x1b[33m",
|
|
14
|
+
blue: "\x1b[34m",
|
|
15
|
+
magenta: "\x1b[35m",
|
|
16
|
+
cyan: "\x1b[36m",
|
|
17
|
+
white: "\x1b[37m",
|
|
18
|
+
gray: "\x1b[90m",
|
|
19
|
+
random: "\x1b[38;5;" + Math.floor(Math.random() * 256) + "m",
|
|
17
20
|
};
|
|
18
|
-
return colors[color.toLowerCase()] || colors[
|
|
21
|
+
return colors[color.toLowerCase()] || colors["reset"];
|
|
19
22
|
}
|
|
20
23
|
function wrapText(text, maxWidth) {
|
|
21
24
|
const lines = [];
|
|
@@ -32,3 +35,30 @@ function wrapText(text, maxWidth) {
|
|
|
32
35
|
lines.push(currentLine.trim());
|
|
33
36
|
return lines;
|
|
34
37
|
}
|
|
38
|
+
function intersectRect(a, b) {
|
|
39
|
+
const x1 = Math.max(a.x, b.x);
|
|
40
|
+
const y1 = Math.max(a.y, b.y);
|
|
41
|
+
const x2 = Math.min(a.x + a.width, b.x + b.width);
|
|
42
|
+
const y2 = Math.min(a.y + a.height, b.y + b.height);
|
|
43
|
+
if (x2 <= x1 || y2 <= y1) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
return { x: x1, y: y1, width: x2 - x1, height: y2 - y1 };
|
|
47
|
+
}
|
|
48
|
+
function setCell(buffer, x, y, value, clip, dirtyRows) {
|
|
49
|
+
if (y < 0 || x < 0 || y >= buffer.length || x >= buffer[0].length) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (clip) {
|
|
53
|
+
if (x < clip.x ||
|
|
54
|
+
y < clip.y ||
|
|
55
|
+
x >= clip.x + clip.width ||
|
|
56
|
+
y >= clip.y + clip.height) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
buffer[y][x] = value;
|
|
61
|
+
if (dirtyRows) {
|
|
62
|
+
dirtyRows.add(y);
|
|
63
|
+
}
|
|
64
|
+
}
|
package/package.json
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tidepool",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"author": "stuncs69",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
6
7
|
"repository": {
|
|
7
8
|
"type": "git",
|
|
8
|
-
"url": "https://github.com/
|
|
9
|
+
"url": "https://github.com/stuncs69/tidepool.git"
|
|
9
10
|
},
|
|
10
11
|
"devDependencies": {
|
|
11
12
|
"@eslint/js": "^9.9.0",
|
|
12
|
-
"@types/node": "^
|
|
13
|
+
"@types/node": "^25.0.8",
|
|
13
14
|
"@typescript-eslint/eslint-plugin": "^8.1.0",
|
|
14
15
|
"@typescript-eslint/parser": "^8.1.0",
|
|
15
16
|
"eslint": "^9.9.0",
|
|
@@ -20,7 +21,24 @@
|
|
|
20
21
|
"description": "A CLI rendering engine in TypeScript.",
|
|
21
22
|
"license": "ISC",
|
|
22
23
|
"scripts": {
|
|
23
|
-
"test": "
|
|
24
|
-
"lint": "eslint ./src/*"
|
|
24
|
+
"test": "npm run build && node --test test/*.test.js",
|
|
25
|
+
"lint": "eslint ./src/*",
|
|
26
|
+
"build": "tsc",
|
|
27
|
+
"prepublishOnly": "npm run build",
|
|
28
|
+
"demo:build": "tsc -p demo/tsconfig.json",
|
|
29
|
+
"demo": "npm run build && npm run demo:build && node dist-demo/demo/demo.js",
|
|
30
|
+
"demo:stack": "npm run build && npm run demo:build && node dist-demo/demo/stacking.js",
|
|
31
|
+
"demo:form": "npm run build && npm run demo:build && node dist-demo/demo/form.js",
|
|
32
|
+
"demo:chat": "npm run build && npm run demo:build && node dist-demo/demo/chat.js"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist"
|
|
36
|
+
],
|
|
37
|
+
"exports": {
|
|
38
|
+
".": {
|
|
39
|
+
"import": "./dist/index.js",
|
|
40
|
+
"require": "./dist/index.js",
|
|
41
|
+
"types": "./dist/index.d.ts"
|
|
42
|
+
}
|
|
25
43
|
}
|
|
26
44
|
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# This workflow uses actions that are not certified by GitHub.
|
|
2
|
-
# They are provided by a third-party and are governed by
|
|
3
|
-
# separate terms of service, privacy policy, and support
|
|
4
|
-
# documentation.
|
|
5
|
-
# ESLint is a tool for identifying and reporting on patterns
|
|
6
|
-
# found in ECMAScript/JavaScript code.
|
|
7
|
-
# More details at https://github.com/eslint/eslint
|
|
8
|
-
# and https://eslint.org
|
|
9
|
-
|
|
10
|
-
name: ESLint
|
|
11
|
-
|
|
12
|
-
on:
|
|
13
|
-
push:
|
|
14
|
-
branches: [ "main" ]
|
|
15
|
-
pull_request:
|
|
16
|
-
# The branches below must be a subset of the branches above
|
|
17
|
-
branches: [ "main" ]
|
|
18
|
-
schedule:
|
|
19
|
-
- cron: '21 0 * * 3'
|
|
20
|
-
|
|
21
|
-
jobs:
|
|
22
|
-
eslint:
|
|
23
|
-
name: Run eslint scanning
|
|
24
|
-
runs-on: ubuntu-latest
|
|
25
|
-
permissions:
|
|
26
|
-
contents: read
|
|
27
|
-
security-events: write
|
|
28
|
-
actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status
|
|
29
|
-
steps:
|
|
30
|
-
- name: Checkout code
|
|
31
|
-
uses: actions/checkout@v4
|
|
32
|
-
|
|
33
|
-
- name: Install ESLint
|
|
34
|
-
run: |
|
|
35
|
-
npm install eslint@8.10.0
|
|
36
|
-
npm install @microsoft/eslint-formatter-sarif@2.1.7
|
|
37
|
-
|
|
38
|
-
- name: Run ESLint
|
|
39
|
-
run: npx eslint .
|
|
40
|
-
--config .eslintrc.js
|
|
41
|
-
--ext .js,.jsx,.ts,.tsx
|
|
42
|
-
--format @microsoft/eslint-formatter-sarif
|
|
43
|
-
--output-file eslint-results.sarif
|
|
44
|
-
continue-on-error: true
|
|
45
|
-
|
|
46
|
-
- name: Upload analysis results to GitHub
|
|
47
|
-
uses: github/codeql-action/upload-sarif@v3
|
|
48
|
-
with:
|
|
49
|
-
sarif_file: eslint-results.sarif
|
|
50
|
-
wait-for-processing: true
|
package/eslint.config.mjs
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import typescriptEslint from "@typescript-eslint/eslint-plugin";
|
|
2
|
-
import globals from "globals";
|
|
3
|
-
import tsParser from "@typescript-eslint/parser";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import { fileURLToPath } from "node:url";
|
|
6
|
-
import js from "@eslint/js";
|
|
7
|
-
import { FlatCompat } from "@eslint/eslintrc";
|
|
8
|
-
|
|
9
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
-
const __dirname = path.dirname(__filename);
|
|
11
|
-
const compat = new FlatCompat({
|
|
12
|
-
baseDirectory: __dirname,
|
|
13
|
-
recommendedConfig: js.configs.recommended,
|
|
14
|
-
allConfig: js.configs.all
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
export default [
|
|
18
|
-
...compat.extends("eslint:recommended", "plugin:@typescript-eslint/recommended"),
|
|
19
|
-
{
|
|
20
|
-
plugins: {
|
|
21
|
-
"@typescript-eslint": typescriptEslint,
|
|
22
|
-
},
|
|
23
|
-
|
|
24
|
-
languageOptions: {
|
|
25
|
-
globals: {
|
|
26
|
-
...globals.node,
|
|
27
|
-
},
|
|
28
|
-
|
|
29
|
-
parser: tsParser,
|
|
30
|
-
ecmaVersion: 12,
|
|
31
|
-
sourceType: "module",
|
|
32
|
-
},
|
|
33
|
-
|
|
34
|
-
rules: {
|
|
35
|
-
"@typescript-eslint/no-unsafe-function-type": "off",
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
|
-
];
|