Skip to content

Commit 3c79cd1

Browse files
feat(elements): listen to prefers-color-scheme event to switch theme (#3518)
1 parent 8310717 commit 3c79cd1

File tree

3 files changed

+32
-23
lines changed

3 files changed

+32
-23
lines changed

packages/elements/src/components/app/app.component.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint-disable @typescript-eslint/no-unsafe-enum-comparison */
22
import type { PropertyValues } from 'lit';
3-
import { html, nothing, unsafeCSS, isServer } from 'lit';
4-
import { customElement, property } from 'lit/decorators.js';
3+
import { html, isServer, nothing, unsafeCSS } from 'lit';
4+
import { customElement, property, query } from 'lit/decorators.js';
55
import type {
66
FileUnderTestModel,
77
Metrics,
@@ -24,10 +24,9 @@ import { mutantChanges } from '../../lib/mutant-changes.js';
2424
import { locationChange$, View } from '../../lib/router.js';
2525
import type { Theme } from '../../lib/theme.js';
2626
import { globals, tailwind } from '../../style/index.js';
27+
import { type MutationTestReportFilePickerComponent } from '../file-picker/file-picker.component.js';
2728
import { RealTimeElement } from '../real-time-element.js';
2829
import theme from './theme.scss?inline';
29-
import { type MutationTestReportFilePickerComponent } from '../file-picker/file-picker.component.js';
30-
import { createRef, ref } from 'lit/directives/ref.js';
3130

3231
interface BaseContext {
3332
path: string[];
@@ -88,7 +87,10 @@ export class MutationTestReportAppComponent extends RealTimeElement {
8887
return getComputedStyle(this).getPropertyValue('--mut-body-bg');
8988
}
9089

91-
#filePickerRef = createRef<MutationTestReportFilePickerComponent>();
90+
@query('mte-file-picker')
91+
private declare filePicker: MutationTestReportFilePickerComponent;
92+
93+
#abortController = new AbortController();
9294

9395
@property()
9496
public get title(): string {
@@ -161,6 +163,10 @@ export class MutationTestReportAppComponent extends RealTimeElement {
161163
}
162164
}
163165

166+
#handlePrefersColorScheme = () => {
167+
this.theme = this.getTheme();
168+
};
169+
164170
private getTheme(): Theme {
165171
// 1. check local storage
166172
const theme = isLocalStorageAvailable() && localStorage.getItem('mutation-testing-elements-theme');
@@ -246,6 +252,9 @@ export class MutationTestReportAppComponent extends RealTimeElement {
246252

247253
public connectedCallback() {
248254
super.connectedCallback();
255+
window
256+
.matchMedia('(prefers-color-scheme: dark)')
257+
.addEventListener?.('change', this.#handlePrefersColorScheme, { signal: this.#abortController.signal });
249258
this.subscriptions.push(locationChange$.subscribe((path) => (this.path = path)));
250259
this.initializeSse();
251260
}
@@ -328,6 +337,7 @@ export class MutationTestReportAppComponent extends RealTimeElement {
328337

329338
public disconnectedCallback() {
330339
super.disconnectedCallback();
340+
this.#abortController.abort();
331341
this.subscriptions.forEach((subscription) => subscription.unsubscribe());
332342
}
333343

@@ -347,15 +357,15 @@ export class MutationTestReportAppComponent extends RealTimeElement {
347357
public render() {
348358
if (this.context.result ?? this.errorMessage) {
349359
return html`
350-
<mte-file-picker ${ref(this.#filePickerRef)} .rootModel="${this.rootModel}"></mte-file-picker>
360+
<mte-file-picker .rootModel="${this.rootModel}"></mte-file-picker>
351361
<div class="container bg-white pb-4 font-sans text-gray-800 motion-safe:transition-max-width">
352362
<div class="space-y-4 transition-colors">
353363
${this.renderErrorMessage()}
354364
<mte-theme-switch @theme-switch="${this.themeSwitch}" class="sticky top-offset z-20 float-right pt-6" .theme="${this.theme}">
355365
</mte-theme-switch>
356366
${this.renderTitle()} ${this.renderTabs()}
357367
<mte-breadcrumb
358-
@mte-file-picker-open="${() => this.#filePickerRef.value?.open()}"
368+
@mte-file-picker-open="${() => this.filePicker.open()}"
359369
.view="${this.context.view}"
360370
.path="${this.context.path}"
361371
></mte-breadcrumb>

packages/elements/src/components/drawer/drawer.component.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import { ResizeController } from '@lit-labs/observers/resize-controller.js';
22
import { html, LitElement, nothing, unsafeCSS } from 'lit';
3-
import { customElement, property } from 'lit/decorators.js';
3+
import { customElement, property, query } from 'lit/decorators.js';
44
import { classMap } from 'lit/directives/class-map.js';
5-
import type { Ref } from 'lit/directives/ref.js';
6-
import { createRef, ref } from 'lit/directives/ref.js';
75
import { renderIf } from '../../lib/html-helpers.js';
86
import { tailwind } from '../../style/index.js';
97
import { renderEmoji } from '../drawer-mutant/util.js';
@@ -34,7 +32,8 @@ export class MutationTestReportDrawer extends LitElement {
3432
}
3533
}
3634

37-
#headerRef: Ref<HTMLElement>;
35+
@query('header')
36+
private declare header: HTMLElement | undefined;
3837

3938
#contentHeightController: ResizeController<number>;
4039

@@ -46,11 +45,10 @@ export class MutationTestReportDrawer extends LitElement {
4645
this.hasDetail = false;
4746
this.#abortController = new AbortController();
4847

49-
this.#headerRef = createRef();
5048
this.#contentHeightController = new ResizeController(this, {
5149
callback: (entries) => {
5250
const total = entries[0]?.contentRect.height ?? 0;
53-
const header = this.#headerRef.value?.clientHeight ?? 0;
51+
const header = this.header?.clientHeight ?? 0;
5452
return total - header;
5553
},
5654
});
@@ -87,7 +85,7 @@ export class MutationTestReportDrawer extends LitElement {
8785
const height = this.#contentHeightController.value;
8886

8987
return html`<aside @click="${(event: Event) => event.stopPropagation()}" class="ml-6 mr-4">
90-
<header class="w-full py-4" ${ref(this.#headerRef)}>
88+
<header class="w-full py-4">
9189
<h2>
9290
<slot name="header"></slot>
9391
${renderIf(

packages/elements/src/components/file/file.component.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import type { PropertyValues } from 'lit';
22
import { html, nothing, svg, unsafeCSS } from 'lit';
3-
import { customElement, property, state } from 'lit/decorators.js';
3+
import { customElement, property, query, state } from 'lit/decorators.js';
44
import { map } from 'lit/directives/map.js';
5-
import { createRef, ref } from 'lit/directives/ref.js';
65
import type { FileUnderTestModel, MutantModel } from 'mutation-testing-metrics';
76
import type { MutantResult, MutantStatus } from 'mutation-testing-report-schema/api';
87
import { findDiffIndices, gte, highlightCode, transformHighlightedLines } from '../../lib/code-helpers.js';
@@ -39,9 +38,10 @@ export class FileComponent extends RealTimeElement {
3938
@state()
4039
public declare mutants: MutantModel[];
4140

42-
#abortController: AbortController;
41+
@query('code')
42+
private declare code: HTMLElement;
4343

44-
private codeRef = createRef<HTMLElement>();
44+
#abortController: AbortController;
4545

4646
public constructor() {
4747
super();
@@ -124,7 +124,7 @@ export class FileComponent extends RealTimeElement {
124124
id="report-code-block"
125125
class="line-numbers ${this.selectedMutantStates.map((state) => `mte-selected-${state}`).join(' ')} flex rounded-md py-4"
126126
>
127-
<code ${ref(this.codeRef)} class="flex language-${this.model.language}">
127+
<code class="flex language-${this.model.language}">
128128
<table>${map(this.lines, (line, lineIndex) => {
129129
const lineNr = lineIndex + 1;
130130
const mutantDots = this.renderMutantDots(mutantLineMap.get(lineNr));
@@ -180,7 +180,7 @@ export class FileComponent extends RealTimeElement {
180180
}
181181

182182
this.selectedMutant = mutant;
183-
const lines = this.codeRef.value!.querySelectorAll('tr.line');
183+
const lines = this.code.querySelectorAll('tr.line');
184184
for (let i = mutant.location.start.line - 1; i < mutant.location.end.line; i++) {
185185
lines.item(i).classList.add(diffOldClass);
186186
}
@@ -192,9 +192,10 @@ export class FileComponent extends RealTimeElement {
192192
}
193193

194194
private removeCurrentDiff() {
195-
const oldDiffLines = this.codeRef.value!.querySelectorAll(`.${diffOldClass}`);
195+
const code = this.code;
196+
const oldDiffLines = code.querySelectorAll(`.${diffOldClass}`);
196197
oldDiffLines.forEach((oldDiffLine) => oldDiffLine.classList.remove(diffOldClass));
197-
const newDiffLines = this.codeRef.value!.querySelectorAll(`.${diffNewClass}`);
198+
const newDiffLines = code.querySelectorAll(`.${diffNewClass}`);
198199
newDiffLines.forEach((newDiffLine) => newDiffLine.remove());
199200
}
200201

@@ -295,7 +296,7 @@ export class FileComponent extends RealTimeElement {
295296
}
296297

297298
#animateMutantToggle(mutant: MutantModel) {
298-
beginElementAnimation(this.codeRef.value, 'mutant-id', mutant.id);
299+
beginElementAnimation(this.code, 'mutant-id', mutant.id);
299300
}
300301
}
301302

0 commit comments

Comments
 (0)