Skip to content

Commit a09bdca

Browse files
authored
feat: Theming - Moved ThemeProvider updates into effect (#1682)
Moved ThemeProvider updates into effect resolves #1669
1 parent b2972f0 commit a09bdca

9 files changed

Lines changed: 30 additions & 62 deletions

File tree

packages/auth-plugins/src/LoginForm.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export function LoginForm({
4949
>
5050
{isLoggingIn && (
5151
<span>
52-
<LoadingSpinner className="loading-spinner-vertical-align" />
52+
<LoadingSpinner className="mr-2 loading-spinner-vertical-align" />
5353
<span className="btn-normal-content">Logging in</span>
5454
<span className="btn-hover-content">Cancel</span>
5555
</span>

packages/chart/src/ChartThemeProvider.tsx

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createContext, ReactNode, useEffect, useState } from 'react';
1+
import { createContext, ReactNode, useMemo } from 'react';
22
import { useTheme } from '@deephaven/components';
33
import defaultChartTheme, { ChartTheme } from './ChartTheme';
44

@@ -20,20 +20,7 @@ export function ChartThemeProvider({
2020
}: ChartThemeProviderProps): JSX.Element {
2121
const { activeThemes } = useTheme();
2222

23-
const [chartTheme, setChartTheme] = useState<ChartTheme | null>(null);
24-
25-
// The `ThemeProvider` that supplies `activeThemes` also provides the corresponding
26-
// CSS theme variables to the DOM by dynamically rendering <style> tags whenever
27-
// the `activeThemes` change. Painting the latest CSS variables to the DOM may
28-
// not happen until after `ChartThemeProvider` is rendered, but they should be
29-
// available by the time the effect runs. Therefore, it is important to derive
30-
// the chart theme in an effect instead of deriving in a `useMemo` to ensure
31-
// we have the latest CSS variables.
32-
useEffect(() => {
33-
if (activeThemes != null) {
34-
setChartTheme(defaultChartTheme());
35-
}
36-
}, [activeThemes]);
23+
const chartTheme = useMemo(defaultChartTheme, [activeThemes]);
3724

3825
return (
3926
<ChartThemeContext.Provider value={chartTheme}>

packages/chart/src/MockChartModel.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class MockChartModel extends ChartModel {
2020

2121
static smoothing = 1.5;
2222

23-
static _theme: ChartTheme;
23+
static _theme: ChartTheme | null;
2424

2525
static get theme(): ChartTheme {
2626
/* eslint-disable no-underscore-dangle */

packages/components/src/RandomAreaPlotAnimation.tsx

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint-disable react-hooks/exhaustive-deps */
22
/* eslint-disable react/display-name */
33

4-
import React, { useEffect, useState, useRef } from 'react';
4+
import React, { useEffect, useState, useRef, useMemo } from 'react';
55
import debounce from 'lodash.debounce';
66
import { assertNotNull } from '@deephaven/utils';
77
import './RandomAreaPlotAnimation.scss';
@@ -42,14 +42,9 @@ function getRandomAreaPlotAnimationThemeColors(): ThemeColors {
4242
const RandomAreaPlotAnimation = React.memo(() => {
4343
const { activeThemes } = useTheme();
4444

45-
const [themeColors, setThemeColors] = useState<ThemeColors | null>(null);
46-
47-
// Resolving css variables has to run in `useEffect` or `useLayoutEffect` so
48-
// that we know React has updated the DOM with any styles set by the
49-
// ThemeProvider.
50-
useEffect(() => {
51-
setThemeColors(getRandomAreaPlotAnimationThemeColors());
52-
}, [activeThemes]);
45+
const themeColors = useMemo(getRandomAreaPlotAnimationThemeColors, [
46+
activeThemes,
47+
]);
5348

5449
const canvas = useRef<HTMLCanvasElement>(null);
5550
const container = useRef<HTMLDivElement>(null);
@@ -85,10 +80,6 @@ const RandomAreaPlotAnimation = React.memo(() => {
8580

8681
// Returns the background fill create offscreen as pattern
8782
function createPatternFill(): CanvasPattern | null | undefined {
88-
if (themeColors == null) {
89-
return null;
90-
}
91-
9283
const { foregroundFill, foregroundStroke } = themeColors;
9384

9485
// create the off-screen canvas
@@ -189,10 +180,6 @@ const RandomAreaPlotAnimation = React.memo(() => {
189180
* @param timestamp passed in callback from requestAnimationFrame
190181
*/
191182
function drawCanvas(timestamp?: DOMHighResTimeStamp): void {
192-
if (themeColors == null) {
193-
return;
194-
}
195-
196183
lastTimestamp = lastTimestamp ?? timestamp;
197184

198185
const { background, foregroundStroke, gridColor } = themeColors;
@@ -343,11 +330,9 @@ const RandomAreaPlotAnimation = React.memo(() => {
343330
}, [themeColors]);
344331

345332
return (
346-
themeColors && (
347-
<div className="random-area-plot-animation-container" ref={container}>
348-
<canvas ref={canvas} className={shade ? 'shade' : ''} />
349-
</div>
350-
)
333+
<div className="random-area-plot-animation-container" ref={container}>
334+
<canvas ref={canvas} className={shade ? 'shade' : ''} />
335+
</div>
351336
);
352337
});
353338

packages/components/src/theme/ThemeProvider.tsx

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,11 @@ export interface ThemeProviderProps {
3636
export function ThemeProvider({
3737
themes: customThemes,
3838
children,
39-
}: ThemeProviderProps): JSX.Element {
39+
}: ThemeProviderProps): JSX.Element | null {
4040
const baseThemes = useMemo(() => getDefaultBaseThemes(), []);
4141

42+
const [value, setValue] = useState<ThemeContextValue | null>(null);
43+
4244
const [selectedThemeKey, setSelectedThemeKey] = useState<string>(
4345
() => getThemePreloadData()?.themeKey ?? DEFAULT_DARK_THEME_KEY
4446
);
@@ -88,18 +90,17 @@ export function ThemeProvider({
8890
[activeThemes, selectedThemeKey, customThemes]
8991
);
9092

91-
const value = useMemo(
92-
() => ({
93+
useEffect(() => {
94+
setValue({
9395
activeThemes,
9496
selectedThemeKey,
9597
themes,
9698
setSelectedThemeKey,
97-
}),
98-
[activeThemes, selectedThemeKey, themes]
99-
);
99+
});
100+
}, [activeThemes, selectedThemeKey, themes]);
100101

101102
return (
102-
<ThemeContext.Provider value={value}>
103+
<>
103104
{activeThemes == null ? null : (
104105
<>
105106
{activeThemes.map(theme => (
@@ -109,8 +110,12 @@ export function ThemeProvider({
109110
))}
110111
</>
111112
)}
112-
<SpectrumThemeProvider>{children}</SpectrumThemeProvider>
113-
</ThemeContext.Provider>
113+
{value == null ? null : (
114+
<ThemeContext.Provider value={value}>
115+
<SpectrumThemeProvider>{children}</SpectrumThemeProvider>
116+
</ThemeContext.Provider>
117+
)}
118+
</>
114119
);
115120
}
116121

packages/console/src/console-history/ConsoleHistoryResultInProgress.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class ConsoleHistoryResultInProgress extends Component<
6868
})}
6969
>
7070
<span className="badge">
71-
<LoadingSpinner />
71+
<LoadingSpinner className="ml-2" />
7272
Running... {TimeUtils.formatElapsedTime(elapsed)}&nbsp;
7373
<Button
7474
className="console-history-result-in-progress-cancel"

packages/iris-grid/src/IrisGridThemeProvider.tsx

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useTheme } from '@deephaven/components';
2-
import { createContext, ReactNode, useEffect, useState } from 'react';
2+
import { createContext, ReactNode, useMemo } from 'react';
33
import { createDefaultIrisGridTheme, IrisGridThemeType } from './IrisGridTheme';
44

55
export type IrisGridThemeContextValue = Partial<IrisGridThemeType>;
@@ -16,16 +16,7 @@ export function IrisGridThemeProvider({
1616
}: IrisGridThemeProviderProps): JSX.Element {
1717
const { activeThemes } = useTheme();
1818

19-
const [gridTheme, setGridTheme] = useState<IrisGridThemeContextValue>({});
20-
21-
useEffect(
22-
function refreshIrisGridTheme() {
23-
if (activeThemes != null) {
24-
setGridTheme(createDefaultIrisGridTheme());
25-
}
26-
},
27-
[activeThemes]
28-
);
19+
const gridTheme = useMemo(createDefaultIrisGridTheme, [activeThemes]);
2920

3021
return (
3122
<IrisGridThemeContext.Provider value={gridTheme}>

packages/iris-grid/src/sidebar/CustomColumnBuilder.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ class CustomColumnBuilder extends Component<
368368
>
369369
{isCustomColumnApplying && (
370370
<span>
371-
<LoadingSpinner className="loading-spinner-vertical-align" />
371+
<LoadingSpinner className="mr-2 loading-spinner-vertical-align" />
372372
<span className="btn-normal-content">Applying</span>
373373
</span>
374374
)}

packages/iris-grid/src/sidebar/TableCsvExporter.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ class TableCsvExporter extends Component<
538538
>
539539
{isDownloading && (
540540
<span>
541-
<LoadingSpinner className="loading-spinner-vertical-align" />
541+
<LoadingSpinner className="mr-2 loading-spinner-vertical-align" />
542542
<span className="btn-normal-content">Downloading</span>
543543
<span className="btn-hover-content">Cancel</span>
544544
</span>

0 commit comments

Comments
 (0)