@fictjs/runtime 0.16.0 → 0.17.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/dist/advanced.cjs +9 -9
- package/dist/advanced.js +4 -4
- package/dist/{chunk-CBRGOLTR.cjs → chunk-5FVWBK4M.cjs} +40 -40
- package/dist/{chunk-CBRGOLTR.cjs.map → chunk-5FVWBK4M.cjs.map} +1 -1
- package/dist/{chunk-BADX4WTQ.cjs → chunk-6DNYVH5U.cjs} +17 -17
- package/dist/{chunk-BADX4WTQ.cjs.map → chunk-6DNYVH5U.cjs.map} +1 -1
- package/dist/{chunk-MAHWGB55.js → chunk-CFAWL76V.js} +5 -5
- package/dist/{chunk-MAHWGB55.js.map → chunk-CFAWL76V.js.map} +1 -1
- package/dist/{chunk-WJMZ7X46.cjs → chunk-ECKYFH5Q.cjs} +5 -5
- package/dist/{chunk-WJMZ7X46.cjs.map → chunk-ECKYFH5Q.cjs.map} +1 -1
- package/dist/{chunk-ZJZ6LMDN.js → chunk-F5SDRX4J.js} +2 -2
- package/dist/{chunk-ZJZ6LMDN.js.map → chunk-F5SDRX4J.js.map} +1 -1
- package/dist/{chunk-4P4DYWLQ.js → chunk-IIWHTV23.js} +3 -3
- package/dist/{chunk-AR2T7JEX.cjs → chunk-INYTG4NG.cjs} +174 -174
- package/dist/{chunk-AR2T7JEX.cjs.map → chunk-INYTG4NG.cjs.map} +1 -1
- package/dist/{chunk-RK2WSQYL.js → chunk-M42N54LG.js} +3 -3
- package/dist/{chunk-ZWQLXWSV.js → chunk-UQTWIV3S.js} +3 -3
- package/dist/{chunk-ECNK25S4.cjs → chunk-WY4LI5PB.cjs} +8 -8
- package/dist/{chunk-ECNK25S4.cjs.map → chunk-WY4LI5PB.cjs.map} +1 -1
- package/dist/index.cjs +42 -42
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.dev.js.map +1 -1
- package/dist/index.js +3 -3
- package/dist/internal-list.cjs +4 -4
- package/dist/internal-list.js +3 -3
- package/dist/internal.cjs +5 -5
- package/dist/internal.d.cts +2 -2
- package/dist/internal.d.ts +2 -2
- package/dist/internal.js +4 -4
- package/dist/jsx-dev-runtime.cjs.map +1 -1
- package/dist/jsx-dev-runtime.d.cts +46 -0
- package/dist/jsx-dev-runtime.d.ts +46 -0
- package/dist/jsx-dev-runtime.js.map +1 -1
- package/dist/jsx-runtime.cjs.map +1 -1
- package/dist/jsx-runtime.d.cts +46 -0
- package/dist/jsx-runtime.d.ts +46 -0
- package/dist/jsx-runtime.js.map +1 -1
- package/dist/loader.cjs +143 -26
- package/dist/loader.cjs.map +1 -1
- package/dist/loader.d.cts +1 -1
- package/dist/loader.d.ts +1 -1
- package/dist/loader.js +122 -5
- package/dist/loader.js.map +1 -1
- package/dist/{props-DabFQwLR.d.ts → props-C04ScJgm.d.ts} +46 -0
- package/dist/{props-tImUZAty.d.cts → props-CdmuXCiu.d.cts} +46 -0
- package/dist/{resume-C5IKAIdh.d.ts → resume-C166aAVg.d.ts} +2 -2
- package/dist/{resume-DPZxmA95.d.cts → resume-C20cRVj9.d.cts} +2 -2
- package/package.json +1 -1
- package/src/jsx.ts +46 -0
- package/src/loader.ts +153 -4
- package/src/resume.ts +5 -5
- /package/dist/{chunk-4P4DYWLQ.js.map → chunk-IIWHTV23.js.map} +0 -0
- /package/dist/{chunk-RK2WSQYL.js.map → chunk-M42N54LG.js.map} +0 -0
- /package/dist/{chunk-ZWQLXWSV.js.map → chunk-UQTWIV3S.js.map} +0 -0
package/src/loader.ts
CHANGED
|
@@ -36,6 +36,115 @@ function resolveModuleUrl(url: string): string {
|
|
|
36
36
|
return url
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
function resolveAbsoluteModuleUrl(url: string, ownerDocument?: Document): string {
|
|
40
|
+
const baseUrl =
|
|
41
|
+
ownerDocument?.baseURI ?? (typeof document !== 'undefined' ? document.baseURI : undefined)
|
|
42
|
+
if (!baseUrl) return url
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
return new URL(url, baseUrl).href
|
|
46
|
+
} catch {
|
|
47
|
+
return url
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function normalizeImportUrl(url: string): string {
|
|
52
|
+
if (!url.startsWith('data:')) {
|
|
53
|
+
return url
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const dataSeparatorIndex = url.indexOf(',')
|
|
57
|
+
if (dataSeparatorIndex === -1) {
|
|
58
|
+
return url
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const metadata = url.slice(0, dataSeparatorIndex)
|
|
62
|
+
const payload = url.slice(dataSeparatorIndex + 1)
|
|
63
|
+
if (metadata.includes(';base64')) {
|
|
64
|
+
return url
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
return `${metadata},${encodeURIComponent(decodeURIComponent(payload))}`
|
|
69
|
+
} catch {
|
|
70
|
+
return `${metadata},${encodeURIComponent(payload)}`
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
interface PreservedControlState {
|
|
75
|
+
value?: string
|
|
76
|
+
checked?: boolean
|
|
77
|
+
selectedIndex?: number
|
|
78
|
+
selectedValues?: string[]
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function captureControlState(node: Element, event: Event): PreservedControlState | null {
|
|
82
|
+
if (event.type !== 'input' && event.type !== 'change') return null
|
|
83
|
+
|
|
84
|
+
if (node instanceof HTMLInputElement) {
|
|
85
|
+
if (node.type === 'file') return null
|
|
86
|
+
if (node.type === 'checkbox' || node.type === 'radio') {
|
|
87
|
+
return { checked: node.checked }
|
|
88
|
+
}
|
|
89
|
+
return { value: node.value }
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (node instanceof HTMLTextAreaElement) {
|
|
93
|
+
return { value: node.value }
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (node instanceof HTMLSelectElement) {
|
|
97
|
+
return node.multiple
|
|
98
|
+
? {
|
|
99
|
+
selectedValues: Array.from(node.selectedOptions).map(option => option.value),
|
|
100
|
+
}
|
|
101
|
+
: {
|
|
102
|
+
value: node.value,
|
|
103
|
+
selectedIndex: node.selectedIndex,
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return null
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function restoreControlState(node: Element, state: PreservedControlState | null): void {
|
|
111
|
+
if (!state) return
|
|
112
|
+
|
|
113
|
+
if (node instanceof HTMLInputElement) {
|
|
114
|
+
if (typeof state.checked === 'boolean') {
|
|
115
|
+
node.checked = state.checked
|
|
116
|
+
}
|
|
117
|
+
if (typeof state.value === 'string' && node.type !== 'file') {
|
|
118
|
+
node.value = state.value
|
|
119
|
+
}
|
|
120
|
+
return
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (node instanceof HTMLTextAreaElement) {
|
|
124
|
+
if (typeof state.value === 'string') {
|
|
125
|
+
node.value = state.value
|
|
126
|
+
}
|
|
127
|
+
return
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (node instanceof HTMLSelectElement) {
|
|
131
|
+
if (Array.isArray(state.selectedValues) && node.multiple) {
|
|
132
|
+
const selected = new Set(state.selectedValues)
|
|
133
|
+
for (const option of Array.from(node.options)) {
|
|
134
|
+
option.selected = selected.has(option.value)
|
|
135
|
+
}
|
|
136
|
+
return
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (typeof state.selectedIndex === 'number') {
|
|
140
|
+
node.selectedIndex = state.selectedIndex
|
|
141
|
+
}
|
|
142
|
+
if (typeof state.value === 'string') {
|
|
143
|
+
node.value = state.value
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
39
148
|
// ============================================================================
|
|
40
149
|
// Types
|
|
41
150
|
// ============================================================================
|
|
@@ -557,29 +666,69 @@ async function handleResumableEventAsync(event: Event): Promise<void> {
|
|
|
557
666
|
}
|
|
558
667
|
}
|
|
559
668
|
|
|
669
|
+
const preservedControlState = captureControlState(node, event)
|
|
670
|
+
let resumedDuringEvent = false
|
|
671
|
+
|
|
560
672
|
// Resume FIRST to set up reactive bindings BEFORE the handler runs
|
|
561
673
|
if (!hydratedScopes.has(scopeId)) {
|
|
562
674
|
const resumeQrl = host.getAttribute('data-fict-h')
|
|
563
675
|
if (resumeQrl) {
|
|
564
676
|
const { url: resumeUrl, exportName: resumeExport } = parseQrl(resumeQrl)
|
|
565
677
|
const resolvedResumeUrl = resolveModuleUrl(resumeUrl)
|
|
678
|
+
const resolvedAbsoluteResumeUrl = resolveAbsoluteModuleUrl(
|
|
679
|
+
resolvedResumeUrl,
|
|
680
|
+
host.ownerDocument ?? undefined,
|
|
681
|
+
)
|
|
682
|
+
const resolvedResumeQrl = `${resolvedResumeUrl}#${resumeExport}`
|
|
683
|
+
const resolvedAbsoluteResumeQrl = `${resolvedAbsoluteResumeUrl}#${resumeExport}`
|
|
684
|
+
const normalizedResumeImportUrl = normalizeImportUrl(resolvedResumeUrl)
|
|
566
685
|
// Load the module to ensure resume functions are registered
|
|
567
|
-
await import(/* @vite-ignore */
|
|
686
|
+
await import(/* @vite-ignore */ normalizedResumeImportUrl)
|
|
568
687
|
// Get resume function from registry (not module exports)
|
|
569
|
-
const resumeFn =
|
|
688
|
+
const resumeFn =
|
|
689
|
+
__fictGetResume(resumeQrl) ??
|
|
690
|
+
__fictGetResume(resolvedResumeQrl) ??
|
|
691
|
+
__fictGetResume(resolvedAbsoluteResumeQrl) ??
|
|
692
|
+
__fictGetResume(resumeExport)
|
|
570
693
|
if (typeof resumeFn === 'function') {
|
|
571
694
|
await (resumeFn as (scopeId: string, host: Element) => unknown)(scopeId, host)
|
|
572
695
|
hydratedScopes.add(scopeId)
|
|
696
|
+
resumedDuringEvent = true
|
|
573
697
|
}
|
|
574
698
|
}
|
|
575
699
|
}
|
|
576
700
|
|
|
701
|
+
if (resumedDuringEvent) {
|
|
702
|
+
restoreControlState(node, preservedControlState)
|
|
703
|
+
}
|
|
704
|
+
|
|
577
705
|
// THEN run the handler - now signal updates will trigger DOM updates
|
|
578
706
|
const resolvedUrl = resolveModuleUrl(url)
|
|
579
|
-
const
|
|
707
|
+
const normalizedImportUrl = normalizeImportUrl(resolvedUrl)
|
|
708
|
+
const mod = await import(/* @vite-ignore */ normalizedImportUrl)
|
|
580
709
|
const handler = (mod as Record<string, unknown>)[exportName]
|
|
581
710
|
if (typeof handler === 'function') {
|
|
582
|
-
|
|
711
|
+
const originalCurrentTarget = event.currentTarget
|
|
712
|
+
Object.defineProperty(event, 'currentTarget', {
|
|
713
|
+
configurable: true,
|
|
714
|
+
get() {
|
|
715
|
+
return node
|
|
716
|
+
},
|
|
717
|
+
})
|
|
718
|
+
try {
|
|
719
|
+
await (handler as (scopeId: string, ev: Event, el: Element) => unknown)(
|
|
720
|
+
scopeId,
|
|
721
|
+
event,
|
|
722
|
+
node,
|
|
723
|
+
)
|
|
724
|
+
} finally {
|
|
725
|
+
Object.defineProperty(event, 'currentTarget', {
|
|
726
|
+
configurable: true,
|
|
727
|
+
get() {
|
|
728
|
+
return originalCurrentTarget
|
|
729
|
+
},
|
|
730
|
+
})
|
|
731
|
+
}
|
|
583
732
|
}
|
|
584
733
|
|
|
585
734
|
return
|
package/src/resume.ts
CHANGED
|
@@ -294,23 +294,23 @@ export function __fictQrl(moduleId: string, exportName: string): string {
|
|
|
294
294
|
return `${moduleId}#${exportName}`
|
|
295
295
|
}
|
|
296
296
|
|
|
297
|
-
// Registry for resume functions to prevent tree-shaking
|
|
297
|
+
// Registry for resume functions to prevent tree-shaking.
|
|
298
298
|
const resumeFunctionRegistry = new Map<string, (...args: unknown[]) => unknown>()
|
|
299
299
|
|
|
300
300
|
/**
|
|
301
301
|
* Register a resume function to prevent it from being tree-shaken.
|
|
302
302
|
* This is called at module load time by compiled component code.
|
|
303
303
|
*/
|
|
304
|
-
export function __fictRegisterResume(
|
|
305
|
-
resumeFunctionRegistry.set(
|
|
304
|
+
export function __fictRegisterResume(key: string, fn: (...args: unknown[]) => unknown): void {
|
|
305
|
+
resumeFunctionRegistry.set(key, fn)
|
|
306
306
|
}
|
|
307
307
|
|
|
308
308
|
/**
|
|
309
309
|
* Get a registered resume function by name.
|
|
310
310
|
* Used by the loader to find resume functions.
|
|
311
311
|
*/
|
|
312
|
-
export function __fictGetResume(
|
|
313
|
-
return resumeFunctionRegistry.get(
|
|
312
|
+
export function __fictGetResume(key: string): ((...args: unknown[]) => unknown) | undefined {
|
|
313
|
+
return resumeFunctionRegistry.get(key)
|
|
314
314
|
}
|
|
315
315
|
|
|
316
316
|
function serializeSlots(ctx: HookContext): SlotSnapshot[] {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|