@typed/ui 0.13.0 → 1.0.0-beta.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/README.md +96 -2
- package/dist/HttpRouter.d.ts +13 -0
- package/dist/HttpRouter.d.ts.map +1 -0
- package/dist/HttpRouter.js +99 -0
- package/dist/Link.d.ts +36 -0
- package/dist/Link.d.ts.map +1 -0
- package/dist/Link.js +45 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/package.json +25 -79
- package/src/HttpRouter.test.ts +294 -0
- package/src/HttpRouter.ts +168 -0
- package/src/Link.test.ts +85 -0
- package/src/Link.ts +97 -90
- package/src/index.ts +2 -40
- package/tsconfig.json +6 -0
- package/LICENSE +0 -21
- package/Link/package.json +0 -6
- package/Props/package.json +0 -6
- package/dist/cjs/Link.js +0 -76
- package/dist/cjs/Link.js.map +0 -1
- package/dist/cjs/Props.js +0 -26
- package/dist/cjs/Props.js.map +0 -1
- package/dist/cjs/dom-properties.js +0 -6
- package/dist/cjs/dom-properties.js.map +0 -1
- package/dist/cjs/hyperscript.js +0 -484
- package/dist/cjs/hyperscript.js.map +0 -1
- package/dist/cjs/index.js +0 -39
- package/dist/cjs/index.js.map +0 -1
- package/dist/cjs/internal/addEventListener.js +0 -19
- package/dist/cjs/internal/addEventListener.js.map +0 -1
- package/dist/cjs/useClickAway.js +0 -43
- package/dist/cjs/useClickAway.js.map +0 -1
- package/dist/cjs/usePagination.js +0 -68
- package/dist/cjs/usePagination.js.map +0 -1
- package/dist/dts/Link.d.ts +0 -26
- package/dist/dts/Link.d.ts.map +0 -1
- package/dist/dts/Props.d.ts +0 -67
- package/dist/dts/Props.d.ts.map +0 -1
- package/dist/dts/dom-properties.d.ts +0 -928
- package/dist/dts/dom-properties.d.ts.map +0 -1
- package/dist/dts/hyperscript.d.ts +0 -461
- package/dist/dts/hyperscript.d.ts.map +0 -1
- package/dist/dts/index.d.ts +0 -16
- package/dist/dts/index.d.ts.map +0 -1
- package/dist/dts/internal/addEventListener.d.ts +0 -6
- package/dist/dts/internal/addEventListener.d.ts.map +0 -1
- package/dist/dts/useClickAway.d.ts +0 -19
- package/dist/dts/useClickAway.d.ts.map +0 -1
- package/dist/dts/usePagination.d.ts +0 -41
- package/dist/dts/usePagination.d.ts.map +0 -1
- package/dist/esm/Link.js +0 -52
- package/dist/esm/Link.js.map +0 -1
- package/dist/esm/Props.js +0 -19
- package/dist/esm/Props.js.map +0 -1
- package/dist/esm/dom-properties.js +0 -5
- package/dist/esm/dom-properties.js.map +0 -1
- package/dist/esm/hyperscript.js +0 -470
- package/dist/esm/hyperscript.js.map +0 -1
- package/dist/esm/index.js +0 -37
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/internal/addEventListener.js +0 -11
- package/dist/esm/internal/addEventListener.js.map +0 -1
- package/dist/esm/package.json +0 -4
- package/dist/esm/useClickAway.js +0 -36
- package/dist/esm/useClickAway.js.map +0 -1
- package/dist/esm/usePagination.js +0 -59
- package/dist/esm/usePagination.js.map +0 -1
- package/dom-properties/package.json +0 -6
- package/hyperscript/package.json +0 -6
- package/src/Props.ts +0 -104
- package/src/dom-properties.ts +0 -1132
- package/src/hyperscript.ts +0 -649
- package/src/internal/addEventListener.ts +0 -22
- package/src/useClickAway.ts +0 -66
- package/src/usePagination.ts +0 -122
- package/useClickAway/package.json +0 -6
- package/usePagination/package.json +0 -6
package/README.md
CHANGED
|
@@ -1,5 +1,99 @@
|
|
|
1
1
|
# @typed/ui
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> **Beta:** This package is in beta; APIs may change.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
`@typed/ui` provides **web integration** for the router and template: **Link** (typed anchor that uses Navigation for same-origin clicks) and **HttpRouter**-related helpers for SSR (`ssrForHttp`, `handleHttpServerError`). Use it when you need navigation-aware links and/or server-side rendering of the router with Effect’s HTTP server.
|
|
6
|
+
|
|
7
|
+
## Dependencies
|
|
8
|
+
|
|
9
|
+
- `effect`
|
|
10
|
+
- `@effect/platform-node`
|
|
11
|
+
- `@typed/fx`
|
|
12
|
+
- `@typed/navigation`
|
|
13
|
+
- `@typed/router`
|
|
14
|
+
- `@typed/template`
|
|
15
|
+
- `happy-dom` (dev)
|
|
16
|
+
|
|
17
|
+
## API overview
|
|
18
|
+
|
|
19
|
+
- **Link** — `Link(options)` renders an `<a href="...">` that intercepts same-origin, same-document clicks and calls `Navigation.navigate` instead of a full page load. Options include `href`, `content`, `replace`, and standard anchor props. Requires **Navigation** and **RenderTemplate** in context (e.g. browser router).
|
|
20
|
+
- **SSR:** `ssrForHttp(router, matcher)` — registers route handlers on an Effect **HttpRouter** for server-side rendering; `handleHttpServerError(router)` — global middleware for HTTP server errors.
|
|
21
|
+
|
|
22
|
+
## API reference
|
|
23
|
+
|
|
24
|
+
### `Link`
|
|
25
|
+
|
|
26
|
+
Renders an `<a href="...">` that intercepts same-origin, same-document clicks and navigates via `Navigation.navigate` instead of a full page load. Requires **Navigation** and **RenderTemplate** in the Effect context (e.g. `BrowserRouter`).
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
function Link<const Opts extends LinkOptions>(
|
|
30
|
+
options: Opts
|
|
31
|
+
): Fx<RenderEvent, Renderable.ErrorFromObject<Opts>, Renderable.ServicesFromObject<Opts> | Scope | RenderTemplate>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**`LinkOptions`**
|
|
35
|
+
|
|
36
|
+
| Property | Type | Required | Description |
|
|
37
|
+
|-----------|------|----------|-------------|
|
|
38
|
+
| `href` | `Renderable<string, any, any>` | Yes | Target URL. |
|
|
39
|
+
| `content` | `Renderable<string \| number \| boolean \| null \| undefined \| void \| RenderEvent, any, any>` | Yes | Link body (text or template content). |
|
|
40
|
+
| `replace` | `boolean` | No | If `true`, use history replace instead of push. Default: `false`. |
|
|
41
|
+
|
|
42
|
+
In addition, `LinkOptions` accepts standard anchor event handlers (e.g. `onclick`), `ref`, and other writable `HTMLAnchorElement` properties. Custom `onclick` runs first; if the event is not `preventDefault`’d, the built-in navigation handler runs.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
### `ssrForHttp`
|
|
47
|
+
|
|
48
|
+
Registers route handlers on an Effect **HttpRouter** for server-side rendering. The matcher’s routes are compiled and each case is exposed as a GET route; requests are parsed, matched, and the corresponding Fx is rendered to HTML. Requires **Router** and **Scope** to be provided elsewhere; other matcher services remain in the effect requirement.
|
|
49
|
+
|
|
50
|
+
**Overloads:**
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
// (router, matcher)
|
|
54
|
+
function ssrForHttp<E, R>(
|
|
55
|
+
router: HttpRouter,
|
|
56
|
+
input: Matcher<RenderEvent, E, R>
|
|
57
|
+
): Effect.Effect<void, never, Exclude<R, Scope | Router>>
|
|
58
|
+
|
|
59
|
+
// (matcher)(router) — curried
|
|
60
|
+
function ssrForHttp<E, R>(
|
|
61
|
+
input: Matcher<RenderEvent, E, R>
|
|
62
|
+
): (router: HttpRouter) => Effect.Effect<void, never, Exclude<R, Scope | Router>>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
- **`router`** — Effect `HttpRouter` to attach GET handlers to.
|
|
66
|
+
- **`input`** — A **Matcher** from `@typed/router` whose cases produce `RenderEvent` Fx (e.g. templates). Route path and query params are decoded and passed to the handler; `Scope` and `Router` are provided by the SSR pipeline.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
### `handleHttpServerError`
|
|
71
|
+
|
|
72
|
+
Adds global middleware to an **HttpRouter** that catches `HttpServerError` and returns appropriate HTTP responses:
|
|
73
|
+
|
|
74
|
+
| Error reason | Status |
|
|
75
|
+
|------------------|--------|
|
|
76
|
+
| `RouteNotFound` | 404 |
|
|
77
|
+
| `RequestParseError` | 400 |
|
|
78
|
+
| `InternalError` / `ResponseError` | 500 |
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
function handleHttpServerError(router: HttpRouter): Effect.Effect<void, never, HttpRouter>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Use after registering routes (e.g. after `ssrForHttp`) so unhandled route and parse errors are converted to 404/400/500 instead of failing the server.
|
|
85
|
+
|
|
86
|
+
## Example
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
import { Link } from "@typed/ui";
|
|
90
|
+
import { html } from "@typed/template";
|
|
91
|
+
|
|
92
|
+
// In a template: link that navigates via Navigation (no full reload)
|
|
93
|
+
const nav = html`<nav>
|
|
94
|
+
${Link({ href: "/", content: "Home" })}
|
|
95
|
+
${Link({ href: "/todos", content: "Todos" })}
|
|
96
|
+
</nav>`;
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
For SSR, provide the router and matcher to `ssrForHttp` when setting up the HTTP server; see Effect’s `HttpRouter` and the TodoMVC example structure.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as Scope from "effect/Scope";
|
|
3
|
+
import { type HttpRouter } from "effect/unstable/http/HttpRouter";
|
|
4
|
+
import { type Matcher, type Router } from "@typed/router";
|
|
5
|
+
import { type RenderEvent } from "@typed/template";
|
|
6
|
+
type ProvidedForSsr = Scope.Scope | Router;
|
|
7
|
+
export declare const ssrForHttp: {
|
|
8
|
+
<E, R>(input: Matcher<RenderEvent, E, R>): (router: HttpRouter) => Effect.Effect<void, never, Exclude<R, ProvidedForSsr>>;
|
|
9
|
+
<E, R>(router: HttpRouter, input: Matcher<RenderEvent, E, R>): Effect.Effect<void, never, Exclude<R, ProvidedForSsr>>;
|
|
10
|
+
};
|
|
11
|
+
export declare function handleHttpServerError(router: HttpRouter): Effect.Effect<void, never, import("effect/unstable/http/HttpRouter").Request<"GlobalError", unknown>>;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=HttpRouter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HttpRouter.d.ts","sourceRoot":"","sources":["../src/HttpRouter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAKxC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAEtC,OAAO,EAAE,KAAK,UAAU,EAA4B,MAAM,iCAAiC,CAAC;AAK5F,OAAO,EAQL,KAAK,OAAO,EAGZ,KAAK,MAAM,EACZ,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAsB,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEvE,KAAK,cAAc,GAAG,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC;AAE3C,eAAO,MAAM,UAAU,EAAE;IACvB,CAAC,CAAC,EAAE,CAAC,EACH,KAAK,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC,GAChC,CAAC,MAAM,EAAE,UAAU,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC;IAClF,CAAC,CAAC,EAAE,CAAC,EACH,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC,GAChC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC;CAY1D,CAAC;AAEH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,UAAU,yGAQvD"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as Exit from "effect/Exit";
|
|
3
|
+
import { dual } from "effect/Function";
|
|
4
|
+
import * as Layer from "effect/Layer";
|
|
5
|
+
import * as Option from "effect/Option";
|
|
6
|
+
import * as Scope from "effect/Scope";
|
|
7
|
+
import * as ServiceMap from "effect/ServiceMap";
|
|
8
|
+
import { RouteContext } from "effect/unstable/http/HttpRouter";
|
|
9
|
+
import * as HttpServerError from "effect/unstable/http/HttpServerError";
|
|
10
|
+
import * as HttpServerRequest from "effect/unstable/http/HttpServerRequest";
|
|
11
|
+
import * as HttpServerResponse from "effect/unstable/http/HttpServerResponse";
|
|
12
|
+
import { RefSubject } from "@typed/fx";
|
|
13
|
+
import { compile, CurrentRoute, makeCatchManager, makeLayerManager, makeLayoutManager, Join, Parse, } from "@typed/router";
|
|
14
|
+
import { initialMemory } from "@typed/navigation";
|
|
15
|
+
import { renderToHtmlString } from "@typed/template";
|
|
16
|
+
export const ssrForHttp = dual(2, (router, input) => {
|
|
17
|
+
return Effect.gen(function* () {
|
|
18
|
+
const matcher = Option.match(yield* Effect.serviceOption(CurrentRoute), {
|
|
19
|
+
onNone: () => input,
|
|
20
|
+
onSome: (parent) => input.prefix(parent.route),
|
|
21
|
+
});
|
|
22
|
+
const entries = compile(matcher.cases);
|
|
23
|
+
const currentServices = yield* Effect.services();
|
|
24
|
+
yield* router.addAll(entries.map((e) => toRoute(e, currentServices)));
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
export function handleHttpServerError(router) {
|
|
28
|
+
return router.addGlobalMiddleware(Effect.catch((error) => HttpServerError.isHttpServerError(error)
|
|
29
|
+
? Effect.succeed(HttpServerResponse.text(error.message, { status: getStatus(error) }))
|
|
30
|
+
: Effect.fail(error)));
|
|
31
|
+
}
|
|
32
|
+
function getStatus(error) {
|
|
33
|
+
switch (error.reason._tag) {
|
|
34
|
+
case "RouteNotFound":
|
|
35
|
+
return 404;
|
|
36
|
+
case "RequestParseError":
|
|
37
|
+
return 400;
|
|
38
|
+
case "InternalError":
|
|
39
|
+
case "ResponseError":
|
|
40
|
+
return 500;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function toRoute(entry, currentServices) {
|
|
44
|
+
return {
|
|
45
|
+
"~effect/http/HttpRouter/Route": "~effect/http/HttpRouter/Route",
|
|
46
|
+
method: "GET",
|
|
47
|
+
path: entry.route.path,
|
|
48
|
+
handler: Effect.gen(function* () {
|
|
49
|
+
const fiberId = yield* Effect.fiberId;
|
|
50
|
+
const rootScope = yield* Effect.scope;
|
|
51
|
+
const routeContext = yield* RouteContext;
|
|
52
|
+
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
53
|
+
const searchParams = yield* HttpServerRequest.ParsedSearchParams;
|
|
54
|
+
const provided = Layer.mergeAll(initialMemory({ url: request.url }), Layer.succeed(CurrentRoute, yield* Effect.serviceOption(CurrentRoute).pipe(Effect.map(Option.match({
|
|
55
|
+
onNone: () => ({
|
|
56
|
+
route: Parse(request.url),
|
|
57
|
+
parent: undefined,
|
|
58
|
+
}),
|
|
59
|
+
onSome: (parent) => ({
|
|
60
|
+
route: Join(parent.route, Parse(request.url)),
|
|
61
|
+
parent,
|
|
62
|
+
}),
|
|
63
|
+
})))));
|
|
64
|
+
const input = { ...routeContext.params, ...searchParams };
|
|
65
|
+
const params = yield* Effect.mapError(entry.decode(input), (cause) => new HttpServerError.HttpServerError({
|
|
66
|
+
reason: new HttpServerError.RequestParseError({ request, cause }),
|
|
67
|
+
}));
|
|
68
|
+
const memoMap = yield* Layer.makeMemoMap;
|
|
69
|
+
const layerManager = makeLayerManager(memoMap, rootScope, fiberId);
|
|
70
|
+
const layoutManager = makeLayoutManager(rootScope, fiberId);
|
|
71
|
+
const catchManager = makeCatchManager(rootScope, fiberId);
|
|
72
|
+
const prepared = yield* layerManager.prepare(entry.layers.concat(provided));
|
|
73
|
+
const guardExit = yield* entry
|
|
74
|
+
.guard(params)
|
|
75
|
+
.pipe(Effect.provideServices(prepared.services), Effect.exit);
|
|
76
|
+
if (Exit.isFailure(guardExit) || Option.isNone(guardExit.value)) {
|
|
77
|
+
yield* prepared.rollback;
|
|
78
|
+
return yield* new HttpServerError.HttpServerError({
|
|
79
|
+
reason: new HttpServerError.RouteNotFound({ request }),
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
const matchedParams = guardExit.value.value;
|
|
83
|
+
yield* prepared.commit;
|
|
84
|
+
const scope = yield* Scope.fork(rootScope);
|
|
85
|
+
const paramsRef = yield* RefSubject.make(matchedParams).pipe(Scope.provide(scope));
|
|
86
|
+
const preparedServices = prepared.services;
|
|
87
|
+
const handlerServices = ServiceMap.merge(ServiceMap.merge(currentServices, preparedServices), ServiceMap.make(Scope.Scope, scope));
|
|
88
|
+
const handlerFx = entry.handler(paramsRef);
|
|
89
|
+
const withLayouts = yield* layoutManager.apply(entry.layouts, matchedParams, handlerFx, preparedServices);
|
|
90
|
+
const withCatches = yield* catchManager.apply(entry.catches, withLayouts, preparedServices);
|
|
91
|
+
const html = yield* renderToHtmlString(withCatches).pipe(Effect.provideServices(handlerServices));
|
|
92
|
+
return HttpServerResponse.text(html, {
|
|
93
|
+
headers: { "content-type": "text/html; charset=utf-8" },
|
|
94
|
+
});
|
|
95
|
+
}),
|
|
96
|
+
uninterruptible: false,
|
|
97
|
+
prefix: undefined,
|
|
98
|
+
};
|
|
99
|
+
}
|
package/dist/Link.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import type { Scope } from "effect/Scope";
|
|
3
|
+
import type { Stream } from "effect/Stream";
|
|
4
|
+
import { type Fx } from "@typed/fx/Fx";
|
|
5
|
+
import { EventHandler, type Renderable, type RenderEvent, type RenderTemplate } from "@typed/template";
|
|
6
|
+
type EventHandlerProperty = `on${string}`;
|
|
7
|
+
type AnchorEventHandlers = {
|
|
8
|
+
readonly [K in keyof HTMLAnchorElement as K extends EventHandlerProperty ? K : never]?: Effect.Effect<unknown, any, any> | EventHandler.EventHandler<Event, any, any>;
|
|
9
|
+
};
|
|
10
|
+
type AnchorRef = {
|
|
11
|
+
readonly ref?: (element: HTMLAnchorElement) => void | Effect.Effect<unknown, any, any> | Stream<unknown, any, any> | Fx<unknown, any, any>;
|
|
12
|
+
};
|
|
13
|
+
type IfEquals<X, Y, Output> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? Output : never;
|
|
14
|
+
type WritableKeys<T> = {
|
|
15
|
+
[P in keyof T]-?: IfEquals<{
|
|
16
|
+
[Q in P]: T[P];
|
|
17
|
+
}, {
|
|
18
|
+
-readonly [Q in P]: T[P];
|
|
19
|
+
}, P>;
|
|
20
|
+
}[keyof T];
|
|
21
|
+
type AnchorProperties = {
|
|
22
|
+
readonly [K in WritableKeys<HTMLAnchorElement> as K extends EventHandlerProperty | "ref" ? never : K]?: Renderable<HTMLAnchorElement[K], any, any>;
|
|
23
|
+
};
|
|
24
|
+
export interface LinkOptions extends AnchorEventHandlers, AnchorRef, AnchorProperties {
|
|
25
|
+
readonly href: Renderable<string, any, any>;
|
|
26
|
+
readonly content: Renderable<string | number | boolean | null | undefined | void | RenderEvent, any, any>;
|
|
27
|
+
readonly replace?: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Renders an `<a href="...">` that intercepts same-origin, same-document clicks
|
|
31
|
+
* and navigates via `Navigation.navigate` instead of full page load. Requires
|
|
32
|
+
* `Navigation` and `RenderTemplate` in the Effect context (e.g. `BrowserRouter`).
|
|
33
|
+
*/
|
|
34
|
+
export declare function Link<const Opts extends LinkOptions>(options: Opts): Fx<RenderEvent, Renderable.ErrorFromObject<Opts>, Renderable.ServicesFromObject<Opts> | Scope | RenderTemplate>;
|
|
35
|
+
export {};
|
|
36
|
+
//# sourceMappingURL=Link.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Link.d.ts","sourceRoot":"","sources":["../src/Link.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,EAAO,MAAM,cAAc,CAAC;AAG5C,OAAO,EACL,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,cAAc,EAEpB,MAAM,iBAAiB,CAAC;AAEzB,KAAK,oBAAoB,GAAG,KAAK,MAAM,EAAE,CAAC;AAE1C,KAAK,mBAAmB,GAAG;IACzB,QAAQ,EAAE,CAAC,IAAI,MAAM,iBAAiB,IAAI,CAAC,SAAS,oBAAoB,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,EAClF,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,GAChC,YAAY,CAAC,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC;CAC/C,CAAC;AAEF,KAAK,SAAS,GAAG;IACf,QAAQ,CAAC,GAAG,CAAC,EAAE,CACb,OAAO,EAAE,iBAAiB,KACvB,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;CAClG,CAAC;AAEF,KAAK,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,IACxB,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,GAAG,KAAK,CAAC;AAEvF,KAAK,YAAY,CAAC,CAAC,IAAI;KACpB,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC;SAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;KAAE,EAAE;QAAE,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;KAAE,EAAE,CAAC,CAAC;CAChF,CAAC,MAAM,CAAC,CAAC,CAAC;AAEX,KAAK,gBAAgB,GAAG;IACtB,QAAQ,EAAE,CAAC,IAAI,YAAY,CAAC,iBAAiB,CAAC,IAAI,CAAC,SAAS,oBAAoB,GAAG,KAAK,GACpF,KAAK,GACL,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC;CACpD,CAAC;AAEF,MAAM,WAAW,WAAY,SAAQ,mBAAmB,EAAE,SAAS,EAAE,gBAAgB;IACnF,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IAC5C,QAAQ,CAAC,OAAO,EAAE,UAAU,CAC1B,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,GAAG,WAAW,EACjE,GAAG,EACH,GAAG,CACJ,CAAC;IACF,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAyBD;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,KAAK,CAAC,IAAI,SAAS,WAAW,EACjD,OAAO,EAAE,IAAI,GACZ,EAAE,CACH,WAAW,EACX,UAAU,CAAC,eAAe,CAAC,IAAI,CAAC,EAChC,UAAU,CAAC,kBAAkB,CAAC,IAAI,CAAC,GAAG,KAAK,GAAG,cAAc,CAC7D,CAqBA"}
|
package/dist/Link.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import { gen } from "@typed/fx/Fx";
|
|
3
|
+
import { RefSubject } from "@typed/fx/RefSubject";
|
|
4
|
+
import { getUrl, Navigation } from "@typed/navigation";
|
|
5
|
+
import { EventHandler, html, } from "@typed/template";
|
|
6
|
+
function makeLinkClickHandler(replace$) {
|
|
7
|
+
return EventHandler.make((ev) => Effect.gen(function* () {
|
|
8
|
+
const href = ev.currentTarget.href;
|
|
9
|
+
if (ev.ctrlKey || ev.metaKey || ev.shiftKey)
|
|
10
|
+
return;
|
|
11
|
+
const t = ev.currentTarget.target;
|
|
12
|
+
if (t && t !== "_self")
|
|
13
|
+
return;
|
|
14
|
+
const nav = yield* Navigation;
|
|
15
|
+
const target = getUrl(nav.origin, href);
|
|
16
|
+
if (target.origin !== nav.origin)
|
|
17
|
+
return;
|
|
18
|
+
ev.preventDefault();
|
|
19
|
+
const replace = yield* replace$;
|
|
20
|
+
yield* nav.navigate(href, { history: replace ? "replace" : "push" });
|
|
21
|
+
}));
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Renders an `<a href="...">` that intercepts same-origin, same-document clicks
|
|
25
|
+
* and navigates via `Navigation.navigate` instead of full page load. Requires
|
|
26
|
+
* `Navigation` and `RenderTemplate` in the Effect context (e.g. `BrowserRouter`).
|
|
27
|
+
*/
|
|
28
|
+
export function Link(options) {
|
|
29
|
+
return gen(function* () {
|
|
30
|
+
const { replace = false, onclick, content: children, ...rest } = options;
|
|
31
|
+
const replace$ = yield* RefSubject.make(replace);
|
|
32
|
+
const navigationHandler = makeLinkClickHandler(replace$);
|
|
33
|
+
const userHandler = onclick ? EventHandler.fromEffectOrEventHandler(onclick) : undefined;
|
|
34
|
+
const clickHandler = userHandler
|
|
35
|
+
? EventHandler.make(Effect.fn(function* (ev) {
|
|
36
|
+
yield* userHandler.handler(ev);
|
|
37
|
+
if (ev.defaultPrevented)
|
|
38
|
+
return;
|
|
39
|
+
yield* navigationHandler.handler(ev);
|
|
40
|
+
}), { ...userHandler.options, preventDefault: true })
|
|
41
|
+
: navigationHandler;
|
|
42
|
+
const props = { ...rest, onclick: clickHandler };
|
|
43
|
+
return html `<a ...${props}>${children}</a>`;
|
|
44
|
+
});
|
|
45
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC"}
|
package/dist/index.js
ADDED
package/package.json
CHANGED
|
@@ -1,89 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@typed/ui",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
|
|
6
|
-
"repository": {
|
|
7
|
-
"type": "git",
|
|
8
|
-
"url": "https://github.com/tylors/typed.git"
|
|
3
|
+
"version": "1.0.0-beta.0",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"access": "public"
|
|
9
6
|
},
|
|
10
|
-
"
|
|
11
|
-
"author": "Typed contributors",
|
|
12
|
-
"dependencies": {
|
|
13
|
-
"@effect/platform": "^0.57.4",
|
|
14
|
-
"@effect/schema": "^0.68.1",
|
|
15
|
-
"csstype": "^3.1.3",
|
|
16
|
-
"effect": "^3.3.5",
|
|
17
|
-
"@typed/context": "0.29.0",
|
|
18
|
-
"@typed/dom": "17.0.0",
|
|
19
|
-
"@typed/environment": "0.10.0",
|
|
20
|
-
"@typed/fx": "1.31.0",
|
|
21
|
-
"@typed/navigation": "0.17.0",
|
|
22
|
-
"@typed/route": "8.0.0",
|
|
23
|
-
"@typed/router": "0.31.0",
|
|
24
|
-
"@typed/template": "0.13.0"
|
|
25
|
-
},
|
|
26
|
-
"main": "./dist/cjs/index.js",
|
|
27
|
-
"module": "./dist/esm/index.js",
|
|
28
|
-
"types": "./dist/dts/index.d.ts",
|
|
7
|
+
"type": "module",
|
|
29
8
|
"exports": {
|
|
30
|
-
"./package.json": "./package.json",
|
|
31
9
|
".": {
|
|
32
|
-
"types": "./dist/
|
|
33
|
-
"import": "./dist/
|
|
34
|
-
"default": "./dist/cjs/index.js"
|
|
35
|
-
},
|
|
36
|
-
"./Link": {
|
|
37
|
-
"types": "./dist/dts/Link.d.ts",
|
|
38
|
-
"import": "./dist/esm/Link.js",
|
|
39
|
-
"default": "./dist/cjs/Link.js"
|
|
40
|
-
},
|
|
41
|
-
"./Props": {
|
|
42
|
-
"types": "./dist/dts/Props.d.ts",
|
|
43
|
-
"import": "./dist/esm/Props.js",
|
|
44
|
-
"default": "./dist/cjs/Props.js"
|
|
45
|
-
},
|
|
46
|
-
"./dom-properties": {
|
|
47
|
-
"types": "./dist/dts/dom-properties.d.ts",
|
|
48
|
-
"import": "./dist/esm/dom-properties.js",
|
|
49
|
-
"default": "./dist/cjs/dom-properties.js"
|
|
50
|
-
},
|
|
51
|
-
"./hyperscript": {
|
|
52
|
-
"types": "./dist/dts/hyperscript.d.ts",
|
|
53
|
-
"import": "./dist/esm/hyperscript.js",
|
|
54
|
-
"default": "./dist/cjs/hyperscript.js"
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
55
12
|
},
|
|
56
|
-
"
|
|
57
|
-
"types": "./dist
|
|
58
|
-
"import": "./dist
|
|
59
|
-
"default": "./dist/cjs/useClickAway.js"
|
|
60
|
-
},
|
|
61
|
-
"./usePagination": {
|
|
62
|
-
"types": "./dist/dts/usePagination.d.ts",
|
|
63
|
-
"import": "./dist/esm/usePagination.js",
|
|
64
|
-
"default": "./dist/cjs/usePagination.js"
|
|
13
|
+
"./*": {
|
|
14
|
+
"types": "./dist/*.d.ts",
|
|
15
|
+
"import": "./dist/*.js"
|
|
65
16
|
}
|
|
66
17
|
},
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
],
|
|
84
|
-
"usePagination": [
|
|
85
|
-
"./dist/dts/usePagination.d.ts"
|
|
86
|
-
]
|
|
87
|
-
}
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@effect/platform-node": "4.0.0-beta.4",
|
|
20
|
+
"effect": "4.0.0-beta.4",
|
|
21
|
+
"happy-dom": "*",
|
|
22
|
+
"@typed/fx": "2.0.0-beta.0",
|
|
23
|
+
"@typed/navigation": "1.0.0-beta.0",
|
|
24
|
+
"@typed/template": "1.0.0-beta.0",
|
|
25
|
+
"@typed/router": "1.0.0-beta.0"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"typescript": "5.9.3",
|
|
29
|
+
"vitest": "4.0.18"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsc",
|
|
33
|
+
"test": "vitest run --passWithNoTests"
|
|
88
34
|
}
|
|
89
35
|
}
|