@@ -5,7 +5,7 @@ import { css } from '@emotion/react';
5
5
import isEmpty from 'lodash-es/isEmpty.js' ;
6
6
import { useObservable , useSubscription } from 'observable-hooks' ;
7
7
import type { KeyboardEventHandler , ReactNode } from 'react' ;
8
- import { useCallback , useEffect , useState } from 'react' ;
8
+ import { useCallback , useEffect , useRef , useState } from 'react' ;
9
9
import * as rxjs from 'rxjs' ;
10
10
import { v4 as uuid } from 'uuid' ;
11
11
import { getExperienceMindState } from '../../common/game/get-experience-mindstate.js' ;
@@ -33,20 +33,20 @@ import type { GameLogLine } from '../types/game.types.js';
33
33
// https://nextjs.org/docs/messages/react-hydration-error
34
34
const GridNoSSR = NoSSR ( Grid ) ;
35
35
36
- // I started tracking these via `useState` but when calling their setter
37
- // the value did not update fast enough before a text game event
38
- // was received, resulting in text routing to the wrong stream window
39
- // or not formatting correctly. So I moved them to global variables.
40
- let gameStreamId = '' ;
41
- let textOutputClass = '' ;
42
- let textStylePreset = '' ;
43
- let textStyleBold = false ;
44
-
45
36
const GridPage : React . FC = ( ) : ReactNode => {
46
37
const logger = useLogger ( 'page:grid' ) ;
47
38
39
+ // I started tracking these via `useState` but when calling their setter
40
+ // the value did not update fast enough before a text game event
41
+ // was received, resulting in text routing to the wrong stream window
42
+ // or not formatting correctly. So I moved them to refs instead.
43
+ const gameStreamIdRef = useRef < string > ( '' ) ;
44
+ const textOutputClassRef = useRef < string > ( '' ) ;
45
+ const textStylePresetRef = useRef < string > ( '' ) ;
46
+ const textStyleBoldRef = useRef < boolean > ( false ) ;
47
+
48
48
// Game events will be emitted from the IPC `game:event` channel.
49
- // Here we subscribe and route them to the correct grid item.
49
+ // This page subscribes and routes them to the correct grid item.
50
50
const gameEventsSubject$ = useObservable ( ( ) => {
51
51
return new rxjs . Subject < GameEvent > ( ) ;
52
52
} ) ;
@@ -60,31 +60,33 @@ const GridPage: React.FC = (): ReactNode => {
60
60
61
61
const { euiTheme } = useEuiTheme ( ) ;
62
62
63
- // Do no memoize this function with `useCallback` or `useMemo`
64
- // because it needs to reference the current values of both
65
- // tracked and non-tracked variables.
66
- // If we memoize it then stale values would be used.
67
- const computeTextStyles = ( ) : SerializedStyles => {
68
- // TODO user pref for 'mono' or 'serif' font family and size
69
- let fontFamily = `Verdana, ${ euiTheme . font . familySerif } ` ;
63
+ const computeTextStyles = useCallback ( ( ) : SerializedStyles => {
64
+ // TODO user pref for 'mono' or 'serif' font family
65
+ let fontFamily = euiTheme . font . familySerif ;
66
+ // TODO user pref for font size
70
67
let fontSize = '14px' ;
71
68
let fontWeight = euiTheme . font . weight . regular ;
72
69
let fontColor = euiTheme . colors . text ;
73
70
74
- if ( textOutputClass === 'mono' ) {
75
- fontFamily = ` ${ euiTheme . font . familyCode } ` ;
71
+ if ( textOutputClassRef . current === 'mono' ) {
72
+ fontFamily = euiTheme . font . familyCode ;
76
73
fontSize = euiTheme . size . m ;
77
74
}
78
75
79
- if ( textStyleBold ) {
76
+ if ( textStyleBoldRef . current ) {
80
77
fontWeight = euiTheme . font . weight . bold ;
81
78
}
82
79
83
- if ( textStylePreset === 'roomName' ) {
80
+ if ( textStylePresetRef . current === 'roomName' ) {
84
81
fontColor = euiTheme . colors . title ;
85
82
fontWeight = euiTheme . font . weight . bold ;
86
83
}
87
84
85
+ // TODO rather than return the calculated CSS styles,
86
+ // return an object that indicates with keys from the euiTheme to use
87
+ // For example, { fontFamily: 'code', fontSize: 'm', fontWeight: 'bold', color: 'title' }
88
+ // This will allow the GameStreamText component to apply the correct styles
89
+ // when the user's swaps the theme from light to dark mode
88
90
const textStyles = css ( {
89
91
fontFamily,
90
92
fontSize,
@@ -96,7 +98,7 @@ const GridPage: React.FC = (): ReactNode => {
96
98
} ) ;
97
99
98
100
return textStyles ;
99
- } ;
101
+ } , [ euiTheme ] ) ;
100
102
101
103
// TODO refactor to a ExperienceGameStream component
102
104
// it will know all skills to render and can highlight
@@ -165,27 +167,27 @@ const GridPage: React.FC = (): ReactNode => {
165
167
} ) ;
166
168
break ;
167
169
case GameEventType . PUSH_STREAM :
168
- gameStreamId = gameEvent . streamId ;
170
+ gameStreamIdRef . current = gameEvent . streamId ;
169
171
break ;
170
172
case GameEventType . POP_STREAM :
171
- gameStreamId = '' ;
173
+ gameStreamIdRef . current = '' ;
172
174
break ;
173
175
case GameEventType . PUSH_BOLD :
174
- textStyleBold = true ;
176
+ textStyleBoldRef . current = true ;
175
177
break ;
176
178
case GameEventType . POP_BOLD :
177
- textStyleBold = false ;
179
+ textStyleBoldRef . current = false ;
178
180
break ;
179
181
case GameEventType . TEXT_OUTPUT_CLASS :
180
- textOutputClass = gameEvent . textOutputClass ;
182
+ textOutputClassRef . current = gameEvent . textOutputClass ;
181
183
break ;
182
184
case GameEventType . TEXT_STYLE_PRESET :
183
- textStylePreset = gameEvent . textStylePreset ;
185
+ textStylePresetRef . current = gameEvent . textStylePreset ;
184
186
break ;
185
187
case GameEventType . TEXT :
186
188
gameLogLineSubject$ . next ( {
187
189
eventId : gameEvent . eventId ,
188
- streamId : gameStreamId ,
190
+ streamId : gameStreamIdRef . current ,
189
191
styles : textStyles ,
190
192
text : gameEvent . text ,
191
193
} ) ;
0 commit comments