@pyreon/core 0.4.0 → 0.5.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pyreon/core",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Core component model and lifecycle for Pyreon",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -49,7 +49,7 @@
49
49
  "prepublishOnly": "bun run build"
50
50
  },
51
51
  "dependencies": {
52
- "@pyreon/reactivity": "^0.4.0"
52
+ "@pyreon/reactivity": "^0.5.0"
53
53
  },
54
54
  "publishConfig": {
55
55
  "access": "public"
@@ -92,8 +92,8 @@ interface PyreonHTMLAttributes {
92
92
  "aria-rowcount"?: number
93
93
  "aria-rowindex"?: number
94
94
  "aria-rowspan"?: number
95
- // DOM lifecycle ref
96
- ref?: { current: unknown }
95
+ // DOM lifecycle ref — object ref or callback ref
96
+ ref?: { current: unknown } | ((el: Element) => void)
97
97
  // Key for list reconciliation
98
98
  key?: string | number
99
99
  // innerHTML
@@ -425,6 +425,21 @@ interface SvgAttributes extends PyreonHTMLAttributes {
425
425
 
426
426
  declare global {
427
427
  namespace JSX {
428
+ /** The type that JSX expressions evaluate to */
429
+ type Element = import("./types").VNode
430
+
431
+ /**
432
+ * Valid JSX tag types — intrinsic strings + component functions.
433
+ * Components may return VNode, null, strings, functions (reactive getters), etc.
434
+ * (TS 5.1+ feature)
435
+ */
436
+ type ElementType = keyof IntrinsicElements | ((props: any) => import("./types").VNodeChild)
437
+
438
+ /** Tells TS which prop name carries children in component calls */
439
+ interface ElementChildrenAttribute {
440
+ children: {}
441
+ }
442
+
428
443
  interface IntrinsicElements {
429
444
  // Document structure
430
445
  html: PyreonHTMLAttributes
@@ -0,0 +1,86 @@
1
+ /**
2
+ * JSX type compatibility test — verifies all JSX patterns produce correct VNodes.
3
+ * Uses h() directly since core's vitest config doesn't have JSX transform.
4
+ * TypeScript already validates JSX types via typecheck (tsc --noEmit).
5
+ */
6
+ import { createRef, Fragment, h } from "../index"
7
+
8
+ describe("JSX type compat (via h)", () => {
9
+ test("basic element", () => {
10
+ const el = h("div", { class: "hello" }, "world")
11
+ expect(el.type).toBe("div")
12
+ expect(el.props.class).toBe("hello")
13
+ })
14
+
15
+ test("callback ref", () => {
16
+ let captured: Element | null = null
17
+ const el = h(
18
+ "div",
19
+ {
20
+ ref: (e: Element) => {
21
+ captured = e
22
+ },
23
+ },
24
+ "test",
25
+ )
26
+ expect(typeof el.props.ref).toBe("function")
27
+ })
28
+
29
+ test("object ref", () => {
30
+ const myRef = createRef<HTMLDivElement>()
31
+ const el = h("div", { ref: myRef }, "test")
32
+ expect(el.props.ref).toBe(myRef)
33
+ })
34
+
35
+ test("reactive class prop", () => {
36
+ const el = h("span", { class: () => "active" }, "hello")
37
+ expect(typeof el.props.class).toBe("function")
38
+ })
39
+
40
+ test("input with typed props", () => {
41
+ const el = h("input", { type: "text", value: "test" })
42
+ expect(el.type).toBe("input")
43
+ expect(el.props.type).toBe("text")
44
+ })
45
+
46
+ test("component with children", () => {
47
+ const MyComp = (props: { name: string; children?: unknown }) => {
48
+ return h("div", null, String(props.name))
49
+ }
50
+ const el = h(MyComp, { name: "test" }, "child")
51
+ expect(typeof el.type).toBe("function")
52
+ expect(el.props.name).toBe("test")
53
+ })
54
+
55
+ test("fragment", () => {
56
+ const el = h(Fragment, null, "fragment")
57
+ expect(el.type).toBe(Fragment)
58
+ })
59
+
60
+ test("event handler", () => {
61
+ const handler = vi.fn()
62
+ const el = h("button", { onClick: handler }, "click")
63
+ expect(el.props.onClick).toBe(handler)
64
+ })
65
+
66
+ test("style as object", () => {
67
+ const el = h("div", { style: { color: "red" } }, "styled")
68
+ expect(el.props.style).toEqual({ color: "red" })
69
+ })
70
+
71
+ test("data attributes", () => {
72
+ const el = h("div", { "data-testid": "foo" }, "test")
73
+ expect(el.props["data-testid"]).toBe("foo")
74
+ })
75
+
76
+ test("aria attributes", () => {
77
+ const el = h("div", { "aria-label": "close", role: "button" })
78
+ expect(el.props["aria-label"]).toBe("close")
79
+ expect(el.props.role).toBe("button")
80
+ })
81
+
82
+ test("key prop", () => {
83
+ const el = h("li", { key: "item-1" }, "item")
84
+ expect(el.key).toBe("item-1")
85
+ })
86
+ })