-
Notifications
You must be signed in to change notification settings - Fork 37
Expand file tree
/
Copy paththeme-switch-element.ts
More file actions
64 lines (54 loc) · 1.93 KB
/
theme-switch-element.ts
File metadata and controls
64 lines (54 loc) · 1.93 KB
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
import {
getDocumentTheme,
THEME_CHANGE_EVENT,
type ThemePreference
} from '../lib/theme'
// Theme switch works by dispatching and listening to
// theme change events to keep UI in sync
class ThemeSwitchElement extends HTMLElement {
connectedCallback() {
this.addEventListener('change', this.handleToggle as EventListener)
this.syncUI(getDocumentTheme())
document.addEventListener(
THEME_CHANGE_EVENT,
this.handleThemeChange as EventListener
)
}
disconnectedCallback() {
this.removeEventListener('change', this.handleToggle as EventListener)
document.removeEventListener(
THEME_CHANGE_EVENT,
this.handleThemeChange as EventListener
)
}
private handleToggle = (event: Event) => {
const target = event.target as HTMLInputElement | null
if (!target || target.type !== 'checkbox') return
const theme: ThemePreference = target.checked ? 'dark' : 'light'
document.dispatchEvent(
new CustomEvent<ThemePreference>(THEME_CHANGE_EVENT, { detail: theme })
)
}
private handleThemeChange = (event: Event) => {
const theme = (event as CustomEvent<ThemePreference>).detail
this.syncUI(theme)
}
private syncUI(theme: ThemePreference) {
const checkbox = this.querySelector(
'input[type="checkbox"]'
) as HTMLInputElement | null
const sunIcon = this.querySelector('#sun') as HTMLElement | null
const moonIcon = this.querySelector('#moon') as HTMLElement | null
if (!checkbox || !sunIcon || !moonIcon) return
const isDark = theme === 'dark'
this.setAttribute('checked', `${isDark}`)
this.setAttribute('aria-checked', `${isDark}`)
checkbox.checked = isDark
checkbox.setAttribute('aria-checked', `${isDark}`)
sunIcon.style.display = isDark ? 'block' : 'none'
moonIcon.style.display = isDark ? 'none' : 'block'
}
}
if (!customElements.get('theme-switch')) {
customElements.define('theme-switch', ThemeSwitchElement)
}