utilium 0.7.10 → 0.8.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.
- package/dist/dom.d.ts +9 -0
- package/dist/dom.js +29 -0
- package/dist/shell.d.ts +37 -0
- package/dist/shell.js +79 -0
- package/package.json +5 -2
- package/readme.md +2 -1
- package/src/dom.ts +32 -0
- package/src/shell.ts +123 -0
package/dist/dom.d.ts
ADDED
package/dist/dom.js
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-expressions */
|
2
|
+
/**
|
3
|
+
* Upload a file
|
4
|
+
* @todo use Promise.withResolvers
|
5
|
+
*/
|
6
|
+
export function upload(type, multiple = false) {
|
7
|
+
return new Promise((resolve, reject) => {
|
8
|
+
const input = document.createElement('input');
|
9
|
+
input.type = 'file';
|
10
|
+
if (type)
|
11
|
+
input.accept = type;
|
12
|
+
if (multiple)
|
13
|
+
input.multiple = true;
|
14
|
+
input.addEventListener('change', e => {
|
15
|
+
const file = input.files?.[0];
|
16
|
+
file ? resolve(file) : reject(new ReferenceError('No files uploaded'));
|
17
|
+
});
|
18
|
+
input.click();
|
19
|
+
});
|
20
|
+
}
|
21
|
+
/**
|
22
|
+
* Downloads some data
|
23
|
+
*/
|
24
|
+
export function download(data, name) {
|
25
|
+
const link = document.createElement('a');
|
26
|
+
link.href = URL.createObjectURL(new Blob([data]));
|
27
|
+
link.download = name;
|
28
|
+
link.click();
|
29
|
+
}
|
package/dist/shell.d.ts
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
import type { Terminal } from '@xterm/xterm';
|
2
|
+
export interface ShellOptions {
|
3
|
+
/**
|
4
|
+
* The terminal associated with the context
|
5
|
+
*/
|
6
|
+
terminal: Terminal;
|
7
|
+
/**
|
8
|
+
* The prompt to use, can be a getter.
|
9
|
+
*/
|
10
|
+
readonly prompt?: string;
|
11
|
+
/**
|
12
|
+
* The handler for when a line is parsed
|
13
|
+
*/
|
14
|
+
onLine?(this: void, line: string): unknown;
|
15
|
+
}
|
16
|
+
export interface ShellContext extends Required<ShellOptions> {
|
17
|
+
/**
|
18
|
+
* The input currently being shown
|
19
|
+
*/
|
20
|
+
input: string;
|
21
|
+
/**
|
22
|
+
* The index for which input is being shown
|
23
|
+
*/
|
24
|
+
index: number;
|
25
|
+
/**
|
26
|
+
* The current, uncached input
|
27
|
+
*/
|
28
|
+
currentInput: string;
|
29
|
+
/**
|
30
|
+
* array of previous inputs
|
31
|
+
*/
|
32
|
+
inputs: string[];
|
33
|
+
}
|
34
|
+
/**
|
35
|
+
* Creates a new shell using the provided options
|
36
|
+
*/
|
37
|
+
export declare function createShell({ terminal, prompt, onLine }: ShellOptions): ShellContext;
|
package/dist/shell.js
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
function handleData($, data) {
|
2
|
+
if ($.index == -1) {
|
3
|
+
$.currentInput = $.input;
|
4
|
+
}
|
5
|
+
function clear() {
|
6
|
+
$.terminal.write('\x1b[2K\r' + $.prompt);
|
7
|
+
}
|
8
|
+
const x = $.terminal.buffer.active.cursorX - $.prompt.length;
|
9
|
+
switch (data) {
|
10
|
+
case 'ArrowUp':
|
11
|
+
case '\x1b[A':
|
12
|
+
clear();
|
13
|
+
if ($.index < $.inputs.length - 1) {
|
14
|
+
$.input = $.inputs[++$.index];
|
15
|
+
}
|
16
|
+
$.terminal.write($.input);
|
17
|
+
break;
|
18
|
+
case 'ArrowDown':
|
19
|
+
case '\x1b[B':
|
20
|
+
clear();
|
21
|
+
if ($.index >= 0) {
|
22
|
+
$.input = $.index-- == 0 ? $.currentInput : $.inputs[$.index];
|
23
|
+
}
|
24
|
+
$.terminal.write($.input);
|
25
|
+
break;
|
26
|
+
case '\x1b[D':
|
27
|
+
if (x > 0) {
|
28
|
+
$.terminal.write(data);
|
29
|
+
}
|
30
|
+
break;
|
31
|
+
case '\x1b[C':
|
32
|
+
if (x < $.currentInput.length) {
|
33
|
+
$.terminal.write(data);
|
34
|
+
}
|
35
|
+
break;
|
36
|
+
case '\x1b[F':
|
37
|
+
$.terminal.write(`\x1b[${$.prompt.length + $.currentInput.length + 1}G`);
|
38
|
+
break;
|
39
|
+
case '\x1b[H':
|
40
|
+
$.terminal.write(`\x1b[${$.prompt.length + 1}G`);
|
41
|
+
break;
|
42
|
+
case '\x7f':
|
43
|
+
if (x <= 0) {
|
44
|
+
return;
|
45
|
+
}
|
46
|
+
$.terminal.write('\b\x1b[P');
|
47
|
+
$.input = $.input.slice(0, x - 1) + $.input.slice(x);
|
48
|
+
break;
|
49
|
+
case '\r':
|
50
|
+
if ($.input != $.inputs[0]) {
|
51
|
+
$.inputs.unshift($.input);
|
52
|
+
}
|
53
|
+
$.index = -1;
|
54
|
+
$.input = '';
|
55
|
+
$.terminal.write('\r\n');
|
56
|
+
$.onLine($.currentInput);
|
57
|
+
$.terminal.write($.prompt);
|
58
|
+
break;
|
59
|
+
default:
|
60
|
+
$.terminal.write(data);
|
61
|
+
$.input = $.input.slice(0, x) + data + $.input.slice(x);
|
62
|
+
}
|
63
|
+
}
|
64
|
+
/**
|
65
|
+
* Creates a new shell using the provided options
|
66
|
+
*/
|
67
|
+
export function createShell({ terminal, prompt = '', onLine = () => { } }) {
|
68
|
+
const context = {
|
69
|
+
terminal,
|
70
|
+
prompt,
|
71
|
+
onLine,
|
72
|
+
input: '',
|
73
|
+
index: -1,
|
74
|
+
currentInput: '',
|
75
|
+
inputs: [],
|
76
|
+
};
|
77
|
+
terminal.onData(data => handleData(context, data));
|
78
|
+
return context;
|
79
|
+
}
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "utilium",
|
3
|
-
"version": "0.
|
4
|
-
"description": "Typescript
|
3
|
+
"version": "0.8.1",
|
4
|
+
"description": "Typescript utilities",
|
5
5
|
"main": "dist/index.js",
|
6
6
|
"types": "dist/index.d.ts",
|
7
7
|
"type": "module",
|
@@ -49,5 +49,8 @@
|
|
49
49
|
},
|
50
50
|
"dependencies": {
|
51
51
|
"eventemitter3": "^5.0.1"
|
52
|
+
},
|
53
|
+
"optionalDependencies": {
|
54
|
+
"@xterm/xterm": "^5.5.0"
|
52
55
|
}
|
53
56
|
}
|
package/readme.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Utilium
|
2
2
|
|
3
|
-
A bunch of
|
3
|
+
A bunch of utilities for Typescript. This includes:
|
4
4
|
|
5
5
|
- Structs (using decorators)
|
6
6
|
- Compile-time math types
|
@@ -10,3 +10,4 @@ A bunch of utilies for Typescript. This includes:
|
|
10
10
|
- `List`, a class that combines the best aspects of `Set` and arrays
|
11
11
|
- `JSONFileMap` and `FolderMap`
|
12
12
|
- Version utilities
|
13
|
+
- Xterm.js shell handling (arrows, home/end, prompting, etc.)
|
package/src/dom.ts
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-expressions */
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Upload a file
|
5
|
+
* @todo use Promise.withResolvers
|
6
|
+
*/
|
7
|
+
export function upload(type: string, multiple = false): Promise<File> {
|
8
|
+
return new Promise<File>((resolve, reject) => {
|
9
|
+
const input = document.createElement('input');
|
10
|
+
input.type = 'file';
|
11
|
+
if (type) input.accept = type;
|
12
|
+
|
13
|
+
if (multiple) input.multiple = true;
|
14
|
+
|
15
|
+
input.addEventListener('change', e => {
|
16
|
+
const file = input.files?.[0];
|
17
|
+
file ? resolve(file) : reject(new ReferenceError('No files uploaded'));
|
18
|
+
});
|
19
|
+
|
20
|
+
input.click();
|
21
|
+
});
|
22
|
+
}
|
23
|
+
|
24
|
+
/**
|
25
|
+
* Downloads some data
|
26
|
+
*/
|
27
|
+
export function download(data: BlobPart, name: string): void {
|
28
|
+
const link = document.createElement('a');
|
29
|
+
link.href = URL.createObjectURL(new Blob([data]));
|
30
|
+
link.download = name;
|
31
|
+
link.click();
|
32
|
+
}
|
package/src/shell.ts
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
/* A simple wrapper for xterm.js that makes implementing shells easier */
|
2
|
+
import type { Terminal } from '@xterm/xterm';
|
3
|
+
|
4
|
+
export interface ShellOptions {
|
5
|
+
/**
|
6
|
+
* The terminal associated with the context
|
7
|
+
*/
|
8
|
+
terminal: Terminal;
|
9
|
+
|
10
|
+
/**
|
11
|
+
* The prompt to use, can be a getter.
|
12
|
+
*/
|
13
|
+
readonly prompt?: string;
|
14
|
+
|
15
|
+
/**
|
16
|
+
* The handler for when a line is parsed
|
17
|
+
*/
|
18
|
+
onLine?(this: void, line: string): unknown;
|
19
|
+
}
|
20
|
+
|
21
|
+
export interface ShellContext extends Required<ShellOptions> {
|
22
|
+
/**
|
23
|
+
* The input currently being shown
|
24
|
+
*/
|
25
|
+
input: string;
|
26
|
+
|
27
|
+
/**
|
28
|
+
* The index for which input is being shown
|
29
|
+
*/
|
30
|
+
index: number;
|
31
|
+
|
32
|
+
/**
|
33
|
+
* The current, uncached input
|
34
|
+
*/
|
35
|
+
currentInput: string;
|
36
|
+
|
37
|
+
/**
|
38
|
+
* array of previous inputs
|
39
|
+
*/
|
40
|
+
inputs: string[];
|
41
|
+
}
|
42
|
+
|
43
|
+
function handleData($: ShellContext, data: string) {
|
44
|
+
if ($.index == -1) {
|
45
|
+
$.currentInput = $.input;
|
46
|
+
}
|
47
|
+
|
48
|
+
function clear(): void {
|
49
|
+
$.terminal.write('\x1b[2K\r' + $.prompt);
|
50
|
+
}
|
51
|
+
const x = $.terminal.buffer.active.cursorX - $.prompt.length;
|
52
|
+
switch (data) {
|
53
|
+
case 'ArrowUp':
|
54
|
+
case '\x1b[A':
|
55
|
+
clear();
|
56
|
+
if ($.index < $.inputs.length - 1) {
|
57
|
+
$.input = $.inputs[++$.index];
|
58
|
+
}
|
59
|
+
$.terminal.write($.input);
|
60
|
+
break;
|
61
|
+
case 'ArrowDown':
|
62
|
+
case '\x1b[B':
|
63
|
+
clear();
|
64
|
+
if ($.index >= 0) {
|
65
|
+
$.input = $.index-- == 0 ? $.currentInput : $.inputs[$.index];
|
66
|
+
}
|
67
|
+
$.terminal.write($.input);
|
68
|
+
break;
|
69
|
+
case '\x1b[D':
|
70
|
+
if (x > 0) {
|
71
|
+
$.terminal.write(data);
|
72
|
+
}
|
73
|
+
break;
|
74
|
+
case '\x1b[C':
|
75
|
+
if (x < $.currentInput.length) {
|
76
|
+
$.terminal.write(data);
|
77
|
+
}
|
78
|
+
break;
|
79
|
+
case '\x1b[F':
|
80
|
+
$.terminal.write(`\x1b[${$.prompt.length + $.currentInput.length + 1}G`);
|
81
|
+
break;
|
82
|
+
case '\x1b[H':
|
83
|
+
$.terminal.write(`\x1b[${$.prompt.length + 1}G`);
|
84
|
+
break;
|
85
|
+
case '\x7f':
|
86
|
+
if (x <= 0) {
|
87
|
+
return;
|
88
|
+
}
|
89
|
+
$.terminal.write('\b\x1b[P');
|
90
|
+
$.input = $.input.slice(0, x - 1) + $.input.slice(x);
|
91
|
+
break;
|
92
|
+
case '\r':
|
93
|
+
if ($.input != $.inputs[0]) {
|
94
|
+
$.inputs.unshift($.input);
|
95
|
+
}
|
96
|
+
$.index = -1;
|
97
|
+
$.input = '';
|
98
|
+
$.terminal.write('\r\n');
|
99
|
+
$.onLine($.currentInput);
|
100
|
+
$.terminal.write($.prompt);
|
101
|
+
break;
|
102
|
+
default:
|
103
|
+
$.terminal.write(data);
|
104
|
+
$.input = $.input.slice(0, x) + data + $.input.slice(x);
|
105
|
+
}
|
106
|
+
}
|
107
|
+
|
108
|
+
/**
|
109
|
+
* Creates a new shell using the provided options
|
110
|
+
*/
|
111
|
+
export function createShell({ terminal, prompt = '', onLine = () => {} }: ShellOptions): ShellContext {
|
112
|
+
const context: ShellContext = {
|
113
|
+
terminal,
|
114
|
+
prompt,
|
115
|
+
onLine,
|
116
|
+
input: '',
|
117
|
+
index: -1,
|
118
|
+
currentInput: '',
|
119
|
+
inputs: [],
|
120
|
+
};
|
121
|
+
terminal.onData(data => handleData(context, data));
|
122
|
+
return context;
|
123
|
+
}
|