Skip to content

Commit 9c9db5c

Browse files
Scott DoverScott Dover
authored andcommitted
fix: fix light/dark theme toggling
Signed-off-by: Scott Dover <[email protected]>
1 parent e2d53a3 commit 9c9db5c

File tree

5 files changed

+58
-28
lines changed

5 files changed

+58
-28
lines changed

client/src/webview/ColumnHeader.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { useRef } from "react";
44

55
import { AgColumn, GridApi } from "ag-grid-community";
66

7+
import useTheme from "./useTheme";
8+
79
const getIconForColumnType = (type: string) => {
810
switch (type.toLocaleLowerCase()) {
911
case "float":
@@ -29,16 +31,15 @@ const ColumnHeader = ({
2931
column,
3032
currentColumn: getCurrentColumn,
3133
columnType,
32-
theme,
3334
displayMenuForColumn,
3435
}: {
3536
api: GridApi;
3637
column: AgColumn;
3738
currentColumn: () => AgColumn | undefined;
3839
columnType: string;
39-
theme: string;
4040
displayMenuForColumn: (api: GridApi, column: AgColumn, rect: DOMRect) => void;
4141
}) => {
42+
const theme = useTheme();
4243
const ref = useRef<HTMLButtonElement>(undefined!);
4344
const currentColumn = getCurrentColumn();
4445
const currentSortedColumns = api.getColumnState().filter((c) => c.sort);

client/src/webview/ColumnMenu.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { AgColumn, ColumnState, GridApi } from "ag-grid-community";
55
import GridMenu from "./GridMenu";
66
import localize from "./localize";
77
import { storeViewProperties } from "./useDataViewer";
8+
import useTheme from "./useTheme";
89

910
export interface ColumnMenuProps {
1011
column: AgColumn;
@@ -15,7 +16,6 @@ export interface ColumnMenuProps {
1516
removeAllSorting: () => void;
1617
removeFromSort: () => void;
1718
sortColumn: (direction: "asc" | "desc") => void;
18-
theme: string;
1919
top: number;
2020
}
2121

@@ -27,7 +27,6 @@ const applyColumnState = (api: GridApi, state: ColumnState[]) => {
2727

2828
export const getColumnMenu = (
2929
api: GridApi,
30-
theme: ColumnMenuProps["theme"],
3130
column: AgColumn,
3231
{ height, top, left }: DOMRect,
3332
dismissMenu: () => void,
@@ -37,7 +36,6 @@ export const getColumnMenu = (
3736
dismissMenu,
3837
hasSort: api.getColumnState().some((c) => c.sort),
3938
left,
40-
theme,
4139
top: top + height,
4240
sortColumn: (direction: "asc" | "desc" | null) => {
4341
const newColumnState = api.getColumnState().filter((c) => c.sort);
@@ -85,9 +83,9 @@ const ColumnMenu = ({
8583
removeAllSorting,
8684
removeFromSort,
8785
sortColumn,
88-
theme,
8986
top,
9087
}: ColumnMenuProps) => {
88+
const theme = useTheme();
9189
const menuItems = [
9290
{
9391
name: localize("Sort"),

client/src/webview/DataViewer.tsx

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
// Copyright © 2023, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
3-
import { useCallback, useEffect, useMemo } from "react";
3+
import { useCallback, useEffect } from "react";
44
import { createRoot } from "react-dom/client";
55

66
import { AgGridReact } from "ag-grid-react";
77

88
import ".";
99
import ColumnMenu from "./ColumnMenu";
1010
import useDataViewer from "./useDataViewer";
11+
import useTheme from "./useTheme";
1112

1213
import "./DataViewer.css";
1314
import "ag-grid-community/styles/ag-grid.css";
@@ -21,22 +22,8 @@ const gridStyles = {
2122
};
2223

2324
const DataViewer = () => {
24-
const theme = useMemo(() => {
25-
const themeKind = document
26-
.querySelector("[data-vscode-theme-kind]")
27-
.getAttribute("data-vscode-theme-kind");
28-
29-
switch (themeKind) {
30-
case "vscode-high-contrast-light":
31-
case "vscode-light":
32-
return "ag-theme-alpine";
33-
case "vscode-high-contrast":
34-
case "vscode-dark":
35-
return "ag-theme-alpine-dark";
36-
}
37-
}, []);
38-
const { columns, onGridReady, columnMenu, dismissMenu } =
39-
useDataViewer(theme);
25+
const theme = useTheme();
26+
const { columns, onGridReady, columnMenu, dismissMenu } = useDataViewer();
4027

4128
const handleKeydown = useCallback(
4229
(event) => {

client/src/webview/useDataViewer.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ export const storeViewProperties = (viewProperties: ViewProperties) =>
114114
data: { viewProperties },
115115
});
116116

117-
const useDataViewer = (theme: string) => {
117+
const useDataViewer = () => {
118118
const [columns, setColumns] = useState<ColDef[]>([]);
119119
const [columnMenu, setColumnMenu] = useState<ColumnMenuProps | undefined>();
120120
const columnMenuRef = useRef<ColumnMenuProps | undefined>(columnMenu);
@@ -168,7 +168,6 @@ const useDataViewer = (theme: string) => {
168168
setColumnMenu(
169169
getColumnMenu(
170170
api,
171-
theme,
172171
column,
173172
rect,
174173
() => setColumnMenu(undefined),
@@ -181,7 +180,7 @@ const useDataViewer = (theme: string) => {
181180
),
182181
);
183182
},
184-
[theme],
183+
[],
185184
);
186185

187186
useEffect(() => {
@@ -201,7 +200,6 @@ const useDataViewer = (theme: string) => {
201200
columnType: column.type,
202201
currentColumn: () => columnMenuRef.current?.column,
203202
displayMenuForColumn,
204-
theme,
205203
},
206204
...getColumnState(column.name),
207205
suppressHeaderKeyboardEvent: (
@@ -247,7 +245,7 @@ const useDataViewer = (theme: string) => {
247245

248246
setColumns(columns);
249247
});
250-
}, [columns.length, theme, displayMenuForColumn]);
248+
}, [columns.length, displayMenuForColumn]);
251249

252250
useEffect(() => {
253251
window.addEventListener("contextmenu", contextMenuHandler, true);

client/src/webview/useTheme.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
import { useEffect, useMemo, useState } from "react";
4+
5+
const THEME_ATTRIBUTE = "data-vscode-theme-kind";
6+
const SELECTOR = `[${THEME_ATTRIBUTE}]`;
7+
8+
/**
9+
* This listens for changes to vscode's theme kind and updates our internal
10+
* theme to match.
11+
* @returns theme:string matching the ag grid theme for the vscode theme kind
12+
*/
13+
const useTheme = () => {
14+
const [themeKind, setThemeKind] = useState(
15+
document.querySelector(SELECTOR).getAttribute(THEME_ATTRIBUTE),
16+
);
17+
useEffect(() => {
18+
const obs = new MutationObserver((record) =>
19+
setThemeKind(
20+
(record[0].target as HTMLElement).getAttribute(THEME_ATTRIBUTE),
21+
),
22+
);
23+
obs.observe(document.querySelector(SELECTOR), {
24+
attributes: true,
25+
attributeFilter: [THEME_ATTRIBUTE],
26+
});
27+
return () => {
28+
obs.disconnect();
29+
};
30+
}, []);
31+
32+
const theme = useMemo(() => {
33+
switch (themeKind) {
34+
case "vscode-high-contrast-light":
35+
case "vscode-light":
36+
return "ag-theme-alpine";
37+
case "vscode-high-contrast":
38+
case "vscode-dark":
39+
return "ag-theme-alpine-dark";
40+
}
41+
}, [themeKind]);
42+
43+
return theme;
44+
};
45+
46+
export default useTheme;

0 commit comments

Comments
 (0)