@pyreon/hooks 0.11.4 → 0.11.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +5 -5
  2. package/lib/index.d.ts +6 -6
  3. package/lib/index.js +4 -6
  4. package/package.json +24 -24
  5. package/src/__tests__/useBreakpoint.test.ts +48 -48
  6. package/src/__tests__/useClickOutside.test.ts +31 -31
  7. package/src/__tests__/useColorScheme.test.ts +22 -22
  8. package/src/__tests__/useControllableState.test.ts +18 -18
  9. package/src/__tests__/useDebouncedCallback.test.ts +19 -19
  10. package/src/__tests__/useDebouncedValue.test.ts +28 -28
  11. package/src/__tests__/useElementSize.test.ts +21 -21
  12. package/src/__tests__/useFocus.test.ts +12 -12
  13. package/src/__tests__/useFocusTrap.test.ts +36 -36
  14. package/src/__tests__/useHover.test.ts +13 -13
  15. package/src/__tests__/useIntersection.test.ts +20 -20
  16. package/src/__tests__/useInterval.test.ts +7 -7
  17. package/src/__tests__/useIsomorphicLayoutEffect.test.ts +5 -5
  18. package/src/__tests__/useKeyboard.test.ts +38 -38
  19. package/src/__tests__/useLatest.test.ts +11 -11
  20. package/src/__tests__/useMediaQuery.test.ts +29 -29
  21. package/src/__tests__/useMergedRef.test.ts +10 -10
  22. package/src/__tests__/usePrevious.test.ts +20 -20
  23. package/src/__tests__/useReducedMotion.test.ts +15 -15
  24. package/src/__tests__/useRootSize.test.ts +9 -9
  25. package/src/__tests__/useScrollLock.test.ts +33 -33
  26. package/src/__tests__/useSpacing.test.ts +11 -11
  27. package/src/__tests__/useThemeValue.test.ts +5 -5
  28. package/src/__tests__/useThrottledCallback.test.ts +16 -16
  29. package/src/__tests__/useTimeout.test.ts +8 -8
  30. package/src/__tests__/useToggle.test.ts +14 -14
  31. package/src/__tests__/useUpdateEffect.test.ts +8 -8
  32. package/src/__tests__/useWindowResize.test.ts +34 -34
  33. package/src/index.ts +56 -56
  34. package/src/useBreakpoint.ts +6 -6
  35. package/src/useClickOutside.ts +5 -5
  36. package/src/useClipboard.ts +2 -2
  37. package/src/useColorScheme.ts +5 -5
  38. package/src/useControllableState.ts +2 -2
  39. package/src/useDebouncedCallback.ts +1 -1
  40. package/src/useDebouncedValue.ts +2 -2
  41. package/src/useDialog.ts +4 -4
  42. package/src/useElementSize.ts +2 -2
  43. package/src/useEventListener.ts +2 -2
  44. package/src/useFocus.ts +1 -1
  45. package/src/useFocusTrap.ts +4 -4
  46. package/src/useHover.ts +1 -1
  47. package/src/useInfiniteScroll.ts +10 -10
  48. package/src/useIntersection.ts +2 -2
  49. package/src/useInterval.ts +3 -4
  50. package/src/useIsomorphicLayoutEffect.ts +2 -2
  51. package/src/useKeyboard.ts +3 -3
  52. package/src/useMediaQuery.ts +4 -4
  53. package/src/useMergedRef.ts +1 -1
  54. package/src/useOnline.ts +6 -6
  55. package/src/usePrevious.ts +1 -1
  56. package/src/useReducedMotion.ts +2 -2
  57. package/src/useRootSize.ts +1 -1
  58. package/src/useScrollLock.ts +3 -3
  59. package/src/useSpacing.ts +1 -1
  60. package/src/useThemeValue.ts +2 -2
  61. package/src/useThrottledCallback.ts +2 -2
  62. package/src/useTimeAgo.ts +15 -15
  63. package/src/useTimeout.ts +3 -4
  64. package/src/useToggle.ts +1 -1
  65. package/src/useUpdateEffect.ts +2 -2
  66. package/src/useWindowResize.ts +6 -6
@@ -1,9 +1,9 @@
1
- import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
2
2
 
3
3
  let mountCallbacks: Array<() => void> = []
4
4
  let unmountCallbacks: Array<() => void> = []
5
5
 
6
- vi.mock("@pyreon/core", () => ({
6
+ vi.mock('@pyreon/core', () => ({
7
7
  onMount: (fn: () => unknown) => {
8
8
  mountCallbacks.push(fn as () => void)
9
9
  },
@@ -12,9 +12,9 @@ vi.mock("@pyreon/core", () => ({
12
12
  },
13
13
  }))
14
14
 
15
- import { useFocusTrap } from "../useFocusTrap"
15
+ import { useFocusTrap } from '../useFocusTrap'
16
16
 
17
- describe("useFocusTrap", () => {
17
+ describe('useFocusTrap', () => {
18
18
  let container: HTMLDivElement
19
19
  let btn1: HTMLButtonElement
20
20
  let btn2: HTMLButtonElement
@@ -23,10 +23,10 @@ describe("useFocusTrap", () => {
23
23
  beforeEach(() => {
24
24
  mountCallbacks = []
25
25
  unmountCallbacks = []
26
- container = document.createElement("div")
27
- btn1 = document.createElement("button")
28
- btn2 = document.createElement("button")
29
- btn3 = document.createElement("button")
26
+ container = document.createElement('div')
27
+ btn1 = document.createElement('button')
28
+ btn2 = document.createElement('button')
29
+ btn3 = document.createElement('button')
30
30
  container.append(btn1, btn2, btn3)
31
31
  document.body.appendChild(container)
32
32
  })
@@ -35,84 +35,84 @@ describe("useFocusTrap", () => {
35
35
  document.body.removeChild(container)
36
36
  })
37
37
 
38
- it("wraps focus from last to first on Tab", () => {
38
+ it('wraps focus from last to first on Tab', () => {
39
39
  useFocusTrap(() => container)
40
40
  mountCallbacks.forEach((cb) => {
41
41
  cb()
42
42
  })
43
43
 
44
44
  btn3.focus()
45
- const event = new KeyboardEvent("keydown", { key: "Tab", bubbles: true })
46
- const prevented = vi.spyOn(event, "preventDefault")
45
+ const event = new KeyboardEvent('keydown', { key: 'Tab', bubbles: true })
46
+ const prevented = vi.spyOn(event, 'preventDefault')
47
47
  document.dispatchEvent(event)
48
48
 
49
49
  expect(prevented).toHaveBeenCalled()
50
50
  expect(document.activeElement).toBe(btn1)
51
51
  })
52
52
 
53
- it("wraps focus from first to last on Shift+Tab", () => {
53
+ it('wraps focus from first to last on Shift+Tab', () => {
54
54
  useFocusTrap(() => container)
55
55
  mountCallbacks.forEach((cb) => {
56
56
  cb()
57
57
  })
58
58
 
59
59
  btn1.focus()
60
- const event = new KeyboardEvent("keydown", {
61
- key: "Tab",
60
+ const event = new KeyboardEvent('keydown', {
61
+ key: 'Tab',
62
62
  shiftKey: true,
63
63
  bubbles: true,
64
64
  })
65
- const prevented = vi.spyOn(event, "preventDefault")
65
+ const prevented = vi.spyOn(event, 'preventDefault')
66
66
  document.dispatchEvent(event)
67
67
 
68
68
  expect(prevented).toHaveBeenCalled()
69
69
  expect(document.activeElement).toBe(btn3)
70
70
  })
71
71
 
72
- it("does not wrap when Tab on middle element", () => {
72
+ it('does not wrap when Tab on middle element', () => {
73
73
  useFocusTrap(() => container)
74
74
  mountCallbacks.forEach((cb) => {
75
75
  cb()
76
76
  })
77
77
 
78
78
  btn2.focus()
79
- const event = new KeyboardEvent("keydown", { key: "Tab", bubbles: true })
80
- const prevented = vi.spyOn(event, "preventDefault")
79
+ const event = new KeyboardEvent('keydown', { key: 'Tab', bubbles: true })
80
+ const prevented = vi.spyOn(event, 'preventDefault')
81
81
  document.dispatchEvent(event)
82
82
 
83
83
  expect(prevented).not.toHaveBeenCalled()
84
84
  })
85
85
 
86
- it("ignores non-Tab keys", () => {
86
+ it('ignores non-Tab keys', () => {
87
87
  useFocusTrap(() => container)
88
88
  mountCallbacks.forEach((cb) => {
89
89
  cb()
90
90
  })
91
91
 
92
92
  btn3.focus()
93
- const event = new KeyboardEvent("keydown", { key: "Enter", bubbles: true })
94
- const prevented = vi.spyOn(event, "preventDefault")
93
+ const event = new KeyboardEvent('keydown', { key: 'Enter', bubbles: true })
94
+ const prevented = vi.spyOn(event, 'preventDefault')
95
95
  document.dispatchEvent(event)
96
96
 
97
97
  expect(prevented).not.toHaveBeenCalled()
98
98
  })
99
99
 
100
- it("does nothing when element is null", () => {
100
+ it('does nothing when element is null', () => {
101
101
  useFocusTrap(() => null)
102
102
  mountCallbacks.forEach((cb) => {
103
103
  cb()
104
104
  })
105
105
 
106
- const event = new KeyboardEvent("keydown", { key: "Tab", bubbles: true })
107
- const prevented = vi.spyOn(event, "preventDefault")
106
+ const event = new KeyboardEvent('keydown', { key: 'Tab', bubbles: true })
107
+ const prevented = vi.spyOn(event, 'preventDefault')
108
108
  document.dispatchEvent(event)
109
109
 
110
110
  expect(prevented).not.toHaveBeenCalled()
111
111
  })
112
112
 
113
- it("does nothing when container has no focusable children", () => {
114
- const emptyContainer = document.createElement("div")
115
- emptyContainer.appendChild(document.createElement("div"))
113
+ it('does nothing when container has no focusable children', () => {
114
+ const emptyContainer = document.createElement('div')
115
+ emptyContainer.appendChild(document.createElement('div'))
116
116
  document.body.appendChild(emptyContainer)
117
117
 
118
118
  useFocusTrap(() => emptyContainer)
@@ -120,16 +120,16 @@ describe("useFocusTrap", () => {
120
120
  cb()
121
121
  })
122
122
 
123
- const event = new KeyboardEvent("keydown", { key: "Tab", bubbles: true })
124
- const prevented = vi.spyOn(event, "preventDefault")
123
+ const event = new KeyboardEvent('keydown', { key: 'Tab', bubbles: true })
124
+ const prevented = vi.spyOn(event, 'preventDefault')
125
125
  document.dispatchEvent(event)
126
126
 
127
127
  expect(prevented).not.toHaveBeenCalled()
128
128
  document.body.removeChild(emptyContainer)
129
129
  })
130
130
 
131
- it("cleans up event listener on unmount", () => {
132
- const removeSpy = vi.spyOn(document, "removeEventListener")
131
+ it('cleans up event listener on unmount', () => {
132
+ const removeSpy = vi.spyOn(document, 'removeEventListener')
133
133
  useFocusTrap(() => container)
134
134
  mountCallbacks.forEach((cb) => {
135
135
  cb()
@@ -138,23 +138,23 @@ describe("useFocusTrap", () => {
138
138
  cb()
139
139
  })
140
140
 
141
- expect(removeSpy).toHaveBeenCalledWith("keydown", expect.any(Function))
141
+ expect(removeSpy).toHaveBeenCalledWith('keydown', expect.any(Function))
142
142
  removeSpy.mockRestore()
143
143
  })
144
144
 
145
- it("does not prevent default when Shift+Tab on non-first element", () => {
145
+ it('does not prevent default when Shift+Tab on non-first element', () => {
146
146
  useFocusTrap(() => container)
147
147
  mountCallbacks.forEach((cb) => {
148
148
  cb()
149
149
  })
150
150
 
151
151
  btn2.focus()
152
- const event = new KeyboardEvent("keydown", {
153
- key: "Tab",
152
+ const event = new KeyboardEvent('keydown', {
153
+ key: 'Tab',
154
154
  shiftKey: true,
155
155
  bubbles: true,
156
156
  })
157
- const prevented = vi.spyOn(event, "preventDefault")
157
+ const prevented = vi.spyOn(event, 'preventDefault')
158
158
  document.dispatchEvent(event)
159
159
 
160
160
  expect(prevented).not.toHaveBeenCalled()
@@ -1,19 +1,19 @@
1
- import { describe, expect, it } from "vitest"
2
- import { useHover } from "../useHover"
1
+ import { describe, expect, it } from 'vitest'
2
+ import { useHover } from '../useHover'
3
3
 
4
- describe("useHover", () => {
5
- it("initializes with hovered=false", () => {
4
+ describe('useHover', () => {
5
+ it('initializes with hovered=false', () => {
6
6
  const { hovered } = useHover()
7
7
  expect(hovered()).toBe(false)
8
8
  })
9
9
 
10
- it("sets hovered to true on mouseEnter", () => {
10
+ it('sets hovered to true on mouseEnter', () => {
11
11
  const { hovered, props } = useHover()
12
12
  props.onMouseEnter()
13
13
  expect(hovered()).toBe(true)
14
14
  })
15
15
 
16
- it("sets hovered to false on mouseLeave", () => {
16
+ it('sets hovered to false on mouseLeave', () => {
17
17
  const { hovered, props } = useHover()
18
18
  props.onMouseEnter()
19
19
  expect(hovered()).toBe(true)
@@ -21,7 +21,7 @@ describe("useHover", () => {
21
21
  expect(hovered()).toBe(false)
22
22
  })
23
23
 
24
- it("toggles hover state correctly through multiple cycles", () => {
24
+ it('toggles hover state correctly through multiple cycles', () => {
25
25
  const { hovered, props } = useHover()
26
26
  props.onMouseEnter()
27
27
  expect(hovered()).toBe(true)
@@ -33,26 +33,26 @@ describe("useHover", () => {
33
33
  expect(hovered()).toBe(false)
34
34
  })
35
35
 
36
- it("calling mouseLeave when already not hovered is safe", () => {
36
+ it('calling mouseLeave when already not hovered is safe', () => {
37
37
  const { hovered, props } = useHover()
38
38
  props.onMouseLeave()
39
39
  expect(hovered()).toBe(false)
40
40
  })
41
41
 
42
- it("calling mouseEnter multiple times stays true", () => {
42
+ it('calling mouseEnter multiple times stays true', () => {
43
43
  const { hovered, props } = useHover()
44
44
  props.onMouseEnter()
45
45
  props.onMouseEnter()
46
46
  expect(hovered()).toBe(true)
47
47
  })
48
48
 
49
- it("returns props object with onMouseEnter and onMouseLeave", () => {
49
+ it('returns props object with onMouseEnter and onMouseLeave', () => {
50
50
  const { props } = useHover()
51
- expect(typeof props.onMouseEnter).toBe("function")
52
- expect(typeof props.onMouseLeave).toBe("function")
51
+ expect(typeof props.onMouseEnter).toBe('function')
52
+ expect(typeof props.onMouseLeave).toBe('function')
53
53
  })
54
54
 
55
- it("returns stable handler references", () => {
55
+ it('returns stable handler references', () => {
56
56
  const { props } = useHover()
57
57
  const enter = props.onMouseEnter
58
58
  const leave = props.onMouseLeave
@@ -1,9 +1,9 @@
1
- import { beforeEach, describe, expect, it, vi } from "vitest"
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest'
2
2
 
3
3
  let mountCallbacks: Array<() => unknown> = []
4
4
  let unmountCallbacks: Array<() => void> = []
5
5
 
6
- vi.mock("@pyreon/core", () => ({
6
+ vi.mock('@pyreon/core', () => ({
7
7
  onMount: (fn: () => unknown) => {
8
8
  mountCallbacks.push(fn)
9
9
  },
@@ -12,9 +12,9 @@ vi.mock("@pyreon/core", () => ({
12
12
  },
13
13
  }))
14
14
 
15
- import { useIntersection } from "../useIntersection"
15
+ import { useIntersection } from '../useIntersection'
16
16
 
17
- describe("useIntersection", () => {
17
+ describe('useIntersection', () => {
18
18
  let intersectionCallback: ((entries: IntersectionObserverEntry[]) => void) | undefined
19
19
  let observeSpy: ReturnType<typeof vi.fn>
20
20
  let disconnectSpy: ReturnType<typeof vi.fn>
@@ -37,7 +37,7 @@ describe("useIntersection", () => {
37
37
  unobserve: vi.fn(),
38
38
  disconnect: disconnectSpy,
39
39
  root: options?.root ?? null,
40
- rootMargin: options?.rootMargin ?? "0px",
40
+ rootMargin: options?.rootMargin ?? '0px',
41
41
  thresholds: Array.isArray(options?.threshold)
42
42
  ? options.threshold
43
43
  : [options?.threshold ?? 0],
@@ -46,13 +46,13 @@ describe("useIntersection", () => {
46
46
  }) as unknown as typeof IntersectionObserver
47
47
  })
48
48
 
49
- it("returns null initially", () => {
49
+ it('returns null initially', () => {
50
50
  const entry = useIntersection(() => null)
51
51
  expect(entry()).toBeNull()
52
52
  })
53
53
 
54
- it("observes the element on mount", () => {
55
- const el = document.createElement("div")
54
+ it('observes the element on mount', () => {
55
+ const el = document.createElement('div')
56
56
  useIntersection(() => el)
57
57
  mountCallbacks.forEach((cb) => {
58
58
  cb()
@@ -61,7 +61,7 @@ describe("useIntersection", () => {
61
61
  expect(observeSpy).toHaveBeenCalledWith(el)
62
62
  })
63
63
 
64
- it("does not observe when element is null", () => {
64
+ it('does not observe when element is null', () => {
65
65
  useIntersection(() => null)
66
66
  mountCallbacks.forEach((cb) => {
67
67
  cb()
@@ -70,8 +70,8 @@ describe("useIntersection", () => {
70
70
  expect(observeSpy).not.toHaveBeenCalled()
71
71
  })
72
72
 
73
- it("updates entry when intersection changes", () => {
74
- const el = document.createElement("div")
73
+ it('updates entry when intersection changes', () => {
74
+ const el = document.createElement('div')
75
75
  const entrySignal = useIntersection(() => el)
76
76
  mountCallbacks.forEach((cb) => {
77
77
  cb()
@@ -92,9 +92,9 @@ describe("useIntersection", () => {
92
92
  expect(entrySignal()?.isIntersecting).toBe(true)
93
93
  })
94
94
 
95
- it("passes options to IntersectionObserver", () => {
96
- const el = document.createElement("div")
97
- const options = { threshold: 0.5, rootMargin: "10px" }
95
+ it('passes options to IntersectionObserver', () => {
96
+ const el = document.createElement('div')
97
+ const options = { threshold: 0.5, rootMargin: '10px' }
98
98
  useIntersection(() => el, options)
99
99
  mountCallbacks.forEach((cb) => {
100
100
  cb()
@@ -103,8 +103,8 @@ describe("useIntersection", () => {
103
103
  expect(IntersectionObserver).toHaveBeenCalledWith(expect.any(Function), options)
104
104
  })
105
105
 
106
- it("disconnects observer on unmount", () => {
107
- const el = document.createElement("div")
106
+ it('disconnects observer on unmount', () => {
107
+ const el = document.createElement('div')
108
108
  useIntersection(() => el)
109
109
  mountCallbacks.forEach((cb) => {
110
110
  cb()
@@ -116,8 +116,8 @@ describe("useIntersection", () => {
116
116
  expect(disconnectSpy).toHaveBeenCalled()
117
117
  })
118
118
 
119
- it("does not crash when callback has empty entries", () => {
120
- const el = document.createElement("div")
119
+ it('does not crash when callback has empty entries', () => {
120
+ const el = document.createElement('div')
121
121
  const entrySignal = useIntersection(() => el)
122
122
  mountCallbacks.forEach((cb) => {
123
123
  cb()
@@ -128,8 +128,8 @@ describe("useIntersection", () => {
128
128
  expect(entrySignal()).toBeNull()
129
129
  })
130
130
 
131
- it("updates to latest entry on subsequent intersections", () => {
132
- const el = document.createElement("div")
131
+ it('updates to latest entry on subsequent intersections', () => {
132
+ const el = document.createElement('div')
133
133
  const entrySignal = useIntersection(() => el)
134
134
  mountCallbacks.forEach((cb) => {
135
135
  cb()
@@ -1,19 +1,19 @@
1
- import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"
2
- import { useInterval } from "../useInterval"
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
2
+ import { useInterval } from '../useInterval'
3
3
 
4
4
  // Mock onUnmount since it requires component lifecycle context
5
- vi.mock("@pyreon/core", () => ({
5
+ vi.mock('@pyreon/core', () => ({
6
6
  onMount: (fn: () => void) => fn(),
7
7
  onUnmount: (_fn: () => void) => {
8
8
  /* no-op */
9
9
  },
10
10
  }))
11
11
 
12
- describe("useInterval", () => {
12
+ describe('useInterval', () => {
13
13
  beforeEach(() => vi.useFakeTimers())
14
14
  afterEach(() => vi.useRealTimers())
15
15
 
16
- it("calls callback at the specified interval", () => {
16
+ it('calls callback at the specified interval', () => {
17
17
  const fn = vi.fn()
18
18
  useInterval(fn, 100)
19
19
 
@@ -24,7 +24,7 @@ describe("useInterval", () => {
24
24
  expect(fn).toHaveBeenCalledTimes(2)
25
25
  })
26
26
 
27
- it("does not call callback when delay is null", () => {
27
+ it('does not call callback when delay is null', () => {
28
28
  const fn = vi.fn()
29
29
  useInterval(fn, null)
30
30
 
@@ -32,7 +32,7 @@ describe("useInterval", () => {
32
32
  expect(fn).not.toHaveBeenCalled()
33
33
  })
34
34
 
35
- it("calls the latest callback", () => {
35
+ it('calls the latest callback', () => {
36
36
  let value = 0
37
37
  let currentCb = () => {
38
38
  value = 1
@@ -1,9 +1,9 @@
1
- import { onMount } from "@pyreon/core"
2
- import { describe, expect, it } from "vitest"
3
- import useIsomorphicLayoutEffect from "../useIsomorphicLayoutEffect"
1
+ import { onMount } from '@pyreon/core'
2
+ import { describe, expect, it } from 'vitest'
3
+ import useIsomorphicLayoutEffect from '../useIsomorphicLayoutEffect'
4
4
 
5
- describe("useIsomorphicLayoutEffect", () => {
6
- it("is onMount in a browser environment", () => {
5
+ describe('useIsomorphicLayoutEffect', () => {
6
+ it('is onMount in a browser environment', () => {
7
7
  expect(useIsomorphicLayoutEffect).toBe(onMount)
8
8
  })
9
9
  })
@@ -1,9 +1,9 @@
1
- import { beforeEach, describe, expect, it, vi } from "vitest"
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest'
2
2
 
3
3
  let mountCallbacks: Array<() => void> = []
4
4
  let unmountCallbacks: Array<() => void> = []
5
5
 
6
- vi.mock("@pyreon/core", () => ({
6
+ vi.mock('@pyreon/core', () => ({
7
7
  onMount: (fn: () => unknown) => {
8
8
  mountCallbacks.push(fn as () => void)
9
9
  },
@@ -12,83 +12,83 @@ vi.mock("@pyreon/core", () => ({
12
12
  },
13
13
  }))
14
14
 
15
- import { useKeyboard } from "../useKeyboard"
15
+ import { useKeyboard } from '../useKeyboard'
16
16
 
17
- describe("useKeyboard", () => {
17
+ describe('useKeyboard', () => {
18
18
  beforeEach(() => {
19
19
  mountCallbacks = []
20
20
  unmountCallbacks = []
21
21
  })
22
22
 
23
- it("calls handler when the target key is pressed", () => {
23
+ it('calls handler when the target key is pressed', () => {
24
24
  const handler = vi.fn()
25
- useKeyboard("Enter", handler)
25
+ useKeyboard('Enter', handler)
26
26
  mountCallbacks.forEach((cb) => {
27
27
  cb()
28
28
  })
29
29
 
30
- const event = new KeyboardEvent("keydown", { key: "Enter", bubbles: true })
30
+ const event = new KeyboardEvent('keydown', { key: 'Enter', bubbles: true })
31
31
  document.dispatchEvent(event)
32
32
 
33
33
  expect(handler).toHaveBeenCalledTimes(1)
34
34
  expect(handler).toHaveBeenCalledWith(event)
35
35
  })
36
36
 
37
- it("does not call handler for different keys", () => {
37
+ it('does not call handler for different keys', () => {
38
38
  const handler = vi.fn()
39
- useKeyboard("Enter", handler)
39
+ useKeyboard('Enter', handler)
40
40
  mountCallbacks.forEach((cb) => {
41
41
  cb()
42
42
  })
43
43
 
44
- const event = new KeyboardEvent("keydown", { key: "Escape", bubbles: true })
44
+ const event = new KeyboardEvent('keydown', { key: 'Escape', bubbles: true })
45
45
  document.dispatchEvent(event)
46
46
 
47
47
  expect(handler).not.toHaveBeenCalled()
48
48
  })
49
49
 
50
- it("listens for keydown by default", () => {
50
+ it('listens for keydown by default', () => {
51
51
  const handler = vi.fn()
52
- const addSpy = vi.spyOn(document, "addEventListener")
53
- useKeyboard("Escape", handler)
52
+ const addSpy = vi.spyOn(document, 'addEventListener')
53
+ useKeyboard('Escape', handler)
54
54
  mountCallbacks.forEach((cb) => {
55
55
  cb()
56
56
  })
57
57
 
58
- expect(addSpy).toHaveBeenCalledWith("keydown", expect.any(Function))
58
+ expect(addSpy).toHaveBeenCalledWith('keydown', expect.any(Function))
59
59
  addSpy.mockRestore()
60
60
  })
61
61
 
62
- it("supports keyup event option", () => {
62
+ it('supports keyup event option', () => {
63
63
  const handler = vi.fn()
64
- useKeyboard("Space", handler, { event: "keyup" })
64
+ useKeyboard('Space', handler, { event: 'keyup' })
65
65
  mountCallbacks.forEach((cb) => {
66
66
  cb()
67
67
  })
68
68
 
69
- const keydownEvent = new KeyboardEvent("keydown", { key: "Space", bubbles: true })
69
+ const keydownEvent = new KeyboardEvent('keydown', { key: 'Space', bubbles: true })
70
70
  document.dispatchEvent(keydownEvent)
71
71
  expect(handler).not.toHaveBeenCalled()
72
72
 
73
- const keyupEvent = new KeyboardEvent("keyup", { key: "Space", bubbles: true })
73
+ const keyupEvent = new KeyboardEvent('keyup', { key: 'Space', bubbles: true })
74
74
  document.dispatchEvent(keyupEvent)
75
75
  expect(handler).toHaveBeenCalledTimes(1)
76
76
  })
77
77
 
78
- it("supports custom target", () => {
78
+ it('supports custom target', () => {
79
79
  const handler = vi.fn()
80
- const customTarget = document.createElement("div")
80
+ const customTarget = document.createElement('div')
81
81
  document.body.appendChild(customTarget)
82
- const addSpy = vi.spyOn(customTarget, "addEventListener")
82
+ const addSpy = vi.spyOn(customTarget, 'addEventListener')
83
83
 
84
- useKeyboard("Enter", handler, { target: customTarget })
84
+ useKeyboard('Enter', handler, { target: customTarget })
85
85
  mountCallbacks.forEach((cb) => {
86
86
  cb()
87
87
  })
88
88
 
89
- expect(addSpy).toHaveBeenCalledWith("keydown", expect.any(Function))
89
+ expect(addSpy).toHaveBeenCalledWith('keydown', expect.any(Function))
90
90
 
91
- const event = new KeyboardEvent("keydown", { key: "Enter", bubbles: true })
91
+ const event = new KeyboardEvent('keydown', { key: 'Enter', bubbles: true })
92
92
  customTarget.dispatchEvent(event)
93
93
  expect(handler).toHaveBeenCalledTimes(1)
94
94
 
@@ -96,10 +96,10 @@ describe("useKeyboard", () => {
96
96
  document.body.removeChild(customTarget)
97
97
  })
98
98
 
99
- it("removes listeners on unmount", () => {
99
+ it('removes listeners on unmount', () => {
100
100
  const handler = vi.fn()
101
- const removeSpy = vi.spyOn(document, "removeEventListener")
102
- useKeyboard("Enter", handler)
101
+ const removeSpy = vi.spyOn(document, 'removeEventListener')
102
+ useKeyboard('Enter', handler)
103
103
  mountCallbacks.forEach((cb) => {
104
104
  cb()
105
105
  })
@@ -107,16 +107,16 @@ describe("useKeyboard", () => {
107
107
  cb()
108
108
  })
109
109
 
110
- expect(removeSpy).toHaveBeenCalledWith("keydown", expect.any(Function))
110
+ expect(removeSpy).toHaveBeenCalledWith('keydown', expect.any(Function))
111
111
  removeSpy.mockRestore()
112
112
  })
113
113
 
114
- it("removes listeners from custom target on unmount", () => {
114
+ it('removes listeners from custom target on unmount', () => {
115
115
  const handler = vi.fn()
116
- const customTarget = document.createElement("div")
117
- const removeSpy = vi.spyOn(customTarget, "removeEventListener")
116
+ const customTarget = document.createElement('div')
117
+ const removeSpy = vi.spyOn(customTarget, 'removeEventListener')
118
118
 
119
- useKeyboard("Enter", handler, { target: customTarget })
119
+ useKeyboard('Enter', handler, { target: customTarget })
120
120
  mountCallbacks.forEach((cb) => {
121
121
  cb()
122
122
  })
@@ -124,20 +124,20 @@ describe("useKeyboard", () => {
124
124
  cb()
125
125
  })
126
126
 
127
- expect(removeSpy).toHaveBeenCalledWith("keydown", expect.any(Function))
127
+ expect(removeSpy).toHaveBeenCalledWith('keydown', expect.any(Function))
128
128
  removeSpy.mockRestore()
129
129
  })
130
130
 
131
- it("calls handler multiple times for repeated key presses", () => {
131
+ it('calls handler multiple times for repeated key presses', () => {
132
132
  const handler = vi.fn()
133
- useKeyboard("a", handler)
133
+ useKeyboard('a', handler)
134
134
  mountCallbacks.forEach((cb) => {
135
135
  cb()
136
136
  })
137
137
 
138
- document.dispatchEvent(new KeyboardEvent("keydown", { key: "a" }))
139
- document.dispatchEvent(new KeyboardEvent("keydown", { key: "a" }))
140
- document.dispatchEvent(new KeyboardEvent("keydown", { key: "a" }))
138
+ document.dispatchEvent(new KeyboardEvent('keydown', { key: 'a' }))
139
+ document.dispatchEvent(new KeyboardEvent('keydown', { key: 'a' }))
140
+ document.dispatchEvent(new KeyboardEvent('keydown', { key: 'a' }))
141
141
 
142
142
  expect(handler).toHaveBeenCalledTimes(3)
143
143
  })
@@ -1,23 +1,23 @@
1
- import { describe, expect, it } from "vitest"
2
- import { useLatest } from "../useLatest"
1
+ import { describe, expect, it } from 'vitest'
2
+ import { useLatest } from '../useLatest'
3
3
 
4
- describe("useLatest", () => {
5
- it("returns a ref with the current value", () => {
4
+ describe('useLatest', () => {
5
+ it('returns a ref with the current value', () => {
6
6
  const ref = useLatest(42)
7
7
  expect(ref.current).toBe(42)
8
8
  })
9
9
 
10
- it("ref object can be manually updated", () => {
11
- const ref = useLatest("a")
12
- expect(ref.current).toBe("a")
10
+ it('ref object can be manually updated', () => {
11
+ const ref = useLatest('a')
12
+ expect(ref.current).toBe('a')
13
13
 
14
14
  // In Pyreon, since component runs once, the caller updates .current manually
15
- ;(ref as { current: string }).current = "b"
16
- expect(ref.current).toBe("b")
15
+ ;(ref as { current: string }).current = 'b'
16
+ expect(ref.current).toBe('b')
17
17
  })
18
18
 
19
- it("returns a stable ref identity", () => {
20
- const ref = useLatest("hello")
19
+ it('returns a stable ref identity', () => {
20
+ const ref = useLatest('hello')
21
21
  const same = ref
22
22
  expect(same).toBe(ref)
23
23
  })