fullstacked 0.11.3-1148 → 0.11.3-1150
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/lib/archive/archive.ts +140 -140
- package/lib/archive/index.ts +4 -4
- package/lib/base64.ts +144 -144
- package/lib/bridge/index.ts +53 -53
- package/lib/bridge/platform/android.ts +18 -18
- package/lib/bridge/platform/apple.ts +46 -46
- package/lib/bridge/platform/electron.ts +14 -14
- package/lib/bridge/platform/linux-gtk.ts +48 -48
- package/lib/bridge/platform/linux-qt.ts +68 -68
- package/lib/bridge/platform/node.ts +32 -32
- package/lib/bridge/platform/wasm.ts +17 -17
- package/lib/bridge/platform/windows.ts +49 -49
- package/lib/bridge/serialization.ts +153 -153
- package/lib/components/snackbar.ts +60 -60
- package/lib/connect/index.ts +125 -125
- package/lib/core_message/core_message.ts +75 -75
- package/lib/core_message/index.ts +3 -3
- package/lib/fetch/index.ts +318 -318
- package/lib/fs/fs.ts +157 -157
- package/lib/fs/index.ts +3 -3
- package/lib/fullstacked.d.ts +208 -208
- package/lib/platform/index.ts +14 -14
- package/package.json +1 -1
|
@@ -1,49 +1,49 @@
|
|
|
1
|
-
import { Bridge } from "..";
|
|
2
|
-
import { fromByteArray, toByteArray } from "../../base64";
|
|
3
|
-
import {
|
|
4
|
-
bytesToNumber,
|
|
5
|
-
deserializeArgs,
|
|
6
|
-
getLowestKeyIdAvailable,
|
|
7
|
-
numberTo4Bytes
|
|
8
|
-
} from "../serialization";
|
|
9
|
-
|
|
10
|
-
const requests = new Map<number, (data: Uint8Array) => void>();
|
|
11
|
-
|
|
12
|
-
export const BridgeWindows: Bridge = (
|
|
13
|
-
payload: Uint8Array,
|
|
14
|
-
transformer?: (responseArgs: any[]) => any
|
|
15
|
-
) => {
|
|
16
|
-
const requestId = getLowestKeyIdAvailable(requests);
|
|
17
|
-
|
|
18
|
-
requests.set(requestId, null);
|
|
19
|
-
|
|
20
|
-
const base64 = fromByteArray(
|
|
21
|
-
new Uint8Array([...numberTo4Bytes(requestId), ...payload])
|
|
22
|
-
);
|
|
23
|
-
|
|
24
|
-
return new Promise((resolve, reject) => {
|
|
25
|
-
requests.set(requestId, (data) => {
|
|
26
|
-
try {
|
|
27
|
-
const args = deserializeArgs(data);
|
|
28
|
-
if (transformer) {
|
|
29
|
-
return resolve(transformer(args));
|
|
30
|
-
}
|
|
31
|
-
resolve(args);
|
|
32
|
-
} catch (e) {
|
|
33
|
-
reject(e);
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
globalThis.chrome.webview.postMessage(base64);
|
|
38
|
-
});
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export function initRespondWindows() {
|
|
42
|
-
globalThis.respond = (base64: string) => {
|
|
43
|
-
const data = toByteArray(base64);
|
|
44
|
-
const id = bytesToNumber(data.slice(0, 4));
|
|
45
|
-
const resolver = requests.get(id);
|
|
46
|
-
resolver(data.slice(4));
|
|
47
|
-
requests.delete(id);
|
|
48
|
-
};
|
|
49
|
-
}
|
|
1
|
+
import { Bridge } from "..";
|
|
2
|
+
import { fromByteArray, toByteArray } from "../../base64";
|
|
3
|
+
import {
|
|
4
|
+
bytesToNumber,
|
|
5
|
+
deserializeArgs,
|
|
6
|
+
getLowestKeyIdAvailable,
|
|
7
|
+
numberTo4Bytes
|
|
8
|
+
} from "../serialization";
|
|
9
|
+
|
|
10
|
+
const requests = new Map<number, (data: Uint8Array) => void>();
|
|
11
|
+
|
|
12
|
+
export const BridgeWindows: Bridge = (
|
|
13
|
+
payload: Uint8Array,
|
|
14
|
+
transformer?: (responseArgs: any[]) => any
|
|
15
|
+
) => {
|
|
16
|
+
const requestId = getLowestKeyIdAvailable(requests);
|
|
17
|
+
|
|
18
|
+
requests.set(requestId, null);
|
|
19
|
+
|
|
20
|
+
const base64 = fromByteArray(
|
|
21
|
+
new Uint8Array([...numberTo4Bytes(requestId), ...payload])
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
return new Promise((resolve, reject) => {
|
|
25
|
+
requests.set(requestId, (data) => {
|
|
26
|
+
try {
|
|
27
|
+
const args = deserializeArgs(data);
|
|
28
|
+
if (transformer) {
|
|
29
|
+
return resolve(transformer(args));
|
|
30
|
+
}
|
|
31
|
+
resolve(args);
|
|
32
|
+
} catch (e) {
|
|
33
|
+
reject(e);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
globalThis.chrome.webview.postMessage(base64);
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export function initRespondWindows() {
|
|
42
|
+
globalThis.respond = (base64: string) => {
|
|
43
|
+
const data = toByteArray(base64);
|
|
44
|
+
const id = bytesToNumber(data.slice(0, 4));
|
|
45
|
+
const resolver = requests.get(id);
|
|
46
|
+
resolver(data.slice(4));
|
|
47
|
+
requests.delete(id);
|
|
48
|
+
};
|
|
49
|
+
}
|
|
@@ -1,153 +1,153 @@
|
|
|
1
|
-
const te = new TextEncoder();
|
|
2
|
-
const td = new TextDecoder();
|
|
3
|
-
|
|
4
|
-
export enum DataType {
|
|
5
|
-
UNDEFINED = 0,
|
|
6
|
-
BOOLEAN = 1,
|
|
7
|
-
STRING = 2,
|
|
8
|
-
NUMBER = 3,
|
|
9
|
-
BUFFER = 4,
|
|
10
|
-
ERROR = 5
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function serializeNumber(n) {
|
|
14
|
-
const view = new DataView(new ArrayBuffer(8));
|
|
15
|
-
view.setFloat64(0, n);
|
|
16
|
-
return new Uint8Array(view.buffer);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function deserializeNumber(bytes: Uint8Array) {
|
|
20
|
-
const buffer = new ArrayBuffer(8);
|
|
21
|
-
new Uint8Array(buffer).set(bytes);
|
|
22
|
-
return new DataView(buffer).getFloat64(0);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function numberTo4Bytes(n: number) {
|
|
26
|
-
const uint8Array = new Uint8Array(4);
|
|
27
|
-
uint8Array[0] = (n & 0xff000000) >> 24;
|
|
28
|
-
uint8Array[1] = (n & 0x00ff0000) >> 16;
|
|
29
|
-
uint8Array[2] = (n & 0x0000ff00) >> 8;
|
|
30
|
-
uint8Array[3] = (n & 0x000000ff) >> 0;
|
|
31
|
-
return uint8Array;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function bytesToNumber(bytes: Uint8Array) {
|
|
35
|
-
return (
|
|
36
|
-
((bytes[0] << 24) |
|
|
37
|
-
(bytes[1] << 16) |
|
|
38
|
-
(bytes[2] << 8) |
|
|
39
|
-
(bytes[3] << 0)) >>>
|
|
40
|
-
0
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/*
|
|
45
|
-
|
|
46
|
-
1 byte for type
|
|
47
|
-
4 bytes for length
|
|
48
|
-
n bytes for data
|
|
49
|
-
|
|
50
|
-
*/
|
|
51
|
-
|
|
52
|
-
export function serializeArgs(args: any[]) {
|
|
53
|
-
const parts = args.map((arg) => {
|
|
54
|
-
let data: Uint8Array, type: DataType;
|
|
55
|
-
if (typeof arg === "undefined" || arg === null) {
|
|
56
|
-
type = DataType.UNDEFINED;
|
|
57
|
-
data = new Uint8Array(0);
|
|
58
|
-
} else if (ArrayBuffer.isView(arg)) {
|
|
59
|
-
type = DataType.BUFFER;
|
|
60
|
-
data = new Uint8Array(arg.buffer);
|
|
61
|
-
} else if (typeof arg === "boolean") {
|
|
62
|
-
type = DataType.BOOLEAN;
|
|
63
|
-
data = new Uint8Array([arg ? 1 : 0]);
|
|
64
|
-
} else if (typeof arg === "string") {
|
|
65
|
-
type = DataType.STRING;
|
|
66
|
-
data = te.encode(arg);
|
|
67
|
-
} else if (typeof arg === "number") {
|
|
68
|
-
type = DataType.NUMBER;
|
|
69
|
-
data = serializeNumber(arg);
|
|
70
|
-
} else {
|
|
71
|
-
console.error("Using unknown type with IPC call");
|
|
72
|
-
return null;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return new Uint8Array([
|
|
76
|
-
type,
|
|
77
|
-
...numberTo4Bytes(data.byteLength),
|
|
78
|
-
...data
|
|
79
|
-
]);
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
const totalLength = parts.reduce(
|
|
83
|
-
(total, part) => total + part.byteLength,
|
|
84
|
-
0
|
|
85
|
-
);
|
|
86
|
-
const data = new Uint8Array(totalLength);
|
|
87
|
-
parts.forEach((part, i) => {
|
|
88
|
-
const offset = parts
|
|
89
|
-
.slice(0, i)
|
|
90
|
-
.reduce((total, b) => total + b.byteLength, 0);
|
|
91
|
-
data.set(part, offset);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
return data;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export function deserializeArgs(data: Uint8Array) {
|
|
98
|
-
const args = [];
|
|
99
|
-
|
|
100
|
-
let cursor = 0;
|
|
101
|
-
while (cursor < data.byteLength) {
|
|
102
|
-
const type = data[cursor] as DataType;
|
|
103
|
-
cursor += 1;
|
|
104
|
-
const length = bytesToNumber(data.slice(cursor, cursor + 4));
|
|
105
|
-
cursor += 4;
|
|
106
|
-
const arg = data.slice(cursor, cursor + length);
|
|
107
|
-
cursor += length;
|
|
108
|
-
|
|
109
|
-
switch (type) {
|
|
110
|
-
case DataType.UNDEFINED:
|
|
111
|
-
args.push(undefined);
|
|
112
|
-
break;
|
|
113
|
-
case DataType.BOOLEAN:
|
|
114
|
-
args.push(arg.at(0) ? true : false);
|
|
115
|
-
break;
|
|
116
|
-
case DataType.STRING:
|
|
117
|
-
args.push(td.decode(arg));
|
|
118
|
-
break;
|
|
119
|
-
case DataType.NUMBER:
|
|
120
|
-
args.push(deserializeNumber(arg));
|
|
121
|
-
break;
|
|
122
|
-
case DataType.BUFFER:
|
|
123
|
-
args.push(arg);
|
|
124
|
-
break;
|
|
125
|
-
case DataType.ERROR:
|
|
126
|
-
throw td.decode(arg);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return args;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
export function convertObjectToArray(obj: object) {
|
|
134
|
-
return Object.entries(obj).flat();
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
export function convertArrayToObject(arr: any[]) {
|
|
138
|
-
let obj = {};
|
|
139
|
-
for (let i = 0; i < arr.length; i += 2) {
|
|
140
|
-
obj[arr[i]] = arr[i + 1];
|
|
141
|
-
}
|
|
142
|
-
return obj;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
export function getLowestKeyIdAvailable(map: Map<number, any>) {
|
|
146
|
-
const currentIds = Array.from(map.keys()).sort((a, b) => a - b);
|
|
147
|
-
let requestId = 0;
|
|
148
|
-
for (const id of currentIds) {
|
|
149
|
-
if (requestId !== id) break;
|
|
150
|
-
requestId++;
|
|
151
|
-
}
|
|
152
|
-
return requestId;
|
|
153
|
-
}
|
|
1
|
+
const te = new TextEncoder();
|
|
2
|
+
const td = new TextDecoder();
|
|
3
|
+
|
|
4
|
+
export enum DataType {
|
|
5
|
+
UNDEFINED = 0,
|
|
6
|
+
BOOLEAN = 1,
|
|
7
|
+
STRING = 2,
|
|
8
|
+
NUMBER = 3,
|
|
9
|
+
BUFFER = 4,
|
|
10
|
+
ERROR = 5
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function serializeNumber(n) {
|
|
14
|
+
const view = new DataView(new ArrayBuffer(8));
|
|
15
|
+
view.setFloat64(0, n);
|
|
16
|
+
return new Uint8Array(view.buffer);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function deserializeNumber(bytes: Uint8Array) {
|
|
20
|
+
const buffer = new ArrayBuffer(8);
|
|
21
|
+
new Uint8Array(buffer).set(bytes);
|
|
22
|
+
return new DataView(buffer).getFloat64(0);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function numberTo4Bytes(n: number) {
|
|
26
|
+
const uint8Array = new Uint8Array(4);
|
|
27
|
+
uint8Array[0] = (n & 0xff000000) >> 24;
|
|
28
|
+
uint8Array[1] = (n & 0x00ff0000) >> 16;
|
|
29
|
+
uint8Array[2] = (n & 0x0000ff00) >> 8;
|
|
30
|
+
uint8Array[3] = (n & 0x000000ff) >> 0;
|
|
31
|
+
return uint8Array;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function bytesToNumber(bytes: Uint8Array) {
|
|
35
|
+
return (
|
|
36
|
+
((bytes[0] << 24) |
|
|
37
|
+
(bytes[1] << 16) |
|
|
38
|
+
(bytes[2] << 8) |
|
|
39
|
+
(bytes[3] << 0)) >>>
|
|
40
|
+
0
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/*
|
|
45
|
+
|
|
46
|
+
1 byte for type
|
|
47
|
+
4 bytes for length
|
|
48
|
+
n bytes for data
|
|
49
|
+
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
export function serializeArgs(args: any[]) {
|
|
53
|
+
const parts = args.map((arg) => {
|
|
54
|
+
let data: Uint8Array, type: DataType;
|
|
55
|
+
if (typeof arg === "undefined" || arg === null) {
|
|
56
|
+
type = DataType.UNDEFINED;
|
|
57
|
+
data = new Uint8Array(0);
|
|
58
|
+
} else if (ArrayBuffer.isView(arg)) {
|
|
59
|
+
type = DataType.BUFFER;
|
|
60
|
+
data = new Uint8Array(arg.buffer);
|
|
61
|
+
} else if (typeof arg === "boolean") {
|
|
62
|
+
type = DataType.BOOLEAN;
|
|
63
|
+
data = new Uint8Array([arg ? 1 : 0]);
|
|
64
|
+
} else if (typeof arg === "string") {
|
|
65
|
+
type = DataType.STRING;
|
|
66
|
+
data = te.encode(arg);
|
|
67
|
+
} else if (typeof arg === "number") {
|
|
68
|
+
type = DataType.NUMBER;
|
|
69
|
+
data = serializeNumber(arg);
|
|
70
|
+
} else {
|
|
71
|
+
console.error("Using unknown type with IPC call");
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return new Uint8Array([
|
|
76
|
+
type,
|
|
77
|
+
...numberTo4Bytes(data.byteLength),
|
|
78
|
+
...data
|
|
79
|
+
]);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const totalLength = parts.reduce(
|
|
83
|
+
(total, part) => total + part.byteLength,
|
|
84
|
+
0
|
|
85
|
+
);
|
|
86
|
+
const data = new Uint8Array(totalLength);
|
|
87
|
+
parts.forEach((part, i) => {
|
|
88
|
+
const offset = parts
|
|
89
|
+
.slice(0, i)
|
|
90
|
+
.reduce((total, b) => total + b.byteLength, 0);
|
|
91
|
+
data.set(part, offset);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
return data;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function deserializeArgs(data: Uint8Array) {
|
|
98
|
+
const args = [];
|
|
99
|
+
|
|
100
|
+
let cursor = 0;
|
|
101
|
+
while (cursor < data.byteLength) {
|
|
102
|
+
const type = data[cursor] as DataType;
|
|
103
|
+
cursor += 1;
|
|
104
|
+
const length = bytesToNumber(data.slice(cursor, cursor + 4));
|
|
105
|
+
cursor += 4;
|
|
106
|
+
const arg = data.slice(cursor, cursor + length);
|
|
107
|
+
cursor += length;
|
|
108
|
+
|
|
109
|
+
switch (type) {
|
|
110
|
+
case DataType.UNDEFINED:
|
|
111
|
+
args.push(undefined);
|
|
112
|
+
break;
|
|
113
|
+
case DataType.BOOLEAN:
|
|
114
|
+
args.push(arg.at(0) ? true : false);
|
|
115
|
+
break;
|
|
116
|
+
case DataType.STRING:
|
|
117
|
+
args.push(td.decode(arg));
|
|
118
|
+
break;
|
|
119
|
+
case DataType.NUMBER:
|
|
120
|
+
args.push(deserializeNumber(arg));
|
|
121
|
+
break;
|
|
122
|
+
case DataType.BUFFER:
|
|
123
|
+
args.push(arg);
|
|
124
|
+
break;
|
|
125
|
+
case DataType.ERROR:
|
|
126
|
+
throw td.decode(arg);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return args;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function convertObjectToArray(obj: object) {
|
|
134
|
+
return Object.entries(obj).flat();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function convertArrayToObject(arr: any[]) {
|
|
138
|
+
let obj = {};
|
|
139
|
+
for (let i = 0; i < arr.length; i += 2) {
|
|
140
|
+
obj[arr[i]] = arr[i + 1];
|
|
141
|
+
}
|
|
142
|
+
return obj;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function getLowestKeyIdAvailable(map: Map<number, any>) {
|
|
146
|
+
const currentIds = Array.from(map.keys()).sort((a, b) => a - b);
|
|
147
|
+
let requestId = 0;
|
|
148
|
+
for (const id of currentIds) {
|
|
149
|
+
if (requestId !== id) break;
|
|
150
|
+
requestId++;
|
|
151
|
+
}
|
|
152
|
+
return requestId;
|
|
153
|
+
}
|
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
/*
|
|
2
|
-
This file must follow the figma design
|
|
3
|
-
https://www.figma.com/design/xb3JBRCvEWpbwGda03T5QQ/Mockups?node-id=415-3655
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { Button } from "@fullstacked/ui";
|
|
7
|
-
|
|
8
|
-
type SnackBarOpt = {
|
|
9
|
-
message: string;
|
|
10
|
-
autoDismissTimeout?: number;
|
|
11
|
-
button?: ReturnType<typeof Button>;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
let snackBarsContainer: HTMLDivElement;
|
|
15
|
-
|
|
16
|
-
export function SnackBar(opts: SnackBarOpt) {
|
|
17
|
-
if (!snackBarsContainer) {
|
|
18
|
-
snackBarsContainer = document.createElement("div");
|
|
19
|
-
snackBarsContainer.classList.add("snack-bars-container");
|
|
20
|
-
document.body.append(snackBarsContainer);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const container = document.createElement("div");
|
|
24
|
-
container.classList.add("snack-bar");
|
|
25
|
-
|
|
26
|
-
const text = document.createElement("div");
|
|
27
|
-
text.innerHTML = opts.message;
|
|
28
|
-
container.append(text);
|
|
29
|
-
|
|
30
|
-
if (opts.button) {
|
|
31
|
-
container.append(opts.button);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
container.style.transform = "translateY(100%)";
|
|
35
|
-
container.style.transition = "300ms transform";
|
|
36
|
-
snackBarsContainer.append(container);
|
|
37
|
-
setTimeout(() => (container.style.transform = "translateY(0%)"));
|
|
38
|
-
|
|
39
|
-
let timeout: ReturnType<typeof setTimeout>;
|
|
40
|
-
const dismiss = () => {
|
|
41
|
-
clearTimeout(timeout);
|
|
42
|
-
|
|
43
|
-
const animDuration = 500;
|
|
44
|
-
container.style.transition = `${animDuration}ms opacity`;
|
|
45
|
-
container.style.opacity = "0";
|
|
46
|
-
setTimeout(() => {
|
|
47
|
-
container.remove();
|
|
48
|
-
if (snackBarsContainer?.children.length === 0) {
|
|
49
|
-
snackBarsContainer.remove();
|
|
50
|
-
snackBarsContainer = null;
|
|
51
|
-
}
|
|
52
|
-
}, animDuration);
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
if (opts.autoDismissTimeout) {
|
|
56
|
-
setTimeout(dismiss, opts.autoDismissTimeout);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return { dismiss };
|
|
60
|
-
}
|
|
1
|
+
/*
|
|
2
|
+
This file must follow the figma design
|
|
3
|
+
https://www.figma.com/design/xb3JBRCvEWpbwGda03T5QQ/Mockups?node-id=415-3655
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Button } from "@fullstacked/ui";
|
|
7
|
+
|
|
8
|
+
type SnackBarOpt = {
|
|
9
|
+
message: string;
|
|
10
|
+
autoDismissTimeout?: number;
|
|
11
|
+
button?: ReturnType<typeof Button>;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
let snackBarsContainer: HTMLDivElement;
|
|
15
|
+
|
|
16
|
+
export function SnackBar(opts: SnackBarOpt) {
|
|
17
|
+
if (!snackBarsContainer) {
|
|
18
|
+
snackBarsContainer = document.createElement("div");
|
|
19
|
+
snackBarsContainer.classList.add("snack-bars-container");
|
|
20
|
+
document.body.append(snackBarsContainer);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const container = document.createElement("div");
|
|
24
|
+
container.classList.add("snack-bar");
|
|
25
|
+
|
|
26
|
+
const text = document.createElement("div");
|
|
27
|
+
text.innerHTML = opts.message;
|
|
28
|
+
container.append(text);
|
|
29
|
+
|
|
30
|
+
if (opts.button) {
|
|
31
|
+
container.append(opts.button);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
container.style.transform = "translateY(100%)";
|
|
35
|
+
container.style.transition = "300ms transform";
|
|
36
|
+
snackBarsContainer.append(container);
|
|
37
|
+
setTimeout(() => (container.style.transform = "translateY(0%)"));
|
|
38
|
+
|
|
39
|
+
let timeout: ReturnType<typeof setTimeout>;
|
|
40
|
+
const dismiss = () => {
|
|
41
|
+
clearTimeout(timeout);
|
|
42
|
+
|
|
43
|
+
const animDuration = 500;
|
|
44
|
+
container.style.transition = `${animDuration}ms opacity`;
|
|
45
|
+
container.style.opacity = "0";
|
|
46
|
+
setTimeout(() => {
|
|
47
|
+
container.remove();
|
|
48
|
+
if (snackBarsContainer?.children.length === 0) {
|
|
49
|
+
snackBarsContainer.remove();
|
|
50
|
+
snackBarsContainer = null;
|
|
51
|
+
}
|
|
52
|
+
}, animDuration);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
if (opts.autoDismissTimeout) {
|
|
56
|
+
setTimeout(dismiss, opts.autoDismissTimeout);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return { dismiss };
|
|
60
|
+
}
|