@pyreon/connector-document 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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pyreon/connector-document",
3
- "version": "0.24.5",
3
+ "version": "0.24.6",
4
4
  "description": "Bridge between @pyreon/pyreon styled components and @pyreon/document rendering",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -13,8 +13,7 @@
13
13
  "!lib/**/*.map",
14
14
  "!lib/analysis",
15
15
  "README.md",
16
- "LICENSE",
17
- "src"
16
+ "LICENSE"
18
17
  ],
19
18
  "type": "module",
20
19
  "sideEffects": false,
@@ -22,7 +21,6 @@
22
21
  "types": "./lib/index.d.ts",
23
22
  "exports": {
24
23
  ".": {
25
- "bun": "./src/index.ts",
26
24
  "import": "./lib/index.js",
27
25
  "types": "./lib/index.d.ts"
28
26
  }
@@ -42,11 +40,11 @@
42
40
  "typecheck": "tsc --noEmit"
43
41
  },
44
42
  "devDependencies": {
45
- "@pyreon/core": "^0.24.5",
46
- "@pyreon/document": "^0.24.5",
47
- "@pyreon/reactivity": "^0.24.5",
43
+ "@pyreon/core": "^0.24.6",
44
+ "@pyreon/document": "^0.24.6",
45
+ "@pyreon/reactivity": "^0.24.6",
48
46
  "@pyreon/test-utils": "^0.13.11",
49
- "@pyreon/typescript": "^0.24.5",
47
+ "@pyreon/typescript": "^0.24.6",
50
48
  "@vitest/browser-playwright": "^4.1.4",
51
49
  "@vitus-labs/tools-rolldown": "^2.4.0"
52
50
  },
@@ -54,7 +52,7 @@
54
52
  "node": ">= 22"
55
53
  },
56
54
  "dependencies": {
57
- "@pyreon/core": "^0.24.5",
58
- "@pyreon/document": "^0.24.5"
55
+ "@pyreon/core": "^0.24.6",
56
+ "@pyreon/document": "^0.24.6"
59
57
  }
60
58
  }
@@ -1,146 +0,0 @@
1
- /** @jsxImportSource @pyreon/core */
2
- import { h } from '@pyreon/core'
3
- import { signal } from '@pyreon/reactivity'
4
- import { afterEach, describe, expect, it } from 'vitest'
5
- import { extractDocumentTree } from '../extractDocumentTree'
6
- import { resolveStyles } from '../resolveStyles'
7
-
8
- // Real-Chromium smoke for @pyreon/connector-document.
9
- //
10
- // The pre-existing unit tests construct mock vnode objects by hand
11
- // (`{ type, props, children }`) — fast but they bypass the real
12
- // `@pyreon/core` `h()` runtime. PR #197 fixed a class of bug that
13
- // hand-mock tests can't catch: `_documentProps` only appears on a
14
- // vnode AFTER rocketstyle's `.attrs()` HOC runs, so the JSX
15
- // vnode (what `h()` returns) only carries USER-provided props.
16
- //
17
- // This suite builds vnodes with the real `h()` runtime and verifies:
18
- // 1. Path A: a documentType component with `_documentProps` already
19
- // set on the JSX vnode extracts cleanly.
20
- // 2. Path B: `extractDocumentTree` invokes the component and reads
21
- // `_documentProps` from the post-call vnode (the rocketstyle
22
- // attrs-style path) — proving the workaround documented in the
23
- // source still functions in a real browser.
24
- // 3. Function-valued `_documentProps` (reactive accessors) are
25
- // resolved to LIVE values at extraction time — covers the
26
- // "metadata reads current signal" path used by document-primitives.
27
- // 4. resolveStyles converts rocketstyle theme objects to plain
28
- // style records in the browser bundle (no Node-only dep leaks).
29
-
30
- describe('@pyreon/connector-document in real browser', () => {
31
- afterEach(() => {
32
- // No globals to reset — extractDocumentTree is pure.
33
- })
34
-
35
- it('Path A — reads _documentProps off the JSX vnode WITHOUT invoking the component', () => {
36
- // Strict Path A: the component function itself must NEVER touch
37
- // `_documentProps` — `_documentProps` is supplied directly on the
38
- // JSX vnode props. To prove the extractor takes the fast path and
39
- // doesn't call the component, we install a throwing body: if
40
- // extractNode falls through to Path B (invoking the component),
41
- // the test fails with the throw. Passing proves Path A is taken.
42
- const Heading = (_props: any) => {
43
- throw new Error('Path A must not invoke the component')
44
- }
45
- ;(Heading as any)._documentType = 'heading'
46
-
47
- const tree = h(
48
- Heading,
49
- { _documentProps: { level: 1 }, $rocketstyle: { color: '#000' } },
50
- 'Hi',
51
- )
52
- const result = extractDocumentTree(tree)
53
-
54
- expect(result.type).toBe('heading')
55
- expect(result.props).toEqual({ level: 1 })
56
- expect(result.children[0]).toBe('Hi')
57
- expect(result.styles?.color).toBe('#000')
58
- })
59
-
60
- it('Path B — invokes the component to recover _documentProps from the post-call vnode', () => {
61
- // Simulates the rocketstyle attrs-HOC pattern: USER passes
62
- // `{ title, author }` as JSX props; the component itself
63
- // injects `_documentProps` into its return vnode via h().
64
- const DocDocument = (props: any) =>
65
- h(
66
- 'div',
67
- {
68
- // Post-attrs props — never visible on the JSX vnode itself.
69
- _documentProps: {
70
- title: props.title,
71
- author: props.author,
72
- },
73
- },
74
- props.children,
75
- )
76
- ;(DocDocument as any)._documentType = 'document'
77
-
78
- const tree = h(DocDocument, { title: 'Manual', author: 'Vít' }, 'body')
79
- const result = extractDocumentTree(tree)
80
-
81
- expect(result.type).toBe('document')
82
- expect(result.props).toEqual({ title: 'Manual', author: 'Vít' })
83
- })
84
-
85
- it('resolves function-valued _documentProps to LIVE values at extraction time', () => {
86
- const titleSig = signal('Initial')
87
- const DocDocument = (props: any) =>
88
- h(
89
- 'div',
90
- {
91
- _documentProps: {
92
- // Accessor — extractor must call this to read the live signal.
93
- title: props.title,
94
- },
95
- },
96
- props.children,
97
- )
98
- ;(DocDocument as any)._documentType = 'document'
99
-
100
- const tree = h(DocDocument, { title: () => titleSig() }, 'x')
101
-
102
- const before = extractDocumentTree(tree)
103
- expect(before.props).toEqual({ title: 'Initial' })
104
-
105
- titleSig.set('Updated')
106
- const after = extractDocumentTree(tree)
107
- // Same vnode, same accessor — but it now reads the new signal value.
108
- expect(after.props).toEqual({ title: 'Updated' })
109
- })
110
-
111
- it('flattens transparent (non-documentType) wrappers built with h()', () => {
112
- const Section = (props: any) => h('div', props, props.children)
113
- ;(Section as any)._documentType = 'section'
114
- const Text = (props: any) => h('span', props, props.children)
115
- ;(Text as any)._documentType = 'text'
116
-
117
- const tree = h(
118
- Section,
119
- null,
120
- // Plain `h('div')` wrapper has no _documentType — should be
121
- // flattened, leaving the inner Text directly under Section.
122
- h('div', null, h(Text, null, 'inner')),
123
- )
124
- const result = extractDocumentTree(tree)
125
- expect(result.type).toBe('section')
126
- expect(result.children).toHaveLength(1)
127
- expect((result.children[0] as any).type).toBe('text')
128
- expect((result.children[0] as any).children[0]).toBe('inner')
129
- })
130
-
131
- it('resolveStyles produces a plain style record in the browser bundle', () => {
132
- const styles = resolveStyles(
133
- {
134
- color: '#fff',
135
- backgroundColor: '#0070f3',
136
- fontSize: 24,
137
- padding: '8px 16px',
138
- },
139
- 16,
140
- )
141
- expect(styles.color).toBe('#fff')
142
- expect(styles.backgroundColor).toBe('#0070f3')
143
- expect(styles.fontSize).toBe(24)
144
- expect(styles.padding).toEqual([8, 16])
145
- })
146
- })
@@ -1,136 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
- import {
3
- parseBoxModel,
4
- parseCssDimension,
5
- parseFontWeight,
6
- parseLineHeight,
7
- } from '../cssValueParser'
8
-
9
- describe('parseCssDimension', () => {
10
- it('passes through numbers', () => {
11
- expect(parseCssDimension(14)).toBe(14)
12
- expect(parseCssDimension(0)).toBe(0)
13
- expect(parseCssDimension(-5)).toBe(-5)
14
- expect(parseCssDimension(1.5)).toBe(1.5)
15
- })
16
-
17
- it('parses px values', () => {
18
- expect(parseCssDimension('14px')).toBe(14)
19
- expect(parseCssDimension('0px')).toBe(0)
20
- expect(parseCssDimension('-5px')).toBe(-5)
21
- expect(parseCssDimension('1.5px')).toBe(1.5)
22
- })
23
-
24
- it('parses rem values', () => {
25
- expect(parseCssDimension('1rem')).toBe(16)
26
- expect(parseCssDimension('1.5rem')).toBe(24)
27
- expect(parseCssDimension('0.5rem')).toBe(8)
28
- expect(parseCssDimension('2rem', 20)).toBe(40)
29
- })
30
-
31
- it('parses em values', () => {
32
- expect(parseCssDimension('1em')).toBe(16)
33
- expect(parseCssDimension('2em')).toBe(32)
34
- })
35
-
36
- it('parses pt values', () => {
37
- expect(parseCssDimension('12pt')).toBeCloseTo(16)
38
- expect(parseCssDimension('9pt')).toBeCloseTo(12)
39
- })
40
-
41
- it('parses bare number strings', () => {
42
- expect(parseCssDimension('14')).toBe(14)
43
- expect(parseCssDimension('0')).toBe(0)
44
- expect(parseCssDimension('-5')).toBe(-5)
45
- })
46
-
47
- it('returns undefined for unresolvable values', () => {
48
- expect(parseCssDimension('auto')).toBeUndefined()
49
- expect(parseCssDimension('100%')).toBeUndefined()
50
- expect(parseCssDimension('calc(100% - 20px)')).toBeUndefined()
51
- expect(parseCssDimension('var(--spacing)')).toBeUndefined()
52
- })
53
-
54
- it('trims whitespace', () => {
55
- expect(parseCssDimension(' 14px ')).toBe(14)
56
- expect(parseCssDimension(' 1rem ')).toBe(16)
57
- })
58
- })
59
-
60
- describe('parseBoxModel', () => {
61
- it('returns undefined for null/undefined', () => {
62
- expect(parseBoxModel(undefined)).toBeUndefined()
63
- expect(parseBoxModel(null as any)).toBeUndefined()
64
- })
65
-
66
- it('passes through numbers', () => {
67
- expect(parseBoxModel(8)).toBe(8)
68
- expect(parseBoxModel(0)).toBe(0)
69
- })
70
-
71
- it('parses single value', () => {
72
- expect(parseBoxModel('8px')).toBe(8)
73
- expect(parseBoxModel('1rem')).toBe(16)
74
- })
75
-
76
- it('parses two values (vertical horizontal)', () => {
77
- expect(parseBoxModel('8px 16px')).toEqual([8, 16])
78
- })
79
-
80
- it('parses three values (top horizontal bottom)', () => {
81
- expect(parseBoxModel('8px 16px 12px')).toEqual([8, 16, 12, 16])
82
- })
83
-
84
- it('parses four values', () => {
85
- expect(parseBoxModel('8px 16px 12px 4px')).toEqual([8, 16, 12, 4])
86
- })
87
-
88
- it('returns undefined when any part is unresolvable', () => {
89
- expect(parseBoxModel('8px auto')).toBeUndefined()
90
- expect(parseBoxModel('8px 16px auto 4px')).toBeUndefined()
91
- })
92
- })
93
-
94
- describe('parseFontWeight', () => {
95
- it('passes through numbers', () => {
96
- expect(parseFontWeight(400)).toBe(400)
97
- expect(parseFontWeight(700)).toBe(700)
98
- })
99
-
100
- it('handles string keywords', () => {
101
- expect(parseFontWeight('normal')).toBe('normal')
102
- expect(parseFontWeight('bold')).toBe('bold')
103
- })
104
-
105
- it('parses numeric strings', () => {
106
- expect(parseFontWeight('400')).toBe(400)
107
- expect(parseFontWeight('700')).toBe(700)
108
- })
109
-
110
- it('returns undefined for null/undefined', () => {
111
- expect(parseFontWeight(undefined)).toBeUndefined()
112
- })
113
-
114
- it('returns undefined for unrecognized values', () => {
115
- expect(parseFontWeight('lighter')).toBeUndefined()
116
- })
117
- })
118
-
119
- describe('parseLineHeight', () => {
120
- it('passes through numbers (unitless)', () => {
121
- expect(parseLineHeight(1.5)).toBe(1.5)
122
- expect(parseLineHeight(2)).toBe(2)
123
- })
124
-
125
- it('parses px values', () => {
126
- expect(parseLineHeight('24px')).toBe(24)
127
- })
128
-
129
- it("returns undefined for 'normal'", () => {
130
- expect(parseLineHeight('normal')).toBeUndefined()
131
- })
132
-
133
- it('returns undefined for null/undefined', () => {
134
- expect(parseLineHeight(undefined)).toBeUndefined()
135
- })
136
- })