fibrae 0.2.3 → 0.3.1
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/atom-utils.d.ts +52 -0
- package/dist/atom-utils.js +64 -0
- package/dist/atom-utils.js.map +1 -0
- package/dist/cli/build.d.ts +34 -0
- package/dist/cli/build.js +92 -0
- package/dist/cli/build.js.map +1 -0
- package/dist/cli/cli.d.ts +10 -0
- package/dist/cli/cli.js +43 -0
- package/dist/cli/cli.js.map +1 -0
- package/dist/cli/config.d.ts +19 -0
- package/dist/cli/config.js +5 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/html.d.ts +19 -0
- package/dist/cli/html.js +95 -0
- package/dist/cli/html.js.map +1 -0
- package/dist/cli/index.d.ts +6 -0
- package/dist/cli/index.js +4 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/vite-plugin.d.ts +9 -0
- package/dist/cli/vite-plugin.js +143 -0
- package/dist/cli/vite-plugin.js.map +1 -0
- package/dist/components.d.ts +28 -30
- package/dist/components.js +35 -53
- package/dist/components.js.map +1 -1
- package/dist/core.js +7 -10
- package/dist/core.js.map +1 -1
- package/dist/dom.d.ts +25 -6
- package/dist/dom.js +161 -27
- package/dist/dom.js.map +1 -1
- package/dist/fiber-boundary.d.ts +39 -0
- package/dist/fiber-boundary.js +151 -0
- package/dist/fiber-boundary.js.map +1 -0
- package/dist/fiber-commit.d.ts +27 -0
- package/dist/fiber-commit.js +247 -0
- package/dist/fiber-commit.js.map +1 -0
- package/dist/fiber-render.d.ts +9 -9
- package/dist/fiber-render.js +165 -958
- package/dist/fiber-render.js.map +1 -1
- package/dist/fiber-tree.d.ts +77 -0
- package/dist/fiber-tree.js +152 -0
- package/dist/fiber-tree.js.map +1 -0
- package/dist/fiber-update.d.ts +46 -0
- package/dist/fiber-update.js +521 -0
- package/dist/fiber-update.js.map +1 -0
- package/dist/h.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/jsx-runtime/index.d.ts +368 -2
- package/dist/live/atom.d.ts +31 -0
- package/dist/live/atom.js +33 -0
- package/dist/live/atom.js.map +1 -0
- package/dist/live/client.d.ts +50 -0
- package/dist/live/client.js +90 -0
- package/dist/live/client.js.map +1 -0
- package/dist/live/codec.d.ts +39 -0
- package/dist/live/codec.js +41 -0
- package/dist/live/codec.js.map +1 -0
- package/dist/live/config.d.ts +13 -0
- package/dist/live/config.js +11 -0
- package/dist/live/config.js.map +1 -0
- package/dist/live/index.d.ts +25 -0
- package/dist/live/index.js +19 -0
- package/dist/live/index.js.map +1 -0
- package/dist/live/server.d.ts +83 -0
- package/dist/live/server.js +106 -0
- package/dist/live/server.js.map +1 -0
- package/dist/live/sse-stream.d.ts +14 -0
- package/dist/live/sse-stream.js +30 -0
- package/dist/live/sse-stream.js.map +1 -0
- package/dist/live/types.d.ts +40 -0
- package/dist/live/types.js +20 -0
- package/dist/live/types.js.map +1 -0
- package/dist/mdx/index.d.ts +125 -0
- package/dist/mdx/index.js +137 -0
- package/dist/mdx/index.js.map +1 -0
- package/dist/mdx/parse.d.ts +42 -0
- package/dist/mdx/parse.js +147 -0
- package/dist/mdx/parse.js.map +1 -0
- package/dist/mdx/render.d.ts +23 -0
- package/dist/mdx/render.js +263 -0
- package/dist/mdx/render.js.map +1 -0
- package/dist/router/Form.d.ts +90 -0
- package/dist/router/Form.js +166 -0
- package/dist/router/Form.js.map +1 -0
- package/dist/router/History.d.ts +4 -9
- package/dist/router/History.js +0 -8
- package/dist/router/History.js.map +1 -1
- package/dist/router/Link.d.ts +27 -28
- package/dist/router/Link.js +50 -119
- package/dist/router/Link.js.map +1 -1
- package/dist/router/Navigator.d.ts +25 -33
- package/dist/router/Navigator.js +41 -149
- package/dist/router/Navigator.js.map +1 -1
- package/dist/router/Route.d.ts +24 -7
- package/dist/router/Route.js +42 -27
- package/dist/router/Route.js.map +1 -1
- package/dist/router/Router.d.ts +27 -19
- package/dist/router/Router.js +112 -120
- package/dist/router/Router.js.map +1 -1
- package/dist/router/RouterBuilder.d.ts +171 -36
- package/dist/router/RouterBuilder.js +101 -39
- package/dist/router/RouterBuilder.js.map +1 -1
- package/dist/router/RouterOutlet.d.ts +1 -18
- package/dist/router/RouterOutlet.js +60 -48
- package/dist/router/RouterOutlet.js.map +1 -1
- package/dist/router/RouterState.d.ts +1 -1
- package/dist/router/index.d.ts +8 -5
- package/dist/router/index.js +6 -3
- package/dist/router/index.js.map +1 -1
- package/dist/router/register.d.ts +37 -0
- package/dist/router/register.js +18 -0
- package/dist/router/register.js.map +1 -0
- package/dist/router/utils.d.ts +36 -0
- package/dist/router/utils.js +48 -0
- package/dist/router/utils.js.map +1 -0
- package/dist/runtime.d.ts +11 -8
- package/dist/runtime.js +20 -2
- package/dist/runtime.js.map +1 -1
- package/dist/server.d.ts +2 -2
- package/dist/server.js +15 -29
- package/dist/server.js.map +1 -1
- package/dist/shared.d.ts +61 -62
- package/dist/shared.js +51 -13
- package/dist/shared.js.map +1 -1
- package/dist/tracking.d.ts +4 -3
- package/dist/tracking.js +6 -1
- package/dist/tracking.js.map +1 -1
- package/package.json +45 -7
- package/dist/hydration.d.ts +0 -30
- package/dist/hydration.js +0 -355
- package/dist/hydration.js.map +0 -1
- package/dist/render.d.ts +0 -19
- package/dist/render.js +0 -285
- package/dist/render.js.map +0 -1
- package/dist/scope-utils.d.ts +0 -14
- package/dist/scope-utils.js +0 -29
- package/dist/scope-utils.js.map +0 -1
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Form component — declarative form submission with schema-decoded payloads.
|
|
3
|
+
*
|
|
4
|
+
* React Router-inspired: connects to the route's action by default,
|
|
5
|
+
* or accepts an explicit action prop for fetcher-style usage.
|
|
6
|
+
*
|
|
7
|
+
* Submission lifecycle:
|
|
8
|
+
* 1. Serialize FormData → plain record
|
|
9
|
+
* 2. Schema.decodeUnknown(PayloadSchema) → typed payload
|
|
10
|
+
* 3. Decode failure → validation error (no action call)
|
|
11
|
+
* 4. Decode success → invoke action Effect
|
|
12
|
+
* 5. State transitions: idle → pending → success/failure
|
|
13
|
+
* 6. If navigate !== false: navigate after success
|
|
14
|
+
*
|
|
15
|
+
* Design: builds VElement directly (no JSX) — consistent with Link.ts pattern.
|
|
16
|
+
*/
|
|
17
|
+
import * as Effect from "effect/Effect";
|
|
18
|
+
import * as Schema from "effect/Schema";
|
|
19
|
+
import * as Option from "effect/Option";
|
|
20
|
+
import * as Context from "effect/Context";
|
|
21
|
+
import { Atom, Registry as AtomRegistry } from "@effect-atom/atom";
|
|
22
|
+
import { Navigator } from "./Navigator.js";
|
|
23
|
+
import { RouterHandlers } from "./RouterBuilder.js";
|
|
24
|
+
// =============================================================================
|
|
25
|
+
// Errors
|
|
26
|
+
// =============================================================================
|
|
27
|
+
/**
|
|
28
|
+
* Validation error from schema decode failure on form data.
|
|
29
|
+
*/
|
|
30
|
+
export class FormValidationError extends Schema.TaggedError()("FormValidationError", {
|
|
31
|
+
message: Schema.String,
|
|
32
|
+
cause: Schema.optional(Schema.Unknown),
|
|
33
|
+
}) {
|
|
34
|
+
}
|
|
35
|
+
// =============================================================================
|
|
36
|
+
// Types
|
|
37
|
+
// =============================================================================
|
|
38
|
+
/**
|
|
39
|
+
* Service tag for the current form's submission state.
|
|
40
|
+
* Components inside a Form can read this to show loading/error states.
|
|
41
|
+
*/
|
|
42
|
+
export class FormState extends Context.Tag("fibrae/FormState")() {
|
|
43
|
+
}
|
|
44
|
+
// =============================================================================
|
|
45
|
+
// Helpers
|
|
46
|
+
// =============================================================================
|
|
47
|
+
/**
|
|
48
|
+
* Serialize FormData into a plain record.
|
|
49
|
+
* Multiple values for the same key become arrays.
|
|
50
|
+
*/
|
|
51
|
+
const formDataToRecord = (formData) => {
|
|
52
|
+
const record = {};
|
|
53
|
+
formData.forEach((value, key) => {
|
|
54
|
+
const existing = record[key];
|
|
55
|
+
if (existing !== undefined) {
|
|
56
|
+
record[key] = Array.isArray(existing) ? [...existing, value] : [existing, value];
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
record[key] = value;
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
return record;
|
|
63
|
+
};
|
|
64
|
+
// =============================================================================
|
|
65
|
+
// Form Component
|
|
66
|
+
// =============================================================================
|
|
67
|
+
/**
|
|
68
|
+
* Create a Form component for the current route context.
|
|
69
|
+
*
|
|
70
|
+
* Wires to the route's action by default. Accepts explicit action for fetcher-style.
|
|
71
|
+
*
|
|
72
|
+
* Usage:
|
|
73
|
+
* ```typescript
|
|
74
|
+
* // Route action form — uses route's action config
|
|
75
|
+
* <Form>
|
|
76
|
+
* <input name="title" />
|
|
77
|
+
* <button type="submit">Save</button>
|
|
78
|
+
* </Form>
|
|
79
|
+
*
|
|
80
|
+
* // Explicit action (fetcher-style)
|
|
81
|
+
* <Form action={myAction} navigate={false}>
|
|
82
|
+
* <input name="query" />
|
|
83
|
+
* <button type="submit">Search</button>
|
|
84
|
+
* </Form>
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export function Form(props) {
|
|
88
|
+
return Effect.gen(function* () {
|
|
89
|
+
const navigator = yield* Navigator;
|
|
90
|
+
const routerHandlers = yield* RouterHandlers;
|
|
91
|
+
const registry = yield* AtomRegistry.AtomRegistry;
|
|
92
|
+
// Resolve the action: explicit prop or from current route
|
|
93
|
+
const resolvedAction = props.action
|
|
94
|
+
? Option.some(props.action)
|
|
95
|
+
: yield* resolveRouteAction(navigator, routerHandlers, registry);
|
|
96
|
+
// Create submission state atom for this form instance
|
|
97
|
+
const stateAtom = Atom.make({ _tag: "Idle" });
|
|
98
|
+
// Build the submit handler
|
|
99
|
+
const handleSubmit = (e) => {
|
|
100
|
+
e.preventDefault();
|
|
101
|
+
const form = e.target;
|
|
102
|
+
const formData = new FormData(form);
|
|
103
|
+
const rawPayload = formDataToRecord(formData);
|
|
104
|
+
return Effect.gen(function* () {
|
|
105
|
+
if (Option.isNone(resolvedAction)) {
|
|
106
|
+
yield* Effect.logWarning("Form submitted but no action configured");
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const routeAction = resolvedAction.value;
|
|
110
|
+
// Transition to pending
|
|
111
|
+
registry.set(stateAtom, { _tag: "Pending" });
|
|
112
|
+
// Decode payload via schema
|
|
113
|
+
const decoded = yield* Schema.decodeUnknown(routeAction.schema)(rawPayload).pipe(Effect.mapError((cause) => new FormValidationError({
|
|
114
|
+
message: "Form validation failed",
|
|
115
|
+
cause,
|
|
116
|
+
})));
|
|
117
|
+
// Invoke action
|
|
118
|
+
const result = yield* routeAction.handler({ payload: decoded });
|
|
119
|
+
// Success
|
|
120
|
+
registry.set(stateAtom, { _tag: "Success", data: result });
|
|
121
|
+
if (props.onSuccess)
|
|
122
|
+
props.onSuccess(result);
|
|
123
|
+
// Navigate after success (unless disabled)
|
|
124
|
+
if (props.navigate !== false && props.navigateTo) {
|
|
125
|
+
yield* navigator.go(props.navigateTo);
|
|
126
|
+
}
|
|
127
|
+
}).pipe(Effect.catchAll((error) => Effect.sync(() => {
|
|
128
|
+
registry.set(stateAtom, { _tag: "Failure", error });
|
|
129
|
+
if (props.onError)
|
|
130
|
+
props.onError(error);
|
|
131
|
+
})));
|
|
132
|
+
};
|
|
133
|
+
// Normalize children
|
|
134
|
+
const normalizedChildren = props.children
|
|
135
|
+
? Array.isArray(props.children)
|
|
136
|
+
? props.children
|
|
137
|
+
: [props.children]
|
|
138
|
+
: [];
|
|
139
|
+
return {
|
|
140
|
+
type: "form",
|
|
141
|
+
props: {
|
|
142
|
+
method: props.method ?? "post",
|
|
143
|
+
class: props.class || undefined,
|
|
144
|
+
"data-cy": props["data-cy"],
|
|
145
|
+
onSubmit: handleSubmit,
|
|
146
|
+
children: normalizedChildren.filter((child) => child !== null && child !== undefined && child !== false && child !== true),
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Resolve the action from the current route.
|
|
153
|
+
* Reads Navigator.currentRoute to find the matched route's action.
|
|
154
|
+
*/
|
|
155
|
+
function resolveRouteAction(navigator, routerHandlers, registry) {
|
|
156
|
+
return Effect.sync(() => {
|
|
157
|
+
const currentRoute = registry.get(navigator.currentRoute);
|
|
158
|
+
if (Option.isNone(currentRoute))
|
|
159
|
+
return Option.none();
|
|
160
|
+
const handler = routerHandlers.getHandler(currentRoute.value.routeName);
|
|
161
|
+
if (Option.isNone(handler))
|
|
162
|
+
return Option.none();
|
|
163
|
+
return handler.value.action;
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=Form.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Form.js","sourceRoot":"","sources":["../../src/router/Form.ts"],"names":[],"mappings":"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"}
|
package/dist/router/History.d.ts
CHANGED
|
@@ -39,11 +39,11 @@ export interface HistoryService {
|
|
|
39
39
|
/**
|
|
40
40
|
* Navigate to a new location (push new entry).
|
|
41
41
|
*/
|
|
42
|
-
readonly push: (path: string, state?: unknown) => Effect.Effect<void
|
|
42
|
+
readonly push: (path: string, state?: unknown) => Effect.Effect<void>;
|
|
43
43
|
/**
|
|
44
44
|
* Replace current location (same entry).
|
|
45
45
|
*/
|
|
46
|
-
readonly replace: (path: string, state?: unknown) => Effect.Effect<void
|
|
46
|
+
readonly replace: (path: string, state?: unknown) => Effect.Effect<void>;
|
|
47
47
|
/**
|
|
48
48
|
* Go back in history.
|
|
49
49
|
*/
|
|
@@ -109,11 +109,11 @@ export declare const getLocation: Effect.Effect<HistoryLocation, never, History
|
|
|
109
109
|
/**
|
|
110
110
|
* Push a new location.
|
|
111
111
|
*/
|
|
112
|
-
export declare const push: (path: string, state?: unknown) => Effect.Effect<void, never,
|
|
112
|
+
export declare const push: (path: string, state?: unknown) => Effect.Effect<void, never, AtomRegistry.AtomRegistry | History>;
|
|
113
113
|
/**
|
|
114
114
|
* Replace current location.
|
|
115
115
|
*/
|
|
116
|
-
export declare const replace: (path: string, state?: unknown) => Effect.Effect<void, never,
|
|
116
|
+
export declare const replace: (path: string, state?: unknown) => Effect.Effect<void, never, AtomRegistry.AtomRegistry | History>;
|
|
117
117
|
/**
|
|
118
118
|
* Go back in history.
|
|
119
119
|
*/
|
|
@@ -126,9 +126,4 @@ export declare const forward: Effect.Effect<void, never, History>;
|
|
|
126
126
|
* Go n entries in history.
|
|
127
127
|
*/
|
|
128
128
|
export declare const go: (n: number) => Effect.Effect<void, never, History>;
|
|
129
|
-
/**
|
|
130
|
-
* SPA-safe navigation without access to the Effect runtime.
|
|
131
|
-
* Uses pushState + synthetic popstate so BrowserHistoryLive picks up the change.
|
|
132
|
-
*/
|
|
133
|
-
export declare function navigateTo(url: string): void;
|
|
134
129
|
export {};
|
package/dist/router/History.js
CHANGED
|
@@ -238,12 +238,4 @@ export const go = (n) => Effect.gen(function* () {
|
|
|
238
238
|
const history = yield* History;
|
|
239
239
|
yield* history.go(n);
|
|
240
240
|
});
|
|
241
|
-
/**
|
|
242
|
-
* SPA-safe navigation without access to the Effect runtime.
|
|
243
|
-
* Uses pushState + synthetic popstate so BrowserHistoryLive picks up the change.
|
|
244
|
-
*/
|
|
245
|
-
export function navigateTo(url) {
|
|
246
|
-
window.history.pushState(null, "", url);
|
|
247
|
-
window.dispatchEvent(new PopStateEvent("popstate"));
|
|
248
|
-
}
|
|
249
241
|
//# sourceMappingURL=History.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"History.js","sourceRoot":"","sources":["../../src/router/History.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,IAAI,EAAE,QAAQ,IAAI,YAAY,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"History.js","sourceRoot":"","sources":["../../src/router/History.ts"],"names":[],"mappings":"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"}
|
package/dist/router/Link.d.ts
CHANGED
|
@@ -1,52 +1,51 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Link component - declarative navigation.
|
|
3
3
|
*
|
|
4
|
-
* Renders an <a> element with correct href and handles click for SPA navigation.
|
|
5
|
-
* - <Link
|
|
6
|
-
* - <Link
|
|
7
|
-
* - <Link
|
|
8
|
-
* - <Link
|
|
4
|
+
* Renders an <a> element with the correct href and handles click for SPA navigation.
|
|
5
|
+
* - <Link href="/posts">text</Link>
|
|
6
|
+
* - <Link href={`/posts/${id}`}>text</Link>
|
|
7
|
+
* - <Link href="/search" search={{ q: "effect" }}>text</Link>
|
|
8
|
+
* - <Link href="/posts" replace>text</Link>
|
|
9
9
|
*
|
|
10
|
-
* Design: href is
|
|
11
|
-
* and uses Navigator for SPA navigation.
|
|
10
|
+
* Design: href is passed through directly (works with SSR). onClick prevents
|
|
11
|
+
* default and uses Navigator for SPA navigation.
|
|
12
12
|
*/
|
|
13
13
|
import * as Effect from "effect/Effect";
|
|
14
14
|
import { Registry as AtomRegistry } from "@effect-atom/atom";
|
|
15
15
|
import { Navigator } from "./Navigator.js";
|
|
16
|
-
import type { Router } from "./Router.js";
|
|
17
16
|
import type { VElement, VChild } from "../shared.js";
|
|
17
|
+
import type { ValidHref } from "./register.js";
|
|
18
18
|
/**
|
|
19
19
|
* Props for the Link component.
|
|
20
|
+
* `href` is validated against registered route paths via RegisteredRouter.
|
|
20
21
|
*/
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
readonly params?: Record<string, unknown>;
|
|
22
|
+
/** Props handled by Link — omitted from the passthrough anchor attributes. */
|
|
23
|
+
type LinkOwnProps = {
|
|
24
|
+
/** Path to navigate to — validated against registered route patterns */
|
|
25
|
+
readonly href: ValidHref;
|
|
26
26
|
/** Search/query parameters */
|
|
27
27
|
readonly search?: Record<string, unknown>;
|
|
28
28
|
/** Use history.replace instead of push */
|
|
29
29
|
readonly replace?: boolean;
|
|
30
|
-
/**
|
|
31
|
-
readonly
|
|
30
|
+
/** Enable View Transitions API for this navigation (CSS-driven animations) */
|
|
31
|
+
readonly viewTransition?: boolean;
|
|
32
32
|
/** Active class name (default: "active") */
|
|
33
33
|
readonly activeClass?: string;
|
|
34
|
-
/** Data attributes for testing */
|
|
35
|
-
readonly "data-cy"?: string;
|
|
36
34
|
/** Children to render inside the anchor (already normalized by JSX runtime) */
|
|
37
35
|
readonly children?: VChild;
|
|
38
|
-
}
|
|
36
|
+
};
|
|
37
|
+
/** Anchor attributes that Link doesn't override — class, data-*, aria-*, etc. */
|
|
38
|
+
type AnchorPassthroughProps = Omit<JSX.IntrinsicElements["a"], "href" | "onClick" | "children">;
|
|
39
|
+
export type LinkProps = LinkOwnProps & AnchorPassthroughProps;
|
|
39
40
|
/**
|
|
40
|
-
*
|
|
41
|
+
* Link component — declarative, type-safe navigation with real paths.
|
|
41
42
|
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* ```typescript
|
|
48
|
-
* const Link = createLink(appRouter);
|
|
49
|
-
* <Link to="posts" params={{ id: 123 }}>View Post</Link>
|
|
43
|
+
* ```tsx
|
|
44
|
+
* import { Link } from "fibrae/router";
|
|
45
|
+
* <Link href="/posts">Posts</Link>
|
|
46
|
+
* <Link href={`/posts/${id}`}>View Post</Link>
|
|
47
|
+
* // <Link href="/typo" /> — compile-time error (with RegisteredRouter)
|
|
50
48
|
* ```
|
|
51
49
|
*/
|
|
52
|
-
export declare function
|
|
50
|
+
export declare function Link(props: LinkProps): Effect.Effect<VElement, never, Navigator | AtomRegistry.AtomRegistry>;
|
|
51
|
+
export {};
|
package/dist/router/Link.js
CHANGED
|
@@ -1,135 +1,66 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Link component - declarative navigation.
|
|
3
3
|
*
|
|
4
|
-
* Renders an <a> element with correct href and handles click for SPA navigation.
|
|
5
|
-
* - <Link
|
|
6
|
-
* - <Link
|
|
7
|
-
* - <Link
|
|
8
|
-
* - <Link
|
|
4
|
+
* Renders an <a> element with the correct href and handles click for SPA navigation.
|
|
5
|
+
* - <Link href="/posts">text</Link>
|
|
6
|
+
* - <Link href={`/posts/${id}`}>text</Link>
|
|
7
|
+
* - <Link href="/search" search={{ q: "effect" }}>text</Link>
|
|
8
|
+
* - <Link href="/posts" replace>text</Link>
|
|
9
9
|
*
|
|
10
|
-
* Design: href is
|
|
11
|
-
* and uses Navigator for SPA navigation.
|
|
10
|
+
* Design: href is passed through directly (works with SSR). onClick prevents
|
|
11
|
+
* default and uses Navigator for SPA navigation.
|
|
12
12
|
*/
|
|
13
|
+
// eslint-disable-next-line no-unused-vars -- jsx is used by the JSX transform (jsxFactory)
|
|
14
|
+
import { jsx } from "../jsx-runtime/index.js";
|
|
13
15
|
import * as Effect from "effect/Effect";
|
|
14
|
-
import
|
|
15
|
-
import { Atom, Registry as AtomRegistry } from "@effect-atom/atom";
|
|
16
|
+
import { Registry as AtomRegistry } from "@effect-atom/atom";
|
|
16
17
|
import { Navigator } from "./Navigator.js";
|
|
18
|
+
import { buildSearchString } from "./utils.js";
|
|
17
19
|
// =============================================================================
|
|
18
|
-
//
|
|
20
|
+
// Link Component
|
|
19
21
|
// =============================================================================
|
|
20
22
|
/**
|
|
21
|
-
*
|
|
22
|
-
*/
|
|
23
|
-
function findRouteByName(router, name) {
|
|
24
|
-
for (const group of router.groups) {
|
|
25
|
-
for (const route of group.routes) {
|
|
26
|
-
if (route.name === name) {
|
|
27
|
-
return Option.some(route);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
return Option.none();
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Build search string from params object.
|
|
35
|
-
*/
|
|
36
|
-
function buildSearchString(params) {
|
|
37
|
-
const searchParams = new URLSearchParams();
|
|
38
|
-
for (const [key, value] of Object.entries(params)) {
|
|
39
|
-
if (value !== undefined && value !== null) {
|
|
40
|
-
searchParams.set(key, String(value));
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
const str = searchParams.toString();
|
|
44
|
-
return str ? `?${str}` : "";
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Build the href for a route with params.
|
|
48
|
-
*/
|
|
49
|
-
function buildHref(router, routeName, params, search, basePath = "") {
|
|
50
|
-
const route = findRouteByName(router, routeName);
|
|
51
|
-
if (Option.isNone(route)) {
|
|
52
|
-
return "#";
|
|
53
|
-
}
|
|
54
|
-
const pathname = route.value.interpolate(params ?? {});
|
|
55
|
-
const searchString = search ? buildSearchString(search) : "";
|
|
56
|
-
return `${basePath}${pathname}${searchString}`;
|
|
57
|
-
}
|
|
58
|
-
// =============================================================================
|
|
59
|
-
// Link Component Factory
|
|
60
|
-
// =============================================================================
|
|
61
|
-
/**
|
|
62
|
-
* Create a Link component bound to a router.
|
|
63
|
-
*
|
|
64
|
-
* The Link component must know which router to use for:
|
|
65
|
-
* - Building hrefs from route names
|
|
66
|
-
* - Checking active state
|
|
23
|
+
* Link component — declarative, type-safe navigation with real paths.
|
|
67
24
|
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
* <Link
|
|
25
|
+
* ```tsx
|
|
26
|
+
* import { Link } from "fibrae/router";
|
|
27
|
+
* <Link href="/posts">Posts</Link>
|
|
28
|
+
* <Link href={`/posts/${id}`}>View Post</Link>
|
|
29
|
+
* // <Link href="/typo" /> — compile-time error (with RegisteredRouter)
|
|
72
30
|
* ```
|
|
73
31
|
*/
|
|
74
|
-
export function
|
|
75
|
-
return function
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
return true;
|
|
97
|
-
},
|
|
32
|
+
export function Link(props) {
|
|
33
|
+
return Effect.gen(function* () {
|
|
34
|
+
const navigator = yield* Navigator;
|
|
35
|
+
// Build full href with basePath and search params
|
|
36
|
+
const searchString = props.search ? buildSearchString(props.search) : "";
|
|
37
|
+
const fullHref = `${navigator.basePath}${props.href}${searchString}`;
|
|
38
|
+
// Active state: currentPathname is already basePath-stripped by Navigator
|
|
39
|
+
const isActive = navigator.currentPathname === props.href;
|
|
40
|
+
// Build class string
|
|
41
|
+
const activeClass = props.activeClass ?? "active";
|
|
42
|
+
const classes = [props.class, isActive ? activeClass : null].filter(Boolean).join(" ");
|
|
43
|
+
// Click handler - prevent default and use Navigator for SPA navigation
|
|
44
|
+
const handleClick = (e) => {
|
|
45
|
+
// Only intercept left clicks without modifier keys
|
|
46
|
+
if (e.button !== 0 || e.ctrlKey || e.metaKey || e.shiftKey) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
e.preventDefault();
|
|
50
|
+
return navigator.go(props.href, {
|
|
51
|
+
search: props.search,
|
|
52
|
+
replace: props.replace,
|
|
53
|
+
viewTransition: props.viewTransition,
|
|
98
54
|
});
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
return navigator.go(props.to, {
|
|
110
|
-
path: props.params,
|
|
111
|
-
searchParams: props.search,
|
|
112
|
-
replace: props.replace,
|
|
113
|
-
});
|
|
114
|
-
};
|
|
115
|
-
// Return VElement directly - children are already normalized by JSX runtime
|
|
116
|
-
// Normalize children to array (VChild can be single value or array)
|
|
117
|
-
const normalizedChildren = props.children
|
|
118
|
-
? Array.isArray(props.children)
|
|
119
|
-
? props.children
|
|
120
|
-
: [props.children]
|
|
121
|
-
: [];
|
|
122
|
-
return {
|
|
123
|
-
type: "a",
|
|
124
|
-
props: {
|
|
125
|
-
href,
|
|
126
|
-
class: classes || undefined,
|
|
127
|
-
"data-cy": props["data-cy"],
|
|
128
|
-
onClick: handleClick,
|
|
129
|
-
children: normalizedChildren.filter((child) => child !== null && child !== undefined && child !== false && child !== true),
|
|
130
|
-
},
|
|
131
|
-
};
|
|
132
|
-
});
|
|
133
|
-
};
|
|
55
|
+
};
|
|
56
|
+
const normalizedChildren = props.children
|
|
57
|
+
? Array.isArray(props.children)
|
|
58
|
+
? props.children
|
|
59
|
+
: [props.children]
|
|
60
|
+
: [];
|
|
61
|
+
// Separate Link-specific props from HTML anchor attributes
|
|
62
|
+
const { href: _href, search: _search, replace: _replace, viewTransition: _viewTransition, activeClass: _activeClass, class: _className, children: _children, ...anchorProps } = props;
|
|
63
|
+
return (jsx("a", { ...anchorProps, href: fullHref, class: classes || undefined, onClick: handleClick }, normalizedChildren));
|
|
64
|
+
});
|
|
134
65
|
}
|
|
135
66
|
//# sourceMappingURL=Link.js.map
|
package/dist/router/Link.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Link.js","sourceRoot":"","sources":["../../src/router/Link.
|
|
1
|
+
{"version":3,"file":"Link.js","sourceRoot":"","sources":["../../src/router/Link.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,2FAA2F;AAC3F,OAAO,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAC9C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,QAAQ,IAAI,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAgC/C,gFAAgF;AAChF,iBAAiB;AACjB,gFAAgF;AAEhF;;;;;;;;;GASG;AACH,MAAM,UAAU,IAAI,CAClB,KAAgB;IAEhB,OAAO,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QACzB,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC;QAEnC,kDAAkD;QAClD,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,iBAAiB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACzE,MAAM,QAAQ,GAAG,GAAG,SAAS,CAAC,QAAQ,GAAG,KAAK,CAAC,IAAI,GAAG,YAAY,EAAE,CAAC;QAErE,0EAA0E;QAC1E,MAAM,QAAQ,GAAG,SAAS,CAAC,eAAe,KAAK,KAAK,CAAC,IAAI,CAAC;QAE1D,qBAAqB;QACrB,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,IAAI,QAAQ,CAAC;QAClD,MAAM,OAAO,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAEvF,uEAAuE;QACvE,MAAM,WAAW,GAAG,CAAC,CAAa,EAAE,EAAE;YACpC,mDAAmD;YACnD,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;gBAC3D,OAAO;YACT,CAAC;YACD,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,OAAO,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE;gBAC9B,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,cAAc,EAAE,KAAK,CAAC,cAAc;aACrC,CAAC,CAAC;QACL,CAAC,CAAC;QAEF,MAAM,kBAAkB,GAAG,KAAK,CAAC,QAAQ;YACvC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC;gBAC7B,CAAC,CAAC,KAAK,CAAC,QAAQ;gBAChB,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;YACpB,CAAC,CAAC,EAAE,CAAC;QAEP,2DAA2D;QAC3D,MAAM,EACJ,IAAI,EAAE,KAAK,EACX,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,QAAQ,EACjB,cAAc,EAAE,eAAe,EAC/B,WAAW,EAAE,YAAY,EACzB,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,SAAS,EACnB,GAAG,WAAW,EACf,GAAG,KAAK,CAAC;QAEV,OAAO,CACL,cAAO,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,IAAI,SAAS,EAAE,OAAO,EAAE,WAAW,IAClF,kBAAkB,CACjB,CACL,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
|