Skip to content

Commit 03551fe

Browse files
authored
feat: add isThemeActive helper (#222)
Co-authored-by: Maximilian Schoell <mxschll@users.noreply.github.com>
1 parent 3ff2844 commit 03551fe

4 files changed

Lines changed: 181 additions & 0 deletions

File tree

src/internal/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ export {
1414
useDensityMode,
1515
useReducedMotion,
1616
useRuntimeVisualRefresh,
17+
isThemeActive,
18+
Theme,
1719
} from './visual-mode/index.js';
1820
export { isDevelopment } from './is-development.js';
1921
export { warnOnce, clearMessageCache } from './logging.js';
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* @jest-environment node
3+
*/
4+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
5+
// SPDX-License-Identifier: Apache-2.0
6+
7+
import { isThemeActive, Theme } from '../index';
8+
import { awsuiGlobalFlagsSymbol, awsuiVisualRefreshFlag, FlagsHolder } from '../../global-flags';
9+
10+
const globalWithFlags = globalThis as FlagsHolder;
11+
12+
afterEach(() => {
13+
delete globalWithFlags[awsuiVisualRefreshFlag];
14+
delete globalWithFlags[awsuiGlobalFlagsSymbol];
15+
});
16+
17+
test('ensure no window in this environment', () => {
18+
expect(typeof window === 'undefined').toBe(true);
19+
});
20+
21+
describe('Theme.VisualRefresh', () => {
22+
test('returns false by default', () => {
23+
expect(isThemeActive(Theme.VisualRefresh)).toBe(false);
24+
});
25+
26+
test('returns true when awsui-visual-refresh-flag is set on globalThis', () => {
27+
globalWithFlags[awsuiVisualRefreshFlag] = () => true;
28+
expect(isThemeActive(Theme.VisualRefresh)).toBe(true);
29+
});
30+
31+
test('returns false when awsui-visual-refresh-flag returns false', () => {
32+
globalWithFlags[awsuiVisualRefreshFlag] = () => false;
33+
expect(isThemeActive(Theme.VisualRefresh)).toBe(false);
34+
});
35+
});
36+
37+
describe('Theme.OneTheme', () => {
38+
test('returns false by default', () => {
39+
expect(isThemeActive(Theme.OneTheme)).toBe(false);
40+
});
41+
42+
test('returns true when oneTheme global flag is set on globalThis', () => {
43+
globalWithFlags[awsuiGlobalFlagsSymbol] = { oneTheme: true };
44+
expect(isThemeActive(Theme.OneTheme)).toBe(true);
45+
});
46+
47+
test('returns false when oneTheme global flag is false', () => {
48+
globalWithFlags[awsuiGlobalFlagsSymbol] = { oneTheme: false };
49+
expect(isThemeActive(Theme.OneTheme)).toBe(false);
50+
});
51+
});
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import { isThemeActive, Theme } from '../index';
5+
import { awsuiGlobalFlagsSymbol, awsuiVisualRefreshFlag, FlagsHolder } from '../../global-flags';
6+
7+
declare const window: Window & FlagsHolder;
8+
9+
afterEach(() => {
10+
document.body.classList.remove('awsui-visual-refresh');
11+
document.body.classList.remove('awsui-one-theme');
12+
delete window[awsuiVisualRefreshFlag];
13+
delete window[awsuiGlobalFlagsSymbol];
14+
});
15+
16+
describe('Theme.VisualRefresh', () => {
17+
test('returns false when nothing is set', () => {
18+
expect(isThemeActive(Theme.VisualRefresh)).toBe(false);
19+
});
20+
21+
test('returns true when the awsui-visual-refresh class is present', () => {
22+
document.body.classList.add('awsui-visual-refresh');
23+
expect(isThemeActive(Theme.VisualRefresh)).toBe(true);
24+
});
25+
26+
test('returns true when awsui-visual-refresh-flag returns true', () => {
27+
window[awsuiVisualRefreshFlag] = () => true;
28+
expect(isThemeActive(Theme.VisualRefresh)).toBe(true);
29+
});
30+
31+
test('returns false when awsui-visual-refresh-flag returns false', () => {
32+
window[awsuiVisualRefreshFlag] = () => false;
33+
expect(isThemeActive(Theme.VisualRefresh)).toBe(false);
34+
});
35+
36+
test('class presence wins over a flag returning false', () => {
37+
document.body.classList.add('awsui-visual-refresh');
38+
window[awsuiVisualRefreshFlag] = () => false;
39+
expect(isThemeActive(Theme.VisualRefresh)).toBe(true);
40+
});
41+
});
42+
43+
describe('Theme.OneTheme', () => {
44+
test('returns false when nothing is set', () => {
45+
expect(isThemeActive(Theme.OneTheme)).toBe(false);
46+
});
47+
48+
test('returns true when the awsui-one-theme class is present', () => {
49+
document.body.classList.add('awsui-one-theme');
50+
expect(isThemeActive(Theme.OneTheme)).toBe(true);
51+
});
52+
53+
test('returns true when the oneTheme global flag is true', () => {
54+
window[awsuiGlobalFlagsSymbol] = { oneTheme: true };
55+
expect(isThemeActive(Theme.OneTheme)).toBe(true);
56+
});
57+
58+
test('returns false when the oneTheme global flag is false', () => {
59+
window[awsuiGlobalFlagsSymbol] = { oneTheme: false };
60+
expect(isThemeActive(Theme.OneTheme)).toBe(false);
61+
});
62+
63+
test('returns false when awsui-global-flags exists but oneTheme is unset', () => {
64+
window[awsuiGlobalFlagsSymbol] = {};
65+
expect(isThemeActive(Theme.OneTheme)).toBe(false);
66+
});
67+
68+
test('class presence wins over a flag set to false', () => {
69+
document.body.classList.add('awsui-one-theme');
70+
window[awsuiGlobalFlagsSymbol] = { oneTheme: false };
71+
expect(isThemeActive(Theme.OneTheme)).toBe(true);
72+
});
73+
});
74+
75+
describe('theme isolation', () => {
76+
test('activating one theme via class does not activate visual refresh', () => {
77+
document.body.classList.add('awsui-one-theme');
78+
expect(isThemeActive(Theme.VisualRefresh)).toBe(false);
79+
expect(isThemeActive(Theme.OneTheme)).toBe(true);
80+
});
81+
82+
test('activating visual refresh via class does not activate one theme', () => {
83+
document.body.classList.add('awsui-visual-refresh');
84+
expect(isThemeActive(Theme.VisualRefresh)).toBe(true);
85+
expect(isThemeActive(Theme.OneTheme)).toBe(false);
86+
});
87+
88+
test('activating one theme via flag does not activate visual refresh', () => {
89+
window[awsuiGlobalFlagsSymbol] = { oneTheme: true };
90+
expect(isThemeActive(Theme.VisualRefresh)).toBe(false);
91+
expect(isThemeActive(Theme.OneTheme)).toBe(true);
92+
});
93+
94+
test('activating visual refresh via symbol does not activate one theme', () => {
95+
window[awsuiVisualRefreshFlag] = () => true;
96+
expect(isThemeActive(Theme.VisualRefresh)).toBe(true);
97+
expect(isThemeActive(Theme.OneTheme)).toBe(false);
98+
});
99+
});

src/internal/visual-mode/index.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,32 @@ export function useRuntimeVisualRefresh() {
137137
}
138138
return visualRefreshState;
139139
}
140+
141+
export enum Theme {
142+
VisualRefresh = 'visual-refresh',
143+
OneTheme = 'one-theme',
144+
}
145+
146+
interface ThemeConfig {
147+
className: string;
148+
isFlagActive: () => boolean;
149+
}
150+
151+
const THEMES: Record<Theme, ThemeConfig> = {
152+
[Theme.VisualRefresh]: {
153+
className: 'awsui-visual-refresh',
154+
isFlagActive: () => !!getGlobal()?.[awsuiVisualRefreshFlag]?.(),
155+
},
156+
[Theme.OneTheme]: {
157+
className: 'awsui-one-theme',
158+
isFlagActive: () => !!getGlobalFlag('oneTheme'),
159+
},
160+
};
161+
162+
export function isThemeActive(theme: Theme): boolean {
163+
const config = THEMES[theme];
164+
if (typeof document !== 'undefined' && document.querySelector(`.${config.className}`)) {
165+
return true;
166+
}
167+
return config.isFlagActive();
168+
}

0 commit comments

Comments
 (0)