feat: nativeTheme.themeSource and a few nativeTheme fixes (#20486)

* feat: add nativeTheme.themeSource to allow apps to override Chromiums theme choice (#19960)

* feat: add nativeTheme.shouldUseDarkColorsOverride to allow apps to override Chromiums theme choice

* spec: add tests for shouldUseDarkColorsOverride

* chore: add missing forward declarations

* refactor: rename overrideShouldUseDarkColors to themeSource

* chore: only run appLevelAppearance specs on Mojave and up

* chore: update patch with more info and no define

* Update spec-main/api-native-theme-spec.ts

Co-Authored-By: Jeremy Apthorp <jeremya@chromium.org>

* Update api-native-theme-spec.ts

* Update api-native-theme-spec.ts

* Update api-native-theme-spec.ts

* fix: don't expose nativeTheme in the renderer process (#20139)

Exposing these in the renderer didn't make sense as they weren't backed
by the same instance / value store.  This API should be browser only
especially now that we have nativeTheme.themeSource.  Exposing in
//common was a mistake from the beginning.

* fix: emit updated on NativeTheme on the UI thread to avoid DCHECK (#20137)

* fix: emit updated on NativeTheme on the UI thread to avoid DCHECK

* Update atom_api_native_theme.cc

* spec: wait a few ticks for async events to emit so that test events do not leak into each other

* chore: add SetGTKDarkThemeEnabled(enabled) internal helper to allow dynamic theme selection on linux (#19964)

This is just a after-creation setter for the `darkTheme` constructor option.  This is delibrately
a method and not a property as there is no getter.

* spec: remove leftover .only
This commit is contained in:
Samuel Attard
2019-10-08 15:18:00 -07:00
committed by John Kleinschmidt
parent e17cd837ef
commit 0a9b201c34
21 changed files with 354 additions and 23 deletions

View File

@@ -2,7 +2,7 @@
> Read and respond to changes in Chromium's native color theme.
Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process)
Process: [Main](../glossary.md#main-process)
## Events
@@ -22,7 +22,38 @@ The `nativeTheme` module has the following properties:
### `nativeTheme.shouldUseDarkColors` _Readonly_
A `Boolean` for if the OS / Chromium currently has a dark mode enabled or is
being instructed to show a dark-style UI.
being instructed to show a dark-style UI. If you want to modify this value you
should use `themeSource` below.
### `nativeTheme.themeSource`
A `String` property that can be `system`, `light` or `dark`. It is used to override and supercede
the value that Chromium has chosen to use internally.
Setting this property to `system` will remove the override and
everything will be reset to the OS default. By default `themeSource` is `system`.
Settings this property to `dark` will have the following effects:
* `nativeTheme.shouldUseDarkColors` will be `true` when accessed
* Any UI Electron renders on Linux and Windows including context menus, devtools, etc. will use the dark UI.
* Any UI the OS renders on macOS including menus, window frames, etc. will use the dark UI.
* The [`prefers-color-scheme`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) CSS query will match `dark` mode.
* The `updated` event will be emitted
Settings this property to `light` will have the following effects:
* `nativeTheme.shouldUseDarkColors` will be `false` when accessed
* Any UI Electron renders on Linux and Windows including context menus, devtools, etc. will use the light UI.
* Any UI the OS renders on macOS including menus, window frames, etc. will use the light UI.
* The [`prefers-color-scheme`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) CSS query will match `light` mode.
* The `updated` event will be emitted
The usage of this property should align with a classic "dark mode" state machine in your application
where the user has three options.
* `Follow OS` --> `themeSource = 'system'`
* `Dark Mode` --> `themeSource = 'dark'`
* `Light Mode` --> `themeSource = 'light'`
Your application should then always use `shouldUseDarkColors` to determine what CSS to apply.
### `nativeTheme.shouldUseHighContrastColors` _macOS_ _Windows_ _Readonly_

View File

@@ -132,7 +132,6 @@ auto_filenames = {
"lib/common/api/deprecate.ts",
"lib/common/api/module-list.js",
"lib/common/api/native-image.js",
"lib/common/api/native-theme.ts",
"lib/common/api/shell.js",
"lib/common/buffer-utils.ts",
"lib/common/clipboard-utils.ts",
@@ -223,6 +222,7 @@ auto_filenames = {
"lib/browser/api/menu-utils.js",
"lib/browser/api/menu.js",
"lib/browser/api/module-list.js",
"lib/browser/api/native-theme.ts",
"lib/browser/api/net-log.js",
"lib/browser/api/net.js",
"lib/browser/api/notification.js",
@@ -264,7 +264,6 @@ auto_filenames = {
"lib/common/api/exports/electron.js",
"lib/common/api/module-list.js",
"lib/common/api/native-image.js",
"lib/common/api/native-theme.ts",
"lib/common/api/shell.js",
"lib/common/buffer-utils.ts",
"lib/common/clipboard-utils.ts",
@@ -290,7 +289,6 @@ auto_filenames = {
"lib/common/api/exports/electron.js",
"lib/common/api/module-list.js",
"lib/common/api/native-image.js",
"lib/common/api/native-theme.ts",
"lib/common/api/shell.js",
"lib/common/buffer-utils.ts",
"lib/common/clipboard-utils.ts",
@@ -341,7 +339,6 @@ auto_filenames = {
"lib/common/api/exports/electron.js",
"lib/common/api/module-list.js",
"lib/common/api/native-image.js",
"lib/common/api/native-theme.ts",
"lib/common/api/shell.js",
"lib/common/buffer-utils.ts",
"lib/common/clipboard-utils.ts",

View File

@@ -65,6 +65,9 @@ filenames = {
"shell/browser/api/atom_api_menu_mac.mm",
"shell/browser/api/atom_api_menu_views.cc",
"shell/browser/api/atom_api_menu_views.h",
"shell/browser/api/atom_api_native_theme.cc",
"shell/browser/api/atom_api_native_theme.h",
"shell/browser/api/atom_api_native_theme_mac.mm",
"shell/browser/api/atom_api_net.cc",
"shell/browser/api/atom_api_net.h",
"shell/browser/api/atom_api_net_log.cc",
@@ -423,8 +426,6 @@ filenames = {
"shell/common/api/atom_api_native_image.cc",
"shell/common/api/atom_api_native_image.h",
"shell/common/api/atom_api_native_image_mac.mm",
"shell/common/api/atom_api_native_theme.cc",
"shell/common/api/atom_api_native_theme.h",
"shell/common/api/atom_api_shell.cc",
"shell/common/api/atom_api_v8_util.cc",
"shell/common/api/electron_bindings.cc",

View File

@@ -18,6 +18,7 @@ module.exports = [
{ name: 'inAppPurchase', loader: () => require('./in-app-purchase') },
{ name: 'Menu', loader: () => require('./menu') },
{ name: 'MenuItem', loader: () => require('./menu-item') },
{ name: 'nativeTheme', loader: () => require('./native-theme') },
{ name: 'net', loader: () => require('./net') },
{ name: 'netLog', loader: () => require('./net-log') },
{ name: 'Notification', loader: () => require('./notification') },

View File

@@ -4,7 +4,6 @@
module.exports = [
{ name: 'clipboard', loader: () => require('./clipboard') },
{ name: 'nativeImage', loader: () => require('./native-image') },
{ name: 'nativeTheme', loader: () => require('./native-theme') },
{ name: 'shell', loader: () => require('./shell') },
// The internal modules, invisible unless you know their names.
{ name: 'deprecate', loader: () => require('./deprecate'), private: true }

View File

@@ -14,6 +14,7 @@
"@types/fs-extra": "^5.0.5",
"@types/mocha": "^5.2.6",
"@types/node": "^12.0.10",
"@types/semver": "^6.0.1",
"@types/split": "^1.0.0",
"@types/webpack": "^4.4.32",
"@types/webpack-env": "^1.13.9",
@@ -125,4 +126,4 @@
"git add filenames.auto.gni"
]
}
}
}

View File

@@ -78,3 +78,4 @@ ssl_security_state_tab_helper.patch
revert_cleanup_remove_menu_subtitles_sublabels.patch
expose_setuseragent_on_networkcontext.patch
net_avoid_vector_const_elements.patch
feat_add_set_theme_source_to_allow_apps_to.patch

View File

@@ -0,0 +1,89 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samuel Attard <sattard@slack-corp.com>
Date: Mon, 26 Aug 2019 14:32:41 -0700
Subject: feat: add set_theme_source to allow apps to override chromiums
internal theme choice
This patch is required as Chromium doesn't currently let folks using
//ui override the theme choice in NativeTheme. It defaults to
respecting the OS theme choice and some apps don't always want to do
that. With this patch we can override the theme value that Chromium
uses internally for things like menus and devtools.
We can remove this patch once it has in some shape been upstreamed.
diff --git a/ui/native_theme/native_theme.cc b/ui/native_theme/native_theme.cc
index 2370d15332c8c6c7dc7e3403b38891c885704d9f..171214379437f319d3feccc289a5d91e74b77f9e 100644
--- a/ui/native_theme/native_theme.cc
+++ b/ui/native_theme/native_theme.cc
@@ -40,6 +40,8 @@ NativeTheme::NativeTheme()
NativeTheme::~NativeTheme() = default;
bool NativeTheme::ShouldUseDarkColors() const {
+ if (theme_source() == ThemeSource::kForcedLight) return false;
+ if (theme_source() == ThemeSource::kForcedDark) return true;
return should_use_dark_colors_;
}
diff --git a/ui/native_theme/native_theme.h b/ui/native_theme/native_theme.h
index 70389e0245993faa2c17e9deefeb000280ef2368..cef1c0d4706e7e720a4004ca54765a39fc29c5e8 100644
--- a/ui/native_theme/native_theme.h
+++ b/ui/native_theme/native_theme.h
@@ -429,6 +429,22 @@ class NATIVE_THEME_EXPORT NativeTheme {
ColorId color_id,
ColorScheme color_scheme = ColorScheme::kDefault) const = 0;
+ enum ThemeSource {
+ kSystem,
+ kForcedDark,
+ kForcedLight,
+ };
+
+ ThemeSource theme_source() const {
+ return theme_source_;
+ }
+
+ void set_theme_source(ThemeSource theme_source) {
+ bool original = ShouldUseDarkColors();
+ theme_source_ = theme_source;
+ if (ShouldUseDarkColors() != original) NotifyObservers();
+ }
+
// Returns a shared instance of the native theme that should be used for web
// rendering. Do not use it in a normal application context (i.e. browser).
// The returned object should not be deleted by the caller. This function is
@@ -547,6 +563,8 @@ class NATIVE_THEME_EXPORT NativeTheme {
PreferredColorScheme preferred_color_scheme_ =
PreferredColorScheme::kNoPreference;
+ ThemeSource theme_source_ = ThemeSource::kSystem;
+
DISALLOW_COPY_AND_ASSIGN(NativeTheme);
};
diff --git a/ui/native_theme/native_theme_dark_aura.cc b/ui/native_theme/native_theme_dark_aura.cc
index a8fbfee3b13672902aac05fd5a65fa8ee81f9f7e..1be6369acf0b7c02a6f862636c2b2de1fbf8cb5a 100644
--- a/ui/native_theme/native_theme_dark_aura.cc
+++ b/ui/native_theme/native_theme_dark_aura.cc
@@ -20,6 +20,8 @@ SkColor NativeThemeDarkAura::GetSystemColor(ColorId color_id,
}
bool NativeThemeDarkAura::ShouldUseDarkColors() const {
+ if (theme_source() == ThemeSource::kForcedLight) return false;
+ if (theme_source() == ThemeSource::kForcedDark) return true;
return true;
}
diff --git a/ui/native_theme/native_theme_win.cc b/ui/native_theme/native_theme_win.cc
index 3003643bfb78cec2f5e84fc9e1471e1ef54aae41..06f2cbc84401958d49445f4ce6acb1b2fef0aa04 100644
--- a/ui/native_theme/native_theme_win.cc
+++ b/ui/native_theme/native_theme_win.cc
@@ -611,6 +611,8 @@ bool NativeThemeWin::ShouldUseDarkColors() const {
// ...unless --force-dark-mode was specified in which case caveat emptor.
if (UsesHighContrastColors() && !IsForcedDarkMode())
return false;
+ if (theme_source() == ThemeSource::kForcedLight) return false;
+ if (theme_source() == ThemeSource::kForcedDark) return true;
return NativeTheme::ShouldUseDarkColors();
}

View File

@@ -2,8 +2,13 @@
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "shell/common/api/atom_api_native_theme.h"
#include "shell/browser/api/atom_api_native_theme.h"
#include <string>
#include "base/task/post_task.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h"
#include "shell/common/node_includes.h"
@@ -24,10 +29,31 @@ NativeTheme::~NativeTheme() {
theme_->RemoveObserver(this);
}
void NativeTheme::OnNativeThemeUpdated(ui::NativeTheme* theme) {
void NativeTheme::OnNativeThemeUpdatedOnUI() {
Emit("updated");
}
void NativeTheme::OnNativeThemeUpdated(ui::NativeTheme* theme) {
base::PostTaskWithTraits(
FROM_HERE, {content::BrowserThread::UI},
base::BindOnce(&NativeTheme::OnNativeThemeUpdatedOnUI,
base::Unretained(this)));
}
void NativeTheme::SetThemeSource(ui::NativeTheme::ThemeSource override) {
theme_->set_theme_source(override);
#if defined(OS_MACOSX)
// Update the macOS appearance setting for this new override value
UpdateMacOSAppearanceForOverrideValue(override);
#endif
// TODO(MarshallOfSound): Update all existing browsers windows to use GTK dark
// theme
}
ui::NativeTheme::ThemeSource NativeTheme::GetThemeSource() const {
return theme_->theme_source();
}
bool NativeTheme::ShouldUseDarkColors() {
return theme_->ShouldUseDarkColors();
}
@@ -68,6 +94,8 @@ void NativeTheme::BuildPrototype(v8::Isolate* isolate,
prototype->SetClassName(mate::StringToV8(isolate, "NativeTheme"));
mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
.SetProperty("shouldUseDarkColors", &NativeTheme::ShouldUseDarkColors)
.SetProperty("themeSource", &NativeTheme::GetThemeSource,
&NativeTheme::SetThemeSource)
.SetProperty("shouldUseHighContrastColors",
&NativeTheme::ShouldUseHighContrastColors)
.SetProperty("shouldUseInvertedColorScheme",
@@ -94,4 +122,42 @@ void Initialize(v8::Local<v8::Object> exports,
} // namespace
namespace mate {
v8::Local<v8::Value> Converter<ui::NativeTheme::ThemeSource>::ToV8(
v8::Isolate* isolate,
const ui::NativeTheme::ThemeSource& val) {
switch (val) {
case ui::NativeTheme::ThemeSource::kForcedDark:
return mate::ConvertToV8(isolate, "dark");
case ui::NativeTheme::ThemeSource::kForcedLight:
return mate::ConvertToV8(isolate, "light");
case ui::NativeTheme::ThemeSource::kSystem:
default:
return mate::ConvertToV8(isolate, "system");
}
}
bool Converter<ui::NativeTheme::ThemeSource>::FromV8(
v8::Isolate* isolate,
v8::Local<v8::Value> val,
ui::NativeTheme::ThemeSource* out) {
std::string theme_source;
if (mate::ConvertFromV8(isolate, val, &theme_source)) {
if (theme_source == "dark") {
*out = ui::NativeTheme::ThemeSource::kForcedDark;
} else if (theme_source == "light") {
*out = ui::NativeTheme::ThemeSource::kForcedLight;
} else if (theme_source == "system") {
*out = ui::NativeTheme::ThemeSource::kSystem;
} else {
return false;
}
return true;
}
return false;
}
} // namespace mate
NODE_LINKED_MODULE_CONTEXT_AWARE(atom_common_native_theme, Initialize)

View File

@@ -2,11 +2,12 @@
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef SHELL_COMMON_API_ATOM_API_NATIVE_THEME_H_
#define SHELL_COMMON_API_ATOM_API_NATIVE_THEME_H_
#ifndef SHELL_BROWSER_API_ATOM_API_NATIVE_THEME_H_
#define SHELL_BROWSER_API_ATOM_API_NATIVE_THEME_H_
#include "native_mate/handle.h"
#include "shell/browser/api/event_emitter.h"
#include "ui/native_theme/native_theme.h"
#include "ui/native_theme/native_theme_observer.h"
namespace electron {
@@ -25,12 +26,19 @@ class NativeTheme : public mate::EventEmitter<NativeTheme>,
NativeTheme(v8::Isolate* isolate, ui::NativeTheme* theme);
~NativeTheme() override;
void SetThemeSource(ui::NativeTheme::ThemeSource override);
#if defined(OS_MACOSX)
void UpdateMacOSAppearanceForOverrideValue(
ui::NativeTheme::ThemeSource override);
#endif
ui::NativeTheme::ThemeSource GetThemeSource() const;
bool ShouldUseDarkColors();
bool ShouldUseHighContrastColors();
bool ShouldUseInvertedColorScheme();
// ui::NativeThemeObserver:
void OnNativeThemeUpdated(ui::NativeTheme* theme) override;
void OnNativeThemeUpdatedOnUI();
private:
ui::NativeTheme* theme_;
@@ -42,4 +50,17 @@ class NativeTheme : public mate::EventEmitter<NativeTheme>,
} // namespace electron
#endif // SHELL_COMMON_API_ATOM_API_NATIVE_THEME_H_
namespace mate {
template <>
struct Converter<ui::NativeTheme::ThemeSource> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
const ui::NativeTheme::ThemeSource& val);
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
ui::NativeTheme::ThemeSource* out);
};
} // namespace mate
#endif // SHELL_BROWSER_API_ATOM_API_NATIVE_THEME_H_

View File

@@ -0,0 +1,37 @@
// Copyright (c) 2019 Slack Technologies, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "shell/browser/api/atom_api_native_theme.h"
#include "base/mac/sdk_forward_declarations.h"
#include "shell/browser/mac/atom_application.h"
namespace electron {
namespace api {
void NativeTheme::UpdateMacOSAppearanceForOverrideValue(
ui::NativeTheme::ThemeSource override) {
if (@available(macOS 10.14, *)) {
NSAppearance* new_appearance;
switch (override) {
case ui::NativeTheme::ThemeSource::kForcedDark:
new_appearance =
[NSAppearance appearanceNamed:NSAppearanceNameDarkAqua];
break;
case ui::NativeTheme::ThemeSource::kForcedLight:
new_appearance = [NSAppearance appearanceNamed:NSAppearanceNameAqua];
break;
case ui::NativeTheme::ThemeSource::kSystem:
default:
new_appearance = nil;
break;
}
[[NSApplication sharedApplication] setAppearance:new_appearance];
}
}
} // namespace api
} // namespace electron

View File

@@ -866,6 +866,10 @@ void TopLevelWindow::CloseFilePreview() {
window_->CloseFilePreview();
}
void TopLevelWindow::SetGTKDarkThemeEnabled(bool use_dark_theme) {
window_->SetGTKDarkThemeEnabled(use_dark_theme);
}
v8::Local<v8::Value> TopLevelWindow::GetContentView() const {
if (content_view_.IsEmpty())
return v8::Null(isolate());

View File

@@ -198,6 +198,7 @@ class TopLevelWindow : public mate::TrackableObject<TopLevelWindow>,
void SetAspectRatio(double aspect_ratio, mate::Arguments* args);
void PreviewFile(const std::string& path, mate::Arguments* args);
void CloseFilePreview();
void SetGTKDarkThemeEnabled(bool use_dark_theme);
// Public getters of NativeWindow.
v8::Local<v8::Value> GetContentView() const;

View File

@@ -218,6 +218,8 @@ class NativeWindow : public base::SupportsUserData,
const std::string& display_name);
virtual void CloseFilePreview();
virtual void SetGTKDarkThemeEnabled(bool use_dark_theme) = 0;
// Converts between content bounds and window bounds.
virtual gfx::Rect ContentBoundsToWindowBounds(
const gfx::Rect& bounds) const = 0;

View File

@@ -135,6 +135,7 @@ class NativeWindowMac : public NativeWindow {
const std::vector<mate::PersistentDictionary>& items) override;
void RefreshTouchBarItem(const std::string& item_id) override;
void SetEscapeTouchBarItem(const mate::PersistentDictionary& item) override;
void SetGTKDarkThemeEnabled(bool use_dark_theme) override {}
gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& bounds) const override;
gfx::Rect WindowBoundsToContentBounds(const gfx::Rect& bounds) const override;

View File

@@ -213,12 +213,7 @@ NativeWindowViews::NativeWindowViews(const mate::Dictionary& options,
// Set _GTK_THEME_VARIANT to dark if we have "dark-theme" option set.
bool use_dark_theme = false;
if (options.Get(options::kDarkTheme, &use_dark_theme) && use_dark_theme) {
XDisplay* xdisplay = gfx::GetXDisplay();
XChangeProperty(xdisplay, GetAcceleratedWidget(),
XInternAtom(xdisplay, "_GTK_THEME_VARIANT", x11::False),
XInternAtom(xdisplay, "UTF8_STRING", x11::False), 8,
PropModeReplace,
reinterpret_cast<const unsigned char*>("dark"), 4);
SetGTKDarkThemeEnabled(use_dark_theme);
}
// Before the window is mapped the SetWMSpecState can not work, so we have
@@ -329,6 +324,25 @@ NativeWindowViews::~NativeWindowViews() {
#endif
}
void NativeWindowViews::SetGTKDarkThemeEnabled(bool use_dark_theme) {
#if defined(USE_X11)
XDisplay* xdisplay = gfx::GetXDisplay();
if (use_dark_theme) {
XChangeProperty(xdisplay, GetAcceleratedWidget(),
XInternAtom(xdisplay, "_GTK_THEME_VARIANT", x11::False),
XInternAtom(xdisplay, "UTF8_STRING", x11::False), 8,
PropModeReplace,
reinterpret_cast<const unsigned char*>("dark"), 4);
} else {
XChangeProperty(xdisplay, GetAcceleratedWidget(),
XInternAtom(xdisplay, "_GTK_THEME_VARIANT", x11::False),
XInternAtom(xdisplay, "UTF8_STRING", x11::False), 8,
PropModeReplace,
reinterpret_cast<const unsigned char*>("light"), 5);
}
#endif
}
void NativeWindowViews::SetContentView(views::View* view) {
if (content_view()) {
root_view_->RemoveChildView(content_view());

View File

@@ -124,6 +124,8 @@ class NativeWindowViews : public NativeWindow,
bool IsVisibleOnAllWorkspaces() override;
void SetGTKDarkThemeEnabled(bool use_dark_theme) override;
gfx::AcceleratedWidget GetAcceleratedWidget() const override;
NativeWindowHandle GetNativeWindowHandle() const override;

View File

@@ -1,5 +1,10 @@
import { expect } from 'chai'
import { nativeTheme } from 'electron'
import { nativeTheme, systemPreferences } from 'electron'
import * as os from 'os'
import * as semver from 'semver'
import { delay, ifdescribe } from './spec-helpers'
import { emittedOnce } from './events-helpers';
describe('nativeTheme module', () => {
describe('nativeTheme.shouldUseDarkColors', () => {
@@ -8,6 +13,57 @@ describe('nativeTheme module', () => {
})
})
describe('nativeTheme.themeSource', () => {
afterEach(async () => {
nativeTheme.themeSource = 'system'
// Wait for any pending events to emit
await delay(20)
})
it('is system by default', () => {
expect(nativeTheme.themeSource).to.equal('system')
})
it('should override the value of shouldUseDarkColors', () => {
nativeTheme.themeSource = 'dark'
expect(nativeTheme.shouldUseDarkColors).to.equal(true)
nativeTheme.themeSource = 'light'
expect(nativeTheme.shouldUseDarkColors).to.equal(false)
})
it('should emit the "updated" event when it is set and the resulting "shouldUseDarkColors" value changes', async () => {
let updatedEmitted = emittedOnce(nativeTheme, 'updated')
nativeTheme.themeSource = 'dark'
await updatedEmitted
updatedEmitted = emittedOnce(nativeTheme, 'updated')
nativeTheme.themeSource = 'light'
await updatedEmitted
})
it('should not emit the "updated" event when it is set and the resulting "shouldUseDarkColors" value is the same', async () => {
nativeTheme.themeSource = 'dark'
// Wait a few ticks to allow an async events to flush
await delay(20)
let called = false
nativeTheme.once('updated', () => {
called = true
})
nativeTheme.themeSource = 'dark'
// Wait a few ticks to allow an async events to flush
await delay(20)
expect(called).to.equal(false)
})
ifdescribe(process.platform === 'darwin' && semver.gte(os.release(), '18.0.0'))('on macOS 10.14', () => {
it('should update appLevelAppearance when set', () => {
nativeTheme.themeSource = 'dark'
expect(systemPreferences.appLevelAppearance).to.equal('dark')
nativeTheme.themeSource = 'light'
expect(systemPreferences.appLevelAppearance).to.equal('light')
})
})
})
describe('nativeTheme.shouldUseInvertedColorScheme', () => {
it('returns a boolean', () => {
expect(nativeTheme.shouldUseInvertedColorScheme).to.be.a('boolean')

View File

@@ -1,2 +1,4 @@
export const ifit = (condition: boolean) => (condition ? it : it.skip)
export const ifdescribe = (condition: boolean) => (condition ? describe : describe.skip)
export const ifdescribe = (condition: boolean) => (condition ? describe : describe.skip)
export const delay = (time: number) => new Promise(r => setTimeout(r, time))

View File

@@ -239,6 +239,11 @@
resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c"
integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==
"@types/semver@^6.0.1":
version "6.0.1"
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-6.0.1.tgz#a984b405c702fa5a7ec6abc56b37f2ba35ef5af6"
integrity sha512-ffCdcrEE5h8DqVxinQjo+2d1q+FV5z7iNtPofw3JsrltSoSVlOGaW0rY8XxtO9XukdTn8TaCGWmk2VFGhI70mg==
"@types/serve-static@*":
version "1.13.2"
resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.2.tgz#f5ac4d7a6420a99a6a45af4719f4dcd8cd907a48"