@pyreon/vue-compat 0.13.1 → 0.14.0

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.
@@ -165,6 +165,21 @@ export function jsx(
165
165
  return h(wrapped, componentProps)
166
166
  }
167
167
 
168
+ // DOM element: convert Vue ref ({ value }) to callback ref for Pyreon's runtime-dom
169
+ if (typeof type === 'string' && propsWithKey.ref != null) {
170
+ const r = propsWithKey.ref
171
+ if (
172
+ typeof r === 'object' &&
173
+ r !== null &&
174
+ (r as Record<symbol, unknown>)[Symbol.for('__v_isRef')] === true
175
+ ) {
176
+ const vueRef = r as { value: unknown }
177
+ propsWithKey.ref = (el: Element | null) => {
178
+ vueRef.value = el
179
+ }
180
+ }
181
+ }
182
+
168
183
  // DOM element or symbol (Fragment): children go in vnode.children
169
184
  const childArray = children === undefined ? [] : Array.isArray(children) ? children : [children]
170
185
 
@@ -0,0 +1,87 @@
1
+ import { mount } from '@pyreon/runtime-dom'
2
+ import { describe, expect, it, vi } from 'vitest'
3
+ import { onMounted, onUnmounted } from '../index'
4
+ import { jsx } from '../jsx-runtime'
5
+
6
+ // Coverage gap closed in PR #323. Exercises the Vue-compat wrapper
7
+ // (`wrapCompatComponent`) end-to-end: JSX → mount → lifecycle hooks
8
+ // → unmount cleanup. Pins the wrapper's setup-and-teardown contract;
9
+ // fine-grained reactivity behavior is covered by the broader
10
+ // vue-compat.test.ts integration suite.
11
+
12
+ function container(): HTMLElement {
13
+ const el = document.createElement('div')
14
+ document.body.appendChild(el)
15
+ return el
16
+ }
17
+
18
+ const tick = () => new Promise<void>((r) => queueMicrotask(() => r()))
19
+
20
+ describe('vue-compat — wrapCompatComponent (jsx-runtime)', () => {
21
+ it('caches the wrapper per source-fn identity (same wrapper on repeat jsx calls)', () => {
22
+ const Comp = () => jsx('div', { children: 'hi' })
23
+ const a = jsx(Comp, {})
24
+ const b = jsx(Comp, {})
25
+ // Both vnodes should reference the same wrapped component (the
26
+ // _wrapperCache WeakMap reuses by source-fn identity)
27
+ expect(a.type).toBe(b.type)
28
+ })
29
+
30
+ it('produces distinct wrappers for distinct source functions', () => {
31
+ const A = () => jsx('div', { children: 'a' })
32
+ const B = () => jsx('div', { children: 'b' })
33
+ expect(jsx(A, {}).type).not.toBe(jsx(B, {}).type)
34
+ })
35
+
36
+ it('mounts a Vue-style component and renders into the container', () => {
37
+ const Comp = () => jsx('div', { children: 'mounted-via-vue-compat' })
38
+ const c = container()
39
+ mount(jsx(Comp, {}), c)
40
+ expect(c.textContent).toContain('mounted-via-vue-compat')
41
+ })
42
+
43
+ it('runs onMounted callback after first render', async () => {
44
+ const mountedSpy = vi.fn()
45
+ const Comp = () => {
46
+ onMounted(mountedSpy)
47
+ return jsx('div', { children: 'hi' })
48
+ }
49
+
50
+ const c = container()
51
+ mount(jsx(Comp, {}), c)
52
+ await tick()
53
+ await tick()
54
+ expect(mountedSpy).toHaveBeenCalledTimes(1)
55
+ })
56
+
57
+ it('runs onUnmounted callback after disposal', async () => {
58
+ const unmountedSpy = vi.fn()
59
+ const Comp = () => {
60
+ onUnmounted(unmountedSpy)
61
+ return jsx('div', { children: 'hi' })
62
+ }
63
+
64
+ const c = container()
65
+ const dispose = mount(jsx(Comp, {}), c)
66
+ await tick()
67
+ expect(unmountedSpy).not.toHaveBeenCalled()
68
+
69
+ dispose()
70
+ expect(unmountedSpy).toHaveBeenCalledTimes(1)
71
+ })
72
+
73
+ it('handles components with children prop (passes children through to wrapped fn)', () => {
74
+ const Wrapper = (props: { children?: string }) =>
75
+ jsx('section', { children: props.children ?? '' })
76
+ const c = container()
77
+ mount(jsx(Wrapper, { children: 'inner' }), c)
78
+ expect(c.textContent).toContain('inner')
79
+ })
80
+
81
+ it('handles components with no props', () => {
82
+ const Comp = () => jsx('div', { children: 'noprops' })
83
+ const c = container()
84
+ mount(jsx(Comp, {}), c)
85
+ expect(c.textContent).toContain('noprops')
86
+ })
87
+ })