fusee-framework 2.7.0 → 2.7.2
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/README.md +98 -26
- package/bin/create-fusee-linux +0 -0
- package/bin/create-fusee-mac-arm64 +0 -0
- package/bin/create-fusee-mac-intel +0 -0
- package/bin/create-fusee-win.exe +0 -0
- package/framework/auto-import-preset.js +20 -12
- package/framework/auto-imports.d.ts +68 -39
- package/framework/core/compiler.js +310 -310
- package/framework/core/component-core.js +445 -0
- package/framework/core/component.js +11 -440
- package/framework/core/composable.js +29 -29
- package/framework/core/h.js +119 -44
- package/framework/core/jsx-helpers.js +11 -2
- package/framework/core/jsx-runtime.js +73 -73
- package/framework/core/rust-compiler/pkg/fusee_compiler_bg.wasm +0 -0
- package/framework/core/store.js +333 -333
- package/framework/globals.js +42 -0
- package/framework/index.js +22 -55
- package/framework/router/file-router.js +184 -184
- package/framework/server/actions.js +183 -183
- package/framework/server/generate-manifest.js +3 -3
- package/framework/types/component.d.ts +97 -86
- package/framework/types/index.d.ts +118 -117
- package/package.json +83 -80
- package/framework/core/rust-compiler/Cargo.toml +0 -31
- package/framework/core/rust-compiler/README.md +0 -69
- package/framework/core/rust-compiler/pkg/README.md +0 -69
- package/framework/core/rust-compiler/pkg/fusee_compiler.d.ts +0 -6
- package/framework/core/rust-compiler/pkg/fusee_compiler.js +0 -9
- package/framework/core/rust-compiler/pkg/fusee_compiler_bg.js +0 -137
- package/framework/core/rust-compiler/pkg/fusee_compiler_bg.wasm.d.ts +0 -11
- package/framework/core/rust-compiler/pkg/package.json +0 -18
- package/framework/core/rust-compiler/src/ast.rs +0 -274
- package/framework/core/rust-compiler/src/errors.rs +0 -204
- package/framework/core/rust-compiler/src/generator.rs +0 -583
- package/framework/core/rust-compiler/src/lexer.rs +0 -414
- package/framework/core/rust-compiler/src/lib.rs +0 -87
- package/framework/core/rust-compiler/src/main_compiler.rs +0 -165
- package/framework/core/rust-compiler/src/parser.rs +0 -516
- package/framework/core/rust-compiler/src/ssr_generator.rs +0 -688
- package/framework/core/rust-compiler/src/transformer.rs +0 -562
- package/framework/core/rust-compiler/src/utils.rs +0 -10
- package/framework/engine-go/actions.go +0 -112
- package/framework/engine-go/cmd/server/main.go +0 -233
- package/framework/engine-go/comet/comet.go +0 -41
- package/framework/engine-go/comet/fragment.go +0 -51
- package/framework/engine-go/dispatcher.go +0 -120
- package/framework/engine-go/elements.go +0 -248
- package/framework/engine-go/evalexpr/evalexpr.go +0 -733
- package/framework/engine-go/go.mod +0 -3
- package/framework/engine-go/hydration.go +0 -43
- package/framework/engine-go/load-helpers.go +0 -29
- package/framework/engine-go/manifest.go +0 -41
- package/framework/engine-go/reactive.go +0 -123
- package/framework/engine-go/render.go +0 -635
- package/framework/engine-go/reqcontext.go +0 -48
- package/framework/engine-go/router.go +0 -85
- package/framework/engine-go/rustast/rustast.go +0 -317
- package/framework/engine-go/ssr.go +0 -103
- package/framework/engine-go/static-assets.go +0 -139
- package/framework/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
package/framework/core/h.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { effect, batch, signal, microEffect } from '../core/signal.js'
|
|
1
|
+
import { effect, batch, signal, microEffect, untrack, runDetached } from '../core/signal.js'
|
|
2
2
|
import { createEventHandler, registerDelegatedEvent, isDelegatedEvent } from '../core/event-delegation.js'
|
|
3
3
|
import { resolveElementProperty } from '../core/element-props.js'
|
|
4
4
|
|
|
@@ -70,14 +70,19 @@ export function hIf(branches) {
|
|
|
70
70
|
|
|
71
71
|
let currentNodes = []
|
|
72
72
|
let currentBranch = -1
|
|
73
|
+
const mounted = _createMountTracker()
|
|
73
74
|
|
|
74
75
|
const cleanup = effect(() => {
|
|
76
|
+
mounted.track()
|
|
75
77
|
let matchIdx = -1
|
|
76
78
|
for (let i = 0; i < branches.length; i++) {
|
|
77
79
|
const [cond] = branches[i]
|
|
78
80
|
if (cond === null || cond()) { matchIdx = i; break }
|
|
79
81
|
}
|
|
80
82
|
|
|
83
|
+
const parent = anchor.parentNode
|
|
84
|
+
if (!parent) return mounted.defer()
|
|
85
|
+
|
|
81
86
|
if (matchIdx === currentBranch) return
|
|
82
87
|
|
|
83
88
|
_unmountNodes(currentNodes)
|
|
@@ -87,24 +92,28 @@ export function hIf(branches) {
|
|
|
87
92
|
if (matchIdx === -1) return
|
|
88
93
|
|
|
89
94
|
const [, getChildren] = branches[matchIdx]
|
|
90
|
-
|
|
91
|
-
const
|
|
95
|
+
// Detached: branch effects belong to the branch, which is unmounted explicitly below.
|
|
96
|
+
const children = runDetached(getChildren)
|
|
92
97
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
+
for (const fnode of children) {
|
|
99
|
+
if (!fnode?.node) continue
|
|
100
|
+
insertFNode(parent, fnode, anchor)
|
|
101
|
+
currentNodes.push(fnode)
|
|
98
102
|
}
|
|
99
103
|
})
|
|
100
104
|
|
|
101
|
-
effects.push(
|
|
105
|
+
effects.push(() => {
|
|
106
|
+
cleanup()
|
|
107
|
+
_unmountNodes(currentNodes)
|
|
108
|
+
currentNodes = []
|
|
109
|
+
})
|
|
102
110
|
|
|
103
111
|
return {
|
|
104
112
|
node: anchor,
|
|
105
113
|
effects,
|
|
106
114
|
_ifBranchNodes: () => currentNodes,
|
|
107
115
|
_isIf: true,
|
|
116
|
+
_afterInsert: mounted.resume,
|
|
108
117
|
}
|
|
109
118
|
}
|
|
110
119
|
|
|
@@ -118,19 +127,28 @@ export function hFor(sourceGetter, renderItem, keyFn) {
|
|
|
118
127
|
let _keyEvalCurrent = null
|
|
119
128
|
const keyEvaluatorGetter = () => _keyEvalCurrent
|
|
120
129
|
keyEvaluatorGetter.isSignal = true
|
|
130
|
+
const mounted = _createMountTracker()
|
|
121
131
|
|
|
122
132
|
const cleanup = effect(() => {
|
|
133
|
+
mounted.track()
|
|
123
134
|
const list = sourceGetter() ?? []
|
|
124
135
|
const parent = anchor.parentNode
|
|
125
136
|
|
|
126
|
-
if (!parent)
|
|
127
|
-
return
|
|
128
|
-
}
|
|
137
|
+
if (!parent) return mounted.defer()
|
|
129
138
|
|
|
130
139
|
const newKeys = new Array(list.length)
|
|
131
140
|
for (let i = 0; i < list.length; i++) {
|
|
132
141
|
_keyEvalCurrent = list[i]
|
|
133
|
-
|
|
142
|
+
const key = keyFn(keyEvaluatorGetter, i)
|
|
143
|
+
// Loops without :key compile to a key of undefined; key them by position, as SSR does.
|
|
144
|
+
newKeys[i] = key === undefined ? i : key
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (newKeys.length === 0 && keyedMap.size > 0) {
|
|
148
|
+
_clearRows(parent, keyedMap)
|
|
149
|
+
keyedMap = new Map()
|
|
150
|
+
oldKeys = newKeys
|
|
151
|
+
return
|
|
134
152
|
}
|
|
135
153
|
|
|
136
154
|
if (oldKeys.length === newKeys.length) {
|
|
@@ -140,10 +158,7 @@ export function hFor(sourceGetter, renderItem, keyFn) {
|
|
|
140
158
|
}
|
|
141
159
|
if (identical) {
|
|
142
160
|
for (let i = 0; i < list.length; i++) {
|
|
143
|
-
|
|
144
|
-
if (entry.itemSignal() !== list[i]) {
|
|
145
|
-
entry.itemSignal(list[i])
|
|
146
|
-
}
|
|
161
|
+
_setItem(keyedMap.get(newKeys[i]), list[i])
|
|
147
162
|
}
|
|
148
163
|
return
|
|
149
164
|
}
|
|
@@ -172,12 +187,9 @@ export function hFor(sourceGetter, renderItem, keyFn) {
|
|
|
172
187
|
const parentEl = nodeA.parentNode
|
|
173
188
|
parentEl.insertBefore(nodeA, nodeB.nextSibling)
|
|
174
189
|
parentEl.insertBefore(nodeB, refA)
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
if (entryB.itemSignal() !== list[diffB]) {
|
|
179
|
-
entryB.itemSignal(list[diffB])
|
|
180
|
-
}
|
|
190
|
+
// The two rows traded places: each keeps its key and receives the item now at its new index.
|
|
191
|
+
_setItem(entryA, list[diffB])
|
|
192
|
+
_setItem(entryB, list[diffA])
|
|
181
193
|
oldKeys = newKeys
|
|
182
194
|
return
|
|
183
195
|
}
|
|
@@ -191,13 +203,13 @@ export function hFor(sourceGetter, renderItem, keyFn) {
|
|
|
191
203
|
|
|
192
204
|
const exists = keyedMap.get(key)
|
|
193
205
|
if (exists) {
|
|
194
|
-
|
|
195
|
-
exists.itemSignal(item)
|
|
196
|
-
}
|
|
206
|
+
_setItem(exists, item)
|
|
197
207
|
newMap.set(key, exists)
|
|
198
208
|
} else {
|
|
199
209
|
const itemSignal = signal(item)
|
|
200
|
-
|
|
210
|
+
// Detached: otherwise every row's effects are registered as children of this
|
|
211
|
+
// list effect and stay reachable after the row is removed.
|
|
212
|
+
const fnode = runDetached(() => renderItem(itemSignal, i))
|
|
201
213
|
newMap.set(key, { fnode, key, itemSignal })
|
|
202
214
|
}
|
|
203
215
|
}
|
|
@@ -228,10 +240,10 @@ export function hFor(sourceGetter, renderItem, keyFn) {
|
|
|
228
240
|
if (inLis) {
|
|
229
241
|
lisPtr--
|
|
230
242
|
if (!entry.fnode.node.parentNode) {
|
|
231
|
-
parent
|
|
243
|
+
insertFNode(parent, entry.fnode, ref)
|
|
232
244
|
}
|
|
233
245
|
} else if (entry.fnode.node.nextSibling !== ref || !entry.fnode.node.parentNode) {
|
|
234
|
-
parent
|
|
246
|
+
insertFNode(parent, entry.fnode, ref)
|
|
235
247
|
}
|
|
236
248
|
}
|
|
237
249
|
|
|
@@ -239,14 +251,80 @@ export function hFor(sourceGetter, renderItem, keyFn) {
|
|
|
239
251
|
oldKeys = newKeys
|
|
240
252
|
})
|
|
241
253
|
|
|
242
|
-
effects.push(
|
|
254
|
+
effects.push(() => {
|
|
255
|
+
cleanup()
|
|
256
|
+
_unmountNodes([...keyedMap.values()].map(e => e.fnode))
|
|
257
|
+
keyedMap = new Map()
|
|
258
|
+
oldKeys = []
|
|
259
|
+
})
|
|
243
260
|
|
|
244
261
|
return {
|
|
245
262
|
node: anchor,
|
|
246
263
|
effects,
|
|
247
264
|
_isFor: true,
|
|
248
265
|
_getNodes: () => [...keyedMap.values()].map(e => e.fnode),
|
|
266
|
+
_afterInsert: mounted.resume,
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Unmounts every row. When the rows are the only elements in the parent, the parent is emptied
|
|
272
|
+
* in one operation instead of one removeChild per row, and its other nodes (the anchor, template
|
|
273
|
+
* whitespace, text) are put back in order.
|
|
274
|
+
*/
|
|
275
|
+
function _clearRows(parent, keyedMap) {
|
|
276
|
+
const fnodes = [...keyedMap.values()].map(e => e.fnode)
|
|
277
|
+
const rowsAreElements = fnodes.every(f => f.node.nodeType === 1)
|
|
278
|
+
|
|
279
|
+
if (rowsAreElements && parent.childElementCount === fnodes.length) {
|
|
280
|
+
const kept = []
|
|
281
|
+
for (let n = parent.firstChild; n; n = n.nextSibling) {
|
|
282
|
+
if (n.nodeType !== 1) kept.push(n)
|
|
283
|
+
}
|
|
284
|
+
for (const fnode of fnodes) _disposeEffects(fnode)
|
|
285
|
+
parent.textContent = ''
|
|
286
|
+
parent.append(...kept)
|
|
287
|
+
return
|
|
249
288
|
}
|
|
289
|
+
_unmountNodes(fnodes)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/** Updates a keyed row's item signal without subscribing the list effect to it. */
|
|
293
|
+
function _setItem(entry, item) {
|
|
294
|
+
if (untrack(entry.itemSignal) !== item) entry.itemSignal(item)
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* hIf/hFor are built before their anchor has a parent (children are created before the
|
|
299
|
+
* element that holds them), so their first render waits until insertFNode() places the
|
|
300
|
+
* anchor and calls _afterInsert.
|
|
301
|
+
*/
|
|
302
|
+
function _createMountTracker() {
|
|
303
|
+
const tick = signal(0)
|
|
304
|
+
let pending = false
|
|
305
|
+
return {
|
|
306
|
+
track: () => tick(),
|
|
307
|
+
defer: () => { pending = true },
|
|
308
|
+
resume: () => {
|
|
309
|
+
if (!pending) return
|
|
310
|
+
pending = false
|
|
311
|
+
tick(untrack(tick) + 1)
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Inserts a framework node (and slot nodes it carries) before ref, then lets anchor-based
|
|
318
|
+
* nodes (hIf/hFor) render now that they have a parent.
|
|
319
|
+
*/
|
|
320
|
+
export function insertFNode(parent, fnode, ref = null) {
|
|
321
|
+
parent.insertBefore(fnode.node, ref)
|
|
322
|
+
if (fnode._isSlot && fnode._slotNodes) {
|
|
323
|
+
for (const sn of fnode._slotNodes) {
|
|
324
|
+
if (sn?.node) insertFNode(parent, sn, ref)
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
if (typeof fnode._afterInsert === 'function') fnode._afterInsert()
|
|
250
328
|
}
|
|
251
329
|
|
|
252
330
|
function _getLIS(arr) {
|
|
@@ -479,13 +557,7 @@ function _mountChildren(parent, children, parentEffects) {
|
|
|
479
557
|
for (const fnode of children) {
|
|
480
558
|
if (!fnode || !fnode.node) continue
|
|
481
559
|
|
|
482
|
-
parent
|
|
483
|
-
|
|
484
|
-
if (fnode._isSlot && fnode._slotNodes) {
|
|
485
|
-
for (const sn of fnode._slotNodes) {
|
|
486
|
-
if (sn?.node) parent.insertBefore(sn.node, null)
|
|
487
|
-
}
|
|
488
|
-
}
|
|
560
|
+
insertFNode(parent, fnode)
|
|
489
561
|
|
|
490
562
|
if (fnode.effects) parentEffects.push(...fnode.effects)
|
|
491
563
|
mounted.push(fnode)
|
|
@@ -494,16 +566,19 @@ function _mountChildren(parent, children, parentEffects) {
|
|
|
494
566
|
return mounted
|
|
495
567
|
}
|
|
496
568
|
|
|
569
|
+
function _disposeEffects(fnode) {
|
|
570
|
+
if (!fnode.effects) return
|
|
571
|
+
for (let i = fnode.effects.length - 1; i >= 0; i--) {
|
|
572
|
+
const cleanup = fnode.effects[i]
|
|
573
|
+
if (typeof cleanup === 'function') cleanup()
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
497
577
|
function _unmountNodes(fnodes) {
|
|
498
578
|
for (const fnode of fnodes) {
|
|
499
579
|
if (!fnode) continue
|
|
500
580
|
|
|
501
|
-
|
|
502
|
-
for (let i = fnode.effects.length - 1; i >= 0; i--) {
|
|
503
|
-
const cleanup = fnode.effects[i]
|
|
504
|
-
if (typeof cleanup === 'function') cleanup()
|
|
505
|
-
}
|
|
506
|
-
}
|
|
581
|
+
_disposeEffects(fnode)
|
|
507
582
|
|
|
508
583
|
if (fnode.node?.parentNode) {
|
|
509
584
|
fnode.node.parentNode.removeChild(fnode.node)
|
|
@@ -545,7 +620,7 @@ export function mount(renderFn, ctx, components, container) {
|
|
|
545
620
|
|
|
546
621
|
for (const fnode of fnodes) {
|
|
547
622
|
if (!fnode?.node) continue
|
|
548
|
-
container
|
|
623
|
+
insertFNode(container, fnode)
|
|
549
624
|
if (fnode.effects) effects.push(...fnode.effects)
|
|
550
625
|
}
|
|
551
626
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { hFor, hIf } from './h.js'
|
|
1
|
+
import { hFor, hIf, hText } from './h.js'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Flattens JSX children into a single array of fnodes, dropping
|
|
@@ -6,7 +6,8 @@ import { hFor, hIf } from './h.js'
|
|
|
6
6
|
* behave the way JSX authors expect. Recursively flattens nested arrays,
|
|
7
7
|
* which is all Fragment needs: it returns its children as-is, and whatever
|
|
8
8
|
* consumes those children (h()'s children arg, or another flattenChildren
|
|
9
|
-
* call) inlines them automatically.
|
|
9
|
+
* call) inlines them automatically. Text and numbers become text nodes, and
|
|
10
|
+
* getters (dynamic `{expr}` wrapped by the Babel plugin) become reactive ones.
|
|
10
11
|
*/
|
|
11
12
|
export function flattenChildren(children) {
|
|
12
13
|
const out = []
|
|
@@ -19,6 +20,14 @@ export function flattenChildren(children) {
|
|
|
19
20
|
stack.unshift(...child)
|
|
20
21
|
continue
|
|
21
22
|
}
|
|
23
|
+
if (typeof child === 'string' || typeof child === 'number' || typeof child === 'bigint') {
|
|
24
|
+
out.push(hText(String(child)))
|
|
25
|
+
continue
|
|
26
|
+
}
|
|
27
|
+
if (typeof child === 'function') {
|
|
28
|
+
out.push(hText(child))
|
|
29
|
+
continue
|
|
30
|
+
}
|
|
22
31
|
out.push(child)
|
|
23
32
|
}
|
|
24
33
|
|
|
@@ -1,74 +1,74 @@
|
|
|
1
|
-
// Point your bundler at this module and JSX compiles here with zero custom
|
|
2
|
-
// parser/Babel plugin needed yet:
|
|
3
|
-
// - esbuild/Vite: jsx: 'automatic', jsxImportSource: '<path-to-this-folder>'
|
|
4
|
-
// - tsconfig.json: "jsx": "react-jsx", "jsxImportSource": "<path-to-this-folder>"
|
|
5
|
-
|
|
6
|
-
import { h, createComponent } from './h.js'
|
|
7
|
-
import {
|
|
8
|
-
Fragment,
|
|
9
|
-
For,
|
|
10
|
-
Show,
|
|
11
|
-
Slot,
|
|
12
|
-
on,
|
|
13
|
-
flattenChildren,
|
|
14
|
-
normalizeEventProps,
|
|
15
|
-
normalizeComponentListenerProps,
|
|
16
|
-
splitSlotChildren
|
|
17
|
-
} from './jsx-helpers.js'
|
|
18
|
-
import {
|
|
19
|
-
|
|
20
|
-
export { Fragment, For, Show, Slot, on }
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Wraps defineComponent so JSX can tell "a fusée component" apart from a
|
|
24
|
-
* plain helper function (Fragment/For/Show/Slot, or your own stateless JSX
|
|
25
|
-
* helpers). Import defineComponent from here instead of component.js in
|
|
26
|
-
* any file that defines components with JSX.
|
|
27
|
-
*/
|
|
28
|
-
export function defineComponent(options) {
|
|
29
|
-
const factory = coreDefineComponent(options)
|
|
30
|
-
factory._isFuseeComponent = true
|
|
31
|
-
factory._componentName = options?.name
|
|
32
|
-
return factory
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/** Dispatches a JSX element to h() (DOM tags), createComponent() (fusée components), or a direct call (helpers). */
|
|
36
|
-
function createNode(type, rawProps) {
|
|
37
|
-
const { children, ...rest } = rawProps || {}
|
|
38
|
-
|
|
39
|
-
if (type === Fragment) {
|
|
40
|
-
return Fragment({ children })
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (typeof type === 'string') {
|
|
44
|
-
return h(type, normalizeEventProps(rest), flattenChildren(children))
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (typeof type === 'function' && type._isFuseeComponent) {
|
|
48
|
-
const name = type._componentName || type.name || 'AnonymousComponent'
|
|
49
|
-
const props = normalizeComponentListenerProps(rest)
|
|
50
|
-
return createComponent(name, type, props, splitSlotChildren(children))
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (typeof type === 'function') {
|
|
54
|
-
return type({ ...rest, children })
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
console.warn('[fusée] Unsupported JSX element type:', type)
|
|
58
|
-
return null
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/** Automatic JSX runtime entry point for a single (or statically known) child. */
|
|
62
|
-
export function jsx(type, props, _key) {
|
|
63
|
-
return createNode(type, props)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/** Automatic JSX runtime entry point when children are a static array. */
|
|
67
|
-
export function jsxs(type, props, _key) {
|
|
68
|
-
return createNode(type, props)
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/** Dev-mode entry point; fusée doesn't use the extra source/self-closing args (yet). */
|
|
72
|
-
export function jsxDEV(type, props, _key, _isStaticChildren, _source, _self) {
|
|
73
|
-
return createNode(type, props)
|
|
1
|
+
// Point your bundler at this module and JSX compiles here with zero custom
|
|
2
|
+
// parser/Babel plugin needed yet:
|
|
3
|
+
// - esbuild/Vite: jsx: 'automatic', jsxImportSource: '<path-to-this-folder>'
|
|
4
|
+
// - tsconfig.json: "jsx": "react-jsx", "jsxImportSource": "<path-to-this-folder>"
|
|
5
|
+
|
|
6
|
+
import { h, createComponent } from './h.js'
|
|
7
|
+
import {
|
|
8
|
+
Fragment,
|
|
9
|
+
For,
|
|
10
|
+
Show,
|
|
11
|
+
Slot,
|
|
12
|
+
on,
|
|
13
|
+
flattenChildren,
|
|
14
|
+
normalizeEventProps,
|
|
15
|
+
normalizeComponentListenerProps,
|
|
16
|
+
splitSlotChildren
|
|
17
|
+
} from './jsx-helpers.js'
|
|
18
|
+
import { defineCompiledComponent as coreDefineComponent } from './component-core.js'
|
|
19
|
+
|
|
20
|
+
export { Fragment, For, Show, Slot, on }
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Wraps defineComponent so JSX can tell "a fusée component" apart from a
|
|
24
|
+
* plain helper function (Fragment/For/Show/Slot, or your own stateless JSX
|
|
25
|
+
* helpers). Import defineComponent from here instead of component.js in
|
|
26
|
+
* any file that defines components with JSX.
|
|
27
|
+
*/
|
|
28
|
+
export function defineComponent(options) {
|
|
29
|
+
const factory = coreDefineComponent(options)
|
|
30
|
+
factory._isFuseeComponent = true
|
|
31
|
+
factory._componentName = options?.name
|
|
32
|
+
return factory
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Dispatches a JSX element to h() (DOM tags), createComponent() (fusée components), or a direct call (helpers). */
|
|
36
|
+
function createNode(type, rawProps) {
|
|
37
|
+
const { children, ...rest } = rawProps || {}
|
|
38
|
+
|
|
39
|
+
if (type === Fragment) {
|
|
40
|
+
return Fragment({ children })
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (typeof type === 'string') {
|
|
44
|
+
return h(type, normalizeEventProps(rest), flattenChildren(children))
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (typeof type === 'function' && type._isFuseeComponent) {
|
|
48
|
+
const name = type._componentName || type.name || 'AnonymousComponent'
|
|
49
|
+
const props = normalizeComponentListenerProps(rest)
|
|
50
|
+
return createComponent(name, type, props, splitSlotChildren(children))
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (typeof type === 'function') {
|
|
54
|
+
return type({ ...rest, children })
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
console.warn('[fusée] Unsupported JSX element type:', type)
|
|
58
|
+
return null
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Automatic JSX runtime entry point for a single (or statically known) child. */
|
|
62
|
+
export function jsx(type, props, _key) {
|
|
63
|
+
return createNode(type, props)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Automatic JSX runtime entry point when children are a static array. */
|
|
67
|
+
export function jsxs(type, props, _key) {
|
|
68
|
+
return createNode(type, props)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Dev-mode entry point; fusée doesn't use the extra source/self-closing args (yet). */
|
|
72
|
+
export function jsxDEV(type, props, _key, _isStaticChildren, _source, _self) {
|
|
73
|
+
return createNode(type, props)
|
|
74
74
|
}
|
|
Binary file
|