fibrae 0.1.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/components.d.ts +40 -0
- package/dist/components.js +63 -0
- package/dist/components.js.map +1 -0
- package/dist/core.d.ts +25 -0
- package/dist/core.js +46 -0
- package/dist/core.js.map +1 -0
- package/dist/dom.d.ts +16 -0
- package/dist/dom.js +67 -0
- package/dist/dom.js.map +1 -0
- package/dist/fiber-render.d.ts +33 -0
- package/dist/fiber-render.js +1069 -0
- package/dist/fiber-render.js.map +1 -0
- package/dist/h.d.ts +19 -0
- package/dist/h.js +26 -0
- package/dist/h.js.map +1 -0
- package/dist/hydration.d.ts +30 -0
- package/dist/hydration.js +375 -0
- package/dist/hydration.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/jsx-runtime/index.d.ts +29 -0
- package/dist/jsx-runtime/index.js +61 -0
- package/dist/jsx-runtime/index.js.map +1 -0
- package/dist/render.d.ts +19 -0
- package/dist/render.js +325 -0
- package/dist/render.js.map +1 -0
- package/dist/router/History.d.ts +129 -0
- package/dist/router/History.js +241 -0
- package/dist/router/History.js.map +1 -0
- package/dist/router/Link.d.ts +52 -0
- package/dist/router/Link.js +131 -0
- package/dist/router/Link.js.map +1 -0
- package/dist/router/Navigator.d.ts +108 -0
- package/dist/router/Navigator.js +225 -0
- package/dist/router/Navigator.js.map +1 -0
- package/dist/router/Route.d.ts +65 -0
- package/dist/router/Route.js +143 -0
- package/dist/router/Route.js.map +1 -0
- package/dist/router/Router.d.ts +167 -0
- package/dist/router/Router.js +328 -0
- package/dist/router/Router.js.map +1 -0
- package/dist/router/RouterBuilder.d.ts +128 -0
- package/dist/router/RouterBuilder.js +112 -0
- package/dist/router/RouterBuilder.js.map +1 -0
- package/dist/router/RouterOutlet.d.ts +57 -0
- package/dist/router/RouterOutlet.js +132 -0
- package/dist/router/RouterOutlet.js.map +1 -0
- package/dist/router/RouterState.d.ts +102 -0
- package/dist/router/RouterState.js +94 -0
- package/dist/router/RouterState.js.map +1 -0
- package/dist/router/index.d.ts +28 -0
- package/dist/router/index.js +31 -0
- package/dist/router/index.js.map +1 -0
- package/dist/runtime.d.ts +55 -0
- package/dist/runtime.js +68 -0
- package/dist/runtime.js.map +1 -0
- package/dist/scope-utils.d.ts +14 -0
- package/dist/scope-utils.js +29 -0
- package/dist/scope-utils.js.map +1 -0
- package/dist/server.d.ts +112 -0
- package/dist/server.js +313 -0
- package/dist/server.js.map +1 -0
- package/dist/shared.d.ts +136 -0
- package/dist/shared.js +53 -0
- package/dist/shared.js.map +1 -0
- package/dist/tracking.d.ts +23 -0
- package/dist/tracking.js +53 -0
- package/dist/tracking.js.map +1 -0
- package/package.json +62 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// Public API
|
|
3
|
+
// =============================================================================
|
|
4
|
+
// Main render function
|
|
5
|
+
export { render } from "./core.js";
|
|
6
|
+
// Runtime
|
|
7
|
+
export { FibraeRuntime, CustomAtomRegistryLayer } from "./runtime.js";
|
|
8
|
+
// Built-in components
|
|
9
|
+
export { Suspense, ErrorBoundary } from "./components.js";
|
|
10
|
+
// Element creation (JSX factory)
|
|
11
|
+
export { h, createTextElement } from "./h.js";
|
|
12
|
+
// Re-export upstream Effect Atom APIs for consumers
|
|
13
|
+
export { Atom, Registry as AtomRegistry } from "@effect-atom/atom";
|
|
14
|
+
// Router
|
|
15
|
+
export * as Route from "./router/Route.js";
|
|
16
|
+
export * as Router from "./router/Router.js";
|
|
17
|
+
export * as RouterBuilder from "./router/RouterBuilder.js";
|
|
18
|
+
export * as History from "./router/History.js";
|
|
19
|
+
export * as Navigator from "./router/Navigator.js";
|
|
20
|
+
export * as RouterState from "./router/RouterState.js";
|
|
21
|
+
export { RouterHandlers } from "./router/RouterBuilder.js";
|
|
22
|
+
export { History as HistoryTag, BrowserHistoryLive, MemoryHistoryLive } from "./router/History.js";
|
|
23
|
+
export { Navigator as NavigatorTag, NavigatorLive } from "./router/Navigator.js";
|
|
24
|
+
export { createLink } from "./router/Link.js";
|
|
25
|
+
export { RouterOutlet } from "./router/RouterOutlet.js";
|
|
26
|
+
export { CurrentRouteElement } from "./router/Router.js";
|
|
27
|
+
export { RouterStateAtom, RouterStateService, RouterStateSchema, getRouterState, getLoaderData, getRouteParams, } from "./router/RouterState.js";
|
|
28
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,aAAa;AACb,gFAAgF;AAEhF,uBAAuB;AACvB,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAEnC,UAAU;AACV,OAAO,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAEtE,sBAAsB;AACtB,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAE1D,iCAAiC;AACjC,OAAO,EAAE,CAAC,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAM9C,oDAAoD;AACpD,OAAO,EAAE,IAAI,EAAE,QAAQ,IAAI,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEnE,SAAS;AACT,OAAO,KAAK,KAAK,MAAM,mBAAmB,CAAC;AAC3C,OAAO,KAAK,MAAM,MAAM,oBAAoB,CAAC;AAC7C,OAAO,KAAK,aAAa,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAC;AAC/C,OAAO,KAAK,SAAS,MAAM,uBAAuB,CAAC;AACnD,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;AAUvD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAG3D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGnG,OAAO,EAAE,SAAS,IAAI,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAGjF,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG9C,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAQxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEzD,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,cAAc,GACf,MAAM,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type * as Effect from "effect/Effect";
|
|
2
|
+
import type * as Stream from "effect/Stream";
|
|
3
|
+
import type { VElement } from "../shared.js";
|
|
4
|
+
export declare const Fragment: "FRAGMENT";
|
|
5
|
+
export type FragmentType = typeof Fragment;
|
|
6
|
+
export type JSXType = typeof Fragment | ((props: object) => VElement | Stream.Stream<VElement> | Effect.Effect<VElement>);
|
|
7
|
+
export type PropsWithChildren<T = object> = T & {
|
|
8
|
+
children?: VElement | string | (VElement | string)[];
|
|
9
|
+
};
|
|
10
|
+
export declare function jsx(type: JSXType, props: PropsWithChildren<{
|
|
11
|
+
[key: string]: unknown;
|
|
12
|
+
}> | null, ...children: (VElement | string)[]): VElement;
|
|
13
|
+
export declare const jsxs: typeof jsx;
|
|
14
|
+
export declare const jsxDEV: typeof jsx;
|
|
15
|
+
export declare const h: typeof jsx;
|
|
16
|
+
declare global {
|
|
17
|
+
namespace JSX {
|
|
18
|
+
type Element = any;
|
|
19
|
+
interface IntrinsicElements {
|
|
20
|
+
[elemName: string]: any;
|
|
21
|
+
}
|
|
22
|
+
interface IntrinsicAttributes {
|
|
23
|
+
key?: string | number;
|
|
24
|
+
}
|
|
25
|
+
interface ElementChildrenAttribute {
|
|
26
|
+
children: {};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// A simple Fragment support for Fibrae
|
|
2
|
+
export const Fragment = "FRAGMENT";
|
|
3
|
+
function createTextElement(text) {
|
|
4
|
+
return {
|
|
5
|
+
type: "TEXT_ELEMENT",
|
|
6
|
+
props: {
|
|
7
|
+
nodeValue: String(text),
|
|
8
|
+
children: [],
|
|
9
|
+
},
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function normalizeChild(child) {
|
|
13
|
+
if (child === null || child === undefined || typeof child === "boolean") {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
if (typeof child === "string" || typeof child === "number" || typeof child === "bigint") {
|
|
17
|
+
return createTextElement(child);
|
|
18
|
+
}
|
|
19
|
+
// Handle arrays of children
|
|
20
|
+
if (Array.isArray(child)) {
|
|
21
|
+
return child.flatMap(c => {
|
|
22
|
+
const normalized = normalizeChild(c);
|
|
23
|
+
return normalized === null ? [] : Array.isArray(normalized) ? normalized : [normalized];
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
// Assume it's an already properly shaped VElement
|
|
27
|
+
return child;
|
|
28
|
+
}
|
|
29
|
+
export function jsx(type, props, ...children) {
|
|
30
|
+
const normalizedProps = props ?? {};
|
|
31
|
+
let finalChildren = [];
|
|
32
|
+
// Prefer children from props (automatic JSX runtime) over rest args (classic runtime)
|
|
33
|
+
if (normalizedProps.children !== undefined) {
|
|
34
|
+
const ch = normalizedProps.children;
|
|
35
|
+
const arr = Array.isArray(ch) ? ch : [ch];
|
|
36
|
+
finalChildren = arr.flatMap(child => {
|
|
37
|
+
const normalized = normalizeChild(child);
|
|
38
|
+
return normalized === null ? [] : Array.isArray(normalized) ? normalized : [normalized];
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
else if (children.length > 0) {
|
|
42
|
+
// Fall back to rest args for classic JSX runtime
|
|
43
|
+
finalChildren = children.flatMap(child => {
|
|
44
|
+
const normalized = normalizeChild(child);
|
|
45
|
+
return normalized === null ? [] : Array.isArray(normalized) ? normalized : [normalized];
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
type: type,
|
|
50
|
+
props: {
|
|
51
|
+
...normalizedProps,
|
|
52
|
+
children: finalChildren,
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export const jsxs = jsx;
|
|
57
|
+
// Development mode JSX transform (used by Bun and other tools)
|
|
58
|
+
export const jsxDEV = jsx;
|
|
59
|
+
// Alias for classic JSX transform (used by esbuild)
|
|
60
|
+
export const h = jsx;
|
|
61
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/jsx-runtime/index.ts"],"names":[],"mappings":"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"}
|
package/dist/render.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as Scope from "effect/Scope";
|
|
3
|
+
import { type VElement } from "./shared.js";
|
|
4
|
+
import { FibraeRuntime } from "./runtime.js";
|
|
5
|
+
/**
|
|
6
|
+
* Recursively render a VElement tree to DOM.
|
|
7
|
+
* This is the core rendering function that handles:
|
|
8
|
+
* - Function components (with stream subscriptions and atom reactivity)
|
|
9
|
+
* - Host elements (DOM nodes)
|
|
10
|
+
* - Text elements
|
|
11
|
+
* - Fragments
|
|
12
|
+
* - Error boundaries
|
|
13
|
+
*
|
|
14
|
+
* @param vElement - Virtual element to render
|
|
15
|
+
* @param parent - Parent DOM node to append to
|
|
16
|
+
* @param runtime - Fibrae runtime instance
|
|
17
|
+
* @param parentScope - Optional scope for registering cleanup (used for proper DOM node removal)
|
|
18
|
+
*/
|
|
19
|
+
export declare const renderVElementToDOM: (vElement: VElement, parent: Node, runtime: FibraeRuntime, parentScope?: Scope.Scope.Closeable) => Effect.Effect<void, unknown, never>;
|
package/dist/render.js
ADDED
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as Stream from "effect/Stream";
|
|
3
|
+
import * as Sink from "effect/Sink";
|
|
4
|
+
import * as Scope from "effect/Scope";
|
|
5
|
+
import * as Exit from "effect/Exit";
|
|
6
|
+
import * as Ref from "effect/Ref";
|
|
7
|
+
import * as Option from "effect/Option";
|
|
8
|
+
import * as Fiber from "effect/Fiber";
|
|
9
|
+
import * as Deferred from "effect/Deferred";
|
|
10
|
+
import * as Context from "effect/Context";
|
|
11
|
+
import * as FiberRef from "effect/FiberRef";
|
|
12
|
+
import { Atom, Registry as AtomRegistry } from "@effect-atom/atom";
|
|
13
|
+
import {} from "./shared.js";
|
|
14
|
+
import { FibraeRuntime, runForkWithRuntime } from "./runtime.js";
|
|
15
|
+
import { setDomProperty, attachEventListeners, isProperty } from "./dom.js";
|
|
16
|
+
import { normalizeToStream, makeTrackingRegistry, subscribeToAtoms } from "./tracking.js";
|
|
17
|
+
import { clearContentScope, registerNodeCleanup } from "./scope-utils.js";
|
|
18
|
+
import { ErrorBoundaryChannel } from "./components.js";
|
|
19
|
+
import { h } from "./h.js";
|
|
20
|
+
// =============================================================================
|
|
21
|
+
// Type Guards
|
|
22
|
+
// =============================================================================
|
|
23
|
+
/**
|
|
24
|
+
* Check if a type is a function component
|
|
25
|
+
*/
|
|
26
|
+
const isFunctionComponent = (type) => typeof type === "function";
|
|
27
|
+
/**
|
|
28
|
+
* Check if a type is a host element (string tag)
|
|
29
|
+
*/
|
|
30
|
+
const isHostElement = (type) => typeof type === "string";
|
|
31
|
+
// =============================================================================
|
|
32
|
+
// Render Implementation
|
|
33
|
+
// =============================================================================
|
|
34
|
+
/**
|
|
35
|
+
* Recursively render a VElement tree to DOM.
|
|
36
|
+
* This is the core rendering function that handles:
|
|
37
|
+
* - Function components (with stream subscriptions and atom reactivity)
|
|
38
|
+
* - Host elements (DOM nodes)
|
|
39
|
+
* - Text elements
|
|
40
|
+
* - Fragments
|
|
41
|
+
* - Error boundaries
|
|
42
|
+
*
|
|
43
|
+
* @param vElement - Virtual element to render
|
|
44
|
+
* @param parent - Parent DOM node to append to
|
|
45
|
+
* @param runtime - Fibrae runtime instance
|
|
46
|
+
* @param parentScope - Optional scope for registering cleanup (used for proper DOM node removal)
|
|
47
|
+
*/
|
|
48
|
+
export const renderVElementToDOM = (vElement, parent, runtime, parentScope) => Effect.gen(function* () {
|
|
49
|
+
const type = vElement.type;
|
|
50
|
+
if (isFunctionComponent(type)) {
|
|
51
|
+
// Function component - create wrapper and subscribe to its stream
|
|
52
|
+
const wrapper = document.createElement("span");
|
|
53
|
+
wrapper.style.display = "contents";
|
|
54
|
+
parent.appendChild(wrapper);
|
|
55
|
+
// Register wrapper cleanup with parent scope if provided
|
|
56
|
+
if (parentScope) {
|
|
57
|
+
yield* registerNodeCleanup(wrapper, parentScope);
|
|
58
|
+
}
|
|
59
|
+
// Component scope - for atom subscriptions and stream subscriptions
|
|
60
|
+
const componentScope = yield* Scope.make();
|
|
61
|
+
// Content scope ref - for rendered children (can be cleared/recreated on re-render)
|
|
62
|
+
const initialContentScope = yield* Scope.make();
|
|
63
|
+
const contentScopeRef = yield* Ref.make(initialContentScope);
|
|
64
|
+
const accessedAtoms = new Set();
|
|
65
|
+
const trackingRegistry = makeTrackingRegistry(runtime.registry, accessedAtoms);
|
|
66
|
+
// Capture current runtime context (includes user services like ThemeService, UserService)
|
|
67
|
+
// FiberRef.currentContext gives us the actual runtime context regardless of static types
|
|
68
|
+
// We add our tracking registry to override AtomRegistry while preserving other services
|
|
69
|
+
const currentContext = yield* FiberRef.get(FiberRef.currentContext);
|
|
70
|
+
const contextWithTracking = Context.add(currentContext, AtomRegistry.AtomRegistry, trackingRegistry);
|
|
71
|
+
// Invoke component - use Effect.try to catch sync render-time crashes
|
|
72
|
+
const output = yield* Effect.try({
|
|
73
|
+
try: () => type(vElement.props),
|
|
74
|
+
catch: (e) => e
|
|
75
|
+
}).pipe(Effect.tapError(() => Effect.sync(() => parent.removeChild(wrapper))));
|
|
76
|
+
// Normalize to stream and provide context (with tracking registry) to it
|
|
77
|
+
// This ensures user-provided services like ThemeService are available to component Effects
|
|
78
|
+
const stream = normalizeToStream(output).pipe(Stream.provideContext(contextWithTracking));
|
|
79
|
+
// Use Stream.peel to properly separate first emission from remaining stream
|
|
80
|
+
// Provide componentScope so the remaining stream stays valid for the component's lifetime
|
|
81
|
+
const peelResult = yield* Effect.either(Effect.gen(function* () {
|
|
82
|
+
const [maybeFirst, remainingStream] = yield* Stream.peel(stream, Sink.head()).pipe(Effect.provideService(Scope.Scope, componentScope));
|
|
83
|
+
if (Option.isNone(maybeFirst)) {
|
|
84
|
+
// Empty stream - nothing to render
|
|
85
|
+
return { rendered: false };
|
|
86
|
+
}
|
|
87
|
+
const contentScope = yield* Ref.get(contentScopeRef);
|
|
88
|
+
yield* renderVElementToDOM(maybeFirst.value, wrapper, runtime, contentScope);
|
|
89
|
+
// Subscribe to atom changes for reactivity
|
|
90
|
+
if (accessedAtoms.size > 0) {
|
|
91
|
+
yield* subscribeToAtoms(accessedAtoms, () => {
|
|
92
|
+
// Queue re-render on atom change
|
|
93
|
+
runForkWithRuntime(runtime)(Effect.gen(function* () {
|
|
94
|
+
// Capture focus state before re-render
|
|
95
|
+
const activeElement = document.activeElement;
|
|
96
|
+
const hasFocusInWrapper = activeElement && wrapper.contains(activeElement);
|
|
97
|
+
const focusData = hasFocusInWrapper && activeElement ? {
|
|
98
|
+
tagName: activeElement.tagName,
|
|
99
|
+
dataAttributes: Object.fromEntries(Array.from(activeElement.attributes)
|
|
100
|
+
.filter(attr => attr.name.startsWith("data-"))
|
|
101
|
+
.map(attr => [attr.name, attr.value])),
|
|
102
|
+
name: activeElement.getAttribute("name"),
|
|
103
|
+
id: activeElement.id,
|
|
104
|
+
selectionStart: "selectionStart" in activeElement ? activeElement.selectionStart : null,
|
|
105
|
+
selectionEnd: "selectionEnd" in activeElement ? activeElement.selectionEnd : null,
|
|
106
|
+
} : null;
|
|
107
|
+
// Clear old content via scope (triggers finalizers, removes DOM nodes)
|
|
108
|
+
const newContentScope = yield* clearContentScope(contentScopeRef);
|
|
109
|
+
const newAccessedAtoms = new Set();
|
|
110
|
+
const newTrackingRegistry = makeTrackingRegistry(runtime.registry, newAccessedAtoms);
|
|
111
|
+
// Re-use captured context but with new tracking registry
|
|
112
|
+
const newContextWithTracking = Context.add(currentContext, AtomRegistry.AtomRegistry, newTrackingRegistry);
|
|
113
|
+
// Invoke component - use Effect.try to catch sync render-time crashes
|
|
114
|
+
const newOutput = yield* Effect.try({
|
|
115
|
+
try: () => type(vElement.props),
|
|
116
|
+
catch: (e) => e
|
|
117
|
+
});
|
|
118
|
+
const newStream = normalizeToStream(newOutput).pipe(Stream.provideContext(newContextWithTracking));
|
|
119
|
+
yield* Stream.runForEach(newStream, (reEmitted) => renderVElementToDOM(reEmitted, wrapper, runtime, newContentScope).pipe(Effect.catchAll((e) => Effect.logError("Re-render child error", e))));
|
|
120
|
+
// Restore focus after re-render
|
|
121
|
+
if (focusData) {
|
|
122
|
+
const candidates = wrapper.querySelectorAll(focusData.tagName);
|
|
123
|
+
for (const candidate of candidates) {
|
|
124
|
+
const el = candidate;
|
|
125
|
+
// Match by id first, then name, then data attributes
|
|
126
|
+
const matchById = focusData.id && el.id === focusData.id;
|
|
127
|
+
const matchByName = focusData.name && el.getAttribute("name") === focusData.name;
|
|
128
|
+
const matchByData = Object.entries(focusData.dataAttributes).length > 0 &&
|
|
129
|
+
Object.entries(focusData.dataAttributes).every(([attr, value]) => el.getAttribute(attr) === value);
|
|
130
|
+
if (matchById || matchByName || matchByData) {
|
|
131
|
+
el.focus();
|
|
132
|
+
// Restore cursor position for inputs/textareas
|
|
133
|
+
if (focusData.selectionStart !== null && "setSelectionRange" in el) {
|
|
134
|
+
el.setSelectionRange(focusData.selectionStart, focusData.selectionEnd ?? focusData.selectionStart);
|
|
135
|
+
}
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}).pipe(
|
|
141
|
+
// Provide captured context to re-render fiber so services (Navigator, etc.) are available
|
|
142
|
+
Effect.provide(currentContext), Effect.catchAllCause((cause) => Effect.logError("Re-render error", cause))));
|
|
143
|
+
}, runtime, componentScope);
|
|
144
|
+
}
|
|
145
|
+
// Fork subscription for remaining emissions
|
|
146
|
+
// Try to report stream errors to error boundary channel if available
|
|
147
|
+
const maybeErrorChannel = Context.getOption(currentContext, ErrorBoundaryChannel);
|
|
148
|
+
const streamErrorHandler = Option.match(maybeErrorChannel, {
|
|
149
|
+
onNone: () => (cause) => Effect.logError("Component stream error (no boundary)", cause),
|
|
150
|
+
onSome: (channel) => (cause) => channel.reportError(cause)
|
|
151
|
+
});
|
|
152
|
+
const subscription = Stream.runForEach(remainingStream, (emitted) => Effect.gen(function* () {
|
|
153
|
+
// Clear old content via scope
|
|
154
|
+
const newContentScope = yield* clearContentScope(contentScopeRef);
|
|
155
|
+
yield* renderVElementToDOM(emitted, wrapper, runtime, newContentScope).pipe(Effect.catchAll((e) => Effect.logError("Stream emission render error", e)));
|
|
156
|
+
})).pipe(Effect.catchAllCause(streamErrorHandler));
|
|
157
|
+
yield* Effect.forkIn(subscription, componentScope);
|
|
158
|
+
return { rendered: true };
|
|
159
|
+
}));
|
|
160
|
+
if (peelResult._tag === "Left") {
|
|
161
|
+
// Stream error before/during first emission - propagate
|
|
162
|
+
const contentScope = yield* Ref.get(contentScopeRef);
|
|
163
|
+
yield* Scope.close(contentScope, Exit.void);
|
|
164
|
+
yield* Scope.close(componentScope, Exit.void);
|
|
165
|
+
parent.removeChild(wrapper);
|
|
166
|
+
return yield* Effect.fail(peelResult.left);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
else if (type === "TEXT_ELEMENT") {
|
|
170
|
+
// Text node
|
|
171
|
+
const textNode = document.createTextNode(String(vElement.props.nodeValue ?? ""));
|
|
172
|
+
parent.appendChild(textNode);
|
|
173
|
+
// Register text node cleanup with parent scope if provided
|
|
174
|
+
if (parentScope) {
|
|
175
|
+
yield* registerNodeCleanup(textNode, parentScope);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
else if (type === "FRAGMENT") {
|
|
179
|
+
// Fragment - render children directly into parent (propagate errors)
|
|
180
|
+
const children = vElement.props.children ?? [];
|
|
181
|
+
for (const child of children) {
|
|
182
|
+
yield* renderVElementToDOM(child, parent, runtime, parentScope);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
else if (type === "ERROR_BOUNDARY") {
|
|
186
|
+
// Error boundary - wrap child rendering in error catching
|
|
187
|
+
// Also catches async errors from event handlers and streams via ErrorBoundaryChannel
|
|
188
|
+
const wrapper = document.createElement("span");
|
|
189
|
+
wrapper.style.display = "contents";
|
|
190
|
+
parent.appendChild(wrapper);
|
|
191
|
+
// Register wrapper cleanup with parent scope if provided
|
|
192
|
+
if (parentScope) {
|
|
193
|
+
yield* registerNodeCleanup(wrapper, parentScope);
|
|
194
|
+
}
|
|
195
|
+
const fallback = vElement.props.fallback;
|
|
196
|
+
const onError = vElement.props.onError;
|
|
197
|
+
const children = vElement.props.children;
|
|
198
|
+
// Create content scope for children - wrapped in Ref so async error handler can access it
|
|
199
|
+
const contentScopeRef = yield* Ref.make(yield* Scope.make());
|
|
200
|
+
// Create error channel for async error reporting
|
|
201
|
+
const errorDeferred = yield* Deferred.make();
|
|
202
|
+
const errorChannel = {
|
|
203
|
+
reportError: (error) => Deferred.fail(errorDeferred, error).pipe(Effect.ignore)
|
|
204
|
+
};
|
|
205
|
+
// Flag to track if we've already shown fallback (to prevent double-triggering)
|
|
206
|
+
const hasTriggeredRef = yield* Ref.make(false);
|
|
207
|
+
// Helper to render fallback (used by both sync and async error paths)
|
|
208
|
+
const renderFallback = (error) => Effect.gen(function* () {
|
|
209
|
+
const alreadyTriggered = yield* Ref.getAndSet(hasTriggeredRef, true);
|
|
210
|
+
if (alreadyTriggered)
|
|
211
|
+
return; // Already showing fallback
|
|
212
|
+
// Close content scope (cleans up DOM nodes), create fallback scope
|
|
213
|
+
const oldContentScope = yield* Ref.get(contentScopeRef);
|
|
214
|
+
yield* Scope.close(oldContentScope, Exit.void);
|
|
215
|
+
const fallbackScope = yield* Scope.make();
|
|
216
|
+
yield* Ref.set(contentScopeRef, fallbackScope);
|
|
217
|
+
onError?.(error);
|
|
218
|
+
yield* Effect.logError("ErrorBoundary caught error", error);
|
|
219
|
+
yield* renderVElementToDOM(fallback, wrapper, runtime, fallbackScope).pipe(Effect.catchAll((e) => Effect.logError("ErrorBoundary fallback render error", e)));
|
|
220
|
+
});
|
|
221
|
+
// Fork listener for async errors (event handlers, stream failures)
|
|
222
|
+
yield* Effect.fork(Deferred.await(errorDeferred).pipe(Effect.catchAllCause((cause) => renderFallback(cause))));
|
|
223
|
+
// Try to render children with error channel in context, catch sync errors
|
|
224
|
+
const contentScope = yield* Ref.get(contentScopeRef);
|
|
225
|
+
const renderResult = yield* Effect.either(Effect.forEach(children, (child) => renderVElementToDOM(child, wrapper, runtime, contentScope), { discard: true }).pipe(Effect.provideService(ErrorBoundaryChannel, errorChannel)));
|
|
226
|
+
if (renderResult._tag === "Left") {
|
|
227
|
+
// Sync error during render - render fallback
|
|
228
|
+
yield* renderFallback(renderResult.left);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
else if (type === "SUSPENSE") {
|
|
232
|
+
// Suspense boundary - show fallback while children are loading
|
|
233
|
+
// Uses proper DOM insertion/removal (not CSS visibility hacks)
|
|
234
|
+
// Children are rendered to a detached container; if they complete within threshold,
|
|
235
|
+
// we append directly. If timeout fires first, we show fallback then swap when ready.
|
|
236
|
+
const fallback = vElement.props.fallback;
|
|
237
|
+
const threshold = vElement.props.threshold ?? 100;
|
|
238
|
+
const children = vElement.props.children;
|
|
239
|
+
const childFragment = h("FRAGMENT", {}, children);
|
|
240
|
+
// Create a DETACHED container for children (not in DOM yet)
|
|
241
|
+
// Using display:contents so it doesn't affect layout when inserted
|
|
242
|
+
const childWrapper = document.createElement("span");
|
|
243
|
+
childWrapper.style.display = "contents";
|
|
244
|
+
// Create scopes for each container
|
|
245
|
+
const fallbackScope = yield* Scope.make();
|
|
246
|
+
const childScope = yield* Scope.make();
|
|
247
|
+
// Deferred to signal when children have completed first render
|
|
248
|
+
const childrenReady = yield* Deferred.make();
|
|
249
|
+
// Fork: render children into DETACHED container, signal when done
|
|
250
|
+
const childFiber = yield* Effect.fork(Effect.gen(function* () {
|
|
251
|
+
yield* renderVElementToDOM(childFragment, childWrapper, runtime, childScope);
|
|
252
|
+
yield* Deferred.succeed(childrenReady, void 0);
|
|
253
|
+
}).pipe(Effect.catchAll((e) => Deferred.fail(childrenReady, e))));
|
|
254
|
+
// Race: wait for children vs timeout
|
|
255
|
+
const childrenWon = yield* Effect.race(Deferred.await(childrenReady).pipe(Effect.as(true)), Effect.sleep(`${threshold} millis`).pipe(Effect.as(false)));
|
|
256
|
+
if (childrenWon) {
|
|
257
|
+
// Children completed before timeout - append directly, skip fallback entirely
|
|
258
|
+
parent.appendChild(childWrapper);
|
|
259
|
+
if (parentScope) {
|
|
260
|
+
yield* registerNodeCleanup(childWrapper, parentScope);
|
|
261
|
+
}
|
|
262
|
+
// Clean up unused fallback scope
|
|
263
|
+
yield* Scope.close(fallbackScope, Exit.void);
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
// Timeout fired first - render fallback to DOM while waiting for children
|
|
267
|
+
const fallbackWrapper = document.createElement("span");
|
|
268
|
+
fallbackWrapper.style.display = "contents";
|
|
269
|
+
parent.appendChild(fallbackWrapper);
|
|
270
|
+
if (parentScope) {
|
|
271
|
+
yield* registerNodeCleanup(fallbackWrapper, parentScope);
|
|
272
|
+
}
|
|
273
|
+
yield* renderVElementToDOM(fallback, fallbackWrapper, runtime, fallbackScope);
|
|
274
|
+
// Wait for children to complete (they're still rendering in background)
|
|
275
|
+
const childResult = yield* Effect.either(Deferred.await(childrenReady));
|
|
276
|
+
if (childResult._tag === "Right") {
|
|
277
|
+
// Children completed successfully - swap: remove fallback, insert children
|
|
278
|
+
fallbackWrapper.remove();
|
|
279
|
+
parent.appendChild(childWrapper);
|
|
280
|
+
if (parentScope) {
|
|
281
|
+
yield* registerNodeCleanup(childWrapper, parentScope);
|
|
282
|
+
}
|
|
283
|
+
// Clean up fallback scope (stops any streams/effects in fallback)
|
|
284
|
+
yield* Scope.close(fallbackScope, Exit.void);
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
// Children failed - keep showing fallback, propagate error
|
|
288
|
+
// (ErrorBoundary above should catch this)
|
|
289
|
+
yield* Fiber.interrupt(childFiber);
|
|
290
|
+
yield* Scope.close(childScope, Exit.void);
|
|
291
|
+
return yield* Effect.fail(childResult.left);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
else if (isHostElement(type)) {
|
|
296
|
+
// Regular host element (div, span, button, etc.)
|
|
297
|
+
const el = document.createElement(type);
|
|
298
|
+
// Apply properties
|
|
299
|
+
for (const [key, value] of Object.entries(vElement.props)) {
|
|
300
|
+
if (isProperty(key)) {
|
|
301
|
+
setDomProperty(el, key, value);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
// Attach event listeners - uses runForkWithRuntime internally for full context
|
|
305
|
+
attachEventListeners(el, vElement.props, runtime);
|
|
306
|
+
// Handle ref
|
|
307
|
+
const ref = vElement.props.ref;
|
|
308
|
+
if (ref && typeof ref === "object" && "current" in ref) {
|
|
309
|
+
ref.current = el;
|
|
310
|
+
}
|
|
311
|
+
parent.appendChild(el);
|
|
312
|
+
// Register element cleanup with parent scope if provided
|
|
313
|
+
if (parentScope) {
|
|
314
|
+
yield* registerNodeCleanup(el, parentScope);
|
|
315
|
+
}
|
|
316
|
+
// Create scope for children of this element
|
|
317
|
+
const childScope = yield* Scope.make();
|
|
318
|
+
// Render children (propagate errors)
|
|
319
|
+
const children = vElement.props.children ?? [];
|
|
320
|
+
for (const child of children) {
|
|
321
|
+
yield* renderVElementToDOM(child, el, runtime, childScope);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* History service - track and manage browser navigation history.
|
|
3
|
+
*
|
|
4
|
+
* Features:
|
|
5
|
+
* - Current location (pathname, search, hash, state)
|
|
6
|
+
* - Navigation methods (push, replace, back, forward, go)
|
|
7
|
+
* - BrowserHistoryLive - real browser history with popstate handling
|
|
8
|
+
* - MemoryHistoryLive - in-memory history for testing/SSR
|
|
9
|
+
* - Cleanly manages event listeners with Effect finalizers
|
|
10
|
+
*
|
|
11
|
+
* Design:
|
|
12
|
+
* - Uses Atom for reactive location updates
|
|
13
|
+
* - Browser history: listens to window.popstate for back/forward
|
|
14
|
+
* - Memory history: in-memory stack, useful for SSR/testing
|
|
15
|
+
* - All navigation returns Effects, integrates with Effect runtime
|
|
16
|
+
*/
|
|
17
|
+
import * as Effect from "effect/Effect";
|
|
18
|
+
import * as Context from "effect/Context";
|
|
19
|
+
import * as Layer from "effect/Layer";
|
|
20
|
+
import { Atom, Registry as AtomRegistry } from "@effect-atom/atom";
|
|
21
|
+
/**
|
|
22
|
+
* Current location - pathname, search, hash, and state.
|
|
23
|
+
*/
|
|
24
|
+
export interface HistoryLocation {
|
|
25
|
+
readonly pathname: string;
|
|
26
|
+
readonly search: string;
|
|
27
|
+
readonly hash: string;
|
|
28
|
+
readonly state?: unknown;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* History service interface.
|
|
32
|
+
* Provides location access and navigation methods.
|
|
33
|
+
*/
|
|
34
|
+
export interface HistoryService {
|
|
35
|
+
/**
|
|
36
|
+
* Current location atom - reactive and serializable.
|
|
37
|
+
*/
|
|
38
|
+
readonly location: Atom.Writable<HistoryLocation, HistoryLocation>;
|
|
39
|
+
/**
|
|
40
|
+
* Navigate to a new location (push new entry).
|
|
41
|
+
*/
|
|
42
|
+
readonly push: (path: string, state?: unknown) => Effect.Effect<void, never, AtomRegistry.AtomRegistry>;
|
|
43
|
+
/**
|
|
44
|
+
* Replace current location (same entry).
|
|
45
|
+
*/
|
|
46
|
+
readonly replace: (path: string, state?: unknown) => Effect.Effect<void, never, AtomRegistry.AtomRegistry>;
|
|
47
|
+
/**
|
|
48
|
+
* Go back in history.
|
|
49
|
+
*/
|
|
50
|
+
readonly back: Effect.Effect<void, never, never>;
|
|
51
|
+
/**
|
|
52
|
+
* Go forward in history.
|
|
53
|
+
*/
|
|
54
|
+
readonly forward: Effect.Effect<void, never, never>;
|
|
55
|
+
/**
|
|
56
|
+
* Go n entries in history.
|
|
57
|
+
*/
|
|
58
|
+
readonly go: (n: number) => Effect.Effect<void, never, never>;
|
|
59
|
+
/**
|
|
60
|
+
* Check if can go back (optional, simplified version).
|
|
61
|
+
*/
|
|
62
|
+
readonly canGoBack: Effect.Effect<boolean, never, never>;
|
|
63
|
+
}
|
|
64
|
+
declare const History_base: Context.TagClass<History, "fibrae/History", HistoryService>;
|
|
65
|
+
/**
|
|
66
|
+
* History service tag for Effect dependency injection.
|
|
67
|
+
*/
|
|
68
|
+
export declare class History extends History_base {
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Browser history layer - real browser history with popstate handling.
|
|
72
|
+
*
|
|
73
|
+
* Features:
|
|
74
|
+
* - Tracks current location in an Atom
|
|
75
|
+
* - Listens to popstate for back/forward
|
|
76
|
+
* - Provides push/replace/go navigation methods
|
|
77
|
+
* - Cleanly removes event listener on scope close
|
|
78
|
+
* - Properly cleans up event listeners on scope close
|
|
79
|
+
*/
|
|
80
|
+
export declare const BrowserHistoryLive: Layer.Layer<History, never, AtomRegistry.AtomRegistry>;
|
|
81
|
+
/**
|
|
82
|
+
* Options for creating memory history.
|
|
83
|
+
*/
|
|
84
|
+
export interface MemoryHistoryOptions {
|
|
85
|
+
/** Initial location (defaults to "/") */
|
|
86
|
+
readonly initialPathname?: string;
|
|
87
|
+
/** Initial search params (defaults to "") */
|
|
88
|
+
readonly initialSearch?: string;
|
|
89
|
+
/** Initial hash (defaults to "") */
|
|
90
|
+
readonly initialHash?: string;
|
|
91
|
+
/** Initial state (defaults to undefined) */
|
|
92
|
+
readonly initialState?: unknown;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Create a memory history layer - useful for testing/SSR.
|
|
96
|
+
*
|
|
97
|
+
* Features:
|
|
98
|
+
* - In-memory navigation stack
|
|
99
|
+
* - Tracks current location in an Atom
|
|
100
|
+
* - No browser API usage (safe for SSR/testing)
|
|
101
|
+
* - Supports push/replace/back/forward/go navigation
|
|
102
|
+
* - Optional initial location/state configuration
|
|
103
|
+
*/
|
|
104
|
+
export declare function MemoryHistoryLive(options?: MemoryHistoryOptions): Layer.Layer<History, never, AtomRegistry.AtomRegistry>;
|
|
105
|
+
/**
|
|
106
|
+
* Get current location.
|
|
107
|
+
*/
|
|
108
|
+
export declare const getLocation: Effect.Effect<HistoryLocation, never, History | AtomRegistry.AtomRegistry>;
|
|
109
|
+
/**
|
|
110
|
+
* Push a new location.
|
|
111
|
+
*/
|
|
112
|
+
export declare const push: (path: string, state?: unknown) => Effect.Effect<void, never, History | AtomRegistry.AtomRegistry>;
|
|
113
|
+
/**
|
|
114
|
+
* Replace current location.
|
|
115
|
+
*/
|
|
116
|
+
export declare const replace: (path: string, state?: unknown) => Effect.Effect<void, never, History | AtomRegistry.AtomRegistry>;
|
|
117
|
+
/**
|
|
118
|
+
* Go back in history.
|
|
119
|
+
*/
|
|
120
|
+
export declare const back: Effect.Effect<void, never, History>;
|
|
121
|
+
/**
|
|
122
|
+
* Go forward in history.
|
|
123
|
+
*/
|
|
124
|
+
export declare const forward: Effect.Effect<void, never, History>;
|
|
125
|
+
/**
|
|
126
|
+
* Go n entries in history.
|
|
127
|
+
*/
|
|
128
|
+
export declare const go: (n: number) => Effect.Effect<void, never, History>;
|
|
129
|
+
export {};
|