@fictjs/runtime 0.0.12 → 0.0.13
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/dist/index.cjs +2330 -3203
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -141
- package/dist/index.d.ts +7 -141
- package/dist/index.dev.js +2526 -2836
- package/dist/index.dev.js.map +1 -1
- package/dist/index.js +2331 -3197
- package/dist/index.js.map +1 -1
- package/package.json +1 -6
- package/src/binding.ts +25 -422
- package/src/constants.ts +368 -344
- package/src/cycle-guard.ts +124 -97
- package/src/dom.ts +19 -25
- package/src/effect.ts +4 -0
- package/src/hooks.ts +9 -1
- package/src/index.ts +1 -19
- package/src/lifecycle.ts +13 -2
- package/src/list-helpers.ts +6 -65
- package/src/signal.ts +59 -39
- package/dist/slim.cjs +0 -3854
- package/dist/slim.cjs.map +0 -1
- package/dist/slim.d.cts +0 -504
- package/dist/slim.d.ts +0 -504
- package/dist/slim.js +0 -3802
- package/dist/slim.js.map +0 -1
- package/src/slim.ts +0 -69
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fictjs/runtime",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.13",
|
|
4
4
|
"description": "Fict reactive runtime",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
@@ -30,11 +30,6 @@
|
|
|
30
30
|
"import": "./dist/index.js",
|
|
31
31
|
"require": "./dist/index.cjs"
|
|
32
32
|
},
|
|
33
|
-
"./slim": {
|
|
34
|
-
"types": "./dist/slim.d.ts",
|
|
35
|
-
"import": "./dist/slim.js",
|
|
36
|
-
"require": "./dist/slim.cjs"
|
|
37
|
-
},
|
|
38
33
|
"./jsx-runtime": {
|
|
39
34
|
"types": "./dist/jsx-runtime.d.ts",
|
|
40
35
|
"import": "./dist/jsx-runtime.js",
|
package/src/binding.ts
CHANGED
|
@@ -19,12 +19,10 @@ import {
|
|
|
19
19
|
ChildProperties,
|
|
20
20
|
getPropAlias,
|
|
21
21
|
SVGNamespace,
|
|
22
|
-
Aliases,
|
|
23
22
|
} from './constants'
|
|
24
23
|
import { createRenderEffect } from './effect'
|
|
25
24
|
import { Fragment } from './jsx'
|
|
26
25
|
import {
|
|
27
|
-
clearRoot,
|
|
28
26
|
createRootContext,
|
|
29
27
|
destroyRoot,
|
|
30
28
|
flushOnMount,
|
|
@@ -36,12 +34,16 @@ import {
|
|
|
36
34
|
registerRootCleanup,
|
|
37
35
|
type RootContext,
|
|
38
36
|
} from './lifecycle'
|
|
39
|
-
import { createVersionedSignalAccessor } from './list-helpers'
|
|
40
37
|
import { toNodeArray, removeNodes, insertNodesBefore } from './node-ops'
|
|
41
38
|
import { batch } from './scheduler'
|
|
42
|
-
import { computed,
|
|
39
|
+
import { computed, untrack } from './signal'
|
|
43
40
|
import type { Cleanup, FictNode } from './types'
|
|
44
41
|
|
|
42
|
+
const isDev =
|
|
43
|
+
typeof __DEV__ !== 'undefined'
|
|
44
|
+
? __DEV__
|
|
45
|
+
: typeof process === 'undefined' || process.env?.NODE_ENV !== 'production'
|
|
46
|
+
|
|
45
47
|
// ============================================================================
|
|
46
48
|
// Type Definitions
|
|
47
49
|
// ============================================================================
|
|
@@ -63,16 +65,6 @@ export interface BindingHandle {
|
|
|
63
65
|
}
|
|
64
66
|
|
|
65
67
|
/** Managed child node with its dispose function */
|
|
66
|
-
interface ManagedBlock<T = unknown> {
|
|
67
|
-
nodes: Node[]
|
|
68
|
-
root: RootContext
|
|
69
|
-
value: Signal<T>
|
|
70
|
-
index: Signal<number>
|
|
71
|
-
start: Comment
|
|
72
|
-
end: Comment
|
|
73
|
-
renderCurrent: () => FictNode
|
|
74
|
-
}
|
|
75
|
-
|
|
76
68
|
// ============================================================================
|
|
77
69
|
// Utility Functions
|
|
78
70
|
// ============================================================================
|
|
@@ -130,151 +122,6 @@ export function callEventHandler(
|
|
|
130
122
|
invoke(handler)
|
|
131
123
|
}
|
|
132
124
|
|
|
133
|
-
export const PRIMITIVE_PROXY = Symbol('fict:primitive-proxy')
|
|
134
|
-
const PRIMITIVE_PROXY_RAW_VALUE = Symbol('fict:primitive-proxy:raw-value')
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Unwrap a primitive proxy value to get the raw primitive value.
|
|
138
|
-
* This is primarily useful for advanced scenarios where you need the actual
|
|
139
|
-
* primitive type (e.g., for typeof checks or strict equality comparisons).
|
|
140
|
-
*
|
|
141
|
-
* @param value - A potentially proxied primitive value
|
|
142
|
-
* @returns The raw primitive value
|
|
143
|
-
*
|
|
144
|
-
* @example
|
|
145
|
-
* ```ts
|
|
146
|
-
* createList(
|
|
147
|
-
* () => [1, 2, 3],
|
|
148
|
-
* (item) => {
|
|
149
|
-
* const raw = unwrapPrimitive(item)
|
|
150
|
-
* typeof raw === 'number' // true
|
|
151
|
-
* raw === 1 // true (for first item)
|
|
152
|
-
* },
|
|
153
|
-
* item => item
|
|
154
|
-
* )
|
|
155
|
-
* ```
|
|
156
|
-
*/
|
|
157
|
-
export function unwrapPrimitive<T>(value: T): T {
|
|
158
|
-
if (value && typeof value === 'object' && PRIMITIVE_PROXY in value) {
|
|
159
|
-
// Use the internal raw value getter
|
|
160
|
-
const getRawValue = (value as Record<PropertyKey, unknown>)[PRIMITIVE_PROXY_RAW_VALUE]
|
|
161
|
-
if (typeof getRawValue === 'function') {
|
|
162
|
-
return (getRawValue as () => T)()
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
return value
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
function _createValueProxy<T>(read: () => T): T {
|
|
169
|
-
const getPrimitivePrototype = (value: unknown): Record<PropertyKey, unknown> | undefined => {
|
|
170
|
-
switch (typeof value) {
|
|
171
|
-
case 'string':
|
|
172
|
-
return String.prototype as unknown as Record<PropertyKey, unknown>
|
|
173
|
-
case 'number':
|
|
174
|
-
return Number.prototype as unknown as Record<PropertyKey, unknown>
|
|
175
|
-
case 'boolean':
|
|
176
|
-
return Boolean.prototype as unknown as Record<PropertyKey, unknown>
|
|
177
|
-
case 'bigint':
|
|
178
|
-
return BigInt.prototype as unknown as Record<PropertyKey, unknown>
|
|
179
|
-
case 'symbol':
|
|
180
|
-
return Symbol.prototype as unknown as Record<PropertyKey, unknown>
|
|
181
|
-
default:
|
|
182
|
-
return undefined
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const target: Record<PropertyKey, unknown> = {}
|
|
187
|
-
const handler: ProxyHandler<Record<PropertyKey, unknown>> = {
|
|
188
|
-
get(_target, prop, receiver) {
|
|
189
|
-
if (prop === PRIMITIVE_PROXY) {
|
|
190
|
-
return true
|
|
191
|
-
}
|
|
192
|
-
if (prop === PRIMITIVE_PROXY_RAW_VALUE) {
|
|
193
|
-
return () => read()
|
|
194
|
-
}
|
|
195
|
-
if (prop === Symbol.toPrimitive) {
|
|
196
|
-
return (hint: 'string' | 'number' | 'default') => {
|
|
197
|
-
const value = read() as unknown
|
|
198
|
-
if (value != null && (typeof value === 'object' || typeof value === 'function')) {
|
|
199
|
-
const toPrimitive = (value as { [Symbol.toPrimitive]?: (hint: string) => unknown })[
|
|
200
|
-
Symbol.toPrimitive
|
|
201
|
-
]
|
|
202
|
-
if (typeof toPrimitive === 'function') {
|
|
203
|
-
return toPrimitive.call(value, hint)
|
|
204
|
-
}
|
|
205
|
-
if (hint === 'string') return value.toString?.() ?? '[object Object]'
|
|
206
|
-
if (hint === 'number') return value.valueOf?.() ?? value
|
|
207
|
-
return value.valueOf?.() ?? value
|
|
208
|
-
}
|
|
209
|
-
return value
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
if (prop === 'valueOf') {
|
|
213
|
-
return () => {
|
|
214
|
-
const value = read() as unknown
|
|
215
|
-
if (value != null && (typeof value === 'object' || typeof value === 'function')) {
|
|
216
|
-
return typeof (value as { valueOf?: () => unknown }).valueOf === 'function'
|
|
217
|
-
? (value as { valueOf: () => unknown }).valueOf()
|
|
218
|
-
: value
|
|
219
|
-
}
|
|
220
|
-
return value
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
if (prop === 'toString') {
|
|
224
|
-
return () => String(read())
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
const value = read() as unknown
|
|
228
|
-
if (value != null && (typeof value === 'object' || typeof value === 'function')) {
|
|
229
|
-
return Reflect.get(value as object, prop, receiver === _target ? value : receiver)
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
const proto = getPrimitivePrototype(value)
|
|
233
|
-
if (proto && prop in proto) {
|
|
234
|
-
const descriptor = Reflect.get(proto, prop, value)
|
|
235
|
-
return typeof descriptor === 'function' ? descriptor.bind(value) : descriptor
|
|
236
|
-
}
|
|
237
|
-
return undefined
|
|
238
|
-
},
|
|
239
|
-
set(_target, prop, newValue, receiver) {
|
|
240
|
-
const value = read() as unknown
|
|
241
|
-
if (value != null && (typeof value === 'object' || typeof value === 'function')) {
|
|
242
|
-
return Reflect.set(value as object, prop, newValue, receiver === _target ? value : receiver)
|
|
243
|
-
}
|
|
244
|
-
return false
|
|
245
|
-
},
|
|
246
|
-
has(_target, prop) {
|
|
247
|
-
if (prop === PRIMITIVE_PROXY || prop === PRIMITIVE_PROXY_RAW_VALUE) {
|
|
248
|
-
return true
|
|
249
|
-
}
|
|
250
|
-
const value = read() as unknown
|
|
251
|
-
if (value != null && (typeof value === 'object' || typeof value === 'function')) {
|
|
252
|
-
return prop in (value as object)
|
|
253
|
-
}
|
|
254
|
-
const proto = getPrimitivePrototype(value)
|
|
255
|
-
return proto ? prop in proto : false
|
|
256
|
-
},
|
|
257
|
-
ownKeys() {
|
|
258
|
-
const value = read() as unknown
|
|
259
|
-
if (value != null && (typeof value === 'object' || typeof value === 'function')) {
|
|
260
|
-
return Reflect.ownKeys(value as object)
|
|
261
|
-
}
|
|
262
|
-
const proto = getPrimitivePrototype(value)
|
|
263
|
-
return proto ? Reflect.ownKeys(proto) : []
|
|
264
|
-
},
|
|
265
|
-
getOwnPropertyDescriptor(_target, prop) {
|
|
266
|
-
const value = read() as unknown
|
|
267
|
-
if (value != null && (typeof value === 'object' || typeof value === 'function')) {
|
|
268
|
-
return Object.getOwnPropertyDescriptor(value as object, prop)
|
|
269
|
-
}
|
|
270
|
-
const proto = getPrimitivePrototype(value)
|
|
271
|
-
return proto ? Object.getOwnPropertyDescriptor(proto, prop) || undefined : undefined
|
|
272
|
-
},
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
return new Proxy(target, handler) as T
|
|
276
|
-
}
|
|
277
|
-
|
|
278
125
|
// ============================================================================
|
|
279
126
|
// Text Binding
|
|
280
127
|
// ============================================================================
|
|
@@ -519,9 +366,9 @@ function applyStyle(
|
|
|
519
366
|
}
|
|
520
367
|
}
|
|
521
368
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
369
|
+
const isUnitlessStyleProperty = isDev
|
|
370
|
+
? (prop: string): boolean => UnitlessStyles.has(prop)
|
|
371
|
+
: (prop: string): boolean => prop === 'opacity' || prop === 'zIndex'
|
|
525
372
|
|
|
526
373
|
// ============================================================================
|
|
527
374
|
// Class Binding
|
|
@@ -1107,7 +954,7 @@ export function bindEvent(
|
|
|
1107
954
|
// Optimization: Global Event Delegation
|
|
1108
955
|
// If the event is delegatable and no special options (capture, passive) are used,
|
|
1109
956
|
// we attach the handler to the element property and rely on the global listener.
|
|
1110
|
-
if (DelegatedEvents.has(eventName) && !options) {
|
|
957
|
+
if (isDev && DelegatedEvents.has(eventName) && !options) {
|
|
1111
958
|
const key = `$$${eventName}`
|
|
1112
959
|
|
|
1113
960
|
// Ensure global delegation is active for this event
|
|
@@ -1388,7 +1235,7 @@ function assignProp(
|
|
|
1388
1235
|
// Standard event handling: onClick, onInput, etc.
|
|
1389
1236
|
if (prop.slice(0, 2) === 'on') {
|
|
1390
1237
|
const eventName = prop.slice(2).toLowerCase()
|
|
1391
|
-
const shouldDelegate = DelegatedEvents.has(eventName)
|
|
1238
|
+
const shouldDelegate = isDev && DelegatedEvents.has(eventName)
|
|
1392
1239
|
if (!shouldDelegate && prev) {
|
|
1393
1240
|
const handler = Array.isArray(prev) ? prev[0] : prev
|
|
1394
1241
|
node.removeEventListener(eventName, handler as EventListener)
|
|
@@ -1432,13 +1279,20 @@ function assignProp(
|
|
|
1432
1279
|
|
|
1433
1280
|
// Property handling (for non-SVG elements)
|
|
1434
1281
|
if (!isSVG) {
|
|
1435
|
-
const propAlias = getPropAlias(prop, node.tagName)
|
|
1436
|
-
const isProperty =
|
|
1437
|
-
|
|
1282
|
+
const propAlias = isDev ? getPropAlias(prop, node.tagName) : undefined
|
|
1283
|
+
const isProperty = isDev
|
|
1284
|
+
? Properties.has(prop)
|
|
1285
|
+
: prop in (node as unknown as Record<string, unknown>)
|
|
1286
|
+
const isChildProp = isDev
|
|
1287
|
+
? ChildProperties.has(prop)
|
|
1288
|
+
: prop === 'innerHTML' ||
|
|
1289
|
+
prop === 'textContent' ||
|
|
1290
|
+
prop === 'innerText' ||
|
|
1291
|
+
prop === 'children'
|
|
1438
1292
|
|
|
1439
1293
|
if (propAlias || isProperty || isChildProp || isCE) {
|
|
1440
1294
|
const propName = propAlias || prop
|
|
1441
|
-
if (isCE && !isProperty && !isChildProp) {
|
|
1295
|
+
if (isCE && !isProperty && !isChildProp && !propAlias) {
|
|
1442
1296
|
;(node as unknown as Record<string, unknown>)[toPropertyName(propName)] = value
|
|
1443
1297
|
} else {
|
|
1444
1298
|
;(node as unknown as Record<string, unknown>)[propName] = value
|
|
@@ -1459,7 +1313,7 @@ function assignProp(
|
|
|
1459
1313
|
}
|
|
1460
1314
|
|
|
1461
1315
|
// Default: set as attribute
|
|
1462
|
-
const attrName =
|
|
1316
|
+
const attrName = prop === 'htmlFor' ? 'for' : prop
|
|
1463
1317
|
if (value == null) node.removeAttribute(attrName)
|
|
1464
1318
|
else node.setAttribute(attrName, String(value))
|
|
1465
1319
|
return value
|
|
@@ -1607,116 +1461,6 @@ export function createConditional(
|
|
|
1607
1461
|
}
|
|
1608
1462
|
}
|
|
1609
1463
|
|
|
1610
|
-
// ============================================================================
|
|
1611
|
-
// List Rendering
|
|
1612
|
-
// ============================================================================
|
|
1613
|
-
|
|
1614
|
-
/** Key extractor function type */
|
|
1615
|
-
export type KeyFn<T> = (item: T, index: number) => string | number
|
|
1616
|
-
|
|
1617
|
-
/**
|
|
1618
|
-
* Create a reactive list rendering binding with optional keying.
|
|
1619
|
-
* The render callback receives signal accessors for the item and index.
|
|
1620
|
-
*/
|
|
1621
|
-
export function createList<T>(
|
|
1622
|
-
items: () => T[],
|
|
1623
|
-
renderItem: (item: Signal<T>, index: Signal<number>) => FictNode,
|
|
1624
|
-
createElementFn: CreateElementFn,
|
|
1625
|
-
getKey?: KeyFn<T>,
|
|
1626
|
-
): BindingHandle {
|
|
1627
|
-
const startMarker = document.createComment('fict:list:start')
|
|
1628
|
-
const endMarker = document.createComment('fict:list:end')
|
|
1629
|
-
const fragment = document.createDocumentFragment()
|
|
1630
|
-
fragment.append(startMarker, endMarker)
|
|
1631
|
-
const hostRoot = getCurrentRoot()
|
|
1632
|
-
|
|
1633
|
-
const nodeMap = new Map<string | number, ManagedBlock<T>>()
|
|
1634
|
-
let pendingItems: T[] | null = null
|
|
1635
|
-
|
|
1636
|
-
const runListUpdate = () => {
|
|
1637
|
-
const arr = items()
|
|
1638
|
-
const parent = startMarker.parentNode as (ParentNode & Node) | null
|
|
1639
|
-
if (!parent) {
|
|
1640
|
-
pendingItems = arr
|
|
1641
|
-
return
|
|
1642
|
-
}
|
|
1643
|
-
pendingItems = null
|
|
1644
|
-
|
|
1645
|
-
const newNodeMap = new Map<string | number, ManagedBlock<T>>()
|
|
1646
|
-
const blocks: ManagedBlock<T>[] = []
|
|
1647
|
-
|
|
1648
|
-
for (let i = 0; i < arr.length; i++) {
|
|
1649
|
-
const item = arr[i]! as T
|
|
1650
|
-
const key = getKey ? getKey(item, i) : i
|
|
1651
|
-
const existing = nodeMap.get(key)
|
|
1652
|
-
|
|
1653
|
-
let block: ManagedBlock<T>
|
|
1654
|
-
if (existing) {
|
|
1655
|
-
const previousValue = existing.value()
|
|
1656
|
-
if (!getKey && previousValue !== item) {
|
|
1657
|
-
destroyRoot(existing.root)
|
|
1658
|
-
removeBlockNodes(existing)
|
|
1659
|
-
block = mountBlock(item, i, renderItem, parent, endMarker, createElementFn, hostRoot)
|
|
1660
|
-
} else {
|
|
1661
|
-
const previousIndex = existing.index()
|
|
1662
|
-
existing.value(item)
|
|
1663
|
-
existing.index(i)
|
|
1664
|
-
|
|
1665
|
-
const needsRerender = getKey ? true : previousValue !== item || previousIndex !== i
|
|
1666
|
-
block = needsRerender ? rerenderBlock(existing, createElementFn) : existing
|
|
1667
|
-
}
|
|
1668
|
-
} else {
|
|
1669
|
-
block = mountBlock(item, i, renderItem, parent, endMarker, createElementFn, hostRoot)
|
|
1670
|
-
}
|
|
1671
|
-
|
|
1672
|
-
newNodeMap.set(key, block)
|
|
1673
|
-
blocks.push(block)
|
|
1674
|
-
}
|
|
1675
|
-
|
|
1676
|
-
for (const [key, managed] of nodeMap) {
|
|
1677
|
-
if (!newNodeMap.has(key)) {
|
|
1678
|
-
destroyRoot(managed.root)
|
|
1679
|
-
removeBlockNodes(managed)
|
|
1680
|
-
}
|
|
1681
|
-
}
|
|
1682
|
-
|
|
1683
|
-
let anchor: Node = endMarker
|
|
1684
|
-
for (let i = blocks.length - 1; i >= 0; i--) {
|
|
1685
|
-
const block = blocks[i]!
|
|
1686
|
-
insertNodesBefore(parent, block.nodes, anchor)
|
|
1687
|
-
if (block.nodes.length > 0) {
|
|
1688
|
-
anchor = block.nodes[0]!
|
|
1689
|
-
}
|
|
1690
|
-
}
|
|
1691
|
-
|
|
1692
|
-
nodeMap.clear()
|
|
1693
|
-
for (const [k, v] of newNodeMap) {
|
|
1694
|
-
nodeMap.set(k, v)
|
|
1695
|
-
}
|
|
1696
|
-
}
|
|
1697
|
-
|
|
1698
|
-
const dispose = createRenderEffect(runListUpdate)
|
|
1699
|
-
|
|
1700
|
-
return {
|
|
1701
|
-
marker: fragment,
|
|
1702
|
-
flush: () => {
|
|
1703
|
-
if (pendingItems !== null) {
|
|
1704
|
-
runListUpdate()
|
|
1705
|
-
}
|
|
1706
|
-
},
|
|
1707
|
-
dispose: () => {
|
|
1708
|
-
dispose()
|
|
1709
|
-
for (const [, managed] of nodeMap) {
|
|
1710
|
-
destroyRoot(managed.root)
|
|
1711
|
-
removeBlockNodes(managed)
|
|
1712
|
-
}
|
|
1713
|
-
nodeMap.clear()
|
|
1714
|
-
startMarker.parentNode?.removeChild(startMarker)
|
|
1715
|
-
endMarker.parentNode?.removeChild(endMarker)
|
|
1716
|
-
},
|
|
1717
|
-
}
|
|
1718
|
-
}
|
|
1719
|
-
|
|
1720
1464
|
// ============================================================================
|
|
1721
1465
|
// Show/Hide Helper
|
|
1722
1466
|
// ==========================================================================
|
|
@@ -1848,131 +1592,6 @@ export function createPortal(
|
|
|
1848
1592
|
}
|
|
1849
1593
|
}
|
|
1850
1594
|
|
|
1851
|
-
// ============================================================================
|
|
1852
|
-
// Internal helpers
|
|
1853
|
-
// ============================================================================
|
|
1854
|
-
|
|
1855
|
-
function mountBlock<T>(
|
|
1856
|
-
initialValue: T,
|
|
1857
|
-
initialIndex: number,
|
|
1858
|
-
renderItem: (item: Signal<T>, index: Signal<number>) => FictNode,
|
|
1859
|
-
parent: ParentNode & Node,
|
|
1860
|
-
anchor: Node,
|
|
1861
|
-
createElementFn: CreateElementFn,
|
|
1862
|
-
hostRoot?: RootContext | undefined,
|
|
1863
|
-
): ManagedBlock<T> {
|
|
1864
|
-
const start = document.createComment('fict:block:start')
|
|
1865
|
-
const end = document.createComment('fict:block:end')
|
|
1866
|
-
const valueSig = createVersionedSignalAccessor<T>(initialValue)
|
|
1867
|
-
const indexSig = createSignal<number>(initialIndex)
|
|
1868
|
-
const renderCurrent = () => renderItem(valueSig, indexSig)
|
|
1869
|
-
const root = createRootContext(hostRoot)
|
|
1870
|
-
const prev = pushRoot(root)
|
|
1871
|
-
const nodes: Node[] = [start]
|
|
1872
|
-
let handledError = false
|
|
1873
|
-
try {
|
|
1874
|
-
const output = renderCurrent()
|
|
1875
|
-
if (output != null && output !== false) {
|
|
1876
|
-
const el = createElementFn(output)
|
|
1877
|
-
const rendered = toNodeArray(el)
|
|
1878
|
-
nodes.push(...rendered)
|
|
1879
|
-
}
|
|
1880
|
-
nodes.push(end)
|
|
1881
|
-
insertNodesBefore(parent, nodes, anchor)
|
|
1882
|
-
} catch (err) {
|
|
1883
|
-
if (handleSuspend(err as any, root)) {
|
|
1884
|
-
handledError = true
|
|
1885
|
-
nodes.push(end)
|
|
1886
|
-
insertNodesBefore(parent, nodes, anchor)
|
|
1887
|
-
} else if (handleError(err, { source: 'renderChild' }, root)) {
|
|
1888
|
-
handledError = true
|
|
1889
|
-
nodes.push(end)
|
|
1890
|
-
insertNodesBefore(parent, nodes, anchor)
|
|
1891
|
-
} else {
|
|
1892
|
-
throw err
|
|
1893
|
-
}
|
|
1894
|
-
} finally {
|
|
1895
|
-
popRoot(prev)
|
|
1896
|
-
if (!handledError) {
|
|
1897
|
-
flushOnMount(root)
|
|
1898
|
-
} else {
|
|
1899
|
-
destroyRoot(root)
|
|
1900
|
-
}
|
|
1901
|
-
}
|
|
1902
|
-
return {
|
|
1903
|
-
nodes,
|
|
1904
|
-
root,
|
|
1905
|
-
value: valueSig,
|
|
1906
|
-
index: indexSig,
|
|
1907
|
-
start,
|
|
1908
|
-
end,
|
|
1909
|
-
renderCurrent,
|
|
1910
|
-
}
|
|
1911
|
-
}
|
|
1912
|
-
|
|
1913
|
-
function rerenderBlock<T>(
|
|
1914
|
-
block: ManagedBlock<T>,
|
|
1915
|
-
createElementFn: CreateElementFn,
|
|
1916
|
-
): ManagedBlock<T> {
|
|
1917
|
-
const currentContent = block.nodes.slice(1, Math.max(1, block.nodes.length - 1))
|
|
1918
|
-
const currentNode = currentContent.length === 1 ? currentContent[0] : null
|
|
1919
|
-
|
|
1920
|
-
clearRoot(block.root)
|
|
1921
|
-
|
|
1922
|
-
const prev = pushRoot(block.root)
|
|
1923
|
-
let nextOutput: FictNode
|
|
1924
|
-
let handledError = false
|
|
1925
|
-
try {
|
|
1926
|
-
nextOutput = block.renderCurrent()
|
|
1927
|
-
} catch (err) {
|
|
1928
|
-
if (handleSuspend(err as any, block.root)) {
|
|
1929
|
-
handledError = true
|
|
1930
|
-
popRoot(prev)
|
|
1931
|
-
destroyRoot(block.root)
|
|
1932
|
-
block.nodes = [block.start, block.end]
|
|
1933
|
-
return block
|
|
1934
|
-
}
|
|
1935
|
-
if (handleError(err, { source: 'renderChild' }, block.root)) {
|
|
1936
|
-
handledError = true
|
|
1937
|
-
popRoot(prev)
|
|
1938
|
-
destroyRoot(block.root)
|
|
1939
|
-
block.nodes = [block.start, block.end]
|
|
1940
|
-
return block
|
|
1941
|
-
}
|
|
1942
|
-
throw err
|
|
1943
|
-
} finally {
|
|
1944
|
-
if (!handledError) {
|
|
1945
|
-
popRoot(prev)
|
|
1946
|
-
}
|
|
1947
|
-
}
|
|
1948
|
-
|
|
1949
|
-
if (isFragmentVNode(nextOutput) && currentContent.length > 0) {
|
|
1950
|
-
const patched = patchFragmentChildren(currentContent, nextOutput.props?.children)
|
|
1951
|
-
if (patched) {
|
|
1952
|
-
block.nodes = [block.start, ...currentContent, block.end]
|
|
1953
|
-
return block
|
|
1954
|
-
}
|
|
1955
|
-
}
|
|
1956
|
-
|
|
1957
|
-
if (currentNode && patchNode(currentNode, nextOutput)) {
|
|
1958
|
-
block.nodes = [block.start, currentNode, block.end]
|
|
1959
|
-
return block
|
|
1960
|
-
}
|
|
1961
|
-
|
|
1962
|
-
clearContent(block)
|
|
1963
|
-
|
|
1964
|
-
if (nextOutput != null && nextOutput !== false) {
|
|
1965
|
-
const newNodes = toNodeArray(
|
|
1966
|
-
nextOutput instanceof Node ? nextOutput : (createElementFn(nextOutput) as Node),
|
|
1967
|
-
)
|
|
1968
|
-
insertNodesBefore(block.start.parentNode as ParentNode & Node, newNodes, block.end)
|
|
1969
|
-
block.nodes = [block.start, ...newNodes, block.end]
|
|
1970
|
-
} else {
|
|
1971
|
-
block.nodes = [block.start, block.end]
|
|
1972
|
-
}
|
|
1973
|
-
return block
|
|
1974
|
-
}
|
|
1975
|
-
|
|
1976
1595
|
function patchElement(el: Element, output: FictNode): boolean {
|
|
1977
1596
|
if (
|
|
1978
1597
|
output === null ||
|
|
@@ -2104,7 +1723,7 @@ function patchNode(currentNode: Node | null, nextOutput: FictNode): boolean {
|
|
|
2104
1723
|
return false
|
|
2105
1724
|
}
|
|
2106
1725
|
|
|
2107
|
-
function
|
|
1726
|
+
function _isFragmentVNode(
|
|
2108
1727
|
value: unknown,
|
|
2109
1728
|
): value is { type: typeof Fragment; props?: { children?: FictNode | FictNode[] } } {
|
|
2110
1729
|
return (
|
|
@@ -2135,7 +1754,7 @@ function normalizeChildren(
|
|
|
2135
1754
|
return result
|
|
2136
1755
|
}
|
|
2137
1756
|
|
|
2138
|
-
function
|
|
1757
|
+
function _patchFragmentChildren(
|
|
2139
1758
|
nodes: Node[],
|
|
2140
1759
|
children: FictNode | FictNode[] | undefined,
|
|
2141
1760
|
): boolean {
|
|
@@ -2151,20 +1770,4 @@ function patchFragmentChildren(
|
|
|
2151
1770
|
return true
|
|
2152
1771
|
}
|
|
2153
1772
|
|
|
2154
|
-
function clearContent<T>(block: ManagedBlock<T>): void {
|
|
2155
|
-
const nodes = block.nodes.slice(1, Math.max(1, block.nodes.length - 1))
|
|
2156
|
-
removeNodes(nodes)
|
|
2157
|
-
}
|
|
2158
|
-
|
|
2159
|
-
function removeBlockNodes<T>(block: ManagedBlock<T>): void {
|
|
2160
|
-
let cursor: Node | null = block.start
|
|
2161
|
-
const end = block.end
|
|
2162
|
-
while (cursor) {
|
|
2163
|
-
const next: Node | null = cursor.nextSibling
|
|
2164
|
-
cursor.parentNode?.removeChild(cursor)
|
|
2165
|
-
if (cursor === end) break
|
|
2166
|
-
cursor = next
|
|
2167
|
-
}
|
|
2168
|
-
}
|
|
2169
|
-
|
|
2170
1773
|
// DOM utility functions are imported from './node-ops' to avoid duplication
|