tgui-core 1.0.2 → 1.0.4

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.
Files changed (158) hide show
  1. package/{src/components → components}/AnimatedNumber.tsx +185 -185
  2. package/{src/components → components}/BlockQuote.tsx +15 -15
  3. package/{src/components → components}/BodyZoneSelector.tsx +149 -149
  4. package/{src/components → components}/Box.tsx +255 -255
  5. package/{src/components → components}/Button.tsx +415 -415
  6. package/{src/components → components}/ByondUi.jsx +121 -121
  7. package/{src/components → components}/Chart.tsx +160 -160
  8. package/{src/components → components}/ColorBox.tsx +30 -30
  9. package/{src/components → components}/Dimmer.tsx +19 -19
  10. package/{src/components → components}/Divider.tsx +26 -26
  11. package/{src/components → components}/DmIcon.tsx +72 -72
  12. package/{src/components → components}/DraggableControl.jsx +282 -282
  13. package/{src/components → components}/Dropdown.tsx +246 -246
  14. package/{src/components → components}/Flex.tsx +105 -105
  15. package/{src/components → components}/Icon.tsx +91 -91
  16. package/{src/components → components}/Input.tsx +181 -181
  17. package/{src/components → components}/KeyListener.tsx +40 -40
  18. package/{src/components → components}/Knob.tsx +185 -185
  19. package/{src/components → components}/LabeledList.tsx +130 -130
  20. package/{src/components → components}/MenuBar.tsx +233 -238
  21. package/{src/components → components}/Modal.tsx +25 -25
  22. package/{src/components → components}/NoticeBox.tsx +48 -48
  23. package/{src/components → components}/NumberInput.tsx +328 -328
  24. package/{src/components → components}/ProgressBar.tsx +79 -79
  25. package/{src/components → components}/RestrictedInput.jsx +301 -301
  26. package/{src/components → components}/RoundGauge.tsx +189 -189
  27. package/{src/components → components}/Section.tsx +125 -125
  28. package/{src/components → components}/Slider.tsx +173 -173
  29. package/{src/components → components}/Stack.tsx +101 -101
  30. package/{src/components → components}/Table.tsx +90 -90
  31. package/{src/components → components}/Tabs.tsx +90 -90
  32. package/{src/components → components}/TextArea.tsx +198 -198
  33. package/{src/components → components}/TimeDisplay.jsx +64 -64
  34. package/components/index.ts +51 -0
  35. package/{src/debug/KitchenSink.jsx → debug/KitchenSink.tsx} +56 -56
  36. package/{src/debug/actions.js → debug/actions.ts} +11 -11
  37. package/{src/debug/hooks.js → debug/hooks.ts} +10 -10
  38. package/{src/debug/middleware.js → debug/middleware.ts} +67 -86
  39. package/{src/debug/reducer.js → debug/reducer.ts} +27 -22
  40. package/{src/debug/selectors.js → debug/selectors.ts} +7 -7
  41. package/{src/layouts → layouts}/Layout.tsx +75 -75
  42. package/{src/layouts → layouts}/NtosWindow.tsx +162 -162
  43. package/{src/layouts → layouts}/Pane.tsx +56 -56
  44. package/{src/layouts → layouts}/Window.tsx +227 -227
  45. package/layouts/index.ts +10 -0
  46. package/package.json +3 -2
  47. package/src/assets.ts +43 -43
  48. package/src/backend.ts +368 -369
  49. package/src/drag.ts +280 -280
  50. package/src/events.ts +237 -237
  51. package/src/hotkeys.ts +212 -212
  52. package/src/renderer.ts +50 -50
  53. package/stories/Blink.stories.tsx +20 -0
  54. package/stories/BlockQuote.stories.tsx +23 -0
  55. package/stories/Box.stories.tsx +27 -0
  56. package/stories/Button.stories.tsx +68 -0
  57. package/stories/ByondUi.stories.tsx +45 -0
  58. package/stories/Collapsible.stories.tsx +23 -0
  59. package/stories/Flex.stories.tsx +68 -0
  60. package/stories/Input.stories.tsx +124 -0
  61. package/stories/LabeledList.stories.tsx +73 -0
  62. package/stories/Popper.stories.tsx +58 -0
  63. package/stories/ProgressBar.stories.tsx +58 -0
  64. package/stories/Stack.stories.tsx +55 -0
  65. package/stories/Storage.stories.tsx +46 -0
  66. package/stories/Themes.stories.tsx +30 -0
  67. package/stories/Tooltip.stories.tsx +48 -0
  68. package/stories/common.tsx +19 -0
  69. package/tsconfig.json +0 -21
  70. package/src/components/Grid.tsx +0 -44
  71. /package/{src/common → common}/collections.ts +0 -0
  72. /package/{src/common → common}/color.ts +0 -0
  73. /package/{src/common → common}/events.ts +0 -0
  74. /package/{src/common → common}/exhaustive.ts +0 -0
  75. /package/{src/common → common}/fp.ts +0 -0
  76. /package/{src/common → common}/keycodes.ts +0 -0
  77. /package/{src/common → common}/keys.ts +0 -0
  78. /package/{src/common → common}/math.ts +0 -0
  79. /package/{src/common → common}/perf.ts +0 -0
  80. /package/{src/common → common}/random.ts +0 -0
  81. /package/{src/common → common}/react.ts +0 -0
  82. /package/{src/common → common}/redux.ts +0 -0
  83. /package/{src/common → common}/storage.js +0 -0
  84. /package/{src/common → common}/string.ts +0 -0
  85. /package/{src/common → common}/timer.ts +0 -0
  86. /package/{src/common → common}/type-utils.ts +0 -0
  87. /package/{src/common → common}/types.ts +0 -0
  88. /package/{src/common → common}/uuid.ts +0 -0
  89. /package/{src/common → common}/vector.ts +0 -0
  90. /package/{src/components → components}/Autofocus.tsx +0 -0
  91. /package/{src/components → components}/Blink.jsx +0 -0
  92. /package/{src/components → components}/Collapsible.tsx +0 -0
  93. /package/{src/components → components}/Dialog.tsx +0 -0
  94. /package/{src/components → components}/FakeTerminal.jsx +0 -0
  95. /package/{src/components → components}/FitText.tsx +0 -0
  96. /package/{src/components → components}/Image.tsx +0 -0
  97. /package/{src/components → components}/InfinitePlane.jsx +0 -0
  98. /package/{src/components → components}/LabeledControls.tsx +0 -0
  99. /package/{src/components → components}/Popper.tsx +0 -0
  100. /package/{src/components → components}/StyleableSection.tsx +0 -0
  101. /package/{src/components → components}/Tooltip.tsx +0 -0
  102. /package/{src/components → components}/TrackOutsideClicks.tsx +0 -0
  103. /package/{src/components → components}/VirtualList.tsx +0 -0
  104. /package/{src/debug → debug}/index.ts +0 -0
  105. /package/{src/styles → styles}/base.scss +0 -0
  106. /package/{src/styles → styles}/colors.scss +0 -0
  107. /package/{src/styles → styles}/components/BlockQuote.scss +0 -0
  108. /package/{src/styles → styles}/components/Button.scss +0 -0
  109. /package/{src/styles → styles}/components/ColorBox.scss +0 -0
  110. /package/{src/styles → styles}/components/Dialog.scss +0 -0
  111. /package/{src/styles → styles}/components/Dimmer.scss +0 -0
  112. /package/{src/styles → styles}/components/Divider.scss +0 -0
  113. /package/{src/styles → styles}/components/Dropdown.scss +0 -0
  114. /package/{src/styles → styles}/components/Flex.scss +0 -0
  115. /package/{src/styles → styles}/components/Icon.scss +0 -0
  116. /package/{src/styles → styles}/components/Input.scss +0 -0
  117. /package/{src/styles → styles}/components/Knob.scss +0 -0
  118. /package/{src/styles → styles}/components/LabeledList.scss +0 -0
  119. /package/{src/styles → styles}/components/MenuBar.scss +0 -0
  120. /package/{src/styles → styles}/components/Modal.scss +0 -0
  121. /package/{src/styles → styles}/components/NoticeBox.scss +0 -0
  122. /package/{src/styles → styles}/components/NumberInput.scss +0 -0
  123. /package/{src/styles → styles}/components/ProgressBar.scss +0 -0
  124. /package/{src/styles → styles}/components/RoundGauge.scss +0 -0
  125. /package/{src/styles → styles}/components/Section.scss +0 -0
  126. /package/{src/styles → styles}/components/Slider.scss +0 -0
  127. /package/{src/styles → styles}/components/Stack.scss +0 -0
  128. /package/{src/styles → styles}/components/Table.scss +0 -0
  129. /package/{src/styles → styles}/components/Tabs.scss +0 -0
  130. /package/{src/styles → styles}/components/TextArea.scss +0 -0
  131. /package/{src/styles → styles}/components/Tooltip.scss +0 -0
  132. /package/{src/styles → styles}/functions.scss +0 -0
  133. /package/{src/styles → styles}/layouts/Layout.scss +0 -0
  134. /package/{src/styles → styles}/layouts/NtosHeader.scss +0 -0
  135. /package/{src/styles → styles}/layouts/NtosWindow.scss +0 -0
  136. /package/{src/styles → styles}/layouts/TitleBar.scss +0 -0
  137. /package/{src/styles → styles}/layouts/Window.scss +0 -0
  138. /package/{src/styles → styles}/main.scss +0 -0
  139. /package/{src/styles → styles}/reset.scss +0 -0
  140. /package/{src/styles → styles}/themes/abductor.scss +0 -0
  141. /package/{src/styles → styles}/themes/admin.scss +0 -0
  142. /package/{src/styles → styles}/themes/cardtable.scss +0 -0
  143. /package/{src/styles → styles}/themes/hackerman.scss +0 -0
  144. /package/{src/styles → styles}/themes/malfunction.scss +0 -0
  145. /package/{src/styles → styles}/themes/neutral.scss +0 -0
  146. /package/{src/styles → styles}/themes/ntOS95.scss +0 -0
  147. /package/{src/styles → styles}/themes/ntos.scss +0 -0
  148. /package/{src/styles → styles}/themes/ntos_cat.scss +0 -0
  149. /package/{src/styles → styles}/themes/ntos_darkmode.scss +0 -0
  150. /package/{src/styles → styles}/themes/ntos_lightmode.scss +0 -0
  151. /package/{src/styles → styles}/themes/ntos_spooky.scss +0 -0
  152. /package/{src/styles → styles}/themes/ntos_synth.scss +0 -0
  153. /package/{src/styles → styles}/themes/ntos_terminal.scss +0 -0
  154. /package/{src/styles → styles}/themes/paper.scss +0 -0
  155. /package/{src/styles → styles}/themes/retro.scss +0 -0
  156. /package/{src/styles → styles}/themes/spookyconsole.scss +0 -0
  157. /package/{src/styles → styles}/themes/syndicate.scss +0 -0
  158. /package/{src/styles → styles}/themes/wizard.scss +0 -0
package/src/hotkeys.ts CHANGED
@@ -1,212 +1,212 @@
1
- /**
2
- * @file
3
- * @copyright 2020 Aleksej Komarov
4
- * @license MIT
5
- */
6
-
7
- import * as keycodes from './common/keycodes';
8
-
9
- import { globalEvents, KeyEvent } from './events';
10
-
11
- // BYOND macros, in `key: command` format.
12
- const byondMacros: Record<string, string> = {};
13
-
14
- // Default set of acquired keys, which will not be sent to BYOND.
15
- const hotKeysAcquired = [
16
- keycodes.KEY_ESCAPE,
17
- keycodes.KEY_ENTER,
18
- keycodes.KEY_SPACE,
19
- keycodes.KEY_TAB,
20
- keycodes.KEY_CTRL,
21
- keycodes.KEY_SHIFT,
22
- keycodes.KEY_UP,
23
- keycodes.KEY_DOWN,
24
- keycodes.KEY_LEFT,
25
- keycodes.KEY_RIGHT,
26
- keycodes.KEY_F5,
27
- ];
28
-
29
- // State of passed-through keys.
30
- const keyState: Record<string, boolean> = {};
31
-
32
- // Custom listeners for key events
33
- const keyListeners: ((key: KeyEvent) => void)[] = [];
34
-
35
- /**
36
- * Converts a browser keycode to BYOND keycode.
37
- */
38
- const keyCodeToByond = (keyCode: number) => {
39
- if (keyCode === 16) return 'Shift';
40
- if (keyCode === 17) return 'Ctrl';
41
- if (keyCode === 18) return 'Alt';
42
- if (keyCode === 33) return 'Northeast';
43
- if (keyCode === 34) return 'Southeast';
44
- if (keyCode === 35) return 'Southwest';
45
- if (keyCode === 36) return 'Northwest';
46
- if (keyCode === 37) return 'West';
47
- if (keyCode === 38) return 'North';
48
- if (keyCode === 39) return 'East';
49
- if (keyCode === 40) return 'South';
50
- if (keyCode === 45) return 'Insert';
51
- if (keyCode === 46) return 'Delete';
52
-
53
- if ((keyCode >= 48 && keyCode <= 57) || (keyCode >= 65 && keyCode <= 90)) {
54
- return String.fromCharCode(keyCode);
55
- }
56
- if (keyCode >= 96 && keyCode <= 105) {
57
- return 'Numpad' + (keyCode - 96);
58
- }
59
- if (keyCode >= 112 && keyCode <= 123) {
60
- return 'F' + (keyCode - 111);
61
- }
62
- if (keyCode === 188) return ',';
63
- if (keyCode === 189) return '-';
64
- if (keyCode === 190) return '.';
65
- };
66
-
67
- /**
68
- * Keyboard passthrough logic. This allows you to keep doing things
69
- * in game while the browser window is focused.
70
- */
71
- const handlePassthrough = (key: KeyEvent) => {
72
- const keyString = String(key);
73
- // In addition to F5, support reloading with Ctrl+R and Ctrl+F5
74
- if (keyString === 'Ctrl+F5' || keyString === 'Ctrl+R') {
75
- location.reload();
76
- return;
77
- }
78
- // Prevent passthrough on Ctrl+F
79
- if (keyString === 'Ctrl+F') {
80
- return;
81
- }
82
- // NOTE: Alt modifier is pretty bad and sticky in IE11.
83
-
84
- if (
85
- key.event.defaultPrevented ||
86
- key.isModifierKey() ||
87
- hotKeysAcquired.includes(key.code)
88
- ) {
89
- return;
90
- }
91
- const byondKeyCode = keyCodeToByond(key.code);
92
- if (!byondKeyCode) {
93
- return;
94
- }
95
- // Macro
96
- const macro = byondMacros[byondKeyCode];
97
- if (macro) {
98
- return Byond.command(macro);
99
- }
100
- // KeyDown
101
- if (key.isDown() && !keyState[byondKeyCode]) {
102
- keyState[byondKeyCode] = true;
103
- const command = `KeyDown "${byondKeyCode}"`;
104
- return Byond.command(command);
105
- }
106
- // KeyUp
107
- if (key.isUp() && keyState[byondKeyCode]) {
108
- keyState[byondKeyCode] = false;
109
- const command = `KeyUp "${byondKeyCode}"`;
110
- return Byond.command(command);
111
- }
112
- };
113
-
114
- /**
115
- * Acquires a lock on the hotkey, which prevents it from being
116
- * passed through to BYOND.
117
- */
118
- export const acquireHotKey = (keyCode: number) => {
119
- hotKeysAcquired.push(keyCode);
120
- };
121
-
122
- /**
123
- * Makes the hotkey available to BYOND again.
124
- */
125
- export const releaseHotKey = (keyCode: number) => {
126
- const index = hotKeysAcquired.indexOf(keyCode);
127
- if (index >= 0) {
128
- hotKeysAcquired.splice(index, 1);
129
- }
130
- };
131
-
132
- export const releaseHeldKeys = () => {
133
- for (let byondKeyCode of Object.keys(keyState)) {
134
- if (keyState[byondKeyCode]) {
135
- keyState[byondKeyCode] = false;
136
- Byond.command(`KeyUp "${byondKeyCode}"`);
137
- }
138
- }
139
- };
140
-
141
- type ByondSkinMacro = {
142
- command: string;
143
- name: string;
144
- };
145
-
146
- export const setupHotKeys = () => {
147
- // Read macros
148
- Byond.winget('default.*').then((data: Record<string, string>) => {
149
- // Group each macro by ref
150
- const groupedByRef: Record<string, ByondSkinMacro> = {};
151
- for (let key of Object.keys(data)) {
152
- const keyPath = key.split('.');
153
- const ref = keyPath[1];
154
- const prop = keyPath[2];
155
- if (ref && prop) {
156
- // This piece of code imperatively adds each property to a
157
- // ByondSkinMacro object in the order we meet it, which is hard
158
- // to express safely in typescript.
159
- if (!groupedByRef[ref]) {
160
- groupedByRef[ref] = {} as any;
161
- }
162
- groupedByRef[ref][prop] = data[key];
163
- }
164
- }
165
- // Insert macros
166
- const escapedQuotRegex = /\\"/g;
167
-
168
- const unescape = (str: string) =>
169
- str.substring(1, str.length - 1).replace(escapedQuotRegex, '"');
170
- for (let ref of Object.keys(groupedByRef)) {
171
- const macro = groupedByRef[ref];
172
- const byondKeyName = unescape(macro.name);
173
- byondMacros[byondKeyName] = unescape(macro.command);
174
- }
175
- });
176
- // Setup event handlers
177
- globalEvents.on('window-blur', () => {
178
- releaseHeldKeys();
179
- });
180
- globalEvents.on('key', (key: KeyEvent) => {
181
- for (const keyListener of keyListeners) {
182
- keyListener(key);
183
- }
184
- handlePassthrough(key);
185
- });
186
- };
187
-
188
- /**
189
- * Registers for any key events, such as key down or key up.
190
- * This should be preferred over directly connecting to keydown/keyup
191
- * as it lets tgui prevent the key from reaching BYOND.
192
- *
193
- * If using in a component, prefer KeyListener, which automatically handles
194
- * stopping listening when unmounting.
195
- *
196
- * @param callback The function to call whenever a key event occurs
197
- * @returns A callback to stop listening
198
- */
199
- export const listenForKeyEvents = (callback: (key: KeyEvent) => void) => {
200
- keyListeners.push(callback);
201
-
202
- let removed = false;
203
-
204
- return () => {
205
- if (removed) {
206
- return;
207
- }
208
-
209
- removed = true;
210
- keyListeners.splice(keyListeners.indexOf(callback), 1);
211
- };
212
- };
1
+ /**
2
+ * @file
3
+ * @copyright 2020 Aleksej Komarov
4
+ * @license MIT
5
+ */
6
+
7
+ import * as keycodes from '../common/keycodes';
8
+
9
+ import { globalEvents, KeyEvent } from './events';
10
+
11
+ // BYOND macros, in `key: command` format.
12
+ const byondMacros: Record<string, string> = {};
13
+
14
+ // Default set of acquired keys, which will not be sent to BYOND.
15
+ const hotKeysAcquired = [
16
+ keycodes.KEY_ESCAPE,
17
+ keycodes.KEY_ENTER,
18
+ keycodes.KEY_SPACE,
19
+ keycodes.KEY_TAB,
20
+ keycodes.KEY_CTRL,
21
+ keycodes.KEY_SHIFT,
22
+ keycodes.KEY_UP,
23
+ keycodes.KEY_DOWN,
24
+ keycodes.KEY_LEFT,
25
+ keycodes.KEY_RIGHT,
26
+ keycodes.KEY_F5,
27
+ ];
28
+
29
+ // State of passed-through keys.
30
+ const keyState: Record<string, boolean> = {};
31
+
32
+ // Custom listeners for key events
33
+ const keyListeners: ((key: KeyEvent) => void)[] = [];
34
+
35
+ /**
36
+ * Converts a browser keycode to BYOND keycode.
37
+ */
38
+ const keyCodeToByond = (keyCode: number) => {
39
+ if (keyCode === 16) return 'Shift';
40
+ if (keyCode === 17) return 'Ctrl';
41
+ if (keyCode === 18) return 'Alt';
42
+ if (keyCode === 33) return 'Northeast';
43
+ if (keyCode === 34) return 'Southeast';
44
+ if (keyCode === 35) return 'Southwest';
45
+ if (keyCode === 36) return 'Northwest';
46
+ if (keyCode === 37) return 'West';
47
+ if (keyCode === 38) return 'North';
48
+ if (keyCode === 39) return 'East';
49
+ if (keyCode === 40) return 'South';
50
+ if (keyCode === 45) return 'Insert';
51
+ if (keyCode === 46) return 'Delete';
52
+
53
+ if ((keyCode >= 48 && keyCode <= 57) || (keyCode >= 65 && keyCode <= 90)) {
54
+ return String.fromCharCode(keyCode);
55
+ }
56
+ if (keyCode >= 96 && keyCode <= 105) {
57
+ return 'Numpad' + (keyCode - 96);
58
+ }
59
+ if (keyCode >= 112 && keyCode <= 123) {
60
+ return 'F' + (keyCode - 111);
61
+ }
62
+ if (keyCode === 188) return ',';
63
+ if (keyCode === 189) return '-';
64
+ if (keyCode === 190) return '.';
65
+ };
66
+
67
+ /**
68
+ * Keyboard passthrough logic. This allows you to keep doing things
69
+ * in game while the browser window is focused.
70
+ */
71
+ const handlePassthrough = (key: KeyEvent) => {
72
+ const keyString = String(key);
73
+ // In addition to F5, support reloading with Ctrl+R and Ctrl+F5
74
+ if (keyString === 'Ctrl+F5' || keyString === 'Ctrl+R') {
75
+ location.reload();
76
+ return;
77
+ }
78
+ // Prevent passthrough on Ctrl+F
79
+ if (keyString === 'Ctrl+F') {
80
+ return;
81
+ }
82
+ // NOTE: Alt modifier is pretty bad and sticky in IE11.
83
+
84
+ if (
85
+ key.event.defaultPrevented ||
86
+ key.isModifierKey() ||
87
+ hotKeysAcquired.includes(key.code)
88
+ ) {
89
+ return;
90
+ }
91
+ const byondKeyCode = keyCodeToByond(key.code);
92
+ if (!byondKeyCode) {
93
+ return;
94
+ }
95
+ // Macro
96
+ const macro = byondMacros[byondKeyCode];
97
+ if (macro) {
98
+ return Byond.command(macro);
99
+ }
100
+ // KeyDown
101
+ if (key.isDown() && !keyState[byondKeyCode]) {
102
+ keyState[byondKeyCode] = true;
103
+ const command = `KeyDown "${byondKeyCode}"`;
104
+ return Byond.command(command);
105
+ }
106
+ // KeyUp
107
+ if (key.isUp() && keyState[byondKeyCode]) {
108
+ keyState[byondKeyCode] = false;
109
+ const command = `KeyUp "${byondKeyCode}"`;
110
+ return Byond.command(command);
111
+ }
112
+ };
113
+
114
+ /**
115
+ * Acquires a lock on the hotkey, which prevents it from being
116
+ * passed through to BYOND.
117
+ */
118
+ export const acquireHotKey = (keyCode: number) => {
119
+ hotKeysAcquired.push(keyCode);
120
+ };
121
+
122
+ /**
123
+ * Makes the hotkey available to BYOND again.
124
+ */
125
+ export const releaseHotKey = (keyCode: number) => {
126
+ const index = hotKeysAcquired.indexOf(keyCode);
127
+ if (index >= 0) {
128
+ hotKeysAcquired.splice(index, 1);
129
+ }
130
+ };
131
+
132
+ export const releaseHeldKeys = () => {
133
+ for (let byondKeyCode of Object.keys(keyState)) {
134
+ if (keyState[byondKeyCode]) {
135
+ keyState[byondKeyCode] = false;
136
+ Byond.command(`KeyUp "${byondKeyCode}"`);
137
+ }
138
+ }
139
+ };
140
+
141
+ type ByondSkinMacro = {
142
+ command: string;
143
+ name: string;
144
+ };
145
+
146
+ export const setupHotKeys = () => {
147
+ // Read macros
148
+ Byond.winget('default.*').then((data: Record<string, string>) => {
149
+ // Group each macro by ref
150
+ const groupedByRef: Record<string, ByondSkinMacro> = {};
151
+ for (let key of Object.keys(data)) {
152
+ const keyPath = key.split('.');
153
+ const ref = keyPath[1];
154
+ const prop = keyPath[2];
155
+ if (ref && prop) {
156
+ // This piece of code imperatively adds each property to a
157
+ // ByondSkinMacro object in the order we meet it, which is hard
158
+ // to express safely in typescript.
159
+ if (!groupedByRef[ref]) {
160
+ groupedByRef[ref] = {} as any;
161
+ }
162
+ groupedByRef[ref][prop] = data[key];
163
+ }
164
+ }
165
+ // Insert macros
166
+ const escapedQuotRegex = /\\"/g;
167
+
168
+ const unescape = (str: string) =>
169
+ str.substring(1, str.length - 1).replace(escapedQuotRegex, '"');
170
+ for (let ref of Object.keys(groupedByRef)) {
171
+ const macro = groupedByRef[ref];
172
+ const byondKeyName = unescape(macro.name);
173
+ byondMacros[byondKeyName] = unescape(macro.command);
174
+ }
175
+ });
176
+ // Setup event handlers
177
+ globalEvents.on('window-blur', () => {
178
+ releaseHeldKeys();
179
+ });
180
+ globalEvents.on('key', (key: KeyEvent) => {
181
+ for (const keyListener of keyListeners) {
182
+ keyListener(key);
183
+ }
184
+ handlePassthrough(key);
185
+ });
186
+ };
187
+
188
+ /**
189
+ * Registers for any key events, such as key down or key up.
190
+ * This should be preferred over directly connecting to keydown/keyup
191
+ * as it lets tgui prevent the key from reaching BYOND.
192
+ *
193
+ * If using in a component, prefer KeyListener, which automatically handles
194
+ * stopping listening when unmounting.
195
+ *
196
+ * @param callback The function to call whenever a key event occurs
197
+ * @returns A callback to stop listening
198
+ */
199
+ export const listenForKeyEvents = (callback: (key: KeyEvent) => void) => {
200
+ keyListeners.push(callback);
201
+
202
+ let removed = false;
203
+
204
+ return () => {
205
+ if (removed) {
206
+ return;
207
+ }
208
+
209
+ removed = true;
210
+ keyListeners.splice(keyListeners.indexOf(callback), 1);
211
+ };
212
+ };
package/src/renderer.ts CHANGED
@@ -1,50 +1,50 @@
1
- import { perf } from './common/perf';
2
- import { ReactNode } from 'react';
3
- import { createRoot, Root } from 'react-dom/client';
4
-
5
- let reactRoot: Root;
6
- let initialRender: string | boolean = true;
7
- let suspended = false;
8
-
9
- // These functions are used purely for profiling.
10
- export const resumeRenderer = () => {
11
- initialRender = initialRender || 'resumed';
12
- suspended = false;
13
- };
14
-
15
- export const suspendRenderer = () => {
16
- suspended = true;
17
- };
18
-
19
- type CreateRenderer = <T extends unknown[] = [unknown]>(
20
- getVNode?: (...args: T) => ReactNode
21
- ) => (...args: T) => void;
22
-
23
- enum Render {
24
- Start = 'render/start',
25
- Finish = 'render/finish',
26
- }
27
-
28
- // prettier-ignore
29
- export const createRenderer: CreateRenderer = (getVNode) => (...args) => {
30
- perf.mark(Render.Start);
31
- // Start rendering
32
- if (!reactRoot) {
33
- const element = document.getElementById('react-root');
34
- reactRoot = createRoot(element!);
35
- }
36
- if (getVNode) {
37
- reactRoot.render(getVNode(...args));
38
- }
39
- else {
40
- reactRoot.render(args[0] as any);
41
- }
42
- perf.mark(Render.Finish);
43
- if (suspended) {
44
- return;
45
- }
46
-
47
- if (initialRender) {
48
- initialRender = false;
49
- }
50
- };
1
+ import { perf } from '../common/perf';
2
+ import { ReactNode } from 'react';
3
+ import { createRoot, Root } from 'react-dom/client';
4
+
5
+ let reactRoot: Root;
6
+ let initialRender: string | boolean = true;
7
+ let suspended = false;
8
+
9
+ // These functions are used purely for profiling.
10
+ export const resumeRenderer = () => {
11
+ initialRender = initialRender || 'resumed';
12
+ suspended = false;
13
+ };
14
+
15
+ export const suspendRenderer = () => {
16
+ suspended = true;
17
+ };
18
+
19
+ type CreateRenderer = <T extends unknown[] = [unknown]>(
20
+ getVNode?: (...args: T) => ReactNode
21
+ ) => (...args: T) => void;
22
+
23
+ enum Render {
24
+ Start = 'render/start',
25
+ Finish = 'render/finish',
26
+ }
27
+
28
+ export const createRenderer: CreateRenderer =
29
+ (getVNode) =>
30
+ (...args) => {
31
+ perf.mark(Render.Start);
32
+ // Start rendering
33
+ if (!reactRoot) {
34
+ const element = document.getElementById('react-root');
35
+ reactRoot = createRoot(element!);
36
+ }
37
+ if (getVNode) {
38
+ reactRoot.render(getVNode(...args));
39
+ } else {
40
+ reactRoot.render(args[0] as any);
41
+ }
42
+ perf.mark(Render.Finish);
43
+ if (suspended) {
44
+ return;
45
+ }
46
+
47
+ if (initialRender) {
48
+ initialRender = false;
49
+ }
50
+ };
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @file
3
+ * @copyright 2021 Aleksej Komarov
4
+ * @license MIT
5
+ */
6
+
7
+ import { Blink, Section } from '../components';
8
+
9
+ export const meta = {
10
+ title: 'Blink',
11
+ render: () => <Story />,
12
+ };
13
+
14
+ const Story = (props) => {
15
+ return (
16
+ <Section>
17
+ <Blink>Blink</Blink>
18
+ </Section>
19
+ );
20
+ };
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @file
3
+ * @copyright 2021 Aleksej Komarov
4
+ * @license MIT
5
+ */
6
+
7
+ import { BlockQuote, Section } from '../components';
8
+ import { BoxWithSampleText } from './common';
9
+
10
+ export const meta = {
11
+ title: 'BlockQuote',
12
+ render: () => <Story />,
13
+ };
14
+
15
+ const Story = (props) => {
16
+ return (
17
+ <Section>
18
+ <BlockQuote>
19
+ <BoxWithSampleText />
20
+ </BlockQuote>
21
+ </Section>
22
+ );
23
+ };
@@ -0,0 +1,27 @@
1
+ /**
2
+ * @file
3
+ * @copyright 2021 Aleksej Komarov
4
+ * @license MIT
5
+ */
6
+
7
+ import { Box, Section } from '../components';
8
+
9
+ export const meta = {
10
+ title: 'Box',
11
+ render: () => <Story />,
12
+ };
13
+
14
+ const Story = (props) => {
15
+ return (
16
+ <Section>
17
+ <Box bold>bold</Box>
18
+ <Box italic>italic</Box>
19
+ <Box opacity={0.5}>opacity 0.5</Box>
20
+ <Box opacity={0.25}>opacity 0.25</Box>
21
+ <Box m={2}>m: 2</Box>
22
+ <Box textAlign="left">left</Box>
23
+ <Box textAlign="center">center</Box>
24
+ <Box textAlign="right">right</Box>
25
+ </Section>
26
+ );
27
+ };
@@ -0,0 +1,68 @@
1
+ /**
2
+ * @file
3
+ * @copyright 2021 Aleksej Komarov
4
+ * @license MIT
5
+ */
6
+
7
+ import { Box, Button, Section } from '../components';
8
+
9
+ export const meta = {
10
+ title: 'Button',
11
+ render: () => <Story />,
12
+ };
13
+
14
+ const COLORS_SPECTRUM = [
15
+ 'red',
16
+ 'orange',
17
+ 'yellow',
18
+ 'olive',
19
+ 'green',
20
+ 'teal',
21
+ 'blue',
22
+ 'violet',
23
+ 'purple',
24
+ 'pink',
25
+ 'brown',
26
+ 'grey',
27
+ ];
28
+
29
+ const COLORS_STATES = ['good', 'average', 'bad', 'black', 'white'];
30
+
31
+ const Story = (props) => {
32
+ return (
33
+ <Section>
34
+ <Box mb={1}>
35
+ <Button content="Simple" />
36
+ <Button selected content="Selected" />
37
+ <Button content="Alt Selected" />
38
+ <Button disabled content="Disabled" />
39
+ <Button color="transparent" content="Transparent" />
40
+ <Button icon="cog" content="Icon" />
41
+ <Button icon="power-off" />
42
+ <Button fluid content="Fluid" />
43
+ <Button
44
+ my={1}
45
+ lineHeight={2}
46
+ minWidth={15}
47
+ textAlign="center"
48
+ content="With Box props"
49
+ />
50
+ </Box>
51
+ <Box mb={1}>
52
+ {COLORS_STATES.map((color) => (
53
+ <Button key={color} color={color} content={color} />
54
+ ))}
55
+ <br />
56
+ {COLORS_SPECTRUM.map((color) => (
57
+ <Button key={color} color={color} content={color} />
58
+ ))}
59
+ <br />
60
+ {COLORS_SPECTRUM.map((color) => (
61
+ <Box inline mx="7px" key={color} color={color}>
62
+ {color}
63
+ </Box>
64
+ ))}
65
+ </Box>
66
+ </Section>
67
+ );
68
+ };