tgui-core 1.1.7 → 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 -21
  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 -31
  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,246 @@
1
+ import { ReactNode, useEffect, useRef, useState } from 'react';
2
+
3
+ import { classes } from '../common/react';
4
+ import { BoxProps, unit } from './Box';
5
+ import { Button } from './Button';
6
+ import { Icon } from './Icon';
7
+ import { Popper } from './Popper';
8
+
9
+ export type DropdownEntry = {
10
+ displayText: ReactNode;
11
+ value: string | number;
12
+ };
13
+
14
+ type DropdownOption = string | DropdownEntry;
15
+
16
+ type Props = {
17
+ /** Called when a value is picked from the list, `value` is the value that was picked */
18
+ onSelected: (value: any) => void;
19
+ /** An array of strings which will be displayed in the
20
+ dropdown when open. See Dropdown.tsx for more advanced usage with DropdownEntry */
21
+ options: DropdownOption[];
22
+ /** Currently selected entry to display. Can be left stateless to permanently display this value. */
23
+ selected: DropdownOption | null | undefined;
24
+ } & Partial<{
25
+ /** Whether to scroll automatically on open. Defaults to true */
26
+ autoScroll: boolean;
27
+ /** Whether to display previous / next buttons */
28
+ buttons: boolean;
29
+ /** Whether to clip the selected text */
30
+ clipSelectedText: boolean;
31
+ /** Color of dropdown button */
32
+ color: string;
33
+ /** Disables the dropdown */
34
+ disabled: boolean;
35
+ /** Overwrites selection text with this. Good for objects etc. */
36
+ displayText: ReactNode;
37
+ /** Icon to display in dropdown button */
38
+ icon: string;
39
+ /** Angle of the icon */
40
+ iconRotation: number;
41
+ /** Whether or not the icon should spin */
42
+ iconSpin: boolean;
43
+ /** Width of the dropdown menu. Default: 15rem */
44
+ menuWidth: string;
45
+ /** Whether or not the arrow on the right hand side of the dropdown button is visible */
46
+ noChevron: boolean;
47
+ /** Called when dropdown button is clicked */
48
+ onClick: (event) => void;
49
+ /** Dropdown renders over instead of below */
50
+ over: boolean;
51
+ /** Text to show when nothing has been selected. */
52
+ placeholder: string;
53
+ }> &
54
+ BoxProps;
55
+
56
+ enum DIRECTION {
57
+ Current = 'current',
58
+ Next = 'next',
59
+ Previous = 'previous',
60
+ }
61
+
62
+ const NONE = -1;
63
+
64
+ function getOptionValue(option: DropdownOption) {
65
+ return typeof option === 'string' ? option : option.value;
66
+ }
67
+
68
+ export function Dropdown(props: Props) {
69
+ const {
70
+ autoScroll = true,
71
+ buttons,
72
+ className,
73
+ clipSelectedText = true,
74
+ color = 'default',
75
+ disabled,
76
+ displayText,
77
+ icon,
78
+ iconRotation,
79
+ iconSpin,
80
+ menuWidth = '15rem',
81
+ noChevron,
82
+ onClick,
83
+ onSelected,
84
+ options = [],
85
+ over,
86
+ placeholder = 'Select...',
87
+ selected,
88
+ width = '15rem',
89
+ } = props;
90
+
91
+ const [open, setOpen] = useState(false);
92
+ const adjustedOpen = over ? !open : open;
93
+ const innerRef = useRef<HTMLDivElement>(null);
94
+
95
+ const selectedIndex =
96
+ options.findIndex((option) => getOptionValue(option) === selected) || 0;
97
+
98
+ function scrollTo(position: number) {
99
+ let scrollPos = position;
100
+ if (position < selectedIndex) {
101
+ scrollPos = position < 2 ? 0 : position - 2;
102
+ } else {
103
+ scrollPos =
104
+ position > options.length - 3 ? options.length - 1 : position - 2;
105
+ }
106
+
107
+ const element = innerRef.current?.children[scrollPos];
108
+ element?.scrollIntoView({ block: 'nearest' });
109
+ }
110
+
111
+ /** Update the selected value when clicking the left/right buttons */
112
+ function updateSelected(direction: DIRECTION) {
113
+ if (options.length < 1 || disabled) {
114
+ return;
115
+ }
116
+
117
+ const startIndex = 0;
118
+ const endIndex = options.length - 1;
119
+
120
+ let newIndex: number;
121
+ if (selectedIndex < 0) {
122
+ newIndex = direction === 'next' ? endIndex : startIndex; // No selection yet
123
+ } else if (direction === 'next') {
124
+ newIndex = selectedIndex === endIndex ? startIndex : selectedIndex + 1; // Move to next option
125
+ } else {
126
+ newIndex = selectedIndex === startIndex ? endIndex : selectedIndex - 1; // Move to previous option
127
+ }
128
+
129
+ if (open && autoScroll) {
130
+ scrollTo(newIndex);
131
+ }
132
+ onSelected?.(getOptionValue(options[newIndex]));
133
+ }
134
+
135
+ /** Allows the menu to be scrollable on open */
136
+ useEffect(() => {
137
+ if (!open) {
138
+ return;
139
+ }
140
+
141
+ if (autoScroll && selectedIndex !== NONE) {
142
+ scrollTo(selectedIndex);
143
+ }
144
+
145
+ innerRef.current?.focus();
146
+ }, [open]);
147
+
148
+ return (
149
+ <Popper
150
+ isOpen={open}
151
+ onClickOutside={() => setOpen(false)}
152
+ placement={over ? 'top-start' : 'bottom-start'}
153
+ content={
154
+ <div
155
+ className="Layout Dropdown__menu"
156
+ style={{ minWidth: menuWidth }}
157
+ ref={innerRef}
158
+ >
159
+ {options.length === 0 && (
160
+ <div className="Dropdown__menuentry">No options</div>
161
+ )}
162
+
163
+ {options.map((option, index) => {
164
+ const value = getOptionValue(option);
165
+
166
+ return (
167
+ <div
168
+ className={classes([
169
+ 'Dropdown__menuentry',
170
+ selected === value && 'selected',
171
+ ])}
172
+ key={index}
173
+ onClick={() => {
174
+ setOpen(false);
175
+ onSelected?.(value);
176
+ }}
177
+ >
178
+ {typeof option === 'string' ? option : option.displayText}
179
+ </div>
180
+ );
181
+ })}
182
+ </div>
183
+ }
184
+ >
185
+ <div className="Dropdown" style={{ width: unit(width) }}>
186
+ <div
187
+ className={classes([
188
+ 'Dropdown__control',
189
+ 'Button',
190
+ 'Button--dropdown',
191
+ 'Button--color--' + color,
192
+ disabled && 'Button--disabled',
193
+ className,
194
+ ])}
195
+ onClick={(event) => {
196
+ if (disabled && !open) {
197
+ return;
198
+ }
199
+ setOpen(!open);
200
+ onClick?.(event);
201
+ }}
202
+ >
203
+ {icon && (
204
+ <Icon mr={1} name={icon} rotation={iconRotation} spin={iconSpin} />
205
+ )}
206
+ <span
207
+ className="Dropdown__selected-text"
208
+ style={{
209
+ overflow: clipSelectedText ? 'hidden' : 'visible',
210
+ }}
211
+ >
212
+ {displayText ||
213
+ (selected && getOptionValue(selected)) ||
214
+ placeholder}
215
+ </span>
216
+ {!noChevron && (
217
+ <span className="Dropdown__arrow-button">
218
+ <Icon name={adjustedOpen ? 'chevron-up' : 'chevron-down'} />
219
+ </span>
220
+ )}
221
+ </div>
222
+ {buttons && (
223
+ <>
224
+ <Button
225
+ disabled={disabled}
226
+ height={1.8}
227
+ icon="chevron-left"
228
+ onClick={() => {
229
+ updateSelected(DIRECTION.Previous);
230
+ }}
231
+ />
232
+
233
+ <Button
234
+ disabled={disabled}
235
+ height={1.8}
236
+ icon="chevron-right"
237
+ onClick={() => {
238
+ updateSelected(DIRECTION.Next);
239
+ }}
240
+ />
241
+ </>
242
+ )}
243
+ </div>
244
+ </Popper>
245
+ );
246
+ }
@@ -0,0 +1,52 @@
1
+ import { Component, Fragment } from 'react';
2
+
3
+ import { Box } from './Box';
4
+
5
+ export class FakeTerminal extends Component {
6
+ constructor(props) {
7
+ super(props);
8
+ this.timer = null;
9
+ this.state = {
10
+ currentIndex: 0,
11
+ currentDisplay: [],
12
+ };
13
+ }
14
+
15
+ tick() {
16
+ const { props, state } = this;
17
+ if (state.currentIndex <= props.allMessages.length) {
18
+ this.setState((prevState) => {
19
+ return {
20
+ currentIndex: prevState.currentIndex + 1,
21
+ };
22
+ });
23
+ const { currentDisplay } = state;
24
+ currentDisplay.push(props.allMessages[state.currentIndex]);
25
+ } else {
26
+ clearTimeout(this.timer);
27
+ setTimeout(props.onFinished, props.finishedTimeout);
28
+ }
29
+ }
30
+
31
+ componentDidMount() {
32
+ const { linesPerSecond = 2.5 } = this.props;
33
+ this.timer = setInterval(() => this.tick(), 1000 / linesPerSecond);
34
+ }
35
+
36
+ componentWillUnmount() {
37
+ clearTimeout(this.timer);
38
+ }
39
+
40
+ render() {
41
+ return (
42
+ <Box m={1}>
43
+ {this.state.currentDisplay.map((value) => (
44
+ <Fragment key={value}>
45
+ {value}
46
+ <br />
47
+ </Fragment>
48
+ ))}
49
+ </Box>
50
+ );
51
+ }
52
+ }
@@ -0,0 +1,99 @@
1
+ import {
2
+ Component,
3
+ createRef,
4
+ HTMLAttributes,
5
+ PropsWithChildren,
6
+ RefObject,
7
+ } from 'react';
8
+
9
+ const DEFAULT_ACCEPTABLE_DIFFERENCE = 5;
10
+
11
+ type Props = {
12
+ acceptableDifference?: number;
13
+ maxFontSize: number;
14
+ maxWidth: number;
15
+ native?: HTMLAttributes<HTMLDivElement>;
16
+ } & PropsWithChildren;
17
+
18
+ type State = {
19
+ fontSize: number;
20
+ };
21
+
22
+ export class FitText extends Component<Props, State> {
23
+ ref: RefObject<HTMLDivElement> = createRef();
24
+ state: State = {
25
+ fontSize: 0,
26
+ };
27
+
28
+ constructor(props: Props) {
29
+ super(props);
30
+
31
+ this.resize = this.resize.bind(this);
32
+
33
+ window.addEventListener('resize', this.resize);
34
+ }
35
+
36
+ componentDidUpdate(prevProps) {
37
+ if (prevProps.children !== this.props.children) {
38
+ this.resize();
39
+ }
40
+ }
41
+
42
+ componentWillUnmount() {
43
+ window.removeEventListener('resize', this.resize);
44
+ }
45
+
46
+ resize() {
47
+ const element = this.ref.current;
48
+ if (!element) {
49
+ return;
50
+ }
51
+
52
+ const maxWidth = this.props.maxWidth;
53
+
54
+ let start = 0;
55
+ let end = this.props.maxFontSize;
56
+
57
+ for (let _ = 0; _ < 10; _++) {
58
+ const middle = Math.round((start + end) / 2);
59
+ element.style.fontSize = `${middle}px`;
60
+
61
+ const difference = element.offsetWidth - maxWidth;
62
+
63
+ if (difference > 0) {
64
+ end = middle;
65
+ } else if (
66
+ difference <
67
+ (this.props.acceptableDifference ?? DEFAULT_ACCEPTABLE_DIFFERENCE)
68
+ ) {
69
+ start = middle;
70
+ } else {
71
+ break;
72
+ }
73
+ }
74
+
75
+ this.setState({
76
+ fontSize: Math.round((start + end) / 2),
77
+ });
78
+ }
79
+
80
+ componentDidMount() {
81
+ this.resize();
82
+ }
83
+
84
+ render() {
85
+ return (
86
+ <span
87
+ ref={this.ref}
88
+ style={{
89
+ fontSize: `${this.state.fontSize}px`,
90
+ ...(typeof this.props.native?.style === 'object'
91
+ ? this.props.native.style
92
+ : {}),
93
+ }}
94
+ >
95
+ {this.props.children}
96
+ </span>
97
+ );
98
+ }
99
+ }
@@ -0,0 +1,159 @@
1
+ import { classes } from '../common/react';
2
+ import styles from '../styles/components/Flex.module.scss';
3
+ import { BoxProps, computeBoxClassName, computeBoxProps, unit } from './Box';
4
+
5
+ export type FlexProps = Partial<{
6
+ /**
7
+ * Default alignment of all children.
8
+ *
9
+ * - `stretch` (default) - stretch to fill the container.
10
+ * - `start` - items are placed at the start of the cross axis.
11
+ * - `end` - items are placed at the end of the cross axis.
12
+ * - `center` - items are centered on the cross axis.
13
+ * - `baseline` - items are aligned such as their baselines align.
14
+ */
15
+ align: string | boolean;
16
+ /**
17
+ * This establishes the main-axis, thus defining the direction flex items are placed in the flex container.
18
+ *
19
+ * - `row` (default) - left to right.
20
+ * - `row-reverse` - right to left.
21
+ * - `column` - top to bottom.
22
+ * - `column-reverse` - bottom to top.
23
+ */
24
+ direction: string;
25
+ /** Makes flexbox container inline, with similar behavior to an `inline` property on a `Box`. */
26
+ inline: boolean;
27
+ /**
28
+ * This defines the alignment along the main axis. It helps distribute extra free space leftover when either all the flex items on a line are
29
+ * inflexible, or are flexible but have reached their maximum size. It also exerts some control over the alignment of items when they overflow
30
+ * the line.
31
+ *
32
+ * - `flex-start` (default) - items are packed toward the start of the
33
+ * flex-direction.
34
+ * - `flex-end` - items are packed toward the end of the flex-direction.
35
+ * - `space-between` - items are evenly distributed in the line; first item is
36
+ * on the start line, last item on the end line
37
+ * - `space-around` - items are evenly distributed in the line with equal space
38
+ * around them. Note that visually the spaces aren't equal, since all the items
39
+ * have equal space on both sides. The first item will have one unit of space
40
+ * against the container edge, but two units of space between the next item
41
+ * because that next item has its own spacing that applies.
42
+ * - `space-evenly` - items are distributed so that the spacing between any two
43
+ * items (and the space to the edges) is equal.
44
+ */
45
+ justify: string;
46
+ /** By default, flex items will all try to fit onto one line. You can change that and allow the items to wrap as needed with this property. */
47
+ scrollable: boolean;
48
+ /**
49
+ * This defines the alignment along the cross axis. It helps distribute extra free space leftover when either all the flex items on a line are
50
+ * inflexible, or are flexible but have reached their maximum size. It also exerts some control over the alignment of items when they overflow
51
+ * the line.
52
+ *
53
+ * - `nowrap` (default) - all flex items will be on one line
54
+ * - `wrap` - flex items will wrap onto multiple lines, from top to bottom.
55
+ * - `wrap-reverse` - flex items will wrap onto multiple lines from bottom to top.
56
+ */
57
+ wrap: string | boolean;
58
+ }> &
59
+ BoxProps;
60
+
61
+ export function computeFlexClassName(props: FlexProps) {
62
+ return classes([
63
+ styles.flex,
64
+ props.inline && styles.inline,
65
+ computeBoxClassName(props),
66
+ ]);
67
+ }
68
+
69
+ export function computeFlexProps(props: FlexProps) {
70
+ const { direction, wrap, align, justify, ...rest } = props;
71
+
72
+ return computeBoxProps({
73
+ style: {
74
+ ...rest.style,
75
+ flexDirection: direction,
76
+ flexWrap: wrap === true ? 'wrap' : wrap,
77
+ alignItems: align,
78
+ justifyContent: justify,
79
+ },
80
+ ...rest,
81
+ });
82
+ }
83
+
84
+ export function Flex(props) {
85
+ const { className, ...rest } = props;
86
+ return (
87
+ <div
88
+ className={classes([className, computeFlexClassName(rest)])}
89
+ {...computeFlexProps(rest)}
90
+ />
91
+ );
92
+ }
93
+
94
+ export type FlexItemProps = Partial<{
95
+ /** This allows the default alignment (or the one specified by align-items) to be overridden for individual flex items. */
96
+ align: string | boolean;
97
+ /**
98
+ * This defines the default size of an element
99
+ * before any flex-related calculations are done. Has to be a length
100
+ * (e.g. `20%`, `5rem`), an `auto` or `content` keyword.
101
+ *
102
+ * - **Important:** IE11 flex is buggy, and auto width/height calculations
103
+ * can sometimes end up in a circular dependency. This usually happens, when
104
+ * working with tables inside flex (they have wacky internal widths and such).
105
+ * Setting basis to `0` breaks the loop and fixes all of the problems.
106
+ */
107
+ basis: string | number;
108
+ /**
109
+ * This defines the ability for a flex item to grow if necessary. It accepts a unitless value that serves as a proportion.
110
+ * It dictates what amount of the available space inside the flex container the item should take up.
111
+ * This number is unit-less and is relative to other siblings.
112
+ */
113
+ grow: number | boolean;
114
+ /**
115
+ * By default, flex items are laid out in the source order. However, the order property controls the order in which they appear in the
116
+ * flex container
117
+ */
118
+ order: number;
119
+ /** This defines the ability for a flex item to shrink if necessary. Inverse of `grow`. */
120
+ shrink: number | boolean;
121
+ }> &
122
+ BoxProps;
123
+
124
+ export function computeFlexItemProps(props: FlexItemProps) {
125
+ const { style, grow, order, shrink, basis, align, ...rest } = props;
126
+
127
+ const computedBasis =
128
+ basis ??
129
+ // IE11: Set basis to specified width if it's known, which fixes certain
130
+ // bugs when rendering tables inside the flex.
131
+ props.width ??
132
+ // If grow is used, basis should be set to 0 to be consistent with
133
+ // flex css shorthand `flex: 1`.
134
+ (grow !== undefined ? 0 : undefined);
135
+
136
+ return computeBoxProps({
137
+ style: {
138
+ ...style,
139
+ flexGrow: grow !== undefined && Number(grow),
140
+ flexShrink: shrink !== undefined && Number(shrink),
141
+ flexBasis: unit(computedBasis),
142
+ order: order,
143
+ alignSelf: align,
144
+ },
145
+ ...rest,
146
+ });
147
+ }
148
+
149
+ function FlexItem(props) {
150
+ const { className, ...rest } = props;
151
+ return (
152
+ <div
153
+ className={classes([className, computeBoxClassName(props)])}
154
+ {...computeFlexItemProps(rest)}
155
+ />
156
+ );
157
+ }
158
+
159
+ Flex.Item = FlexItem;
@@ -0,0 +1,95 @@
1
+ import { CSSProperties, ReactNode } from 'react';
2
+
3
+ import { BooleanLike, classes } from '../common/react';
4
+ import style from '../styles/components/Icon.module.scss';
5
+ import { BoxProps, computeBoxClassName, computeBoxProps } from './Box';
6
+
7
+ type Props = {
8
+ /** Icon name. See [icon list](https://fontawesome.com/v5/search?o=r&m=free) */
9
+ name: string;
10
+ } & Partial<{
11
+ /** Custom CSS class. */
12
+ className: string;
13
+ /** Icon rotation, in degrees. */
14
+ rotation: number;
15
+ /** Icon size. `1` is normal size, `2` is two times bigger. Fractional numbers are supported. */
16
+ size: number;
17
+ /** Whether an icon should be spinning. Good for load indicators. */
18
+ spin: BooleanLike;
19
+ /** Custom CSS. */
20
+ style: CSSProperties;
21
+ }> &
22
+ BoxProps;
23
+
24
+ const FA_OUTLINE_REGEX = /-o$/;
25
+
26
+ export function Icon(props: Props) {
27
+ const { name, size, spin, className, rotation, ...rest } = props;
28
+
29
+ const customStyle = rest.style || {};
30
+ if (size) {
31
+ customStyle.fontSize = size * 100 + '%';
32
+ }
33
+ if (rotation) {
34
+ customStyle.transform = `rotate(${rotation}deg)`;
35
+ }
36
+ rest.style = customStyle;
37
+
38
+ const boxProps = computeBoxProps(rest);
39
+
40
+ let iconClass = '';
41
+ if (name.startsWith('tg-')) {
42
+ // tgfont icon
43
+ iconClass = name;
44
+ } else {
45
+ // font awesome icon
46
+ const faRegular = FA_OUTLINE_REGEX.test(name);
47
+ const faName = name.replace(FA_OUTLINE_REGEX, '');
48
+ const preprendFa = !faName.startsWith('fa-');
49
+
50
+ iconClass = faRegular ? 'far ' : 'fas ';
51
+ if (preprendFa) {
52
+ iconClass += 'fa-';
53
+ }
54
+ iconClass += faName;
55
+ if (spin) {
56
+ iconClass += ' fa-spin';
57
+ }
58
+ }
59
+ return (
60
+ <i
61
+ className={classes([
62
+ style.icon,
63
+ iconClass,
64
+ className,
65
+ computeBoxClassName(rest),
66
+ ])}
67
+ {...boxProps}
68
+ />
69
+ );
70
+ }
71
+
72
+ type IconStackUnique = {
73
+ children: ReactNode;
74
+ className?: string;
75
+ };
76
+
77
+ export type IconStackProps = IconStackUnique & BoxProps;
78
+
79
+ export function IconStack(props: IconStackProps) {
80
+ const { className, children, ...rest } = props;
81
+ return (
82
+ <span
83
+ className={classes([
84
+ style.iconStack,
85
+ className,
86
+ computeBoxClassName(rest),
87
+ ])}
88
+ {...computeBoxProps(rest)}
89
+ >
90
+ {children}
91
+ </span>
92
+ );
93
+ }
94
+
95
+ Icon.Stack = IconStack;
@@ -0,0 +1,54 @@
1
+ import { useRef } from 'react';
2
+
3
+ import { BoxProps, computeBoxProps } from './Box';
4
+
5
+ type Props = Partial<{
6
+ className: string;
7
+ /** True is default, this fixes an ie thing */
8
+ fixBlur: boolean;
9
+ /** False by default. Good if you're fetching images on UIs that do not auto update. This will attempt to fix the 'x' icon 5 times. */
10
+ fixErrors: boolean;
11
+ /** Fill is default. */
12
+ objectFit: 'contain' | 'cover';
13
+ src: string;
14
+ }> &
15
+ BoxProps;
16
+
17
+ // at least one of these is required
18
+
19
+ const maxAttempts = 5;
20
+
21
+ export function Image(props: Props) {
22
+ const {
23
+ fixBlur = true,
24
+ fixErrors = false,
25
+ objectFit = 'fill',
26
+ src,
27
+ ...rest
28
+ } = props;
29
+ const attempts = useRef(0);
30
+
31
+ const computedProps = computeBoxProps(rest);
32
+ computedProps['style'] = {
33
+ ...computedProps.style,
34
+ '-ms-interpolation-mode': fixBlur ? 'nearest-neighbor' : 'auto',
35
+ objectFit,
36
+ };
37
+
38
+ return (
39
+ <img
40
+ onError={(event) => {
41
+ if (fixErrors && attempts.current < maxAttempts) {
42
+ const imgElement = event.currentTarget;
43
+
44
+ setTimeout(() => {
45
+ imgElement.src = `${src}?attempt=${attempts.current}`;
46
+ attempts.current++;
47
+ }, 1000);
48
+ }
49
+ }}
50
+ src={src}
51
+ {...computedProps}
52
+ />
53
+ );
54
+ }