tgui-core 1.0.2 → 1.0.3

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} +86 -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 +369 -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
@@ -1,198 +1,198 @@
1
- /**
2
- * @file
3
- * @copyright 2020 Aleksej Komarov
4
- * @author Warlockd
5
- * @license MIT
6
- */
7
-
8
- import { KEY } from '../common/keys';
9
- import { classes } from '../common/react';
10
- import {
11
- forwardRef,
12
- RefObject,
13
- useEffect,
14
- useImperativeHandle,
15
- useRef,
16
- useState,
17
- } from 'react';
18
- import { KeyboardEvent, SyntheticEvent } from 'react';
19
-
20
- import { Box, BoxProps } from './Box';
21
- import { toInputValue } from './Input';
22
-
23
- type Props = Partial<{
24
- autoFocus: boolean;
25
- autoSelect: boolean;
26
- displayedValue: string;
27
- dontUseTabForIndent: boolean;
28
- fluid: boolean;
29
- maxLength: number;
30
- noborder: boolean;
31
- /** Fires when user is 'done typing': Clicked out, blur, enter key (but not shift+enter) */
32
- onChange: (event: SyntheticEvent<HTMLTextAreaElement>, value: string) => void;
33
- /** Fires once the enter key is pressed */
34
- onEnter: (event: SyntheticEvent<HTMLTextAreaElement>, value: string) => void;
35
- /** Fires once the escape key is pressed */
36
- onEscape: (event: SyntheticEvent<HTMLTextAreaElement>) => void;
37
- /** Fires on each key press / value change. Used for searching */
38
- onInput: (event: SyntheticEvent<HTMLTextAreaElement>, value: string) => void;
39
- placeholder: string;
40
- scrollbar: boolean;
41
- selfClear: boolean;
42
- value: string;
43
- }> &
44
- BoxProps;
45
-
46
- export const TextArea = forwardRef(
47
- (props: Props, forwardedRef: RefObject<HTMLTextAreaElement>) => {
48
- const {
49
- autoFocus,
50
- autoSelect,
51
- displayedValue,
52
- dontUseTabForIndent,
53
- maxLength,
54
- noborder,
55
- onChange,
56
- onEnter,
57
- onEscape,
58
- onInput,
59
- placeholder,
60
- scrollbar,
61
- selfClear,
62
- value,
63
- ...boxProps
64
- } = props;
65
- const { className, fluid, nowrap, ...rest } = boxProps;
66
-
67
- const textareaRef = useRef<HTMLTextAreaElement>(null);
68
- const [scrolledAmount, setScrolledAmount] = useState(0);
69
-
70
- const handleKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>) => {
71
- if (event.key === KEY.Enter) {
72
- if (event.shiftKey) {
73
- event.currentTarget.focus();
74
- return;
75
- }
76
-
77
- onEnter?.(event, event.currentTarget.value);
78
- if (selfClear) {
79
- event.currentTarget.value = '';
80
- }
81
- event.currentTarget.blur();
82
- return;
83
- }
84
-
85
- if (event.key === KEY.Escape) {
86
- onEscape?.(event);
87
- if (selfClear) {
88
- event.currentTarget.value = '';
89
- } else {
90
- event.currentTarget.value = toInputValue(value);
91
- event.currentTarget.blur();
92
- }
93
-
94
- return;
95
- }
96
-
97
- if (!dontUseTabForIndent && event.key === KEY.Tab) {
98
- event.preventDefault();
99
- const { value, selectionStart, selectionEnd } = event.currentTarget;
100
- event.currentTarget.value =
101
- value.substring(0, selectionStart) +
102
- '\t' +
103
- value.substring(selectionEnd);
104
- event.currentTarget.selectionEnd = selectionStart + 1;
105
- }
106
- };
107
-
108
- useImperativeHandle(
109
- forwardedRef,
110
- () => textareaRef.current as HTMLTextAreaElement
111
- );
112
-
113
- /** Focuses the input on mount */
114
- useEffect(() => {
115
- if (!autoFocus && !autoSelect) return;
116
-
117
- const input = textareaRef.current;
118
- if (!input) return;
119
-
120
- if (autoFocus || autoSelect) {
121
- setTimeout(() => {
122
- input.focus();
123
-
124
- if (autoSelect) {
125
- input.select();
126
- }
127
- }, 1);
128
- }
129
- }, []);
130
-
131
- /** Updates the initial value on props change */
132
- useEffect(() => {
133
- const input = textareaRef.current;
134
- if (!input) return;
135
-
136
- const newValue = toInputValue(value);
137
- if (input.value === newValue) return;
138
-
139
- input.value = newValue;
140
- }, [value]);
141
-
142
- return (
143
- <Box
144
- className={classes([
145
- 'TextArea',
146
- fluid && 'TextArea--fluid',
147
- noborder && 'TextArea--noborder',
148
- className,
149
- ])}
150
- {...rest}
151
- >
152
- {!!displayedValue && (
153
- <div
154
- style={{
155
- height: '100%',
156
- overflow: 'hidden',
157
- position: 'absolute',
158
- width: '100%',
159
- }}
160
- >
161
- <div
162
- className={classes([
163
- 'TextArea__textarea',
164
- 'TextArea__textarea_custom',
165
- ])}
166
- style={{
167
- transform: `translateY(-${scrolledAmount}px)`,
168
- }}
169
- >
170
- {displayedValue}
171
- </div>
172
- </div>
173
- )}
174
- <textarea
175
- className={classes([
176
- 'TextArea__textarea',
177
- scrollbar && 'TextArea__textarea--scrollable',
178
- nowrap && 'TextArea__nowrap',
179
- ])}
180
- maxLength={maxLength}
181
- onBlur={(event) => onChange?.(event, event.target.value)}
182
- onChange={(event) => onInput?.(event, event.target.value)}
183
- onKeyDown={handleKeyDown}
184
- onScroll={() => {
185
- if (displayedValue && textareaRef.current) {
186
- setScrolledAmount(textareaRef.current.scrollTop);
187
- }
188
- }}
189
- placeholder={placeholder}
190
- ref={textareaRef}
191
- style={{
192
- color: displayedValue ? 'rgba(0, 0, 0, 0)' : 'inherit',
193
- }}
194
- />
195
- </Box>
196
- );
197
- }
198
- );
1
+ /**
2
+ * @file
3
+ * @copyright 2020 Aleksej Komarov
4
+ * @author Warlockd
5
+ * @license MIT
6
+ */
7
+
8
+ import { KEY } from '../common/keys';
9
+ import { classes } from '../common/react';
10
+ import {
11
+ forwardRef,
12
+ RefObject,
13
+ useEffect,
14
+ useImperativeHandle,
15
+ useRef,
16
+ useState,
17
+ } from 'react';
18
+ import { KeyboardEvent, SyntheticEvent } from 'react';
19
+
20
+ import { Box, BoxProps } from './Box';
21
+ import { toInputValue } from './Input';
22
+
23
+ type Props = Partial<{
24
+ autoFocus: boolean;
25
+ autoSelect: boolean;
26
+ displayedValue: string;
27
+ dontUseTabForIndent: boolean;
28
+ fluid: boolean;
29
+ maxLength: number;
30
+ noborder: boolean;
31
+ /** Fires when user is 'done typing': Clicked out, blur, enter key (but not shift+enter) */
32
+ onChange: (event: SyntheticEvent<HTMLTextAreaElement>, value: string) => void;
33
+ /** Fires once the enter key is pressed */
34
+ onEnter: (event: SyntheticEvent<HTMLTextAreaElement>, value: string) => void;
35
+ /** Fires once the escape key is pressed */
36
+ onEscape: (event: SyntheticEvent<HTMLTextAreaElement>) => void;
37
+ /** Fires on each key press / value change. Used for searching */
38
+ onInput: (event: SyntheticEvent<HTMLTextAreaElement>, value: string) => void;
39
+ placeholder: string;
40
+ scrollbar: boolean;
41
+ selfClear: boolean;
42
+ value: string;
43
+ }> &
44
+ BoxProps;
45
+
46
+ export const TextArea = forwardRef(
47
+ (props: Props, forwardedRef: RefObject<HTMLTextAreaElement>) => {
48
+ const {
49
+ autoFocus,
50
+ autoSelect,
51
+ displayedValue,
52
+ dontUseTabForIndent,
53
+ maxLength,
54
+ noborder,
55
+ onChange,
56
+ onEnter,
57
+ onEscape,
58
+ onInput,
59
+ placeholder,
60
+ scrollbar,
61
+ selfClear,
62
+ value,
63
+ ...boxProps
64
+ } = props;
65
+ const { className, fluid, nowrap, ...rest } = boxProps;
66
+
67
+ const textareaRef = useRef<HTMLTextAreaElement>(null);
68
+ const [scrolledAmount, setScrolledAmount] = useState(0);
69
+
70
+ const handleKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>) => {
71
+ if (event.key === KEY.Enter) {
72
+ if (event.shiftKey) {
73
+ event.currentTarget.focus();
74
+ return;
75
+ }
76
+
77
+ onEnter?.(event, event.currentTarget.value);
78
+ if (selfClear) {
79
+ event.currentTarget.value = '';
80
+ }
81
+ event.currentTarget.blur();
82
+ return;
83
+ }
84
+
85
+ if (event.key === KEY.Escape) {
86
+ onEscape?.(event);
87
+ if (selfClear) {
88
+ event.currentTarget.value = '';
89
+ } else {
90
+ event.currentTarget.value = toInputValue(value);
91
+ event.currentTarget.blur();
92
+ }
93
+
94
+ return;
95
+ }
96
+
97
+ if (!dontUseTabForIndent && event.key === KEY.Tab) {
98
+ event.preventDefault();
99
+ const { value, selectionStart, selectionEnd } = event.currentTarget;
100
+ event.currentTarget.value =
101
+ value.substring(0, selectionStart) +
102
+ '\t' +
103
+ value.substring(selectionEnd);
104
+ event.currentTarget.selectionEnd = selectionStart + 1;
105
+ }
106
+ };
107
+
108
+ useImperativeHandle(
109
+ forwardedRef,
110
+ () => textareaRef.current as HTMLTextAreaElement
111
+ );
112
+
113
+ /** Focuses the input on mount */
114
+ useEffect(() => {
115
+ if (!autoFocus && !autoSelect) return;
116
+
117
+ const input = textareaRef.current;
118
+ if (!input) return;
119
+
120
+ if (autoFocus || autoSelect) {
121
+ setTimeout(() => {
122
+ input.focus();
123
+
124
+ if (autoSelect) {
125
+ input.select();
126
+ }
127
+ }, 1);
128
+ }
129
+ }, []);
130
+
131
+ /** Updates the initial value on props change */
132
+ useEffect(() => {
133
+ const input = textareaRef.current;
134
+ if (!input) return;
135
+
136
+ const newValue = toInputValue(value);
137
+ if (input.value === newValue) return;
138
+
139
+ input.value = newValue;
140
+ }, [value]);
141
+
142
+ return (
143
+ <Box
144
+ className={classes([
145
+ 'TextArea',
146
+ fluid && 'TextArea--fluid',
147
+ noborder && 'TextArea--noborder',
148
+ className,
149
+ ])}
150
+ {...rest}
151
+ >
152
+ {!!displayedValue && (
153
+ <div
154
+ style={{
155
+ height: '100%',
156
+ overflow: 'hidden',
157
+ position: 'absolute',
158
+ width: '100%',
159
+ }}
160
+ >
161
+ <div
162
+ className={classes([
163
+ 'TextArea__textarea',
164
+ 'TextArea__textarea_custom',
165
+ ])}
166
+ style={{
167
+ transform: `translateY(-${scrolledAmount}px)`,
168
+ }}
169
+ >
170
+ {displayedValue}
171
+ </div>
172
+ </div>
173
+ )}
174
+ <textarea
175
+ className={classes([
176
+ 'TextArea__textarea',
177
+ scrollbar && 'TextArea__textarea--scrollable',
178
+ nowrap && 'TextArea__nowrap',
179
+ ])}
180
+ maxLength={maxLength}
181
+ onBlur={(event) => onChange?.(event, event.target.value)}
182
+ onChange={(event) => onInput?.(event, event.target.value)}
183
+ onKeyDown={handleKeyDown}
184
+ onScroll={() => {
185
+ if (displayedValue && textareaRef.current) {
186
+ setScrolledAmount(textareaRef.current.scrollTop);
187
+ }
188
+ }}
189
+ placeholder={placeholder}
190
+ ref={textareaRef}
191
+ style={{
192
+ color: displayedValue ? 'rgba(0, 0, 0, 0)' : 'inherit',
193
+ }}
194
+ />
195
+ </Box>
196
+ );
197
+ }
198
+ );
@@ -1,64 +1,64 @@
1
- import { Component } from 'react';
2
-
3
- import { formatTime } from '../format';
4
-
5
- // AnimatedNumber Copypaste
6
- const isSafeNumber = (value) => {
7
- return (
8
- typeof value === 'number' && Number.isFinite(value) && !Number.isNaN(value)
9
- );
10
- };
11
-
12
- export class TimeDisplay extends Component {
13
- constructor(props) {
14
- super(props);
15
- this.timer = null;
16
- this.last_seen_value = undefined;
17
- this.state = {
18
- value: 0,
19
- };
20
- // Set initial state with value provided in props
21
- if (isSafeNumber(props.value)) {
22
- this.state.value = Number(props.value);
23
- this.last_seen_value = Number(props.value);
24
- }
25
- }
26
-
27
- componentDidUpdate() {
28
- if (this.props.auto !== undefined) {
29
- clearInterval(this.timer);
30
- this.timer = setInterval(() => this.tick(), 1000); // every 1 s
31
- }
32
- }
33
-
34
- tick() {
35
- let current = Number(this.state.value);
36
- if (this.props.value !== this.last_seen_value) {
37
- this.last_seen_value = this.props.value;
38
- current = this.props.value;
39
- }
40
- const mod = this.props.auto === 'up' ? 10 : -10; // Time down by default.
41
- const value = Math.max(0, current + mod); // one sec tick
42
- this.setState({ value });
43
- }
44
-
45
- componentDidMount() {
46
- if (this.props.auto !== undefined) {
47
- this.timer = setInterval(() => this.tick(), 1000); // every 1 s
48
- }
49
- }
50
-
51
- componentWillUnmount() {
52
- clearInterval(this.timer);
53
- }
54
-
55
- render() {
56
- const val = this.state.value;
57
- // Directly display weird stuff
58
- if (!isSafeNumber(val)) {
59
- return this.state.value || null;
60
- }
61
-
62
- return formatTime(val);
63
- }
64
- }
1
+ import { Component } from 'react';
2
+
3
+ import { formatTime } from '../src/format';
4
+
5
+ // AnimatedNumber Copypaste
6
+ const isSafeNumber = (value) => {
7
+ return (
8
+ typeof value === 'number' && Number.isFinite(value) && !Number.isNaN(value)
9
+ );
10
+ };
11
+
12
+ export class TimeDisplay extends Component {
13
+ constructor(props) {
14
+ super(props);
15
+ this.timer = null;
16
+ this.last_seen_value = undefined;
17
+ this.state = {
18
+ value: 0,
19
+ };
20
+ // Set initial state with value provided in props
21
+ if (isSafeNumber(props.value)) {
22
+ this.state.value = Number(props.value);
23
+ this.last_seen_value = Number(props.value);
24
+ }
25
+ }
26
+
27
+ componentDidUpdate() {
28
+ if (this.props.auto !== undefined) {
29
+ clearInterval(this.timer);
30
+ this.timer = setInterval(() => this.tick(), 1000); // every 1 s
31
+ }
32
+ }
33
+
34
+ tick() {
35
+ let current = Number(this.state.value);
36
+ if (this.props.value !== this.last_seen_value) {
37
+ this.last_seen_value = this.props.value;
38
+ current = this.props.value;
39
+ }
40
+ const mod = this.props.auto === 'up' ? 10 : -10; // Time down by default.
41
+ const value = Math.max(0, current + mod); // one sec tick
42
+ this.setState({ value });
43
+ }
44
+
45
+ componentDidMount() {
46
+ if (this.props.auto !== undefined) {
47
+ this.timer = setInterval(() => this.tick(), 1000); // every 1 s
48
+ }
49
+ }
50
+
51
+ componentWillUnmount() {
52
+ clearInterval(this.timer);
53
+ }
54
+
55
+ render() {
56
+ const val = this.state.value;
57
+ // Directly display weird stuff
58
+ if (!isSafeNumber(val)) {
59
+ return this.state.value || null;
60
+ }
61
+
62
+ return formatTime(val);
63
+ }
64
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * @file
3
+ * @copyright 2020 Aleksej Komarov
4
+ * @license MIT
5
+ */
6
+
7
+ export { AnimatedNumber } from './AnimatedNumber';
8
+ export { Autofocus } from './Autofocus';
9
+ export { Blink } from './Blink';
10
+ export { BlockQuote } from './BlockQuote';
11
+ export { Box } from './Box';
12
+ export { Button } from './Button';
13
+ export { ByondUi } from './ByondUi';
14
+ export { Chart } from './Chart';
15
+ export { Collapsible } from './Collapsible';
16
+ export { ColorBox } from './ColorBox';
17
+ export { Dialog } from './Dialog';
18
+ export { Dimmer } from './Dimmer';
19
+ export { Divider } from './Divider';
20
+ export { DmIcon } from './DmIcon';
21
+ export { DraggableControl } from './DraggableControl';
22
+ export { Dropdown } from './Dropdown';
23
+ export { FitText } from './FitText';
24
+ export { Flex } from './Flex';
25
+ export { Icon } from './Icon';
26
+ export { Image } from './Image';
27
+ export { InfinitePlane } from './InfinitePlane';
28
+ export { Input } from './Input';
29
+ export { KeyListener } from './KeyListener';
30
+ export { Knob } from './Knob';
31
+ export { LabeledControls } from './LabeledControls';
32
+ export { LabeledList } from './LabeledList';
33
+ export { MenuBar } from './MenuBar';
34
+ export { Modal } from './Modal';
35
+ export { NoticeBox } from './NoticeBox';
36
+ export { NumberInput } from './NumberInput';
37
+ export { Popper } from './Popper';
38
+ export { ProgressBar } from './ProgressBar';
39
+ export { RestrictedInput } from './RestrictedInput';
40
+ export { RoundGauge } from './RoundGauge';
41
+ export { Section } from './Section';
42
+ export { Slider } from './Slider';
43
+ export { Stack } from './Stack';
44
+ export { StyleableSection } from './StyleableSection';
45
+ export { Table } from './Table';
46
+ export { Tabs } from './Tabs';
47
+ export { TextArea } from './TextArea';
48
+ export { TimeDisplay } from './TimeDisplay';
49
+ export { Tooltip } from './Tooltip';
50
+ export { TrackOutsideClicks } from './TrackOutsideClicks';
51
+ export { VirtualList } from './VirtualList';