tgui-core 1.1.11 → 1.1.13
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/ProgressBar.module-BkAFfFy0.js +29 -0
- package/dist/Section.module-CLVHJ4yA.js +15 -0
- package/dist/assets/BlockQuote.css +1 -0
- package/dist/assets/Button.css +1 -0
- package/dist/assets/ColorBox.css +1 -0
- package/dist/assets/Dialog.css +1 -0
- package/dist/assets/Dimmer.css +1 -0
- package/dist/assets/Divider.css +1 -0
- package/dist/assets/Flex.css +1 -0
- package/dist/assets/Icon.css +6 -0
- package/dist/assets/Input.css +1 -0
- package/dist/assets/Knob.css +1 -0
- package/dist/assets/LabeledList.css +1 -0
- package/dist/assets/MenuBar.css +1 -0
- package/dist/assets/Modal.css +1 -0
- package/dist/assets/NoticeBox.css +1 -0
- package/dist/assets/NumberInput.css +1 -0
- package/dist/assets/ProgressBar.css +1 -0
- package/dist/assets/RoundGauge.css +1 -0
- package/dist/assets/Section.css +1 -0
- package/dist/assets/Slider.css +1 -0
- package/dist/assets/Stack.css +1 -0
- package/dist/assets/Table.css +1 -0
- package/dist/assets/Tabs.css +1 -0
- package/dist/assets/TextArea.css +1 -0
- package/dist/assets/Tooltip.css +1 -0
- package/dist/common/assets.d.ts +4 -0
- package/dist/common/assets.js +25 -0
- package/dist/common/collections.d.ts +10 -0
- package/dist/common/collections.js +15 -0
- package/dist/common/color.d.ts +25 -0
- package/dist/common/color.js +69 -0
- package/dist/common/constants.d.ts +102 -0
- package/dist/common/constants.js +312 -0
- package/dist/common/events.d.ts +33 -0
- package/dist/common/events.js +147 -0
- package/{lib/common/exhaustive.ts → dist/common/exhaustive.d.ts} +1 -3
- package/dist/common/exhaustive.js +6 -0
- package/dist/common/format.d.ts +11 -0
- package/dist/common/format.js +114 -0
- package/{lib/common/fp.ts → dist/common/fp.d.ts} +2 -16
- package/dist/common/fp.js +9 -0
- package/dist/common/hotkeys.d.ts +25 -0
- package/dist/common/hotkeys.js +112 -0
- package/dist/common/http.d.ts +4 -0
- package/dist/common/http.js +10 -0
- package/dist/common/keycodes.d.ts +85 -0
- package/dist/common/keycodes.js +88 -0
- package/{lib/common/keys.ts → dist/common/keys.d.ts} +21 -24
- package/dist/common/keys.js +8 -0
- package/dist/common/math.d.ts +39 -0
- package/dist/common/math.js +41 -0
- package/dist/common/perf.d.ts +24 -0
- package/dist/common/perf.js +33 -0
- package/dist/common/random.d.ts +16 -0
- package/dist/common/random.js +18 -0
- package/dist/common/react.d.ts +23 -0
- package/dist/common/react.js +30 -0
- package/dist/common/redux.d.ts +64 -0
- package/dist/common/redux.js +72 -0
- package/dist/common/storage.d.ts +24 -0
- package/dist/common/storage.js +133 -0
- package/dist/common/string.d.ts +65 -0
- package/dist/common/string.js +83 -0
- package/dist/common/timer.d.ts +18 -0
- package/dist/common/timer.js +28 -0
- package/dist/common/type-utils.d.ts +9 -0
- package/dist/common/type-utils.js +25 -0
- package/dist/common/uuid.d.ts +9 -0
- package/dist/common/uuid.js +10 -0
- package/dist/components/AnimatedNumber.d.ts +60 -0
- package/dist/components/AnimatedNumber.js +76 -0
- package/dist/components/Autofocus.d.ts +4 -0
- package/dist/components/Autofocus.js +17 -0
- package/dist/components/Blink.d.ts +26 -0
- package/dist/components/Blink.js +56 -0
- package/dist/components/BlockQuote.d.ts +3 -0
- package/dist/components/BlockQuote.js +13 -0
- package/dist/components/BodyZoneSelector.d.ts +28 -0
- package/dist/components/BodyZoneSelector.js +115 -0
- package/dist/components/Box.d.ts +91 -0
- package/dist/components/Box.js +133 -0
- package/dist/components/Button.d.ts +93 -0
- package/dist/components/Button.js +298 -0
- package/dist/components/ByondUi.js +73 -0
- package/dist/components/Chart.d.ts +28 -0
- package/dist/components/Chart.js +95 -0
- package/dist/components/Collapsible.d.ts +15 -0
- package/dist/components/Collapsible.js +27 -0
- package/dist/components/ColorBox.d.ts +8 -0
- package/dist/components/ColorBox.js +24 -0
- package/dist/components/Dialog.d.ts +24 -0
- package/dist/components/Dialog.js +67 -0
- package/dist/components/Dimmer.d.ts +3 -0
- package/dist/components/Dimmer.js +13 -0
- package/dist/components/Divider.d.ts +6 -0
- package/dist/components/Divider.js +22 -0
- package/dist/components/DmIcon.d.ts +33 -0
- package/dist/components/DmIcon.js +29 -0
- package/dist/components/DraggableControl.js +176 -0
- package/dist/components/Dropdown.d.ts +48 -0
- package/dist/components/Dropdown.js +152 -0
- package/dist/components/FakeTerminal.js +38 -0
- package/dist/components/FitText.d.ts +22 -0
- package/dist/components/FitText.js +63 -0
- package/dist/components/Flex.d.ts +93 -0
- package/dist/components/Flex.js +72 -0
- package/dist/components/Icon.d.ts +30 -0
- package/dist/components/Icon.js +51 -0
- package/dist/components/Image.d.ts +14 -0
- package/dist/components/Image.js +35 -0
- package/dist/components/InfinitePlane.js +139 -0
- package/dist/components/Input.d.ts +61 -0
- package/dist/components/Input.js +89 -0
- package/dist/components/KeyListener.d.ts +15 -0
- package/dist/components/KeyListener.js +23 -0
- package/dist/components/Knob.d.ts +49 -0
- package/dist/components/Knob.js +162 -0
- package/dist/components/LabeledControls.d.ts +11 -0
- package/dist/components/LabeledControls.js +39 -0
- package/dist/components/LabeledList.d.ts +57 -0
- package/dist/components/LabeledList.js +94 -0
- package/dist/components/MenuBar.d.ts +28 -0
- package/dist/components/MenuBar.js +174 -0
- package/dist/components/Modal.d.ts +3 -0
- package/dist/components/Modal.js +25 -0
- package/dist/components/NoticeBox.d.ts +20 -0
- package/dist/components/NoticeBox.js +49 -0
- package/dist/components/NumberInput.d.ts +45 -0
- package/dist/components/NumberInput.js +221 -0
- package/dist/components/Popper.d.ts +27 -0
- package/dist/components/Popper.js +177 -0
- package/dist/components/ProgressBar.d.ts +46 -0
- package/dist/components/ProgressBar.js +37 -0
- package/dist/components/RestrictedInput.js +155 -0
- package/dist/components/RoundGauge.d.ts +53 -0
- package/dist/components/RoundGauge.js +147 -0
- package/dist/components/Section.d.ts +63 -0
- package/dist/components/Section.js +62 -0
- package/dist/components/Slider.d.ts +46 -0
- package/dist/components/Slider.js +124 -0
- package/dist/components/Stack.d.ts +27 -0
- package/dist/components/Stack.js +67 -0
- package/dist/components/StyleableSection.d.ts +11 -0
- package/dist/components/StyleableSection.js +16 -0
- package/dist/components/Table.d.ts +29 -0
- package/dist/components/Table.js +67 -0
- package/dist/components/Tabs.d.ts +23 -0
- package/dist/components/Tabs.js +89 -0
- package/dist/components/TextArea.d.ts +39 -0
- package/dist/components/TextArea.js +118 -0
- package/dist/components/TimeDisplay.js +34 -0
- package/dist/components/Tooltip.d.ts +29 -0
- package/dist/components/Tooltip.js +83 -0
- package/dist/components/TrackOutsideClicks.d.ts +13 -0
- package/dist/components/TrackOutsideClicks.js +24 -0
- package/dist/components/VirtualList.d.ts +8 -0
- package/dist/components/VirtualList.js +34 -0
- package/dist/components/index.js +92 -0
- package/dist/popper-CiqSDJTE.js +906 -0
- package/package.json +8 -10
- package/lib/common/assets.ts +0 -38
- package/lib/common/collections.ts +0 -27
- package/lib/common/color.ts +0 -88
- package/lib/common/constants.ts +0 -349
- package/lib/common/events.ts +0 -262
- package/lib/common/format.ts +0 -167
- package/lib/common/hotkeys.ts +0 -207
- package/lib/common/http.ts +0 -16
- package/lib/common/keycodes.ts +0 -86
- package/lib/common/math.ts +0 -76
- package/lib/common/perf.ts +0 -72
- package/lib/common/random.ts +0 -32
- package/lib/common/react.ts +0 -59
- package/lib/common/redux.ts +0 -187
- package/lib/common/storage.ts +0 -207
- package/lib/common/string.ts +0 -169
- package/lib/common/timer.ts +0 -63
- package/lib/common/type-utils.ts +0 -41
- package/lib/common/types.d.ts +0 -12
- package/lib/common/uuid.ts +0 -18
- package/lib/components/AnimatedNumber.tsx +0 -180
- package/lib/components/Autofocus.tsx +0 -23
- package/lib/components/Blink.tsx +0 -91
- package/lib/components/BlockQuote.tsx +0 -9
- package/lib/components/BodyZoneSelector.tsx +0 -149
- package/lib/components/Box.tsx +0 -252
- package/lib/components/Button.tsx +0 -425
- package/lib/components/ByondUi.jsx +0 -110
- package/lib/components/Chart.tsx +0 -155
- package/lib/components/Collapsible.tsx +0 -43
- package/lib/components/ColorBox.tsx +0 -29
- package/lib/components/Dialog.tsx +0 -81
- package/lib/components/Dimmer.tsx +0 -13
- package/lib/components/Divider.tsx +0 -20
- package/lib/components/DmIcon.tsx +0 -86
- package/lib/components/DraggableControl.jsx +0 -276
- package/lib/components/Dropdown.tsx +0 -246
- package/lib/components/FakeTerminal.jsx +0 -52
- package/lib/components/FitText.tsx +0 -99
- package/lib/components/Flex.tsx +0 -159
- package/lib/components/Icon.tsx +0 -95
- package/lib/components/Image.tsx +0 -54
- package/lib/components/InfinitePlane.jsx +0 -192
- package/lib/components/Input.tsx +0 -176
- package/lib/components/KeyListener.tsx +0 -40
- package/lib/components/Knob.tsx +0 -178
- package/lib/components/LabeledControls.tsx +0 -44
- package/lib/components/LabeledList.tsx +0 -154
- package/lib/components/MenuBar.tsx +0 -228
- package/lib/components/Modal.tsx +0 -23
- package/lib/components/NoticeBox.tsx +0 -45
- package/lib/components/NumberInput.tsx +0 -328
- package/lib/components/Popper.tsx +0 -100
- package/lib/components/ProgressBar.tsx +0 -105
- package/lib/components/RestrictedInput.jsx +0 -301
- package/lib/components/RoundGauge.tsx +0 -180
- package/lib/components/Section.tsx +0 -120
- package/lib/components/Slider.tsx +0 -169
- package/lib/components/Stack.tsx +0 -96
- package/lib/components/StyleableSection.tsx +0 -33
- package/lib/components/Table.tsx +0 -84
- package/lib/components/Tabs.tsx +0 -89
- package/lib/components/TextArea.tsx +0 -182
- package/lib/components/TimeDisplay.jsx +0 -64
- package/lib/components/Tooltip.tsx +0 -152
- package/lib/components/TrackOutsideClicks.tsx +0 -35
- package/lib/components/VirtualList.tsx +0 -69
- package/lib/styles/atomic/candystripe.scss +0 -8
- package/lib/styles/atomic/centered-image.scss +0 -7
- package/lib/styles/atomic/color.scss +0 -21
- package/lib/styles/atomic/debug-layout.scss +0 -17
- package/lib/styles/atomic/fit-text.scss +0 -14
- package/lib/styles/atomic/links.scss +0 -12
- package/lib/styles/atomic/outline.scss +0 -47
- package/lib/styles/atomic/text.scss +0 -44
- package/lib/styles/base.scss +0 -32
- package/lib/styles/colors.scss +0 -92
- package/lib/styles/components/BlockQuote.module.scss +0 -20
- package/lib/styles/components/BlockQuote.module.scss.d.ts +0 -4
- package/lib/styles/components/Button.module.scss +0 -157
- package/lib/styles/components/Button.module.scss.d.ts +0 -46
- package/lib/styles/components/ColorBox.module.scss +0 -12
- package/lib/styles/components/ColorBox.module.scss.d.ts +0 -4
- package/lib/styles/components/Dialog.module.scss +0 -60
- package/lib/styles/components/Dialog.module.scss.d.ts +0 -10
- package/lib/styles/components/Dimmer.module.scss +0 -22
- package/lib/styles/components/Dimmer.module.scss.d.ts +0 -4
- package/lib/styles/components/Divider.module.scss +0 -27
- package/lib/styles/components/Divider.module.scss.d.ts +0 -6
- package/lib/styles/components/Dropdown.scss +0 -72
- package/lib/styles/components/Flex.module.scss +0 -13
- package/lib/styles/components/Flex.module.scss.d.ts +0 -5
- package/lib/styles/components/Icon.module.scss +0 -25
- package/lib/styles/components/Icon.module.scss.d.ts +0 -5
- package/lib/styles/components/Input.module.scss +0 -64
- package/lib/styles/components/Input.module.scss.d.ts +0 -8
- package/lib/styles/components/Knob.module.scss +0 -131
- package/lib/styles/components/Knob.module.scss.d.ts +0 -33
- package/lib/styles/components/LabeledList.module.scss +0 -49
- package/lib/styles/components/LabeledList.module.scss.d.ts +0 -8
- package/lib/styles/components/MenuBar.module.scss +0 -75
- package/lib/styles/components/MenuBar.module.scss.d.ts +0 -14
- package/lib/styles/components/Modal.module.scss +0 -14
- package/lib/styles/components/Modal.module.scss.d.ts +0 -4
- package/lib/styles/components/NoticeBox.module.scss +0 -65
- package/lib/styles/components/NoticeBox.module.scss.d.ts +0 -27
- package/lib/styles/components/NumberInput.module.scss +0 -71
- package/lib/styles/components/NumberInput.module.scss.d.ts +0 -9
- package/lib/styles/components/ProgressBar.module.scss +0 -63
- package/lib/styles/components/ProgressBar.module.scss.d.ts +0 -27
- package/lib/styles/components/RoundGauge.module.scss +0 -85
- package/lib/styles/components/RoundGauge.module.scss.d.ts +0 -49
- package/lib/styles/components/Section.module.scss +0 -130
- package/lib/styles/components/Section.module.scss.d.ts +0 -13
- package/lib/styles/components/Slider.module.scss +0 -54
- package/lib/styles/components/Slider.module.scss.d.ts +0 -8
- package/lib/styles/components/Stack.module.scss +0 -60
- package/lib/styles/components/Stack.module.scss.d.ts +0 -12
- package/lib/styles/components/Table.module.scss +0 -44
- package/lib/styles/components/Table.module.scss.d.ts +0 -10
- package/lib/styles/components/Tabs.module.scss +0 -144
- package/lib/styles/components/Tabs.module.scss.d.ts +0 -35
- package/lib/styles/components/TextArea.module.scss +0 -86
- package/lib/styles/components/TextArea.module.scss.d.ts +0 -11
- package/lib/styles/components/Tooltip.module.scss +0 -24
- package/lib/styles/components/Tooltip.module.scss.d.ts +0 -4
- package/lib/styles/functions.scss +0 -79
- package/lib/styles/input.scss +0 -9
- package/lib/styles/main.scss +0 -20
- package/lib/styles/reset.scss +0 -68
- /package/{lib/components/index.ts → dist/components/index.d.ts} +0 -0
package/lib/common/storage.ts
DELETED
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Browser-agnostic abstraction of key-value web storage.
|
|
3
|
-
*
|
|
4
|
-
* @file
|
|
5
|
-
* @copyright 2020 Aleksej Komarov
|
|
6
|
-
* @license MIT
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
export const IMPL_MEMORY = 0;
|
|
10
|
-
export const IMPL_LOCAL_STORAGE = 1;
|
|
11
|
-
export const IMPL_INDEXED_DB = 2;
|
|
12
|
-
|
|
13
|
-
const INDEXED_DB_VERSION = 1;
|
|
14
|
-
const INDEXED_DB_NAME = 'tgui';
|
|
15
|
-
const INDEXED_DB_STORE_NAME = 'storage-v1';
|
|
16
|
-
|
|
17
|
-
const READ_ONLY = 'readonly';
|
|
18
|
-
const READ_WRITE = 'readwrite';
|
|
19
|
-
|
|
20
|
-
const testGeneric = (testFn) => () => {
|
|
21
|
-
try {
|
|
22
|
-
return Boolean(testFn());
|
|
23
|
-
} catch {
|
|
24
|
-
return false;
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
// Localstorage can sometimes throw an error, even if DOM storage is not
|
|
29
|
-
// disabled in IE11 settings.
|
|
30
|
-
// See: https://superuser.com/questions/1080011
|
|
31
|
-
|
|
32
|
-
const testLocalStorage = testGeneric(
|
|
33
|
-
() => window.localStorage && window.localStorage.getItem,
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
const testIndexedDb = testGeneric(
|
|
37
|
-
() =>
|
|
38
|
-
(window.indexedDB || window.msIndexedDB) &&
|
|
39
|
-
(window.IDBTransaction || window.msIDBTransaction),
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
class MemoryBackend {
|
|
43
|
-
impl = IMPL_MEMORY;
|
|
44
|
-
store: Record<string, any> = {};
|
|
45
|
-
|
|
46
|
-
constructor() {
|
|
47
|
-
this.impl = IMPL_MEMORY;
|
|
48
|
-
this.store = {};
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
get(key) {
|
|
52
|
-
return this.store[key];
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
set(key, value) {
|
|
56
|
-
this.store[key] = value;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
remove(key) {
|
|
60
|
-
this.store[key] = undefined;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
clear() {
|
|
64
|
-
this.store = {};
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
class LocalStorageBackend {
|
|
69
|
-
impl = IMPL_LOCAL_STORAGE;
|
|
70
|
-
|
|
71
|
-
constructor() {
|
|
72
|
-
this.impl = IMPL_LOCAL_STORAGE;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
get(key) {
|
|
76
|
-
const value = localStorage.getItem(key);
|
|
77
|
-
if (typeof value === 'string') {
|
|
78
|
-
return JSON.parse(value);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
set(key, value) {
|
|
83
|
-
localStorage.setItem(key, JSON.stringify(value));
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
remove(key) {
|
|
87
|
-
localStorage.removeItem(key);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
clear() {
|
|
91
|
-
localStorage.clear();
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
class IndexedDbBackend {
|
|
96
|
-
impl = IMPL_INDEXED_DB;
|
|
97
|
-
dbPromise: Promise<IDBDatabase>;
|
|
98
|
-
|
|
99
|
-
constructor() {
|
|
100
|
-
this.impl = IMPL_INDEXED_DB;
|
|
101
|
-
this.dbPromise = new Promise((resolve, reject) => {
|
|
102
|
-
const indexedDB = window.indexedDB || window.msIndexedDB;
|
|
103
|
-
const req = indexedDB.open(INDEXED_DB_NAME, INDEXED_DB_VERSION);
|
|
104
|
-
req.onupgradeneeded = () => {
|
|
105
|
-
try {
|
|
106
|
-
req.result.createObjectStore(INDEXED_DB_STORE_NAME);
|
|
107
|
-
} catch (err) {
|
|
108
|
-
reject(new Error('Failed to upgrade IDB: ' + req.error));
|
|
109
|
-
}
|
|
110
|
-
};
|
|
111
|
-
req.onsuccess = () => resolve(req.result);
|
|
112
|
-
req.onerror = () => {
|
|
113
|
-
reject(new Error('Failed to open IDB: ' + req.error));
|
|
114
|
-
};
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
getStore(mode) {
|
|
119
|
-
return this.dbPromise.then((db) =>
|
|
120
|
-
db
|
|
121
|
-
.transaction(INDEXED_DB_STORE_NAME, mode)
|
|
122
|
-
.objectStore(INDEXED_DB_STORE_NAME),
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
async get(key) {
|
|
127
|
-
const store = await this.getStore(READ_ONLY);
|
|
128
|
-
return new Promise((resolve, reject) => {
|
|
129
|
-
const req = store.get(key);
|
|
130
|
-
req.onsuccess = () => resolve(req.result);
|
|
131
|
-
req.onerror = () => reject(req.error);
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
async set(key, value) {
|
|
136
|
-
// The reason we don't _save_ null is because IE 10 does
|
|
137
|
-
// not support saving the `null` type in IndexedDB. How
|
|
138
|
-
// ironic, given the bug below!
|
|
139
|
-
// See: https://github.com/mozilla/localForage/issues/161
|
|
140
|
-
if (value === null) {
|
|
141
|
-
value = undefined;
|
|
142
|
-
}
|
|
143
|
-
// NOTE: We deliberately make this operation transactionless
|
|
144
|
-
const store = await this.getStore(READ_WRITE);
|
|
145
|
-
store.put(value, key);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
async remove(key) {
|
|
149
|
-
// NOTE: We deliberately make this operation transactionless
|
|
150
|
-
const store = await this.getStore(READ_WRITE);
|
|
151
|
-
store.delete(key);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
async clear() {
|
|
155
|
-
// NOTE: We deliberately make this operation transactionless
|
|
156
|
-
const store = await this.getStore(READ_WRITE);
|
|
157
|
-
store.clear();
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Web Storage Proxy object, which selects the best backend available
|
|
163
|
-
* depending on the environment.
|
|
164
|
-
*/
|
|
165
|
-
class StorageProxy {
|
|
166
|
-
backendPromise: Promise<any>;
|
|
167
|
-
|
|
168
|
-
constructor() {
|
|
169
|
-
this.backendPromise = (async () => {
|
|
170
|
-
if (testIndexedDb()) {
|
|
171
|
-
try {
|
|
172
|
-
const backend = new IndexedDbBackend();
|
|
173
|
-
await backend.dbPromise;
|
|
174
|
-
return backend;
|
|
175
|
-
} catch {
|
|
176
|
-
// Ignore errors
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
if (testLocalStorage()) {
|
|
180
|
-
return new LocalStorageBackend();
|
|
181
|
-
}
|
|
182
|
-
return new MemoryBackend();
|
|
183
|
-
})();
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
async get(key) {
|
|
187
|
-
const backend = await this.backendPromise;
|
|
188
|
-
return backend.get(key);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
async set(key, value) {
|
|
192
|
-
const backend = await this.backendPromise;
|
|
193
|
-
return backend.set(key, value);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
async remove(key) {
|
|
197
|
-
const backend = await this.backendPromise;
|
|
198
|
-
return backend.remove(key);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
async clear() {
|
|
202
|
-
const backend = await this.backendPromise;
|
|
203
|
-
return backend.clear();
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
export const storage = new StorageProxy();
|
package/lib/common/string.ts
DELETED
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Creates a search terms matcher. Returns true if given string matches the search text.
|
|
3
|
-
*
|
|
4
|
-
* @example
|
|
5
|
-
* ```tsx
|
|
6
|
-
* type Thing = { id: string; name: string };
|
|
7
|
-
*
|
|
8
|
-
* const objects = [
|
|
9
|
-
* { id: '123', name: 'Test' },
|
|
10
|
-
* { id: '456', name: 'Test' },
|
|
11
|
-
* ];
|
|
12
|
-
*
|
|
13
|
-
* const search = createSearch('123', (obj: Thing) => obj.id);
|
|
14
|
-
*
|
|
15
|
-
* objects.filter(search); // returns [{ id: '123', name: 'Test' }]
|
|
16
|
-
* ```
|
|
17
|
-
*/
|
|
18
|
-
export function createSearch<TObj>(
|
|
19
|
-
searchText: string,
|
|
20
|
-
stringifier = (obj: TObj) => JSON.stringify(obj),
|
|
21
|
-
): (obj: TObj) => boolean {
|
|
22
|
-
const preparedSearchText = searchText.toLowerCase().trim();
|
|
23
|
-
|
|
24
|
-
return (obj) => {
|
|
25
|
-
if (!preparedSearchText) {
|
|
26
|
-
return true;
|
|
27
|
-
}
|
|
28
|
-
const str = stringifier(obj);
|
|
29
|
-
if (!str) {
|
|
30
|
-
return false;
|
|
31
|
-
}
|
|
32
|
-
return str.toLowerCase().includes(preparedSearchText);
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Capitalizes a word and lowercases the rest.
|
|
38
|
-
*
|
|
39
|
-
* @example
|
|
40
|
-
* ```tsx
|
|
41
|
-
* capitalize('heLLo') // Hello
|
|
42
|
-
* ```
|
|
43
|
-
*/
|
|
44
|
-
export function capitalize(str: string): string {
|
|
45
|
-
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Similar to capitalize, this takes a string and replaces all first letters
|
|
50
|
-
* of any words.
|
|
51
|
-
*
|
|
52
|
-
* @example
|
|
53
|
-
* ```tsx
|
|
54
|
-
* capitalizeAll('heLLo woRLd') // 'HeLLo WoRLd'
|
|
55
|
-
* ```
|
|
56
|
-
*/
|
|
57
|
-
export function capitalizeAll(str: string): string {
|
|
58
|
-
return str.replace(/(^\w{1})|(\s+\w{1})/g, (letter) => letter.toUpperCase());
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Capitalizes only the first letter of the str, leaving others untouched.
|
|
63
|
-
*
|
|
64
|
-
* @example
|
|
65
|
-
* ```tsx
|
|
66
|
-
* capitalizeFirst('heLLo woRLd') // 'HeLLo woRLd'
|
|
67
|
-
* ```
|
|
68
|
-
*/
|
|
69
|
-
export function capitalizeFirst(str: string): string {
|
|
70
|
-
return str.replace(/^\w/, (letter) => letter.toUpperCase());
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const WORDS_UPPER = ['Id', 'Tv'] as const;
|
|
74
|
-
|
|
75
|
-
const WORDS_LOWER = [
|
|
76
|
-
'A',
|
|
77
|
-
'An',
|
|
78
|
-
'And',
|
|
79
|
-
'As',
|
|
80
|
-
'At',
|
|
81
|
-
'But',
|
|
82
|
-
'By',
|
|
83
|
-
'For',
|
|
84
|
-
'For',
|
|
85
|
-
'From',
|
|
86
|
-
'In',
|
|
87
|
-
'Into',
|
|
88
|
-
'Near',
|
|
89
|
-
'Nor',
|
|
90
|
-
'Of',
|
|
91
|
-
'On',
|
|
92
|
-
'Onto',
|
|
93
|
-
'Or',
|
|
94
|
-
'The',
|
|
95
|
-
'To',
|
|
96
|
-
'With',
|
|
97
|
-
] as const;
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Converts a string to title case.
|
|
101
|
-
*
|
|
102
|
-
* @example
|
|
103
|
-
* ```tsx
|
|
104
|
-
* toTitleCase('a tale of two cities') // 'A Tale of Two Cities'
|
|
105
|
-
* ```
|
|
106
|
-
*/
|
|
107
|
-
export function toTitleCase(str: string): string {
|
|
108
|
-
if (!str) return str;
|
|
109
|
-
|
|
110
|
-
let currentStr = str.replace(/([^\W_]+[^\s-]*) */g, (str) => {
|
|
111
|
-
return capitalize(str);
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
for (const word of WORDS_LOWER) {
|
|
115
|
-
const regex = new RegExp('\\s' + word + '\\s', 'g');
|
|
116
|
-
currentStr = currentStr.replace(regex, (str) => str.toLowerCase());
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
for (const word of WORDS_UPPER) {
|
|
120
|
-
const regex = new RegExp('\\b' + word + '\\b', 'g');
|
|
121
|
-
currentStr = currentStr.replace(regex, (str) => str.toLowerCase());
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return currentStr;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const TRANSLATIONS = {
|
|
128
|
-
amp: '&',
|
|
129
|
-
apos: "'",
|
|
130
|
-
gt: '>',
|
|
131
|
-
lt: '<',
|
|
132
|
-
nbsp: ' ',
|
|
133
|
-
quot: '"',
|
|
134
|
-
} as const;
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Decodes HTML entities and removes unnecessary HTML tags.
|
|
138
|
-
*
|
|
139
|
-
* @example
|
|
140
|
-
* ```tsx
|
|
141
|
-
* decodeHtmlEntities('&') // returns '&'
|
|
142
|
-
* decodeHtmlEntities('<') // returns '<'
|
|
143
|
-
* ```
|
|
144
|
-
*/
|
|
145
|
-
export function decodeHtmlEntities(str: string): string {
|
|
146
|
-
if (!str) return str;
|
|
147
|
-
|
|
148
|
-
return (
|
|
149
|
-
str
|
|
150
|
-
// Newline tags
|
|
151
|
-
.replace(/<br>/gi, '\n')
|
|
152
|
-
.replace(/<\/?[a-z0-9-_]+[^>]*>/gi, '')
|
|
153
|
-
// Basic entities
|
|
154
|
-
.replace(
|
|
155
|
-
/&(nbsp|amp|quot|lt|gt|apos);/g,
|
|
156
|
-
(_match, entity) => TRANSLATIONS[entity],
|
|
157
|
-
)
|
|
158
|
-
// Decimal entities
|
|
159
|
-
.replace(/&#?([0-9]+);/gi, (_match, numStr) => {
|
|
160
|
-
const num = parseInt(numStr, 10);
|
|
161
|
-
return String.fromCharCode(num);
|
|
162
|
-
})
|
|
163
|
-
// Hex entities
|
|
164
|
-
.replace(/&#x?([0-9a-f]+);/gi, (_match, numStr) => {
|
|
165
|
-
const num = parseInt(numStr, 16);
|
|
166
|
-
return String.fromCharCode(num);
|
|
167
|
-
})
|
|
168
|
-
);
|
|
169
|
-
}
|
package/lib/common/timer.ts
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Returns a function, that, as long as it continues to be invoked, will
|
|
3
|
-
* not be triggered. The function will be called after it stops being
|
|
4
|
-
* called for N milliseconds. If `immediate` is passed, trigger the
|
|
5
|
-
* function on the leading edge, instead of the trailing.
|
|
6
|
-
*/
|
|
7
|
-
export function debounce<F extends (...args: any[]) => any>(
|
|
8
|
-
fn: F,
|
|
9
|
-
time: number,
|
|
10
|
-
immediate = false,
|
|
11
|
-
): (...args: Parameters<F>) => void {
|
|
12
|
-
let timeout: ReturnType<typeof setTimeout> | null;
|
|
13
|
-
return (...args: Parameters<F>) => {
|
|
14
|
-
function later() {
|
|
15
|
-
timeout = null;
|
|
16
|
-
if (!immediate) {
|
|
17
|
-
fn(...args);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
const callNow = immediate && !timeout;
|
|
21
|
-
clearTimeout(timeout!);
|
|
22
|
-
timeout = setTimeout(later, time);
|
|
23
|
-
if (callNow) {
|
|
24
|
-
fn(...args);
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Returns a function, that, when invoked, will only be triggered at most once
|
|
31
|
-
* during a given window of time.
|
|
32
|
-
*/
|
|
33
|
-
export function throttle<F extends (...args: any[]) => any>(
|
|
34
|
-
fn: F,
|
|
35
|
-
time: number,
|
|
36
|
-
): (...args: Parameters<F>) => void {
|
|
37
|
-
let previouslyRun: number | null,
|
|
38
|
-
queuedToRun: ReturnType<typeof setTimeout> | null;
|
|
39
|
-
return function invokeFn(...args: Parameters<F>) {
|
|
40
|
-
const now = Date.now();
|
|
41
|
-
if (queuedToRun) {
|
|
42
|
-
clearTimeout(queuedToRun);
|
|
43
|
-
}
|
|
44
|
-
if (!previouslyRun || now - previouslyRun >= time) {
|
|
45
|
-
fn(...args);
|
|
46
|
-
previouslyRun = now;
|
|
47
|
-
} else {
|
|
48
|
-
queuedToRun = setTimeout(
|
|
49
|
-
() => invokeFn(...args),
|
|
50
|
-
time - (now - (previouslyRun ?? 0)),
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Suspends an asynchronous function for N milliseconds.
|
|
58
|
-
*
|
|
59
|
-
* @param {number} time
|
|
60
|
-
*/
|
|
61
|
-
export function sleep(time: number): Promise<void> {
|
|
62
|
-
return new Promise((resolve) => setTimeout(resolve, time));
|
|
63
|
-
}
|
package/lib/common/type-utils.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Helps visualize highly complex ui data on the fly.
|
|
3
|
-
* @example
|
|
4
|
-
* ```tsx
|
|
5
|
-
* const { data } = useBackend<CargoData>();
|
|
6
|
-
* logger.log(getShallowTypes(data));
|
|
7
|
-
* ```
|
|
8
|
-
*/
|
|
9
|
-
export function getShallowTypes(
|
|
10
|
-
data: Record<string, any>,
|
|
11
|
-
): Record<string, any> {
|
|
12
|
-
const output = {};
|
|
13
|
-
|
|
14
|
-
for (const key in data) {
|
|
15
|
-
if (Array.isArray(data[key])) {
|
|
16
|
-
const arr: any[] = data[key];
|
|
17
|
-
|
|
18
|
-
// Return the first array item if it exists
|
|
19
|
-
if (data[key].length > 0) {
|
|
20
|
-
output[key] = arr[0];
|
|
21
|
-
continue;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
output[key] = 'emptyarray';
|
|
25
|
-
} else if (typeof data[key] === 'object' && data[key] !== null) {
|
|
26
|
-
// Please inspect it further and make a new type for it
|
|
27
|
-
output[key] = 'object (inspect) || Record<string, any>';
|
|
28
|
-
} else if (typeof data[key] === 'number') {
|
|
29
|
-
const num = Number(data[key]);
|
|
30
|
-
|
|
31
|
-
// 0 and 1 could be booleans from byond
|
|
32
|
-
if (num === 1 || num === 0) {
|
|
33
|
-
output[key] = `${num}, BooleanLike?`;
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
output[key] = data[key];
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return output;
|
|
41
|
-
}
|
package/lib/common/types.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Returns the arguments of a function F as an array.
|
|
3
|
-
*/
|
|
4
|
-
export type ArgumentsOf<F extends Fn> = F extends (...args: infer A) => unknown
|
|
5
|
-
? A
|
|
6
|
-
: never;
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* A function. Use this instead of `Function` to avoid issues with
|
|
10
|
-
* type inference.
|
|
11
|
-
*/
|
|
12
|
-
export type Fn = (...args: any[]) => void;
|
package/lib/common/uuid.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Creates a UUID v4 string
|
|
3
|
-
*
|
|
4
|
-
* @example
|
|
5
|
-
* ```tsx
|
|
6
|
-
* createUuid(); // 'f47ac10b-58cc-4372-a567-0e02b2c3d479'
|
|
7
|
-
* ```
|
|
8
|
-
*/
|
|
9
|
-
export function createUuid(): string {
|
|
10
|
-
let d = new Date().getTime();
|
|
11
|
-
|
|
12
|
-
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
13
|
-
const r = (d + Math.random() * 16) % 16 | 0;
|
|
14
|
-
d = Math.floor(d / 16);
|
|
15
|
-
|
|
16
|
-
return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16);
|
|
17
|
-
});
|
|
18
|
-
}
|
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
import { Component, createRef } from 'react';
|
|
2
|
-
|
|
3
|
-
import { clamp, toFixed } from '../common/math';
|
|
4
|
-
|
|
5
|
-
type Props = {
|
|
6
|
-
/**
|
|
7
|
-
* If provided, a function that formats the inner string. By default,
|
|
8
|
-
* attempts to match the numeric precision of `value`.
|
|
9
|
-
*/
|
|
10
|
-
format?: (value: number) => string;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* If provided, the initial value displayed. By default, the same as `value`.
|
|
14
|
-
* If `initial` and `value` are different, the component immediately starts
|
|
15
|
-
* animating.
|
|
16
|
-
*/
|
|
17
|
-
initial?: number;
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* The target value to approach.
|
|
21
|
-
*/
|
|
22
|
-
value: number;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
function isSafeNumber(value: number): boolean {
|
|
26
|
-
return (
|
|
27
|
-
typeof value === 'number' && Number.isFinite(value) && !Number.isNaN(value)
|
|
28
|
-
);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Animated numbers are animated at roughly 60 frames per second.
|
|
33
|
-
*/
|
|
34
|
-
const SIXTY_HZ = 1_000.0 / 60.0;
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* The exponential moving average coefficient. Larger values result in a faster
|
|
38
|
-
* convergence.
|
|
39
|
-
*/
|
|
40
|
-
const Q = 0.8333;
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* A small number.
|
|
44
|
-
*/
|
|
45
|
-
const EPSILON = 10e-4;
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* An animated number label. Shows a number, formatted with an optionally
|
|
49
|
-
* provided function, and animates it towards its target value.
|
|
50
|
-
*/
|
|
51
|
-
export class AnimatedNumber extends Component<Props> {
|
|
52
|
-
/**
|
|
53
|
-
* The inner `<span/>` being updated sixty times per second.
|
|
54
|
-
*/
|
|
55
|
-
ref = createRef<HTMLSpanElement>();
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* The interval being used to update the inner span.
|
|
59
|
-
*/
|
|
60
|
-
interval?: NodeJS.Timeout;
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* The current value. This values approaches the target value.
|
|
64
|
-
*/
|
|
65
|
-
currentValue: number = 0;
|
|
66
|
-
|
|
67
|
-
constructor(props: Props) {
|
|
68
|
-
super(props);
|
|
69
|
-
|
|
70
|
-
const { initial, value } = props;
|
|
71
|
-
|
|
72
|
-
if (initial !== undefined && isSafeNumber(initial)) {
|
|
73
|
-
this.currentValue = initial;
|
|
74
|
-
} else if (isSafeNumber(value)) {
|
|
75
|
-
this.currentValue = value;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
componentDidMount() {
|
|
80
|
-
if (this.currentValue !== this.props.value) {
|
|
81
|
-
this.startTicking();
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
componentWillUnmount() {
|
|
86
|
-
// Stop animating when the component is unmounted.
|
|
87
|
-
this.stopTicking();
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
shouldComponentUpdate(newProps: Props) {
|
|
91
|
-
if (newProps.value !== this.props.value) {
|
|
92
|
-
// The target value has been adjusted; start animating if we aren't
|
|
93
|
-
// already.
|
|
94
|
-
this.startTicking();
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return false;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Starts animating the inner span. If the inner span is already animating,
|
|
102
|
-
* this is a no-op.
|
|
103
|
-
*/
|
|
104
|
-
startTicking() {
|
|
105
|
-
if (this.interval !== undefined) {
|
|
106
|
-
// We're already ticking; do nothing.
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
this.interval = setInterval(() => this.tick(), SIXTY_HZ);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Stops animating the inner span.
|
|
115
|
-
*/
|
|
116
|
-
stopTicking() {
|
|
117
|
-
if (this.interval === undefined) {
|
|
118
|
-
// We're not ticking; do nothing.
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
clearInterval(this.interval);
|
|
123
|
-
|
|
124
|
-
this.interval = undefined;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Steps forward one frame.
|
|
129
|
-
*/
|
|
130
|
-
tick() {
|
|
131
|
-
const { currentValue } = this;
|
|
132
|
-
const { value } = this.props;
|
|
133
|
-
|
|
134
|
-
if (isSafeNumber(value)) {
|
|
135
|
-
// Converge towards the value.
|
|
136
|
-
this.currentValue = currentValue * Q + value * (1 - Q);
|
|
137
|
-
} else {
|
|
138
|
-
// If the value is unsafe, we're never going to converge, so stop ticking.
|
|
139
|
-
this.stopTicking();
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
if (
|
|
143
|
-
Math.abs(value - this.currentValue) < Math.max(EPSILON, EPSILON * value)
|
|
144
|
-
) {
|
|
145
|
-
// We're about as close as we're going to get--snap to the value and
|
|
146
|
-
// stop ticking.
|
|
147
|
-
this.currentValue = value;
|
|
148
|
-
this.stopTicking();
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
if (this.ref.current) {
|
|
152
|
-
this.ref.current.textContent = this.getText();
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Gets the inner text of the span.
|
|
158
|
-
*/
|
|
159
|
-
getText() {
|
|
160
|
-
const { props, currentValue } = this;
|
|
161
|
-
const { format, value } = props;
|
|
162
|
-
|
|
163
|
-
if (!isSafeNumber(value)) {
|
|
164
|
-
return String(value);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if (format) {
|
|
168
|
-
return format(this.currentValue);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const fraction = String(value).split('.')[1];
|
|
172
|
-
const precision = fraction ? fraction.length : 0;
|
|
173
|
-
|
|
174
|
-
return toFixed(currentValue, clamp(precision, 0, 8));
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
render() {
|
|
178
|
-
return <span ref={this.ref}>{this.getText()}</span>;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { PropsWithChildren, useEffect, useRef } from 'react';
|
|
2
|
-
|
|
3
|
-
/** Used to force the window to steal focus on load. Children optional */
|
|
4
|
-
export function Autofocus(props: PropsWithChildren) {
|
|
5
|
-
const { children } = props;
|
|
6
|
-
const ref = useRef<HTMLDivElement>(null);
|
|
7
|
-
|
|
8
|
-
useEffect(() => {
|
|
9
|
-
const timer = setTimeout(() => {
|
|
10
|
-
ref.current?.focus();
|
|
11
|
-
}, 1);
|
|
12
|
-
|
|
13
|
-
return () => {
|
|
14
|
-
clearTimeout(timer);
|
|
15
|
-
};
|
|
16
|
-
}, []);
|
|
17
|
-
|
|
18
|
-
return (
|
|
19
|
-
<div ref={ref} tabIndex={-1}>
|
|
20
|
-
{children}
|
|
21
|
-
</div>
|
|
22
|
-
);
|
|
23
|
-
}
|