Skip to content

Commit 1efbc91

Browse files
committed
Update useTheme
1 parent caebbe4 commit 1efbc91

File tree

4 files changed

+40
-22
lines changed

4 files changed

+40
-22
lines changed

packages/react/src/hooks/__tests__/use-theme.browser.test.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,31 @@ import { renderHook, waitFor } from '@testing-library/react'
22

33
beforeEach(() => {
44
vi.resetModules()
5+
vi.resetAllMocks()
56
})
67

78
describe('useTheme', () => {
89
it('should return theme', async () => {
910
const { useTheme } = await import('../use-theme')
10-
const { result } = renderHook(() => useTheme())
11+
const { result, unmount } = renderHook(() => useTheme())
1112
expect(result.current).toBeNull()
1213

1314
document.documentElement.setAttribute('data-theme', 'dark')
1415
await waitFor(() => {
1516
expect(result.current).toBe('dark')
1617
})
17-
const { result: newResult } = renderHook(() => useTheme())
18+
const { result: newResult, unmount: newUnmount } = renderHook(() =>
19+
useTheme(),
20+
)
1821
expect(newResult.current).toBe('dark')
22+
newUnmount()
23+
unmount()
1924
})
2025
it('should return theme when already set', async () => {
2126
const { useTheme } = await import('../use-theme')
2227
document.documentElement.setAttribute('data-theme', 'dark')
23-
const { result } = renderHook(() => useTheme())
28+
const { result, unmount } = renderHook(() => useTheme())
2429
expect(result.current).toBe('dark')
30+
unmount()
2531
})
2632
})

packages/react/src/hooks/use-theme.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
'use client'
22

33
import { useSyncExternalStore } from 'react'
4-
import { themeStore } from 'src/stores/themeStore'
4+
5+
import { createThemeStore } from '../stores/theme-store'
6+
7+
const themeStore = createThemeStore()
58

69
export function useTheme() {
710
const theme = useSyncExternalStore(
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
beforeEach(() => {
2+
vi.resetModules()
3+
})
4+
5+
describe('themeStore', () => {
6+
it('should return themeStore object for browser', async () => {
7+
const { createThemeStore } = await import('../theme-store')
8+
const themeStore = createThemeStore()
9+
expect(themeStore).toBeDefined()
10+
expect(themeStore.get).toEqual(expect.any(Function))
11+
expect(themeStore.set).toEqual(expect.any(Function))
12+
expect(themeStore.subscribe).toEqual(expect.any(Function))
13+
expect(themeStore.get()).toBeNull()
14+
expect(themeStore.set('dark' as any)).toBeUndefined()
15+
expect(themeStore.subscribe(() => {})()).toBeUndefined()
16+
themeStore.subscribe(() => {})
17+
expect(themeStore.set('dark' as any)).toBeUndefined()
18+
})
19+
})
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,23 @@
11
'use client'
2-
3-
import { DevupTheme } from '@devup-ui/react'
2+
import type { DevupTheme } from '../types/theme'
43

54
type Theme = keyof DevupTheme | null
65
type StoreChangeEvent = (newTheme: Theme) => void
76

87
const initTheme = null
98

10-
export const themeStore = (() => {
9+
export function createThemeStore() {
1110
if (typeof window === 'undefined')
1211
return {
1312
get: () => initTheme,
1413
set: () => {},
1514
subscribe: () => () => {},
1615
}
17-
const el = document.documentElement
1816

17+
const el = document.documentElement
1918
const subscribers: Set<StoreChangeEvent> = new Set()
2019
let theme: Theme = initTheme
21-
const get = () => {
22-
return theme
23-
}
20+
const get = () => theme
2421
const set = (newTheme: Theme) => {
2522
theme = newTheme
2623
subscribers.forEach((subscriber) => subscriber(theme))
@@ -33,25 +30,18 @@ export const themeStore = (() => {
3330
}
3431

3532
const mo = new MutationObserver((mutations) => {
36-
mutations.forEach((mutation) => {
37-
if (
38-
mutation.type === 'attributes' &&
39-
mutation.target instanceof HTMLElement
40-
) {
41-
set(mutation.target.getAttribute('data-theme') as Theme)
42-
}
43-
})
33+
for (const m of mutations)
34+
if (m.type === 'attributes' && m.target instanceof HTMLElement)
35+
set(m.target.getAttribute('data-theme') as Theme)
4436
})
45-
4637
mo.observe(el, {
4738
attributes: true,
4839
attributeFilter: ['data-theme'],
4940
subtree: false,
5041
})
51-
5242
return {
5343
get,
5444
set,
5545
subscribe,
5646
}
57-
})()
47+
}

0 commit comments

Comments
 (0)