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
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as Context from "effect/Context";
|
|
3
|
+
import { type VElement } from "./shared.js";
|
|
4
|
+
declare const ErrorBoundaryChannel_base: Context.TagClass<ErrorBoundaryChannel, "ErrorBoundaryChannel", {
|
|
5
|
+
readonly reportError: (error: unknown) => Effect.Effect<void, never, never>;
|
|
6
|
+
}>;
|
|
7
|
+
/**
|
|
8
|
+
* Error boundary channel - a Deferred that async errors can fail to trigger fallback.
|
|
9
|
+
* Created by ErrorBoundary and provided via context to children.
|
|
10
|
+
* Children (event handlers, stream subscriptions) can fail this to report errors.
|
|
11
|
+
*/
|
|
12
|
+
export declare class ErrorBoundaryChannel extends ErrorBoundaryChannel_base {
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Suspense component - shows fallback while waiting for children to emit.
|
|
16
|
+
* Returns a special VElement that renderVElementToDOM handles specially.
|
|
17
|
+
*
|
|
18
|
+
* Uses a threshold-based strategy:
|
|
19
|
+
* - If children complete rendering within `threshold` ms, skip fallback entirely
|
|
20
|
+
* - If children take longer, show fallback immediately, then swap to children when ready
|
|
21
|
+
*
|
|
22
|
+
* @param fallback - VElement to show while waiting (only if children are slow)
|
|
23
|
+
* @param threshold - Milliseconds to wait before showing fallback (default: 100ms)
|
|
24
|
+
* @param children - Child components (may be async Effects or Streams)
|
|
25
|
+
*/
|
|
26
|
+
export declare const Suspense: (props: {
|
|
27
|
+
fallback: VElement;
|
|
28
|
+
threshold?: number;
|
|
29
|
+
children?: VElement | VElement[];
|
|
30
|
+
}) => VElement;
|
|
31
|
+
/**
|
|
32
|
+
* ErrorBoundary - catches errors from children and renders fallback.
|
|
33
|
+
* Returns a special VElement that renderVElementToDOM handles specially.
|
|
34
|
+
*/
|
|
35
|
+
export declare const ErrorBoundary: (props: {
|
|
36
|
+
fallback: VElement;
|
|
37
|
+
onError?: (cause: unknown) => void;
|
|
38
|
+
children?: VElement | VElement[];
|
|
39
|
+
}) => VElement;
|
|
40
|
+
export {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as Context from "effect/Context";
|
|
3
|
+
import {} from "./shared.js";
|
|
4
|
+
// =============================================================================
|
|
5
|
+
// Error Boundary Channel
|
|
6
|
+
// =============================================================================
|
|
7
|
+
/**
|
|
8
|
+
* Error boundary channel - a Deferred that async errors can fail to trigger fallback.
|
|
9
|
+
* Created by ErrorBoundary and provided via context to children.
|
|
10
|
+
* Children (event handlers, stream subscriptions) can fail this to report errors.
|
|
11
|
+
*/
|
|
12
|
+
export class ErrorBoundaryChannel extends Context.Tag("ErrorBoundaryChannel")() {
|
|
13
|
+
}
|
|
14
|
+
// =============================================================================
|
|
15
|
+
// Built-in Components
|
|
16
|
+
// =============================================================================
|
|
17
|
+
/**
|
|
18
|
+
* Suspense component - shows fallback while waiting for children to emit.
|
|
19
|
+
* Returns a special VElement that renderVElementToDOM handles specially.
|
|
20
|
+
*
|
|
21
|
+
* Uses a threshold-based strategy:
|
|
22
|
+
* - If children complete rendering within `threshold` ms, skip fallback entirely
|
|
23
|
+
* - If children take longer, show fallback immediately, then swap to children when ready
|
|
24
|
+
*
|
|
25
|
+
* @param fallback - VElement to show while waiting (only if children are slow)
|
|
26
|
+
* @param threshold - Milliseconds to wait before showing fallback (default: 100ms)
|
|
27
|
+
* @param children - Child components (may be async Effects or Streams)
|
|
28
|
+
*/
|
|
29
|
+
export const Suspense = (props) => {
|
|
30
|
+
const childrenArray = Array.isArray(props.children) ? props.children : props.children ? [props.children] : [];
|
|
31
|
+
if (childrenArray.length === 0) {
|
|
32
|
+
throw new Error("Suspense requires at least one child");
|
|
33
|
+
}
|
|
34
|
+
// Return a special marker element that renderVElementToDOM will handle
|
|
35
|
+
return {
|
|
36
|
+
type: "SUSPENSE",
|
|
37
|
+
props: {
|
|
38
|
+
fallback: props.fallback,
|
|
39
|
+
threshold: props.threshold ?? 100,
|
|
40
|
+
children: childrenArray,
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* ErrorBoundary - catches errors from children and renders fallback.
|
|
46
|
+
* Returns a special VElement that renderVElementToDOM handles specially.
|
|
47
|
+
*/
|
|
48
|
+
export const ErrorBoundary = (props) => {
|
|
49
|
+
const childrenArray = Array.isArray(props.children) ? props.children : props.children ? [props.children] : [];
|
|
50
|
+
if (childrenArray.length === 0) {
|
|
51
|
+
throw new Error("ErrorBoundary requires at least one child");
|
|
52
|
+
}
|
|
53
|
+
// Return a special marker element that renderVElementToDOM will handle
|
|
54
|
+
return {
|
|
55
|
+
type: "ERROR_BOUNDARY",
|
|
56
|
+
props: {
|
|
57
|
+
fallback: props.fallback,
|
|
58
|
+
onError: props.onError,
|
|
59
|
+
children: childrenArray,
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
//# sourceMappingURL=components.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"components.js","sourceRoot":"","sources":["../src/components.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAE1C,OAAO,EAAiB,MAAM,aAAa,CAAC;AAE5C,gFAAgF;AAChF,yBAAyB;AACzB,gFAAgF;AAEhF;;;;GAIG;AACH,MAAM,OAAO,oBAAqB,SAAQ,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,EAK1E;CAAI;AAEP,gFAAgF;AAChF,sBAAsB;AACtB,gFAAgF;AAEhF;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAIxB,EAAY,EAAE;IACb,MAAM,aAAa,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAE9G,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IAED,uEAAuE;IACvE,OAAO;QACL,IAAI,EAAE,UAAmB;QACzB,KAAK,EAAE;YACL,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,GAAG;YACjC,QAAQ,EAAE,aAAa;SACxB;KACF,CAAC;AACJ,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAI7B,EAAY,EAAE;IACb,MAAM,aAAa,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAE9G,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC/D,CAAC;IAED,uEAAuE;IACvE,OAAO;QACL,IAAI,EAAE,gBAAyB;QAC/B,KAAK,EAAE;YACL,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,QAAQ,EAAE,aAAa;SACxB;KACF,CAAC;AACJ,CAAC,CAAC"}
|
package/dist/core.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as Layer from "effect/Layer";
|
|
3
|
+
import { Registry as AtomRegistry, Hydration } from "@effect-atom/atom";
|
|
4
|
+
import { type VElement } from "./shared.js";
|
|
5
|
+
/**
|
|
6
|
+
* Render a VElement tree to a container.
|
|
7
|
+
* Returns an Effect that runs forever (until interrupted).
|
|
8
|
+
*
|
|
9
|
+
* If the container already has children, hydration mode is used:
|
|
10
|
+
* - Existing DOM nodes are reused (not replaced)
|
|
11
|
+
* - Event handlers are attached to existing elements
|
|
12
|
+
* - Throws HydrationMismatch if structure doesn't match
|
|
13
|
+
*
|
|
14
|
+
* @param element - The VElement tree to render
|
|
15
|
+
* @param container - The DOM container to render into
|
|
16
|
+
* @param options - Optional configuration
|
|
17
|
+
* @param options.layer - Additional layer to provide (will have access to AtomRegistry)
|
|
18
|
+
* @param options.initialState - Dehydrated atom state from SSR (enables atom hydration)
|
|
19
|
+
*/
|
|
20
|
+
export declare function render(element: VElement, container: HTMLElement): Effect.Effect<never, never, never>;
|
|
21
|
+
export declare function render(element: VElement, container: HTMLElement, options: {
|
|
22
|
+
layer?: Layer.Layer<unknown, unknown, AtomRegistry.AtomRegistry>;
|
|
23
|
+
initialState?: ReadonlyArray<Hydration.DehydratedAtom>;
|
|
24
|
+
}): Effect.Effect<never, never, never>;
|
|
25
|
+
export declare function render(element: VElement): (container: HTMLElement) => Effect.Effect<never, never, never>;
|
package/dist/core.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as Layer from "effect/Layer";
|
|
3
|
+
import * as Ref from "effect/Ref";
|
|
4
|
+
import * as FiberRef from "effect/FiberRef";
|
|
5
|
+
import * as Context from "effect/Context";
|
|
6
|
+
import { Registry as AtomRegistry, Hydration } from "@effect-atom/atom";
|
|
7
|
+
import {} from "./shared.js";
|
|
8
|
+
import { FibraeRuntime } from "./runtime.js";
|
|
9
|
+
import { renderFiber, hydrateFiber } from "./fiber-render.js";
|
|
10
|
+
export function render(element, container, options) {
|
|
11
|
+
const program = (cont) => Effect.gen(function* () {
|
|
12
|
+
const runtime = yield* FibraeRuntime;
|
|
13
|
+
const registry = yield* AtomRegistry.AtomRegistry;
|
|
14
|
+
// Capture the full context NOW (after all layers are built) and store it in runtime
|
|
15
|
+
// This ensures user-provided services like Navigator are available for forked effects
|
|
16
|
+
const fullContext = (yield* FiberRef.get(FiberRef.currentContext));
|
|
17
|
+
yield* Ref.set(runtime.fullContextRef, fullContext);
|
|
18
|
+
// If initialState provided, hydrate atoms first
|
|
19
|
+
if (options?.initialState) {
|
|
20
|
+
Hydration.hydrate(registry, options.initialState);
|
|
21
|
+
}
|
|
22
|
+
// If container has element children, use hydration mode
|
|
23
|
+
// (skip whitespace-only text nodes that may exist in pre-rendered HTML)
|
|
24
|
+
const firstElementChild = cont.firstElementChild;
|
|
25
|
+
if (firstElementChild) {
|
|
26
|
+
yield* hydrateFiber(element, cont);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
// Fresh render - create new DOM using fiber-based reconciliation
|
|
30
|
+
yield* renderFiber(element, cont);
|
|
31
|
+
}
|
|
32
|
+
// Note: renderFiber/hydrateFiber already return Effect.never
|
|
33
|
+
// This line is unreachable but satisfies the type system
|
|
34
|
+
return yield* Effect.never;
|
|
35
|
+
}).pipe(
|
|
36
|
+
// Always use LiveWithRegistry so the program has access to both FibraeRuntime AND AtomRegistry
|
|
37
|
+
// If user provided a layer, merge it in as well
|
|
38
|
+
Effect.provide(options?.layer
|
|
39
|
+
? Layer.provideMerge(options.layer, FibraeRuntime.LiveWithRegistry)
|
|
40
|
+
: FibraeRuntime.LiveWithRegistry));
|
|
41
|
+
if (container === undefined) {
|
|
42
|
+
return (cont) => program(cont);
|
|
43
|
+
}
|
|
44
|
+
return program(container);
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=core.js.map
|
package/dist/core.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.js","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,GAAG,MAAM,YAAY,CAAC;AAClC,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAE1C,OAAO,EAAE,QAAQ,IAAI,YAAY,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACxE,OAAO,EAAiB,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AA2B9D,MAAM,UAAU,MAAM,CACpB,OAAiB,EACjB,SAAuB,EACvB,OAGC;IAED,MAAM,OAAO,GAAG,CAAC,IAAiB,EAAE,EAAE,CACpC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,aAAa,CAAC;QACrC,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,YAAY,CAAC,YAAY,CAAC;QAElD,oFAAoF;QACpF,sFAAsF;QACtF,MAAM,WAAW,GAAG,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,cAAc,CAAC,CAA6B,CAAC;QAC/F,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;QAEpD,gDAAgD;QAChD,IAAI,OAAO,EAAE,YAAY,EAAE,CAAC;YAC1B,SAAS,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;QACpD,CAAC;QAED,wDAAwD;QACxD,wEAAwE;QACxE,MAAM,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,CAAC;QACjD,IAAI,iBAAiB,EAAE,CAAC;YACtB,KAAK,CAAC,CAAC,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACrC,CAAC;aAAM,CAAC;YACN,iEAAiE;YACjE,KAAK,CAAC,CAAC,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACpC,CAAC;QAED,6DAA6D;QAC7D,yDAAyD;QACzD,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;IAC7B,CAAC,CAAC,CAAC,IAAI;IACL,+FAA+F;IAC/F,gDAAgD;IAChD,MAAM,CAAC,OAAO,CACZ,OAAO,EAAE,KAAK;QACZ,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,aAAa,CAAC,gBAAgB,CAAC;QACnE,CAAC,CAAC,aAAa,CAAC,gBAAgB,CACnC,CACF,CAAC;IAEJ,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,OAAO,CAAC,IAAiB,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,OAAO,CAAC,SAAS,CAAC,CAAC;AAC5B,CAAC"}
|
package/dist/dom.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { FibraeRuntime } from "./runtime.js";
|
|
2
|
+
/**
|
|
3
|
+
* Property update strategies for different DOM properties
|
|
4
|
+
*/
|
|
5
|
+
export declare const propertyUpdateMap: Record<string, "attribute" | "property" | "classList" | "booleanAttribute">;
|
|
6
|
+
export declare const isEvent: (key: string) => boolean;
|
|
7
|
+
export declare const isProperty: (key: string) => boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Set a DOM property using the appropriate method
|
|
10
|
+
*/
|
|
11
|
+
export declare const setDomProperty: (el: HTMLElement, name: string, value: unknown) => void;
|
|
12
|
+
/**
|
|
13
|
+
* Attach event listeners to a DOM element.
|
|
14
|
+
* Uses runForkWithRuntime to get the full application context.
|
|
15
|
+
*/
|
|
16
|
+
export declare const attachEventListeners: (el: HTMLElement, props: Record<string, unknown>, runtime: FibraeRuntime) => void;
|
package/dist/dom.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import { FibraeRuntime, runForkWithRuntime } from "./runtime.js";
|
|
3
|
+
// =============================================================================
|
|
4
|
+
// DOM Property Handling
|
|
5
|
+
// =============================================================================
|
|
6
|
+
/**
|
|
7
|
+
* Property update strategies for different DOM properties
|
|
8
|
+
*/
|
|
9
|
+
export const propertyUpdateMap = {
|
|
10
|
+
class: "classList",
|
|
11
|
+
className: "classList",
|
|
12
|
+
value: "property",
|
|
13
|
+
checked: "property",
|
|
14
|
+
};
|
|
15
|
+
export const isEvent = (key) => key.startsWith("on");
|
|
16
|
+
export const isProperty = (key) => key !== "children" && key !== "ref" && key !== "key" && !isEvent(key);
|
|
17
|
+
/**
|
|
18
|
+
* Set a DOM property using the appropriate method
|
|
19
|
+
*/
|
|
20
|
+
export const setDomProperty = (el, name, value) => {
|
|
21
|
+
const method = propertyUpdateMap[name] ||
|
|
22
|
+
(name.startsWith("data-") || name.startsWith("aria-") ? "attribute" : "attribute");
|
|
23
|
+
switch (method) {
|
|
24
|
+
case "attribute":
|
|
25
|
+
el.setAttribute(name, String(value ?? ""));
|
|
26
|
+
break;
|
|
27
|
+
case "property":
|
|
28
|
+
Reflect.set(el, name, value);
|
|
29
|
+
break;
|
|
30
|
+
case "classList":
|
|
31
|
+
if (Array.isArray(value)) {
|
|
32
|
+
value.forEach((v) => el.classList.add(v));
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
el.setAttribute("class", String(value ?? ""));
|
|
36
|
+
}
|
|
37
|
+
break;
|
|
38
|
+
case "booleanAttribute":
|
|
39
|
+
if (value) {
|
|
40
|
+
el.setAttribute(name, "");
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
el.removeAttribute(name);
|
|
44
|
+
}
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Attach event listeners to a DOM element.
|
|
50
|
+
* Uses runForkWithRuntime to get the full application context.
|
|
51
|
+
*/
|
|
52
|
+
export const attachEventListeners = (el, props, runtime) => {
|
|
53
|
+
for (const [key, handler] of Object.entries(props)) {
|
|
54
|
+
if (isEvent(key) && typeof handler === "function") {
|
|
55
|
+
const eventType = key.toLowerCase().substring(2);
|
|
56
|
+
el.addEventListener(eventType, (event) => {
|
|
57
|
+
const result = handler(event);
|
|
58
|
+
if (Effect.isEffect(result)) {
|
|
59
|
+
// Use runForkWithRuntime to get the full application context
|
|
60
|
+
const effectWithErrorHandling = result.pipe(Effect.catchAllCause((cause) => Effect.logError("Event handler error", cause)));
|
|
61
|
+
runForkWithRuntime(runtime)(effectWithErrorHandling);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
//# sourceMappingURL=dom.js.map
|
package/dist/dom.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dom.js","sourceRoot":"","sources":["../src/dom.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fiber-based rendering implementation.
|
|
3
|
+
*
|
|
4
|
+
* This module implements a proper fiber reconciliation system that:
|
|
5
|
+
* - Uses a fiber tree for incremental rendering
|
|
6
|
+
* - Supports key-based diffing for efficient list updates
|
|
7
|
+
* - Two-phase rendering: render phase builds fiber tree, commit phase touches DOM
|
|
8
|
+
* - Function components have `dom: Option.none()` - no wrapper spans!
|
|
9
|
+
*
|
|
10
|
+
* This fixes SSR hydration by producing identical DOM structure on server and client.
|
|
11
|
+
*/
|
|
12
|
+
import * as Effect from "effect/Effect";
|
|
13
|
+
import { type VElement } from "./shared.js";
|
|
14
|
+
import { FibraeRuntime } from "./runtime.js";
|
|
15
|
+
/**
|
|
16
|
+
* Render a VElement tree to a DOM container using fiber-based reconciliation.
|
|
17
|
+
*
|
|
18
|
+
* This implementation:
|
|
19
|
+
* - Uses a fiber tree for efficient updates
|
|
20
|
+
* - Supports key-based diffing
|
|
21
|
+
* - Function components have no DOM wrapper - fixing SSR hydration
|
|
22
|
+
*
|
|
23
|
+
* @param element - VElement to render
|
|
24
|
+
* @param container - DOM container to render into
|
|
25
|
+
*/
|
|
26
|
+
export declare const renderFiber: (element: VElement, container: HTMLElement) => Effect.Effect<never, never, FibraeRuntime>;
|
|
27
|
+
/**
|
|
28
|
+
* Hydrate an existing DOM tree with a VElement tree.
|
|
29
|
+
*
|
|
30
|
+
* This walks the existing DOM and builds a fiber tree that matches it,
|
|
31
|
+
* enabling reactive updates without re-creating the DOM.
|
|
32
|
+
*/
|
|
33
|
+
export declare const hydrateFiber: (element: VElement, container: HTMLElement) => Effect.Effect<never, unknown, FibraeRuntime>;
|