fibrae 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/cli/vite-plugin.js +39 -0
  2. package/dist/cli/vite-plugin.js.map +1 -1
  3. package/dist/core.js +37 -10
  4. package/dist/core.js.map +1 -1
  5. package/dist/dom.d.ts +9 -0
  6. package/dist/dom.js +30 -4
  7. package/dist/dom.js.map +1 -1
  8. package/dist/fiber-commit.d.ts +2 -0
  9. package/dist/fiber-commit.js +171 -36
  10. package/dist/fiber-commit.js.map +1 -1
  11. package/dist/fiber-render.js +13 -27
  12. package/dist/fiber-render.js.map +1 -1
  13. package/dist/fiber-update.d.ts +1 -1
  14. package/dist/fiber-update.js +26 -11
  15. package/dist/fiber-update.js.map +1 -1
  16. package/dist/h.d.ts +65 -10
  17. package/dist/h.js +98 -22
  18. package/dist/h.js.map +1 -1
  19. package/dist/head.d.ts +64 -0
  20. package/dist/head.js +257 -0
  21. package/dist/head.js.map +1 -0
  22. package/dist/hydration-dev.d.ts +24 -0
  23. package/dist/hydration-dev.js +138 -0
  24. package/dist/hydration-dev.js.map +1 -0
  25. package/dist/index.d.ts +4 -1
  26. package/dist/index.js +2 -1
  27. package/dist/index.js.map +1 -1
  28. package/dist/jsx-runtime/index.d.ts +174 -9
  29. package/dist/jsx-runtime/index.js +2 -0
  30. package/dist/jsx-runtime/index.js.map +1 -1
  31. package/dist/mdx/index.d.ts +4 -4
  32. package/dist/mdx/index.js +1 -1
  33. package/dist/mdx/index.js.map +1 -1
  34. package/dist/mdx/parse.d.ts +1 -1
  35. package/dist/mdx/parse.js.map +1 -1
  36. package/dist/mdx/render.d.ts +6 -5
  37. package/dist/mdx/render.js +62 -64
  38. package/dist/mdx/render.js.map +1 -1
  39. package/dist/router/Link.js +7 -1
  40. package/dist/router/Link.js.map +1 -1
  41. package/dist/router/Navigator.d.ts +24 -0
  42. package/dist/router/Navigator.js +24 -0
  43. package/dist/router/Navigator.js.map +1 -1
  44. package/dist/router/RouterOutlet.js +28 -5
  45. package/dist/router/RouterOutlet.js.map +1 -1
  46. package/dist/router/index.d.ts +5 -1
  47. package/dist/router/index.js +3 -1
  48. package/dist/router/index.js.map +1 -1
  49. package/dist/server.js +7 -3
  50. package/dist/server.js.map +1 -1
  51. package/dist/shared.d.ts +34 -4
  52. package/dist/shared.js +12 -2
  53. package/dist/shared.js.map +1 -1
  54. package/dist/tracking.d.ts +3 -2
  55. package/dist/tracking.js +4 -1
  56. package/dist/tracking.js.map +1 -1
  57. package/dist/transition.d.ts +51 -0
  58. package/dist/transition.js +46 -0
  59. package/dist/transition.js.map +1 -0
  60. package/package.json +2 -2
package/dist/head.d.ts ADDED
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Head component — lets any component set document head elements.
3
+ *
4
+ * On the client, directly mutates document.head (title, meta, link tags).
5
+ * On SSR, contributes to HeadCollector for server-side rendering.
6
+ * Cleans up added/modified elements on unmount via ComponentScope finalizer.
7
+ *
8
+ * Usage:
9
+ * ```tsx
10
+ * const PostPage = (props: { title: string }) =>
11
+ * Effect.gen(function* () {
12
+ * return (
13
+ * <div>
14
+ * <Head title={`${props.title} | My Site`} meta={[
15
+ * { name: "description", content: "A blog post" }
16
+ * ]} />
17
+ * <h1>{props.title}</h1>
18
+ * </div>
19
+ * );
20
+ * });
21
+ * ```
22
+ */
23
+ import * as Effect from "effect/Effect";
24
+ import * as Context from "effect/Context";
25
+ import { ComponentScope, type VElement } from "./shared.js";
26
+ import type { HeadData, MetaDescriptor } from "./router/RouterBuilder.js";
27
+ /**
28
+ * Service for accumulating head elements during SSR.
29
+ * Components call add() during render; the SSR layer calls collect() after.
30
+ */
31
+ export interface HeadCollectorService {
32
+ /** Register head data from a component. */
33
+ readonly add: (data: HeadData) => Effect.Effect<void>;
34
+ /** Collect all registered head data, merged and deduplicated. */
35
+ readonly collect: () => Effect.Effect<HeadData>;
36
+ }
37
+ declare const HeadCollector_base: Context.TagClass<HeadCollector, "fibrae/HeadCollector", HeadCollectorService>;
38
+ /**
39
+ * Context tag for the HeadCollector service.
40
+ * Only present during SSR — client-side Head components skip this.
41
+ */
42
+ export declare class HeadCollector extends HeadCollector_base {
43
+ }
44
+ /**
45
+ * Create a HeadCollector backed by a mutable Ref.
46
+ * Returns a Layer providing the HeadCollector service.
47
+ */
48
+ export declare const HeadCollectorLive: Effect.Effect<Context.Context<HeadCollector>, never, never>;
49
+ export interface HeadProps {
50
+ readonly title?: string;
51
+ readonly meta?: ReadonlyArray<MetaDescriptor>;
52
+ readonly links?: ReadonlyArray<Record<string, string>>;
53
+ }
54
+ /**
55
+ * General-purpose Head component.
56
+ *
57
+ * Accepts title, meta, and link props. On the client, directly mutates
58
+ * document.head and registers cleanup via ComponentScope. On SSR,
59
+ * contributes to HeadCollector if available.
60
+ *
61
+ * Returns an empty fragment (renders nothing visible).
62
+ */
63
+ export declare const Head: (props: HeadProps) => Effect.Effect<VElement, never, ComponentScope>;
64
+ export {};
package/dist/head.js ADDED
@@ -0,0 +1,257 @@
1
+ /**
2
+ * Head component — lets any component set document head elements.
3
+ *
4
+ * On the client, directly mutates document.head (title, meta, link tags).
5
+ * On SSR, contributes to HeadCollector for server-side rendering.
6
+ * Cleans up added/modified elements on unmount via ComponentScope finalizer.
7
+ *
8
+ * Usage:
9
+ * ```tsx
10
+ * const PostPage = (props: { title: string }) =>
11
+ * Effect.gen(function* () {
12
+ * return (
13
+ * <div>
14
+ * <Head title={`${props.title} | My Site`} meta={[
15
+ * { name: "description", content: "A blog post" }
16
+ * ]} />
17
+ * <h1>{props.title}</h1>
18
+ * </div>
19
+ * );
20
+ * });
21
+ * ```
22
+ */
23
+ import { jsx } from "./jsx-runtime/index.js";
24
+ import * as Effect from "effect/Effect";
25
+ import * as Context from "effect/Context";
26
+ import * as Scope from "effect/Scope";
27
+ import * as Option from "effect/Option";
28
+ import * as Ref from "effect/Ref";
29
+ import { ComponentScope } from "./shared.js";
30
+ /**
31
+ * Context tag for the HeadCollector service.
32
+ * Only present during SSR — client-side Head components skip this.
33
+ */
34
+ export class HeadCollector extends Context.Tag("fibrae/HeadCollector")() {
35
+ }
36
+ /**
37
+ * Dedup key for a meta descriptor — same logic as cli/html.ts.
38
+ * Tags with matching keys are deduplicated (later wins).
39
+ */
40
+ const metaKey = (meta) => {
41
+ if ("name" in meta)
42
+ return `name:${meta.name}`;
43
+ if ("property" in meta)
44
+ return `property:${meta.property}`;
45
+ if ("httpEquiv" in meta)
46
+ return `httpEquiv:${meta.httpEquiv}`;
47
+ if ("charset" in meta)
48
+ return "charset";
49
+ return undefined;
50
+ };
51
+ /**
52
+ * Merge two HeadData objects. Later data wins for title and deduped meta.
53
+ * Links and scripts are concatenated.
54
+ */
55
+ const mergeHeadData = (a, b) => {
56
+ // Deduplicate meta: b overrides a when keys match
57
+ const aMeta = a.meta ?? [];
58
+ const bMeta = b.meta ?? [];
59
+ const bKeys = new Set(bMeta.map(metaKey).filter(Boolean));
60
+ const mergedMeta = [
61
+ ...aMeta.filter((m) => {
62
+ const key = metaKey(m);
63
+ return key === undefined || !bKeys.has(key);
64
+ }),
65
+ ...bMeta,
66
+ ];
67
+ return {
68
+ title: b.title ?? a.title,
69
+ meta: mergedMeta.length > 0 ? mergedMeta : undefined,
70
+ links: [...(a.links ?? []), ...(b.links ?? [])],
71
+ scripts: [...(a.scripts ?? []), ...(b.scripts ?? [])],
72
+ };
73
+ };
74
+ /**
75
+ * Create a HeadCollector backed by a mutable Ref.
76
+ * Returns a Layer providing the HeadCollector service.
77
+ */
78
+ export const HeadCollectorLive = Effect.gen(function* () {
79
+ const ref = yield* Ref.make({});
80
+ return HeadCollector.of({
81
+ add: (data) => Ref.update(ref, (current) => mergeHeadData(current, data)),
82
+ collect: () => Ref.get(ref),
83
+ });
84
+ }).pipe(Effect.map((service) => Context.make(HeadCollector, service)));
85
+ // =============================================================================
86
+ // Client-side DOM helpers
87
+ // =============================================================================
88
+ const DEV = typeof import.meta !== "undefined" && !!import.meta.hot;
89
+ /**
90
+ * Find an existing meta element by its dedup key.
91
+ */
92
+ const findMetaElement = (meta) => {
93
+ if ("name" in meta && !("tagName" in meta))
94
+ return document.head.querySelector(`meta[name="${meta.name}"]`);
95
+ if ("property" in meta && !("tagName" in meta))
96
+ return document.head.querySelector(`meta[property="${meta.property}"]`);
97
+ if ("httpEquiv" in meta)
98
+ return document.head.querySelector(`meta[http-equiv="${meta.httpEquiv}"]`);
99
+ if ("charset" in meta)
100
+ return document.head.querySelector("meta[charset]");
101
+ return null;
102
+ };
103
+ /**
104
+ * Set attributes on an element from a MetaDescriptor.
105
+ */
106
+ const applyMetaAttrs = (el, meta) => {
107
+ if ("charset" in meta) {
108
+ el.setAttribute("charset", meta.charset);
109
+ return;
110
+ }
111
+ if ("name" in meta && "content" in meta && !("tagName" in meta)) {
112
+ el.setAttribute("name", meta.name);
113
+ el.setAttribute("content", meta.content);
114
+ return;
115
+ }
116
+ if ("property" in meta && "content" in meta && !("tagName" in meta)) {
117
+ el.setAttribute("property", meta.property);
118
+ el.setAttribute("content", meta.content);
119
+ return;
120
+ }
121
+ if ("httpEquiv" in meta && "content" in meta) {
122
+ el.setAttribute("http-equiv", meta.httpEquiv);
123
+ el.setAttribute("content", meta.content);
124
+ return;
125
+ }
126
+ if ("script:ld+json" in meta) {
127
+ el.setAttribute("type", "application/ld+json");
128
+ el.textContent = JSON.stringify(meta["script:ld+json"]);
129
+ return;
130
+ }
131
+ if ("tagName" in meta) {
132
+ const { tagName: _, ...attrs } = meta;
133
+ Object.entries(attrs).forEach(([k, v]) => el.setAttribute(k, v));
134
+ return;
135
+ }
136
+ };
137
+ /**
138
+ * Apply a single MetaDescriptor to the document head.
139
+ * Returns a cleanup function that restores the previous state.
140
+ */
141
+ const applyMeta = (meta) => {
142
+ // ld+json scripts are separate elements
143
+ if ("script:ld+json" in meta) {
144
+ const el = document.createElement("script");
145
+ applyMetaAttrs(el, meta);
146
+ document.head.appendChild(el);
147
+ return () => el.remove();
148
+ }
149
+ // tagName meta — create element of specified tag
150
+ if ("tagName" in meta) {
151
+ const el = document.createElement(meta.tagName);
152
+ applyMetaAttrs(el, meta);
153
+ document.head.appendChild(el);
154
+ return () => el.remove();
155
+ }
156
+ // title meta — handled by title prop, skip here
157
+ if ("title" in meta)
158
+ return () => { };
159
+ // Standard meta tags — find existing or create new
160
+ const existing = findMetaElement(meta);
161
+ if (existing) {
162
+ // Save previous attributes for restore
163
+ const prevAttrs = new Map();
164
+ Array.from(existing.attributes).forEach((attr) => prevAttrs.set(attr.name, attr.value));
165
+ applyMetaAttrs(existing, meta);
166
+ return () => {
167
+ // Restore previous attributes
168
+ prevAttrs.forEach((v, k) => existing.setAttribute(k, v));
169
+ };
170
+ }
171
+ // Create new element
172
+ const el = document.createElement("meta");
173
+ applyMetaAttrs(el, meta);
174
+ document.head.appendChild(el);
175
+ return () => el.remove();
176
+ };
177
+ /**
178
+ * Apply a link descriptor to the document head.
179
+ * Returns a cleanup function.
180
+ */
181
+ const applyLink = (attrs) => {
182
+ // Try to find existing link by rel+href
183
+ const selector = attrs.rel && attrs.href ? `link[rel="${attrs.rel}"][href="${attrs.href}"]` : null;
184
+ const existing = selector ? document.head.querySelector(selector) : null;
185
+ if (existing) {
186
+ const prevAttrs = new Map();
187
+ Array.from(existing.attributes).forEach((attr) => prevAttrs.set(attr.name, attr.value));
188
+ Object.entries(attrs).forEach(([k, v]) => existing.setAttribute(k, v));
189
+ return () => {
190
+ prevAttrs.forEach((v, k) => existing.setAttribute(k, v));
191
+ };
192
+ }
193
+ const el = document.createElement("link");
194
+ Object.entries(attrs).forEach(([k, v]) => el.setAttribute(k, v));
195
+ document.head.appendChild(el);
196
+ return () => el.remove();
197
+ };
198
+ // =============================================================================
199
+ // Head Component
200
+ // =============================================================================
201
+ /**
202
+ * General-purpose Head component.
203
+ *
204
+ * Accepts title, meta, and link props. On the client, directly mutates
205
+ * document.head and registers cleanup via ComponentScope. On SSR,
206
+ * contributes to HeadCollector if available.
207
+ *
208
+ * Returns an empty fragment (renders nothing visible).
209
+ */
210
+ export const Head = (props) => Effect.gen(function* () {
211
+ const headData = {
212
+ title: props.title,
213
+ meta: props.meta ? [...props.meta] : undefined,
214
+ links: props.links ? [...props.links] : undefined,
215
+ };
216
+ // SSR path: contribute to HeadCollector if available
217
+ const collectorOption = yield* Effect.serviceOption(HeadCollector);
218
+ if (Option.isSome(collectorOption)) {
219
+ yield* collectorOption.value.add(headData);
220
+ return jsx("FRAGMENT", { children: [] });
221
+ }
222
+ // Client path: mutate document.head directly
223
+ if (typeof document !== "undefined") {
224
+ const { scope } = yield* ComponentScope;
225
+ const cleanups = [];
226
+ // Apply title
227
+ if (props.title !== undefined) {
228
+ const prevTitle = document.title;
229
+ document.title = props.title;
230
+ cleanups.push(() => {
231
+ document.title = prevTitle;
232
+ });
233
+ }
234
+ // Apply meta tags
235
+ if (props.meta) {
236
+ props.meta.forEach((meta) => {
237
+ cleanups.push(applyMeta(meta));
238
+ });
239
+ }
240
+ // Apply link tags
241
+ if (props.links) {
242
+ props.links.forEach((link) => {
243
+ cleanups.push(applyLink(link));
244
+ });
245
+ }
246
+ // Register cleanup on unmount
247
+ yield* Scope.addFinalizer(scope, Effect.sync(() => {
248
+ // Run cleanups in reverse order
249
+ cleanups.toReversed().forEach((fn) => fn());
250
+ }));
251
+ if (DEV) {
252
+ yield* Effect.logDebug(`Head: applied ${cleanups.length} head mutations`);
253
+ }
254
+ }
255
+ return jsx("FRAGMENT", { children: [] });
256
+ });
257
+ //# sourceMappingURL=head.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"head.js","sourceRoot":"","sources":["../src/head.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Hydration mismatch detection — dev mode only.
3
+ *
4
+ * All functions in this module are gated behind the DEV flag and will
5
+ * tree-shake to nothing in production builds.
6
+ */
7
+ import * as Effect from "effect/Effect";
8
+ import type { VElement } from "./shared.js";
9
+ /**
10
+ * Check if a host element's tag name matches the VElement type.
11
+ * Warns if server rendered a different tag than client expects.
12
+ */
13
+ export declare const checkTagMismatch: (vElement: VElement, domNode: Node) => Effect.Effect<void, never, never>;
14
+ /**
15
+ * Check if a text node's content matches the VElement's text value.
16
+ * Only compares trimmed content — whitespace differences are expected
17
+ * between SSR serialization and client render.
18
+ */
19
+ export declare const checkTextMismatch: (vElement: VElement, domNode: Node) => Effect.Effect<void, never, never>;
20
+ /**
21
+ * Check key attributes on a host element for mismatches.
22
+ * Compares: class/className, id, style, data-*, aria-* attributes.
23
+ */
24
+ export declare const checkAttributeMismatches: (vElement: VElement, domNode: Node) => Effect.Effect<void, never, never>;
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Hydration mismatch detection — dev mode only.
3
+ *
4
+ * All functions in this module are gated behind the DEV flag and will
5
+ * tree-shake to nothing in production builds.
6
+ */
7
+ import * as Effect from "effect/Effect";
8
+ import { isProperty } from "./dom.js";
9
+ // Same DEV pattern as core.ts — import.meta.hot present = dev mode
10
+ const DEV = typeof import.meta !== "undefined" && !!import.meta.hot;
11
+ // =============================================================================
12
+ // Attribute normalization helpers
13
+ // =============================================================================
14
+ /** Map JSX prop names to their DOM attribute equivalents */
15
+ const propToAttr = {
16
+ className: "class",
17
+ htmlFor: "for",
18
+ tabIndex: "tabindex",
19
+ readOnly: "readonly",
20
+ autoFocus: "autofocus",
21
+ autoPlay: "autoplay",
22
+ noValidate: "novalidate",
23
+ formNoValidate: "formnovalidate",
24
+ allowFullscreen: "allowfullscreen",
25
+ playsInline: "playsinline",
26
+ };
27
+ /** Normalize a JSX prop name to the corresponding DOM attribute name */
28
+ const normalizeAttrName = (name) => propToAttr[name] ??
29
+ (name.startsWith("data-") || name.startsWith("aria-") ? name : name.toLowerCase());
30
+ /** Normalize a style prop (object or string) to a comparable string */
31
+ const normalizeStyle = (value) => {
32
+ if (typeof value === "string")
33
+ return value.replace(/\s+/g, " ").trim();
34
+ if (typeof value === "object" && value !== null) {
35
+ return Object.entries(value)
36
+ .map(([k, v]) => {
37
+ const prop = k.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
38
+ return `${prop}: ${v}`;
39
+ })
40
+ .join("; ");
41
+ }
42
+ return "";
43
+ };
44
+ // =============================================================================
45
+ // Mismatch warning helpers
46
+ // =============================================================================
47
+ const warnMismatch = (message) => Effect.logWarning(`[fibrae] Hydration mismatch: ${message}`);
48
+ // =============================================================================
49
+ // Public check functions — all no-op in production
50
+ // =============================================================================
51
+ /**
52
+ * Check if a host element's tag name matches the VElement type.
53
+ * Warns if server rendered a different tag than client expects.
54
+ */
55
+ export const checkTagMismatch = (vElement, domNode) => {
56
+ if (!DEV)
57
+ return Effect.void;
58
+ const type = vElement.type;
59
+ if (typeof type !== "string")
60
+ return Effect.void;
61
+ if (type === "TEXT_ELEMENT" || type === "FRAGMENT" || type === "SUSPENSE" || type === "BOUNDARY")
62
+ return Effect.void;
63
+ if (domNode.nodeType === Node.ELEMENT_NODE) {
64
+ const expected = type.toUpperCase();
65
+ const actual = domNode.tagName;
66
+ if (expected !== actual) {
67
+ return warnMismatch(`expected <${type}> but found <${actual.toLowerCase()}>`);
68
+ }
69
+ }
70
+ else if (domNode.nodeType === Node.TEXT_NODE) {
71
+ const text = domNode.textContent?.substring(0, 50) ?? "";
72
+ return warnMismatch(`expected <${type}> but found text node "${text}"`);
73
+ }
74
+ return Effect.void;
75
+ };
76
+ /**
77
+ * Check if a text node's content matches the VElement's text value.
78
+ * Only compares trimmed content — whitespace differences are expected
79
+ * between SSR serialization and client render.
80
+ */
81
+ export const checkTextMismatch = (vElement, domNode) => {
82
+ if (!DEV)
83
+ return Effect.void;
84
+ if (vElement.type !== "TEXT_ELEMENT")
85
+ return Effect.void;
86
+ if (domNode.nodeType !== Node.TEXT_NODE)
87
+ return Effect.void;
88
+ const expected = String(vElement.props.nodeValue ?? "");
89
+ const actual = domNode.textContent ?? "";
90
+ // Trim both sides — SSR and client may differ in whitespace
91
+ if (expected.trim() !== actual.trim()) {
92
+ return warnMismatch(`text content differs: server "${actual.substring(0, 50)}" vs client "${expected.substring(0, 50)}"`);
93
+ }
94
+ return Effect.void;
95
+ };
96
+ /**
97
+ * Check key attributes on a host element for mismatches.
98
+ * Compares: class/className, id, style, data-*, aria-* attributes.
99
+ */
100
+ export const checkAttributeMismatches = (vElement, domNode) => {
101
+ if (!DEV)
102
+ return Effect.void;
103
+ if (typeof vElement.type !== "string")
104
+ return Effect.void;
105
+ if (vElement.type === "TEXT_ELEMENT" || vElement.type === "FRAGMENT")
106
+ return Effect.void;
107
+ if (domNode.nodeType !== Node.ELEMENT_NODE)
108
+ return Effect.void;
109
+ const el = domNode;
110
+ const props = vElement.props;
111
+ // Collect warnings for all mismatched attributes, then emit them together
112
+ return Effect.forEach(Object.keys(props).filter(isProperty), (key) => {
113
+ const value = props[key];
114
+ if (value == null || value === false)
115
+ return Effect.void;
116
+ // Style needs special comparison
117
+ if (key === "style") {
118
+ const expectedStyle = normalizeStyle(value);
119
+ const actualStyle = el.getAttribute("style") ?? "";
120
+ // Only warn if substantially different (ignore trailing semicolons, whitespace)
121
+ if (expectedStyle.replace(/;\s*$/, "").trim() !== actualStyle.replace(/;\s*$/, "").trim()) {
122
+ return warnMismatch(`attribute "style" on <${vElement.type}>: server "${actualStyle}" vs client "${expectedStyle}"`);
123
+ }
124
+ return Effect.void;
125
+ }
126
+ const attrName = normalizeAttrName(key);
127
+ const actualValue = el.getAttribute(attrName);
128
+ const expectedValue = value === true ? "" : String(value);
129
+ if (actualValue === null) {
130
+ return warnMismatch(`attribute "${attrName}" missing on <${vElement.type}>: expected "${expectedValue}"`);
131
+ }
132
+ if (actualValue !== expectedValue) {
133
+ return warnMismatch(`attribute "${attrName}" on <${vElement.type}>: server "${actualValue}" vs client "${expectedValue}"`);
134
+ }
135
+ return Effect.void;
136
+ }, { discard: true });
137
+ };
138
+ //# sourceMappingURL=hydration-dev.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hydration-dev.js","sourceRoot":"","sources":["../src/hydration-dev.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -5,7 +5,10 @@ export { h, createTextElement } from "./h.js";
5
5
  export type { VElement, ElementType, Primitive } from "./shared.js";
6
6
  export type { VElement as VNode } from "./shared.js";
7
7
  export { RenderError, StreamError, EventHandlerError, type ComponentError } from "./shared.js";
8
- export { ComponentScope } from "./shared.js";
8
+ export { ComponentScope, createRef } from "./shared.js";
9
+ export type { Ref } from "./shared.js";
9
10
  export { HydrationState, HydrationStateLive, HydrationStateEmpty } from "./hydration-state.js";
10
11
  export { Atom, AtomHttpApi, AtomRef, AtomRpc, Hydration, Registry as AtomRegistry, Result, } from "@effect-atom/atom";
11
12
  export { mountAtom, subscribeAtom } from "./atom-utils.js";
13
+ export type { TransitionService } from "./transition.js";
14
+ export { Transition, TransitionLive } from "./transition.js";
package/dist/index.js CHANGED
@@ -12,12 +12,13 @@ export { h, createTextElement } from "./h.js";
12
12
  // Error types
13
13
  export { RenderError, StreamError, EventHandlerError } from "./shared.js";
14
14
  // Component lifecycle
15
- export { ComponentScope } from "./shared.js";
15
+ export { ComponentScope, createRef } from "./shared.js";
16
16
  // Hydration state service
17
17
  export { HydrationState, HydrationStateLive, HydrationStateEmpty } from "./hydration-state.js";
18
18
  // Re-export upstream Effect Atom APIs for consumers
19
19
  export { Atom, AtomHttpApi, AtomRef, AtomRpc, Hydration, Registry as AtomRegistry, Result, } from "@effect-atom/atom";
20
20
  // Component-scoped atom utilities
21
21
  export { mountAtom, subscribeAtom } from "./atom-utils.js";
22
+ export { Transition, TransitionLive } from "./transition.js";
22
23
  // Router available via "fibrae/router" import
23
24
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +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,cAAc;AACd,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,iBAAiB,EAAuB,MAAM,aAAa,CAAC;AAE/F,sBAAsB;AACtB,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,0BAA0B;AAC1B,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE/F,oDAAoD;AACpD,OAAO,EACL,IAAI,EACJ,WAAW,EACX,OAAO,EACP,OAAO,EACP,SAAS,EACT,QAAQ,IAAI,YAAY,EACxB,MAAM,GACP,MAAM,mBAAmB,CAAC;AAE3B,kCAAkC;AAClC,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAE3D,8CAA8C"}
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,cAAc;AACd,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,iBAAiB,EAAuB,MAAM,aAAa,CAAC;AAE/F,sBAAsB;AACtB,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAGxD,0BAA0B;AAC1B,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE/F,oDAAoD;AACpD,OAAO,EACL,IAAI,EACJ,WAAW,EACX,OAAO,EACP,OAAO,EACP,SAAS,EACT,QAAQ,IAAI,YAAY,EACxB,MAAM,GACP,MAAM,mBAAmB,CAAC;AAE3B,kCAAkC;AAClC,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAI3D,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAE7D,8CAA8C"}