tgui-core 1.1.8 → 1.1.9

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 (291) hide show
  1. package/lib/common/assets.ts +38 -0
  2. package/lib/common/collections.ts +27 -0
  3. package/lib/common/color.ts +88 -0
  4. package/lib/common/constants.ts +349 -0
  5. package/lib/common/events.ts +262 -0
  6. package/{dist/common/exhaustive.d.ts → lib/common/exhaustive.ts} +3 -1
  7. package/lib/common/format.ts +167 -0
  8. package/{dist/common/fp.d.ts → lib/common/fp.ts} +16 -2
  9. package/lib/common/hotkeys.ts +207 -0
  10. package/lib/common/http.ts +16 -0
  11. package/lib/common/keycodes.ts +86 -0
  12. package/{dist/common/keys.d.ts → lib/common/keys.ts} +24 -21
  13. package/lib/common/math.ts +76 -0
  14. package/lib/common/perf.ts +72 -0
  15. package/lib/common/random.ts +32 -0
  16. package/lib/common/react.ts +59 -0
  17. package/lib/common/redux.ts +187 -0
  18. package/lib/common/storage.ts +207 -0
  19. package/lib/common/string.ts +169 -0
  20. package/lib/common/timer.ts +63 -0
  21. package/lib/common/type-utils.ts +41 -0
  22. package/lib/common/types.d.ts +12 -0
  23. package/lib/common/uuid.ts +18 -0
  24. package/lib/components/AnimatedNumber.tsx +180 -0
  25. package/lib/components/Autofocus.tsx +23 -0
  26. package/lib/components/Blink.tsx +91 -0
  27. package/lib/components/BlockQuote.tsx +9 -0
  28. package/lib/components/BodyZoneSelector.tsx +149 -0
  29. package/lib/components/Box.tsx +252 -0
  30. package/lib/components/Button.tsx +425 -0
  31. package/lib/components/ByondUi.jsx +110 -0
  32. package/lib/components/Chart.tsx +155 -0
  33. package/lib/components/Collapsible.tsx +43 -0
  34. package/lib/components/ColorBox.tsx +29 -0
  35. package/lib/components/Dialog.tsx +81 -0
  36. package/lib/components/Dimmer.tsx +13 -0
  37. package/lib/components/Divider.tsx +20 -0
  38. package/lib/components/DmIcon.tsx +86 -0
  39. package/lib/components/DraggableControl.jsx +276 -0
  40. package/lib/components/Dropdown.tsx +246 -0
  41. package/lib/components/FakeTerminal.jsx +52 -0
  42. package/lib/components/FitText.tsx +99 -0
  43. package/lib/components/Flex.tsx +159 -0
  44. package/lib/components/Icon.tsx +95 -0
  45. package/lib/components/Image.tsx +54 -0
  46. package/lib/components/InfinitePlane.jsx +192 -0
  47. package/lib/components/Input.tsx +176 -0
  48. package/lib/components/KeyListener.tsx +40 -0
  49. package/lib/components/Knob.tsx +178 -0
  50. package/lib/components/LabeledControls.tsx +44 -0
  51. package/lib/components/LabeledList.tsx +154 -0
  52. package/lib/components/MenuBar.tsx +228 -0
  53. package/lib/components/Modal.tsx +23 -0
  54. package/lib/components/NoticeBox.tsx +45 -0
  55. package/lib/components/NumberInput.tsx +328 -0
  56. package/lib/components/Popper.tsx +100 -0
  57. package/lib/components/ProgressBar.tsx +105 -0
  58. package/lib/components/RestrictedInput.jsx +301 -0
  59. package/lib/components/RoundGauge.tsx +180 -0
  60. package/lib/components/Section.tsx +120 -0
  61. package/lib/components/Slider.tsx +169 -0
  62. package/lib/components/Stack.tsx +96 -0
  63. package/lib/components/StyleableSection.tsx +33 -0
  64. package/lib/components/Table.tsx +84 -0
  65. package/lib/components/Tabs.tsx +89 -0
  66. package/lib/components/TextArea.tsx +182 -0
  67. package/lib/components/TimeDisplay.jsx +64 -0
  68. package/lib/components/Tooltip.tsx +152 -0
  69. package/lib/components/TrackOutsideClicks.tsx +35 -0
  70. package/lib/components/VirtualList.tsx +69 -0
  71. package/lib/styles/atomic/candystripe.scss +8 -0
  72. package/lib/styles/atomic/centered-image.scss +7 -0
  73. package/lib/styles/atomic/color.scss +21 -0
  74. package/lib/styles/atomic/debug-layout.scss +17 -0
  75. package/lib/styles/atomic/fit-text.scss +14 -0
  76. package/lib/styles/atomic/links.scss +12 -0
  77. package/lib/styles/atomic/outline.scss +47 -0
  78. package/lib/styles/atomic/text.scss +44 -0
  79. package/lib/styles/base.scss +32 -0
  80. package/lib/styles/colors.scss +92 -0
  81. package/lib/styles/components/BlockQuote.module.scss +20 -0
  82. package/lib/styles/components/BlockQuote.module.scss.d.ts +4 -0
  83. package/lib/styles/components/Button.module.scss +157 -0
  84. package/lib/styles/components/Button.module.scss.d.ts +46 -0
  85. package/lib/styles/components/ColorBox.module.scss +12 -0
  86. package/lib/styles/components/ColorBox.module.scss.d.ts +4 -0
  87. package/lib/styles/components/Dialog.module.scss +60 -0
  88. package/lib/styles/components/Dialog.module.scss.d.ts +10 -0
  89. package/lib/styles/components/Dimmer.module.scss +22 -0
  90. package/lib/styles/components/Dimmer.module.scss.d.ts +4 -0
  91. package/lib/styles/components/Divider.module.scss +27 -0
  92. package/lib/styles/components/Divider.module.scss.d.ts +6 -0
  93. package/lib/styles/components/Dropdown.scss +72 -0
  94. package/lib/styles/components/Flex.module.scss +13 -0
  95. package/lib/styles/components/Flex.module.scss.d.ts +5 -0
  96. package/lib/styles/components/Icon.module.scss +25 -0
  97. package/lib/styles/components/Icon.module.scss.d.ts +5 -0
  98. package/lib/styles/components/Input.module.scss +64 -0
  99. package/lib/styles/components/Input.module.scss.d.ts +8 -0
  100. package/lib/styles/components/Knob.module.scss +131 -0
  101. package/lib/styles/components/Knob.module.scss.d.ts +33 -0
  102. package/lib/styles/components/LabeledList.module.scss +49 -0
  103. package/lib/styles/components/LabeledList.module.scss.d.ts +8 -0
  104. package/lib/styles/components/MenuBar.module.scss +75 -0
  105. package/lib/styles/components/MenuBar.module.scss.d.ts +14 -0
  106. package/lib/styles/components/Modal.module.scss +14 -0
  107. package/lib/styles/components/Modal.module.scss.d.ts +4 -0
  108. package/lib/styles/components/NoticeBox.module.scss +65 -0
  109. package/lib/styles/components/NoticeBox.module.scss.d.ts +27 -0
  110. package/lib/styles/components/NumberInput.module.scss +71 -0
  111. package/lib/styles/components/NumberInput.module.scss.d.ts +9 -0
  112. package/lib/styles/components/ProgressBar.module.scss +63 -0
  113. package/lib/styles/components/ProgressBar.module.scss.d.ts +27 -0
  114. package/lib/styles/components/RoundGauge.module.scss +85 -0
  115. package/lib/styles/components/RoundGauge.module.scss.d.ts +49 -0
  116. package/lib/styles/components/Section.module.scss +130 -0
  117. package/lib/styles/components/Section.module.scss.d.ts +13 -0
  118. package/lib/styles/components/Slider.module.scss +54 -0
  119. package/lib/styles/components/Slider.module.scss.d.ts +8 -0
  120. package/lib/styles/components/Stack.module.scss +60 -0
  121. package/lib/styles/components/Stack.module.scss.d.ts +12 -0
  122. package/lib/styles/components/Table.module.scss +44 -0
  123. package/lib/styles/components/Table.module.scss.d.ts +10 -0
  124. package/lib/styles/components/Tabs.module.scss +144 -0
  125. package/lib/styles/components/Tabs.module.scss.d.ts +35 -0
  126. package/lib/styles/components/TextArea.module.scss +86 -0
  127. package/lib/styles/components/TextArea.module.scss.d.ts +11 -0
  128. package/lib/styles/components/Tooltip.module.scss +24 -0
  129. package/lib/styles/components/Tooltip.module.scss.d.ts +4 -0
  130. package/lib/styles/functions.scss +79 -0
  131. package/lib/styles/input.scss +9 -0
  132. package/lib/styles/main.scss +20 -0
  133. package/lib/styles/reset.scss +68 -0
  134. package/package.json +6 -6
  135. package/dist/ProgressBar.module-BkAFfFy0.js +0 -29
  136. package/dist/Section.module-CLVHJ4yA.js +0 -15
  137. package/dist/assets/BlockQuote.css +0 -1
  138. package/dist/assets/Button.css +0 -1
  139. package/dist/assets/ColorBox.css +0 -1
  140. package/dist/assets/Dialog.css +0 -1
  141. package/dist/assets/Dimmer.css +0 -1
  142. package/dist/assets/Divider.css +0 -1
  143. package/dist/assets/Flex.css +0 -1
  144. package/dist/assets/Icon.css +0 -6
  145. package/dist/assets/Input.css +0 -1
  146. package/dist/assets/Knob.css +0 -1
  147. package/dist/assets/LabeledList.css +0 -1
  148. package/dist/assets/MenuBar.css +0 -1
  149. package/dist/assets/Modal.css +0 -1
  150. package/dist/assets/NoticeBox.css +0 -1
  151. package/dist/assets/NumberInput.css +0 -1
  152. package/dist/assets/ProgressBar.css +0 -1
  153. package/dist/assets/RoundGauge.css +0 -1
  154. package/dist/assets/Section.css +0 -1
  155. package/dist/assets/Slider.css +0 -1
  156. package/dist/assets/Stack.css +0 -1
  157. package/dist/assets/Table.css +0 -1
  158. package/dist/assets/Tabs.css +0 -1
  159. package/dist/assets/TextArea.css +0 -1
  160. package/dist/assets/Tooltip.css +0 -1
  161. package/dist/common/assets.d.ts +0 -4
  162. package/dist/common/assets.js +0 -25
  163. package/dist/common/collections.d.ts +0 -10
  164. package/dist/common/collections.js +0 -15
  165. package/dist/common/color.d.ts +0 -25
  166. package/dist/common/color.js +0 -69
  167. package/dist/common/constants.d.ts +0 -102
  168. package/dist/common/constants.js +0 -312
  169. package/dist/common/events.d.ts +0 -33
  170. package/dist/common/events.js +0 -147
  171. package/dist/common/exhaustive.js +0 -6
  172. package/dist/common/format.d.ts +0 -11
  173. package/dist/common/format.js +0 -114
  174. package/dist/common/fp.js +0 -9
  175. package/dist/common/hotkeys.d.ts +0 -25
  176. package/dist/common/hotkeys.js +0 -112
  177. package/dist/common/http.d.ts +0 -4
  178. package/dist/common/http.js +0 -10
  179. package/dist/common/keycodes.d.ts +0 -85
  180. package/dist/common/keycodes.js +0 -88
  181. package/dist/common/keys.js +0 -8
  182. package/dist/common/math.d.ts +0 -39
  183. package/dist/common/math.js +0 -41
  184. package/dist/common/perf.d.ts +0 -24
  185. package/dist/common/perf.js +0 -33
  186. package/dist/common/random.d.ts +0 -16
  187. package/dist/common/random.js +0 -18
  188. package/dist/common/react.d.ts +0 -23
  189. package/dist/common/react.js +0 -30
  190. package/dist/common/redux.d.ts +0 -64
  191. package/dist/common/redux.js +0 -72
  192. package/dist/common/storage.js +0 -124
  193. package/dist/common/string.d.ts +0 -65
  194. package/dist/common/string.js +0 -83
  195. package/dist/common/timer.d.ts +0 -18
  196. package/dist/common/timer.js +0 -28
  197. package/dist/common/type-utils.d.ts +0 -9
  198. package/dist/common/type-utils.js +0 -25
  199. package/dist/common/uuid.d.ts +0 -9
  200. package/dist/common/uuid.js +0 -10
  201. package/dist/components/AnimatedNumber.d.ts +0 -60
  202. package/dist/components/AnimatedNumber.js +0 -76
  203. package/dist/components/Autofocus.d.ts +0 -4
  204. package/dist/components/Autofocus.js +0 -17
  205. package/dist/components/Blink.d.ts +0 -26
  206. package/dist/components/Blink.js +0 -56
  207. package/dist/components/BlockQuote.d.ts +0 -3
  208. package/dist/components/BlockQuote.js +0 -13
  209. package/dist/components/BodyZoneSelector.d.ts +0 -28
  210. package/dist/components/BodyZoneSelector.js +0 -115
  211. package/dist/components/Box.d.ts +0 -91
  212. package/dist/components/Box.js +0 -133
  213. package/dist/components/Button.d.ts +0 -93
  214. package/dist/components/Button.js +0 -298
  215. package/dist/components/ByondUi.js +0 -73
  216. package/dist/components/Chart.d.ts +0 -28
  217. package/dist/components/Chart.js +0 -95
  218. package/dist/components/Collapsible.d.ts +0 -15
  219. package/dist/components/Collapsible.js +0 -27
  220. package/dist/components/ColorBox.d.ts +0 -8
  221. package/dist/components/ColorBox.js +0 -24
  222. package/dist/components/Dialog.d.ts +0 -24
  223. package/dist/components/Dialog.js +0 -67
  224. package/dist/components/Dimmer.d.ts +0 -3
  225. package/dist/components/Dimmer.js +0 -13
  226. package/dist/components/Divider.d.ts +0 -6
  227. package/dist/components/Divider.js +0 -22
  228. package/dist/components/DmIcon.d.ts +0 -31
  229. package/dist/components/DmIcon.js +0 -34
  230. package/dist/components/DraggableControl.js +0 -176
  231. package/dist/components/Dropdown.d.ts +0 -48
  232. package/dist/components/Dropdown.js +0 -152
  233. package/dist/components/FakeTerminal.js +0 -38
  234. package/dist/components/FitText.d.ts +0 -22
  235. package/dist/components/FitText.js +0 -63
  236. package/dist/components/Flex.d.ts +0 -93
  237. package/dist/components/Flex.js +0 -72
  238. package/dist/components/Icon.d.ts +0 -30
  239. package/dist/components/Icon.js +0 -51
  240. package/dist/components/Image.d.ts +0 -14
  241. package/dist/components/Image.js +0 -35
  242. package/dist/components/InfinitePlane.js +0 -139
  243. package/dist/components/Input.d.ts +0 -61
  244. package/dist/components/Input.js +0 -89
  245. package/dist/components/KeyListener.d.ts +0 -15
  246. package/dist/components/KeyListener.js +0 -23
  247. package/dist/components/Knob.d.ts +0 -49
  248. package/dist/components/Knob.js +0 -162
  249. package/dist/components/LabeledControls.d.ts +0 -11
  250. package/dist/components/LabeledControls.js +0 -39
  251. package/dist/components/LabeledList.d.ts +0 -57
  252. package/dist/components/LabeledList.js +0 -94
  253. package/dist/components/MenuBar.d.ts +0 -28
  254. package/dist/components/MenuBar.js +0 -174
  255. package/dist/components/Modal.d.ts +0 -3
  256. package/dist/components/Modal.js +0 -25
  257. package/dist/components/NoticeBox.d.ts +0 -20
  258. package/dist/components/NoticeBox.js +0 -49
  259. package/dist/components/NumberInput.d.ts +0 -45
  260. package/dist/components/NumberInput.js +0 -221
  261. package/dist/components/Popper.d.ts +0 -27
  262. package/dist/components/Popper.js +0 -177
  263. package/dist/components/ProgressBar.d.ts +0 -46
  264. package/dist/components/ProgressBar.js +0 -37
  265. package/dist/components/RestrictedInput.js +0 -155
  266. package/dist/components/RoundGauge.d.ts +0 -53
  267. package/dist/components/RoundGauge.js +0 -147
  268. package/dist/components/Section.d.ts +0 -63
  269. package/dist/components/Section.js +0 -62
  270. package/dist/components/Slider.d.ts +0 -46
  271. package/dist/components/Slider.js +0 -124
  272. package/dist/components/Stack.d.ts +0 -27
  273. package/dist/components/Stack.js +0 -67
  274. package/dist/components/StyleableSection.d.ts +0 -11
  275. package/dist/components/StyleableSection.js +0 -16
  276. package/dist/components/Table.d.ts +0 -29
  277. package/dist/components/Table.js +0 -67
  278. package/dist/components/Tabs.d.ts +0 -23
  279. package/dist/components/Tabs.js +0 -89
  280. package/dist/components/TextArea.d.ts +0 -39
  281. package/dist/components/TextArea.js +0 -118
  282. package/dist/components/TimeDisplay.js +0 -34
  283. package/dist/components/Tooltip.d.ts +0 -29
  284. package/dist/components/Tooltip.js +0 -83
  285. package/dist/components/TrackOutsideClicks.d.ts +0 -13
  286. package/dist/components/TrackOutsideClicks.js +0 -24
  287. package/dist/components/VirtualList.d.ts +0 -8
  288. package/dist/components/VirtualList.js +0 -34
  289. package/dist/components/index.js +0 -92
  290. package/dist/popper-CiqSDJTE.js +0 -906
  291. /package/{dist/components/index.d.ts → lib/components/index.ts} +0 -0
@@ -0,0 +1,43 @@
1
+ import { ReactNode, useState } from 'react';
2
+
3
+ import { Box, BoxProps } from './Box';
4
+ import { Button } from './Button';
5
+
6
+ type Props = Partial<{
7
+ /** Buttons or other content to render inline with the button */
8
+ buttons: ReactNode;
9
+ /** Icon to display with the collapsible */
10
+ icon: string;
11
+ /** Whether the collapsible is open */
12
+ open: boolean;
13
+ /** Text to display on the button for collapsing */
14
+ title: ReactNode;
15
+ }> &
16
+ BoxProps;
17
+
18
+ export function Collapsible(props: Props) {
19
+ const { children, color, title, buttons, icon, ...rest } = props;
20
+ const [open, setOpen] = useState(props.open);
21
+
22
+ return (
23
+ <Box mb={1}>
24
+ <div className="Table">
25
+ <div className="Table__cell">
26
+ <Button
27
+ fluid
28
+ color={color}
29
+ icon={icon ? icon : open ? 'chevron-down' : 'chevron-right'}
30
+ onClick={() => setOpen(!open)}
31
+ {...rest}
32
+ >
33
+ {title}
34
+ </Button>
35
+ </div>
36
+ {buttons && (
37
+ <div className="Table__cell Table__cell--collapsing">{buttons}</div>
38
+ )}
39
+ </div>
40
+ {open && <Box mt={1}>{children}</Box>}
41
+ </Box>
42
+ );
43
+ }
@@ -0,0 +1,29 @@
1
+ import { ReactNode } from 'react';
2
+
3
+ import { classes } from '../common/react';
4
+ import styles from '../styles/components/ColorBox.module.scss';
5
+ import { BoxProps, computeBoxClassName, computeBoxProps } from './Box';
6
+
7
+ type Props = {
8
+ content?: ReactNode;
9
+ } & BoxProps;
10
+
11
+ export function ColorBox(props: Props) {
12
+ const { content, children, className, ...rest } = props;
13
+
14
+ rest.color = content ? null : 'default';
15
+ rest.backgroundColor = props.color || 'default';
16
+
17
+ return (
18
+ <div
19
+ className={classes([
20
+ styles.colorBox,
21
+ className,
22
+ computeBoxClassName(rest),
23
+ ])}
24
+ {...computeBoxProps(rest)}
25
+ >
26
+ {content || '.'}
27
+ </div>
28
+ );
29
+ }
@@ -0,0 +1,81 @@
1
+ import styles from '../styles/components/Dialog.module.scss';
2
+ import { Box } from './Box';
3
+ import { Button } from './Button';
4
+
5
+ type DialogProps = {
6
+ children: any;
7
+ height?: string;
8
+ onClose: () => void;
9
+ title: any;
10
+ width?: string;
11
+ };
12
+
13
+ export function Dialog(props: DialogProps) {
14
+ const { title, onClose, children, width, height } = props;
15
+ return (
16
+ <div className={styles.dialog}>
17
+ <Box className={styles.content} width={width || '370px'} height={height}>
18
+ <div className={styles.header}>
19
+ <div className={styles.title}>{title}</div>
20
+ <Box mr={2}>
21
+ <Button
22
+ mr="-3px"
23
+ width="26px"
24
+ lineHeight="22px"
25
+ textAlign="center"
26
+ color="transparent"
27
+ icon="window-close-o"
28
+ tooltip="Close"
29
+ tooltipPosition="bottom-start"
30
+ onClick={onClose}
31
+ />
32
+ </Box>
33
+ </div>
34
+ {children}
35
+ </Box>
36
+ </div>
37
+ );
38
+ }
39
+
40
+ type DialogButtonProps = {
41
+ children: any;
42
+ onClick: () => void;
43
+ };
44
+
45
+ function DialogButton(props: DialogButtonProps) {
46
+ const { onClick, children } = props;
47
+ return (
48
+ <Button
49
+ onClick={onClick}
50
+ className={styles.button}
51
+ verticalAlignContent="middle"
52
+ >
53
+ {children}
54
+ </Button>
55
+ );
56
+ }
57
+
58
+ Dialog.Button = DialogButton;
59
+
60
+ type UnsavedChangesDialogProps = {
61
+ documentName: string;
62
+ onClose: () => void;
63
+ onDiscard: () => void;
64
+ onSave: () => void;
65
+ };
66
+
67
+ export function UnsavedChangesDialog(props: UnsavedChangesDialogProps) {
68
+ const { documentName, onSave, onDiscard, onClose } = props;
69
+ return (
70
+ <Dialog title="Notepad" onClose={onClose}>
71
+ <div className={styles.body}>
72
+ Do you want to save changes to {documentName}?
73
+ </div>
74
+ <div className={styles.footer}>
75
+ <DialogButton onClick={onSave}>Save</DialogButton>
76
+ <DialogButton onClick={onDiscard}>Don&apos;t Save</DialogButton>
77
+ <DialogButton onClick={onClose}>Cancel</DialogButton>
78
+ </div>
79
+ </Dialog>
80
+ );
81
+ }
@@ -0,0 +1,13 @@
1
+ import { classes } from '../common/react';
2
+ import styles from '../styles/components/Dimmer.module.scss';
3
+ import { Box, BoxProps } from './Box';
4
+
5
+ export function Dimmer(props: BoxProps) {
6
+ const { className, children, ...rest } = props;
7
+
8
+ return (
9
+ <Box className={classes([styles.dimmer, className])} {...rest}>
10
+ <div className="Dimmer__inner">{children}</div>
11
+ </Box>
12
+ );
13
+ }
@@ -0,0 +1,20 @@
1
+ import { classes } from '../common/react';
2
+ import styles from '../styles/components/Divider.module.scss';
3
+
4
+ type Props = Partial<{
5
+ hidden: boolean;
6
+ vertical: boolean;
7
+ }>;
8
+
9
+ export function Divider(props: Props) {
10
+ const { hidden, vertical } = props;
11
+
12
+ return (
13
+ <div
14
+ className={classes([
15
+ hidden && styles.hidden,
16
+ vertical ? styles.vertical : styles.horizontal,
17
+ ])}
18
+ />
19
+ );
20
+ }
@@ -0,0 +1,86 @@
1
+ import { ReactNode, useEffect, useState } from 'react';
2
+
3
+ import { resolveAsset } from '../common/assets';
4
+ import { fetchRetry } from '../common/http';
5
+ import { BooleanLike } from '../common/react';
6
+ import { BoxProps } from './Box';
7
+ import { Image } from './Image';
8
+
9
+ enum Direction {
10
+ NORTH = 1,
11
+ SOUTH = 2,
12
+ EAST = 4,
13
+ WEST = 8,
14
+ NORTHEAST = NORTH | EAST,
15
+ NORTHWEST = NORTH | WEST,
16
+ SOUTHEAST = SOUTH | EAST,
17
+ SOUTHWEST = SOUTH | WEST,
18
+ }
19
+
20
+ type Props = {
21
+ /** Required: The path of the icon */
22
+ icon: string;
23
+ /** Required: The state of the icon */
24
+ icon_state: string;
25
+ } & Partial<{
26
+ /** Facing direction. See direction enum. Default is South */
27
+ direction: Direction;
28
+ /** Fallback icon. */
29
+ fallback: ReactNode;
30
+ /** Frame number. Default is 1 */
31
+ frame: number;
32
+ /** Movement state. Default is false */
33
+ movement: BooleanLike;
34
+ }> &
35
+ BoxProps;
36
+
37
+ let refMap: Record<string, string> | undefined;
38
+
39
+ export function DmIcon(props: Props) {
40
+ const {
41
+ className,
42
+ direction = Direction.SOUTH,
43
+ fallback,
44
+ frame = 1,
45
+ icon_state,
46
+ icon,
47
+ movement = false,
48
+ ...rest
49
+ } = props;
50
+
51
+ const [iconRef, setIconRef] = useState('');
52
+ const [toDisplay, setToDisplay] = useState('');
53
+
54
+ const query = `${iconRef}?state=${icon_state}&dir=${direction}&movement=${movement}&frame=${frame}`;
55
+
56
+ useEffect(() => {
57
+ if (refMap) {
58
+ setToDisplay(Object.keys(refMap).length.toString());
59
+ setIconRef(refMap[icon]);
60
+ return;
61
+ }
62
+
63
+ fetchRetry(resolveAsset('icon_ref_map.json'))
64
+ .then((response) => {
65
+ setToDisplay('!');
66
+ return response.json();
67
+ })
68
+ .then((data) => {
69
+ refMap = data;
70
+ setIconRef(data[icon]);
71
+ setToDisplay('!!');
72
+ })
73
+ .catch(() => {
74
+ // Ignore errors
75
+ });
76
+ }, []);
77
+
78
+ if (!iconRef) return fallback;
79
+
80
+ return (
81
+ <>
82
+ <Image fixErrors src={query} {...rest} />
83
+ {toDisplay}
84
+ </>
85
+ );
86
+ }
@@ -0,0 +1,276 @@
1
+ import { clamp } from '../common/math';
2
+ import { Component, createRef } from 'react';
3
+
4
+ import { AnimatedNumber } from './AnimatedNumber';
5
+
6
+ const DEFAULT_UPDATE_RATE = 400;
7
+
8
+ /**
9
+ * Reduces screen offset to a single number based on the matrix provided.
10
+ */
11
+ function getScalarScreenOffset(e, matrix) {
12
+ return e.screenX * matrix[0] + e.screenY * matrix[1];
13
+ }
14
+
15
+ export class DraggableControl extends Component {
16
+ constructor(props) {
17
+ super(props);
18
+ this.inputRef = createRef();
19
+ this.state = {
20
+ value: props.value,
21
+ dragging: false,
22
+ editing: false,
23
+ internalValue: null,
24
+ origin: null,
25
+ suppressingFlicker: false,
26
+ };
27
+
28
+ // Suppresses flickering while the value propagates through the backend
29
+ this.flickerTimer = null;
30
+ this.suppressFlicker = () => {
31
+ const { suppressFlicker } = this.props;
32
+ if (suppressFlicker > 0) {
33
+ this.setState({
34
+ suppressingFlicker: true,
35
+ });
36
+ clearTimeout(this.flickerTimer);
37
+ this.flickerTimer = setTimeout(() => {
38
+ this.setState({
39
+ suppressingFlicker: false,
40
+ });
41
+ }, suppressFlicker);
42
+ }
43
+ };
44
+
45
+ this.handleDragStart = (e) => {
46
+ const { value, dragMatrix } = this.props;
47
+ const { editing } = this.state;
48
+ if (editing) {
49
+ return;
50
+ }
51
+ document.body.style['pointer-events'] = 'none';
52
+ this.ref = e.target;
53
+ this.setState({
54
+ dragging: false,
55
+ origin: getScalarScreenOffset(e, dragMatrix),
56
+ value,
57
+ internalValue: value,
58
+ });
59
+ this.timer = setTimeout(() => {
60
+ this.setState({
61
+ dragging: true,
62
+ });
63
+ }, 250);
64
+ this.dragInterval = setInterval(() => {
65
+ const { dragging, value } = this.state;
66
+ const { onDrag } = this.props;
67
+ if (dragging && onDrag) {
68
+ onDrag(e, value);
69
+ }
70
+ }, this.props.updateRate || DEFAULT_UPDATE_RATE);
71
+ document.addEventListener('mousemove', this.handleDragMove);
72
+ document.addEventListener('mouseup', this.handleDragEnd);
73
+ };
74
+
75
+ this.handleDragMove = (e) => {
76
+ const { minValue, maxValue, step, stepPixelSize, dragMatrix } =
77
+ this.props;
78
+ this.setState((prevState) => {
79
+ const state = { ...prevState };
80
+ const offset = getScalarScreenOffset(e, dragMatrix) - state.origin;
81
+ if (prevState.dragging) {
82
+ const stepOffset = Number.isFinite(minValue) ? minValue % step : 0;
83
+ // Translate mouse movement to value
84
+ // Give it some headroom (by increasing clamp range by 1 step)
85
+ state.internalValue = clamp(
86
+ state.internalValue + (offset * step) / stepPixelSize,
87
+ minValue - step,
88
+ maxValue + step,
89
+ );
90
+ // Clamp the final value
91
+ state.value = clamp(
92
+ state.internalValue - (state.internalValue % step) + stepOffset,
93
+ minValue,
94
+ maxValue,
95
+ );
96
+ state.origin = getScalarScreenOffset(e, dragMatrix);
97
+ } else if (Math.abs(offset) > 4) {
98
+ state.dragging = true;
99
+ }
100
+ return state;
101
+ });
102
+ };
103
+
104
+ this.handleDragEnd = (e) => {
105
+ const { onChange, onDrag } = this.props;
106
+ const { dragging, value, internalValue } = this.state;
107
+ document.body.style['pointer-events'] = 'auto';
108
+ clearTimeout(this.timer);
109
+ clearInterval(this.dragInterval);
110
+ this.setState({
111
+ dragging: false,
112
+ editing: !dragging,
113
+ origin: null,
114
+ });
115
+ document.removeEventListener('mousemove', this.handleDragMove);
116
+ document.removeEventListener('mouseup', this.handleDragEnd);
117
+ if (dragging) {
118
+ this.suppressFlicker();
119
+ if (onChange) {
120
+ onChange(e, value);
121
+ }
122
+ if (onDrag) {
123
+ onDrag(e, value);
124
+ }
125
+ } else if (this.inputRef) {
126
+ const input = this.inputRef.current;
127
+ input.value = internalValue;
128
+ // IE8: Dies when trying to focus a hidden element
129
+ // (Error: Object does not support this action)
130
+ try {
131
+ input.focus();
132
+ input.select();
133
+ } catch {}
134
+ }
135
+ };
136
+ }
137
+
138
+ render() {
139
+ const {
140
+ dragging,
141
+ editing,
142
+ value: intermediateValue,
143
+ suppressingFlicker,
144
+ } = this.state;
145
+ const {
146
+ animated,
147
+ value,
148
+ unit,
149
+ minValue,
150
+ maxValue,
151
+ unclamped,
152
+ format,
153
+ onChange,
154
+ onDrag,
155
+ children,
156
+ // Input props
157
+ height,
158
+ lineHeight,
159
+ fontSize,
160
+ } = this.props;
161
+ let displayValue = value;
162
+ if (dragging || suppressingFlicker) {
163
+ displayValue = intermediateValue;
164
+ }
165
+
166
+ const displayElement = (
167
+ <>
168
+ {animated && !dragging && !suppressingFlicker ? (
169
+ <AnimatedNumber value={displayValue} format={format} />
170
+ ) : format ? (
171
+ format(displayValue)
172
+ ) : (
173
+ displayValue
174
+ )}
175
+
176
+ {unit ? ' ' + unit : ''}
177
+ </>
178
+ );
179
+
180
+ // Setup an input element
181
+ // Handles direct input via the keyboard
182
+ const inputElement = (
183
+ <input
184
+ ref={this.inputRef}
185
+ className="NumberInput__input"
186
+ style={{
187
+ display: !editing ? 'none' : undefined,
188
+ height: height,
189
+ lineHeight: lineHeight,
190
+ fontsize: fontSize,
191
+ }}
192
+ onBlur={(e) => {
193
+ if (!editing) {
194
+ return;
195
+ }
196
+ let value;
197
+ if (unclamped) {
198
+ value = parseFloat(e.target.value);
199
+ } else {
200
+ value = clamp(parseFloat(e.target.value), minValue, maxValue);
201
+ }
202
+ if (Number.isNaN(value)) {
203
+ this.setState({
204
+ editing: false,
205
+ });
206
+ return;
207
+ }
208
+ this.setState({
209
+ editing: false,
210
+ value,
211
+ });
212
+ this.suppressFlicker();
213
+ if (onChange) {
214
+ onChange(e, value);
215
+ }
216
+ if (onDrag) {
217
+ onDrag(e, value);
218
+ }
219
+ }}
220
+ onKeyDown={(e) => {
221
+ if (e.keyCode === 13) {
222
+ let value;
223
+ if (unclamped) {
224
+ value = parseFloat(e.target.value);
225
+ } else {
226
+ value = clamp(parseFloat(e.target.value), minValue, maxValue);
227
+ }
228
+ if (Number.isNaN(value)) {
229
+ this.setState({
230
+ editing: false,
231
+ });
232
+ return;
233
+ }
234
+ this.setState({
235
+ editing: false,
236
+ value,
237
+ });
238
+ this.suppressFlicker();
239
+ if (onChange) {
240
+ onChange(e, value);
241
+ }
242
+ if (onDrag) {
243
+ onDrag(e, value);
244
+ }
245
+ return;
246
+ }
247
+ if (e.keyCode === 27) {
248
+ this.setState({
249
+ editing: false,
250
+ });
251
+ return;
252
+ }
253
+ }}
254
+ />
255
+ );
256
+ // Return a part of the state for higher-level components to use.
257
+ return children({
258
+ dragging,
259
+ editing,
260
+ value,
261
+ displayValue,
262
+ displayElement,
263
+ inputElement,
264
+ handleDragStart: this.handleDragStart,
265
+ });
266
+ }
267
+ }
268
+
269
+ DraggableControl.defaultProps = {
270
+ minValue: -Infinity,
271
+ maxValue: +Infinity,
272
+ step: 1,
273
+ stepPixelSize: 1,
274
+ suppressFlicker: 50,
275
+ dragMatrix: [1, 0],
276
+ };