@pyreon/router 0.24.5 → 0.24.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.
@@ -1,158 +0,0 @@
1
- import { _rp, h } from '@pyreon/core'
2
- import { flush, mountInBrowser } from '@pyreon/test-utils/browser'
3
- import { afterEach, beforeEach, describe, expect, it } from 'vitest'
4
- import { createRouter, RouterLink, RouterProvider, useIsActive } from '../index'
5
- import { setActiveRouter } from '../router'
6
-
7
- describe('RouterLink reactive `to` prop', () => {
8
- beforeEach(() => {
9
- window.location.hash = ''
10
- })
11
- afterEach(() => {
12
- setActiveRouter(null)
13
- window.location.hash = ''
14
- })
15
-
16
- it('resolves _rp-wrapped `to` accessor to its string value, not the function literal', async () => {
17
- const routes = [{ path: '/', component: () => h('div', null, 'home') }]
18
- const router = createRouter({ routes, mode: 'hash' })
19
- const { container, unmount } = mountInBrowser(
20
- h(
21
- RouterProvider,
22
- { router },
23
- h(RouterLink, { to: _rp(() => '/about') as unknown as string, id: 'link' }, 'Go'),
24
- ),
25
- )
26
- await flush()
27
- const link = container.querySelector<HTMLAnchorElement>('#link')
28
- expect(link).not.toBeNull()
29
- expect(link!.getAttribute('href')).toBe('#/about')
30
- unmount()
31
- })
32
-
33
- it('NavItem-shape: parent gets `path` as `_rp` getter and forwards it to RouterLink', async () => {
34
- // Mirrors `examples/fundamentals-playground/src/routes/_layout.tsx`:
35
- // function NavItem(props) {
36
- // return <RouterLink to={props.path} ...>{props.label}</RouterLink>
37
- // }
38
- // <NavItem path={tab.path} ... />
39
- // The compiler emits `_rp(() => tab.path)` for the parent's `path` prop,
40
- // which `makeReactiveProps` turns into a getter on NavItem's `props`.
41
- // Then `<RouterLink to={props.path}>` re-wraps that getter access as
42
- // `_rp(() => props.path)`. The outermost getter points back through
43
- // NavItem's getter to the literal value.
44
- const NavItem = (props: Record<string, unknown>) =>
45
- h(RouterLink, {
46
- to: _rp(() => props.path as string) as unknown as string,
47
- id: 'nav-link',
48
- })
49
-
50
- const routes = [
51
- { path: '/', component: () => h('div', { id: 'home' }, 'home') },
52
- { path: '/about', component: () => h('div', { id: 'about' }, 'about') },
53
- ]
54
- const router = createRouter({ routes, mode: 'hash' })
55
- const { container, unmount } = mountInBrowser(
56
- h(
57
- RouterProvider,
58
- { router },
59
- h(NavItem, { path: _rp(() => '/about') as unknown as string }),
60
- ),
61
- )
62
- await flush()
63
- const link = container.querySelector<HTMLAnchorElement>('#nav-link')
64
- expect(link).not.toBeNull()
65
- expect(link!.getAttribute('href')).toBe('#/about')
66
- expect(link!.getAttribute('href')).not.toContain('=>')
67
- unmount()
68
- })
69
-
70
- it('activeClass updates reactively when `to` is `_rp`-wrapped and route changes', async () => {
71
- // Pre-fix, `RouterLink`'s own `activeClass` computation read `props.to`
72
- // ONCE at component setup time and compared against the current path.
73
- // Even if `props.to` correctly resolved to the string, the comparison
74
- // was static — `activeClass` was a function returning a string but the
75
- // captured `target = props.to` (declared inline) was hoisted in setup
76
- // scope. After fixing setup-time captures of `props.to` (so the activeClass
77
- // accessor reads `props.to` lazily on each invocation), navigation
78
- // updates the class reactively.
79
- const routes = [
80
- { path: '/', component: () => h('div', { id: 'home' }, 'home') },
81
- { path: '/about', component: () => h('div', { id: 'about' }, 'about') },
82
- ]
83
- const router = createRouter({ routes, mode: 'hash' })
84
-
85
- const NavItem = (props: Record<string, unknown>) =>
86
- h(RouterLink, {
87
- to: _rp(() => props.path as string) as unknown as string,
88
- id: `link-${(props as { _id: string })._id}`,
89
- })
90
-
91
- const { container, unmount } = mountInBrowser(
92
- h(
93
- RouterProvider,
94
- { router },
95
- h('div', null, [
96
- h(NavItem, { _id: 'home', path: _rp(() => '/') as unknown as string }),
97
- h(NavItem, { _id: 'about', path: _rp(() => '/about') as unknown as string }),
98
- ]),
99
- ),
100
- )
101
- await flush()
102
-
103
- // RouterLink applies the default `router-link-active` class when the
104
- // current path matches `to`.
105
- expect(container.querySelector('#link-home')!.className).toContain('router-link-active')
106
- expect(container.querySelector('#link-about')!.className).not.toContain('router-link-active')
107
-
108
- await router.push('/about')
109
- await flush()
110
-
111
- expect(container.querySelector('#link-about')!.className).toContain('router-link-active')
112
- expect(container.querySelector('#link-home')!.className).not.toContain('router-link-active')
113
- unmount()
114
- })
115
-
116
- it('useIsActive(props.path) reactively flips when current route matches', async () => {
117
- // The full fundamentals layout shape: NavItem reads `props.path` (a
118
- // getter from `_rp`) and passes it BOTH to `RouterLink.to` AND to
119
- // `useIsActive`. Pre-fix, `useIsActive(props.path)` captured the
120
- // getter as the `path` argument — non-string — and silently returned
121
- // false for every route check.
122
- const routes = [
123
- { path: '/', component: () => h('div', { id: 'home' }, 'home') },
124
- { path: '/about', component: () => h('div', { id: 'about' }, 'about') },
125
- ]
126
- const router = createRouter({ routes, mode: 'hash' })
127
-
128
- const NavItem = (props: Record<string, unknown>) => {
129
- const isActive = useIsActive(props.path as string, true)
130
- return h(RouterLink, {
131
- to: _rp(() => props.path as string) as unknown as string,
132
- id: `link-${(props as { _id: string })._id}`,
133
- class: () => (isActive() ? 'is-active' : ''),
134
- })
135
- }
136
-
137
- const { container, unmount } = mountInBrowser(
138
- h(
139
- RouterProvider,
140
- { router },
141
- h('div', null, [
142
- h(NavItem, { _id: 'home', path: _rp(() => '/') as unknown as string }),
143
- h(NavItem, { _id: 'about', path: _rp(() => '/about') as unknown as string }),
144
- ]),
145
- ),
146
- )
147
- await flush()
148
-
149
- await router.push('/about')
150
- await flush()
151
-
152
- // The /about NavItem's useIsActive should now be true → className
153
- // includes 'is-active'.
154
- expect(container.querySelector('#link-about')!.className).toContain('is-active')
155
- expect(container.querySelector('#link-home')!.className).not.toContain('is-active')
156
- unmount()
157
- })
158
- })
@@ -1,31 +0,0 @@
1
- import { describe, expect, test } from 'vitest'
2
- import { ScrollManager } from '../scroll'
3
-
4
- describe('ScrollManager — LRU bound', () => {
5
- test('evicts oldest entry when cap (100) is exceeded', () => {
6
- const mgr = new ScrollManager('top')
7
- // Fake window.scrollY for each save — happy-dom provides window.
8
- Object.defineProperty(window, 'scrollY', { value: 42, configurable: true })
9
- // Save 150 distinct paths.
10
- for (let i = 0; i < 150; i++) mgr.save(`/path-${i}`)
11
- // Oldest 50 evicted; newest 100 remain.
12
- expect(mgr.getSavedPosition('/path-0')).toBeNull()
13
- expect(mgr.getSavedPosition('/path-49')).toBeNull()
14
- expect(mgr.getSavedPosition('/path-50')).toBe(42)
15
- expect(mgr.getSavedPosition('/path-149')).toBe(42)
16
- })
17
-
18
- test('re-saving an existing path bumps it to newest (LRU, not FIFO)', () => {
19
- const mgr = new ScrollManager('top')
20
- Object.defineProperty(window, 'scrollY', { value: 42, configurable: true })
21
- for (let i = 0; i < 100; i++) mgr.save(`/path-${i}`)
22
- // Touch the oldest entry — should move to newest.
23
- Object.defineProperty(window, 'scrollY', { value: 99, configurable: true })
24
- mgr.save('/path-0')
25
- // Now add one more to push out the new-oldest (/path-1).
26
- mgr.save('/new-path')
27
- expect(mgr.getSavedPosition('/path-1')).toBeNull()
28
- expect(mgr.getSavedPosition('/path-0')).toBe(99)
29
- expect(mgr.getSavedPosition('/new-path')).toBe(99)
30
- })
31
- })
@@ -1,3 +0,0 @@
1
- import { GlobalRegistrator } from '@happy-dom/global-registrator'
2
-
3
- GlobalRegistrator.register()