-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.ts
67 lines (52 loc) · 2.25 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import { LitElement, customElement, property, html, PropertyValues } from 'lit-element'
export type ThemeEvent = CustomEvent<Theme>
declare global {
interface HTMLElementEventMap {
'theme-change': ThemeEvent
}
}
const enum Theme {
DARK = 'dark',
LIGHT = 'light',
}
// Check for dark mode preference at the OS level
const darkMatchMedia = matchMedia("(prefers-color-scheme: dark)")
@customElement('theme-toggle')
export default class extends LitElement {
@property({ type: Boolean })
persistent = false
@property({ type: String, reflect: true })
theme = darkMatchMedia.matches ? Theme.DARK : Theme.LIGHT
// TODO should this be cached?
private readonly stylesheets: Record<Theme, readonly HTMLLinkElement[]> = {
[Theme.LIGHT]: [],
[Theme.DARK]: [],
}
protected firstUpdated() {
darkMatchMedia.addEventListener('change', ({matches}) => this.theme = matches ? Theme.DARK : Theme.LIGHT)
for (const theme of [Theme.DARK, Theme.LIGHT])
// We need to support `media="(prefers-color-scheme: dark)"` (with space)
// and `media="(prefers-color-scheme:dark)"` (without space)
this.stylesheets[theme] = document
.querySelectorAll(`link[rel=stylesheet][media*=prefers-color-scheme][media*="${theme}"]`) as unknown as HTMLLinkElement[]
}
protected updated(changed: PropertyValues) {
if (changed.has('persistent') && this.persistent)
this.theme = localStorage.getItem('theme') as Theme ?? this.theme
if (changed.has('theme')) {
document.body.setAttribute('theme', this.theme)
if (changed.get('theme')) // Not the first load to avoid the flicker
for (const theme of [Theme.DARK, Theme.LIGHT])
for (const stylesheet of this.stylesheets[theme]) {
stylesheet.disabled = theme != this.theme
stylesheet.media = theme == this.theme ? 'all' : 'not all'
}
if (this.persistent)
localStorage.setItem('theme', this.theme)
this.dispatchEvent(new CustomEvent('theme-change', { detail: this.theme }))
}
}
protected readonly render = () => this.theme == Theme.LIGHT
? html`<slot name="light" @click=${() => this.theme = Theme.DARK}></slot>`
: html`<slot name="dark" @click=${() => this.theme = Theme.LIGHT}></slot>`
}