@zenithbuild/router 0.6.13 → 0.7.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 +13 -129
- package/dist/ZenLink.zen +66 -3
- package/dist/events.d.ts +7 -3
- package/dist/events.js +62 -3
- package/index.d.ts +47 -5
- package/package.json +5 -1
- package/template-core.js +422 -0
- package/template-lifecycle.js +127 -0
- package/template-navigation.js +468 -0
- package/template.js +5 -412
package/README.md
CHANGED
|
@@ -1,136 +1,20 @@
|
|
|
1
1
|
# @zenith/router
|
|
2
2
|
|
|
3
|
-
>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
File-based SPA router for Zenith framework with **deterministic, compile-time route resolution**.
|
|
3
|
+
> Internal Zenith package. The generated router runtime is the authoritative surface here, not a general SPA framework API.
|
|
7
4
|
|
|
8
5
|
## Canonical Docs
|
|
9
6
|
|
|
10
|
-
- Routing
|
|
11
|
-
- Navigation
|
|
12
|
-
- Router
|
|
13
|
-
|
|
14
|
-
## Features
|
|
15
|
-
|
|
16
|
-
- 📁 **File-based routing** — Pages in `pages/` directory become routes automatically
|
|
17
|
-
- ⚡ **Compile-time resolution** — Route manifest generated at build time, not runtime
|
|
18
|
-
- 🔗 **ZenLink component** — Declarative navigation with prefetching
|
|
19
|
-
- 🧭 **Programmatic navigation** — `navigate()`, `prefetch()`, `isActive()` APIs
|
|
20
|
-
- 🎯 **Type-safe** — Full TypeScript support with route parameter inference
|
|
21
|
-
- 🚀 **Hydration-safe** — No runtime hacks, works seamlessly with SSR/SSG
|
|
22
|
-
|
|
23
|
-
## Installation
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
bun add @zenith/router
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
## Usage
|
|
30
|
-
|
|
31
|
-
### Programmatic Navigation
|
|
32
|
-
|
|
33
|
-
```ts
|
|
34
|
-
import { navigate, prefetch, isActive, getRoute } from '@zenith/router'
|
|
35
|
-
|
|
36
|
-
// Navigate to a route
|
|
37
|
-
navigate('/about')
|
|
38
|
-
|
|
39
|
-
// Navigate with replace (no history entry)
|
|
40
|
-
navigate('/dashboard', { replace: true })
|
|
41
|
-
|
|
42
|
-
// Prefetch a route for faster navigation
|
|
43
|
-
prefetch('/blog')
|
|
44
|
-
|
|
45
|
-
// Check if a route is active
|
|
46
|
-
if (isActive('/blog')) {
|
|
47
|
-
console.log('Currently on blog section')
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Get current route state
|
|
51
|
-
const { path, params, query } = getRoute()
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
### ZenLink Component (in .zen files)
|
|
55
|
-
|
|
56
|
-
```html
|
|
57
|
-
<ZenLink href="/about">About Us</ZenLink>
|
|
58
|
-
|
|
59
|
-
<!-- With prefetching on hover -->
|
|
60
|
-
<ZenLink href="/blog" preload>Blog</ZenLink>
|
|
61
|
-
|
|
62
|
-
<!-- External links automatically open in new tab -->
|
|
63
|
-
<ZenLink href="https://github.com">GitHub</ZenLink>
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
### Build-time Route Manifest
|
|
67
|
-
|
|
68
|
-
The router generates a route manifest at compile time:
|
|
69
|
-
|
|
70
|
-
```ts
|
|
71
|
-
import { generateRouteManifest, discoverPages } from '@zenith/router/manifest'
|
|
72
|
-
|
|
73
|
-
const pagesDir = './src/pages'
|
|
74
|
-
const manifest = generateRouteManifest(pagesDir)
|
|
75
|
-
|
|
76
|
-
// manifest contains:
|
|
77
|
-
// - path: Route pattern (e.g., /blog/:id)
|
|
78
|
-
// - regex: Compiled RegExp for matching
|
|
79
|
-
// - paramNames: Dynamic segment names
|
|
80
|
-
// - score: Priority for deterministic matching
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
## Route Patterns
|
|
84
|
-
|
|
85
|
-
| File Path | Route Pattern |
|
|
86
|
-
|-----------|---------------|
|
|
87
|
-
| `pages/index.zen` | `/` |
|
|
88
|
-
| `pages/about.zen` | `/about` |
|
|
89
|
-
| `pages/blog/index.zen` | `/blog` |
|
|
90
|
-
| `pages/blog/[id].zen` | `/blog/:id` |
|
|
91
|
-
| `pages/posts/[...slug].zen` | `/posts/*slug` |
|
|
92
|
-
| `pages/[[...all]].zen` | `/*all?` (optional) |
|
|
93
|
-
|
|
94
|
-
## Architecture
|
|
95
|
-
|
|
96
|
-
```
|
|
97
|
-
@zenith/router
|
|
98
|
-
├── src/
|
|
99
|
-
│ ├── index.ts # Main exports
|
|
100
|
-
│ ├── types.ts # Core types
|
|
101
|
-
│ ├── manifest.ts # Build-time manifest generation
|
|
102
|
-
│ ├── runtime.ts # Client-side SPA router
|
|
103
|
-
│ └── navigation/
|
|
104
|
-
│ ├── index.ts # Navigation exports
|
|
105
|
-
│ ├── zen-link.ts # Navigation API
|
|
106
|
-
│ └── ZenLink.zen # Declarative component
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
## API Reference
|
|
110
|
-
|
|
111
|
-
### Navigation Functions
|
|
112
|
-
|
|
113
|
-
- `navigate(path, options?)` — Navigate to a path
|
|
114
|
-
- `prefetch(path)` — Prefetch a route for faster navigation
|
|
115
|
-
- `isActive(path, exact?)` — Check if path is currently active
|
|
116
|
-
- `getRoute()` — Get current route state
|
|
117
|
-
- `back()`, `forward()`, `go(delta)` — History navigation
|
|
118
|
-
|
|
119
|
-
### Manifest Generation
|
|
120
|
-
|
|
121
|
-
- `discoverPages(pagesDir)` — Find all .zen files in pages directory
|
|
122
|
-
- `generateRouteManifest(pagesDir)` — Generate complete route manifest
|
|
123
|
-
- `filePathToRoutePath(filePath, pagesDir)` — Convert file path to route
|
|
124
|
-
- `routePathToRegex(routePath)` — Compile route to RegExp
|
|
125
|
-
|
|
126
|
-
### Types
|
|
127
|
-
|
|
128
|
-
- `RouteState` — Current route state (path, params, query)
|
|
129
|
-
- `RouteRecord` — Compiled route definition
|
|
130
|
-
- `NavigateOptions` — Options for navigation
|
|
131
|
-
- `ZenLinkProps` — Props for ZenLink component
|
|
7
|
+
- [Routing Contract](../../docs/documentation/contracts/routing.md)
|
|
8
|
+
- [Navigation Contract](../../docs/documentation/contracts/navigation.md)
|
|
9
|
+
- [Router Contract](../../docs/documentation/contracts/router-contract.md)
|
|
10
|
+
- [Navigation Lifecycle Contract](../../docs/documentation/contracts/navigation-lifecycle.md)
|
|
132
11
|
|
|
133
|
-
##
|
|
12
|
+
## Phase 2 Runtime Summary
|
|
134
13
|
|
|
135
|
-
|
|
136
|
-
|
|
14
|
+
- Plain anchors hard navigate by default.
|
|
15
|
+
- Soft navigation is opt-in only through `a[data-zen-link]`.
|
|
16
|
+
- `ZenLink` is a thin anchor wrapper over the same marker contract.
|
|
17
|
+
- Soft navigation fetches fresh same-origin HTML before committing history.
|
|
18
|
+
- Redirects, denies, unmatched routes, non-HTML responses, and runtime failures fall back to browser navigation.
|
|
19
|
+
- Client routing mirrors server route precedence and pathname-based identity.
|
|
20
|
+
- Phase 2 adds awaited lifecycle barriers at `navigation:before-leave`, `navigation:before-swap`, and `navigation:before-enter`.
|
package/dist/ZenLink.zen
CHANGED
|
@@ -1,7 +1,70 @@
|
|
|
1
|
-
<script
|
|
2
|
-
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export interface Props {
|
|
3
|
+
href?: string;
|
|
4
|
+
class?: string;
|
|
5
|
+
target?: string;
|
|
6
|
+
rel?: string;
|
|
7
|
+
id?: string;
|
|
8
|
+
title?: string;
|
|
9
|
+
ariaLabel?: string;
|
|
10
|
+
ariaCurrent?: string;
|
|
11
|
+
ariaDisabled?: string;
|
|
12
|
+
elementRef?: any;
|
|
13
|
+
onClick?: (event: MouseEvent) => void;
|
|
14
|
+
onHoverIn?: (event: PointerEvent) => void;
|
|
15
|
+
onHoverOut?: (event: PointerEvent) => void;
|
|
16
|
+
onFocus?: (event: FocusEvent) => void;
|
|
17
|
+
onBlur?: (event: FocusEvent) => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const zenLinkProps = props as Props;
|
|
21
|
+
const zenLinkHref = typeof zenLinkProps.href === "string" ? zenLinkProps.href : "";
|
|
22
|
+
const zenLinkClass = typeof zenLinkProps.class === "string" ? zenLinkProps.class : "";
|
|
23
|
+
const zenLinkTarget = typeof zenLinkProps.target === "string" ? zenLinkProps.target : "";
|
|
24
|
+
const zenLinkRel = typeof zenLinkProps.rel === "string" ? zenLinkProps.rel : "";
|
|
25
|
+
const zenLinkId = typeof zenLinkProps.id === "string" ? zenLinkProps.id : "";
|
|
26
|
+
const zenLinkTitle = typeof zenLinkProps.title === "string" ? zenLinkProps.title : "";
|
|
27
|
+
const zenLinkAriaLabel = typeof zenLinkProps.ariaLabel === "string" ? zenLinkProps.ariaLabel : "";
|
|
28
|
+
const zenLinkAriaCurrent = typeof zenLinkProps.ariaCurrent === "string" ? zenLinkProps.ariaCurrent : "";
|
|
29
|
+
const zenLinkAriaDisabled = typeof zenLinkProps.ariaDisabled === "string" ? zenLinkProps.ariaDisabled : "";
|
|
30
|
+
const zenLinkElementRef = zenLinkProps.elementRef;
|
|
31
|
+
const zenLinkRef = ref<HTMLAnchorElement>();
|
|
32
|
+
const zenLinkClick = typeof zenLinkProps.onClick === "function" ? zenLinkProps.onClick : undefined;
|
|
33
|
+
const zenLinkHoverIn = typeof zenLinkProps.onHoverIn === "function" ? zenLinkProps.onHoverIn : undefined;
|
|
34
|
+
const zenLinkHoverOut = typeof zenLinkProps.onHoverOut === "function" ? zenLinkProps.onHoverOut : undefined;
|
|
35
|
+
const zenLinkFocus = typeof zenLinkProps.onFocus === "function" ? zenLinkProps.onFocus : undefined;
|
|
36
|
+
const zenLinkBlur = typeof zenLinkProps.onBlur === "function" ? zenLinkProps.onBlur : undefined;
|
|
37
|
+
|
|
38
|
+
zenMount((ctx) => {
|
|
39
|
+
if (zenLinkElementRef) {
|
|
40
|
+
zenLinkElementRef.current = zenLinkRef.current;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
ctx.cleanup(() => {
|
|
44
|
+
if (zenLinkElementRef) {
|
|
45
|
+
zenLinkElementRef.current = null;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
});
|
|
3
49
|
</script>
|
|
4
50
|
|
|
5
|
-
<a
|
|
51
|
+
<a
|
|
52
|
+
ref={zenLinkRef}
|
|
53
|
+
data-zen-link="true"
|
|
54
|
+
href={zenLinkHref || undefined}
|
|
55
|
+
class={zenLinkClass || undefined}
|
|
56
|
+
target={zenLinkTarget || undefined}
|
|
57
|
+
rel={zenLinkRel || undefined}
|
|
58
|
+
id={zenLinkId || undefined}
|
|
59
|
+
title={zenLinkTitle || undefined}
|
|
60
|
+
aria-label={zenLinkAriaLabel || undefined}
|
|
61
|
+
aria-current={zenLinkAriaCurrent || undefined}
|
|
62
|
+
aria-disabled={zenLinkAriaDisabled || undefined}
|
|
63
|
+
on:click={zenLinkClick}
|
|
64
|
+
on:hoverin={zenLinkHoverIn}
|
|
65
|
+
on:hoverout={zenLinkHoverOut}
|
|
66
|
+
on:focus={zenLinkFocus}
|
|
67
|
+
on:blur={zenLinkBlur}
|
|
68
|
+
>
|
|
6
69
|
<slot></slot>
|
|
7
70
|
</a>
|
package/dist/events.d.ts
CHANGED
|
@@ -5,10 +5,12 @@ type RouteChangeDetail = {
|
|
|
5
5
|
matched: boolean;
|
|
6
6
|
};
|
|
7
7
|
type RouteProtectionPolicy = {
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
onDeny?: 'stay' | 'redirect' | 'render403' | ((ctx: any) => void);
|
|
9
|
+
defaultLoginPath?: string;
|
|
10
|
+
deny401RedirectToLogin?: boolean;
|
|
11
|
+
forbiddenPath?: string;
|
|
10
12
|
};
|
|
11
|
-
type RouteEventHandler = (payload: unknown) => void
|
|
13
|
+
type RouteEventHandler = (payload: unknown) => void | Promise<void>;
|
|
12
14
|
export declare function onRouteChange(callback: (detail: RouteChangeDetail) => void): () => void;
|
|
13
15
|
export declare function _dispatchRouteChange(detail: RouteChangeDetail): void;
|
|
14
16
|
export declare function _clearSubscribers(): void;
|
|
@@ -18,4 +20,6 @@ export declare function _getRouteProtectionPolicy(): RouteProtectionPolicy;
|
|
|
18
20
|
export declare function on(eventName: string, handler: RouteEventHandler): void;
|
|
19
21
|
export declare function off(eventName: string, handler: RouteEventHandler): void;
|
|
20
22
|
export declare function _dispatchRouteEvent(eventName: string, payload: unknown): void;
|
|
23
|
+
export declare function _dispatchRouteEventAsync(eventName: string, payload: unknown): Promise<void>;
|
|
24
|
+
export declare function _clearRouteEventListeners(): void;
|
|
21
25
|
export {};
|
package/dist/events.js
CHANGED
|
@@ -34,7 +34,17 @@ const ROUTE_EVENT_NAMES = [
|
|
|
34
34
|
'route-check:end',
|
|
35
35
|
'route-check:error',
|
|
36
36
|
'route:deny',
|
|
37
|
-
'route:redirect'
|
|
37
|
+
'route:redirect',
|
|
38
|
+
'navigation:request',
|
|
39
|
+
'navigation:before-leave',
|
|
40
|
+
'navigation:leave-complete',
|
|
41
|
+
'navigation:data-ready',
|
|
42
|
+
'navigation:before-swap',
|
|
43
|
+
'navigation:content-swapped',
|
|
44
|
+
'navigation:before-enter',
|
|
45
|
+
'navigation:enter-complete',
|
|
46
|
+
'navigation:abort',
|
|
47
|
+
'navigation:error'
|
|
38
48
|
];
|
|
39
49
|
function getRouteProtectionScope() {
|
|
40
50
|
return typeof globalThis === 'object' && globalThis
|
|
@@ -80,6 +90,27 @@ export function off(eventName, handler) {
|
|
|
80
90
|
eventListeners.delete(handler);
|
|
81
91
|
}
|
|
82
92
|
}
|
|
93
|
+
function dispatchRouteEventError(eventName, payload, error) {
|
|
94
|
+
console.error(`[Zenith Router] Error in ${eventName} listener:`, error);
|
|
95
|
+
if (eventName === 'navigation:error' ||
|
|
96
|
+
!payload ||
|
|
97
|
+
typeof payload !== 'object' ||
|
|
98
|
+
typeof payload.navigationId !== 'number') {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
_dispatchRouteEvent('navigation:error', {
|
|
102
|
+
navigationId: payload.navigationId,
|
|
103
|
+
navigationType: payload.navigationType,
|
|
104
|
+
to: payload.to,
|
|
105
|
+
from: payload.from,
|
|
106
|
+
routeId: payload.routeId,
|
|
107
|
+
params: payload.params,
|
|
108
|
+
stage: payload.stage ?? 'listener',
|
|
109
|
+
reason: 'listener-error',
|
|
110
|
+
hook: eventName,
|
|
111
|
+
error
|
|
112
|
+
});
|
|
113
|
+
}
|
|
83
114
|
export function _dispatchRouteEvent(eventName, payload) {
|
|
84
115
|
const eventListeners = ensureRouteProtectionState().listeners[eventName];
|
|
85
116
|
if (!(eventListeners instanceof Set)) {
|
|
@@ -87,10 +118,38 @@ export function _dispatchRouteEvent(eventName, payload) {
|
|
|
87
118
|
}
|
|
88
119
|
for (const handler of eventListeners) {
|
|
89
120
|
try {
|
|
90
|
-
handler(payload);
|
|
121
|
+
const result = handler(payload);
|
|
122
|
+
if (result && typeof result.catch === 'function') {
|
|
123
|
+
result.catch((error) => {
|
|
124
|
+
dispatchRouteEventError(eventName, payload, error);
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
dispatchRouteEventError(eventName, payload, error);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
export async function _dispatchRouteEventAsync(eventName, payload) {
|
|
134
|
+
const eventListeners = ensureRouteProtectionState().listeners[eventName];
|
|
135
|
+
if (!(eventListeners instanceof Set)) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const handlers = Array.from(eventListeners);
|
|
139
|
+
for (const handler of handlers) {
|
|
140
|
+
try {
|
|
141
|
+
await handler(payload);
|
|
91
142
|
}
|
|
92
143
|
catch (error) {
|
|
93
|
-
|
|
144
|
+
dispatchRouteEventError(eventName, payload, error);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
export function _clearRouteEventListeners() {
|
|
149
|
+
const listeners = ensureRouteProtectionState().listeners;
|
|
150
|
+
for (const eventName of Object.keys(listeners)) {
|
|
151
|
+
if (listeners[eventName] instanceof Set) {
|
|
152
|
+
listeners[eventName].clear();
|
|
94
153
|
}
|
|
95
154
|
}
|
|
96
155
|
}
|
package/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export type RouteResult =
|
|
2
2
|
| { kind: "allow" }
|
|
3
3
|
| { kind: "redirect"; location: string; status?: number }
|
|
4
|
-
| { kind: "deny"; status: 401 | 403 |
|
|
4
|
+
| { kind: "deny"; status: 401 | 403 | 404; message?: string }
|
|
5
5
|
| { kind: "data"; data: any };
|
|
6
6
|
|
|
7
7
|
export type GuardResult = Extract<RouteResult, { kind: "allow" | "redirect" | "deny" }>;
|
|
@@ -22,7 +22,7 @@ export interface RouteContext {
|
|
|
22
22
|
};
|
|
23
23
|
allow(): { kind: "allow" };
|
|
24
24
|
redirect(location: string, status?: number): { kind: "redirect"; location: string; status: number };
|
|
25
|
-
deny(status: 401 | 403 |
|
|
25
|
+
deny(status: 401 | 403 | 404, message?: string): { kind: "deny"; status: 401 | 403 | 404; message?: string };
|
|
26
26
|
data(payload: any): { kind: "data"; data: any };
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -41,6 +41,38 @@ export interface RouteProtectionPolicy {
|
|
|
41
41
|
forbiddenPath?: string;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
export type NavigationType = "push" | "pop";
|
|
45
|
+
|
|
46
|
+
export interface NavigationLifecyclePayload {
|
|
47
|
+
navigationId: number;
|
|
48
|
+
navigationType: NavigationType;
|
|
49
|
+
to: URL | null;
|
|
50
|
+
from: URL | null;
|
|
51
|
+
routeId: string;
|
|
52
|
+
params: Record<string, string>;
|
|
53
|
+
stage: string;
|
|
54
|
+
document?: {
|
|
55
|
+
title: string;
|
|
56
|
+
hasSsrData: boolean;
|
|
57
|
+
status: number;
|
|
58
|
+
};
|
|
59
|
+
scroll?: {
|
|
60
|
+
mode: "top" | "restore" | "hash";
|
|
61
|
+
x: number;
|
|
62
|
+
y: number;
|
|
63
|
+
hash: string;
|
|
64
|
+
};
|
|
65
|
+
reason?: string;
|
|
66
|
+
hook?: string;
|
|
67
|
+
location?: string;
|
|
68
|
+
status?: number;
|
|
69
|
+
historyCommitted?: boolean;
|
|
70
|
+
error?: unknown;
|
|
71
|
+
[key: string]: unknown;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export type RouteEventHandler = (payload: unknown) => void | Promise<void>;
|
|
75
|
+
|
|
44
76
|
export type RouteEventName =
|
|
45
77
|
| "guard:start"
|
|
46
78
|
| "guard:end"
|
|
@@ -48,8 +80,18 @@ export type RouteEventName =
|
|
|
48
80
|
| "route-check:end"
|
|
49
81
|
| "route-check:error"
|
|
50
82
|
| "route:deny"
|
|
51
|
-
| "route:redirect"
|
|
83
|
+
| "route:redirect"
|
|
84
|
+
| "navigation:request"
|
|
85
|
+
| "navigation:before-leave"
|
|
86
|
+
| "navigation:leave-complete"
|
|
87
|
+
| "navigation:data-ready"
|
|
88
|
+
| "navigation:before-swap"
|
|
89
|
+
| "navigation:content-swapped"
|
|
90
|
+
| "navigation:before-enter"
|
|
91
|
+
| "navigation:enter-complete"
|
|
92
|
+
| "navigation:abort"
|
|
93
|
+
| "navigation:error";
|
|
52
94
|
|
|
53
95
|
export declare function setRouteProtectionPolicy(policy: RouteProtectionPolicy): void;
|
|
54
|
-
export declare function on(eventName: RouteEventName, handler:
|
|
55
|
-
export declare function off(eventName: RouteEventName, handler:
|
|
96
|
+
export declare function on(eventName: RouteEventName, handler: RouteEventHandler): void;
|
|
97
|
+
export declare function off(eventName: RouteEventName, handler: RouteEventHandler): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zenithbuild/router",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "File-based SPA router for Zenith framework with deterministic, compile-time route resolution",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -8,6 +8,9 @@
|
|
|
8
8
|
"files": [
|
|
9
9
|
"dist",
|
|
10
10
|
"template.js",
|
|
11
|
+
"template-core.js",
|
|
12
|
+
"template-lifecycle.js",
|
|
13
|
+
"template-navigation.js",
|
|
11
14
|
"index.js",
|
|
12
15
|
"index.d.ts",
|
|
13
16
|
"README.md",
|
|
@@ -18,6 +21,7 @@
|
|
|
18
21
|
"exports": {
|
|
19
22
|
".": "./dist/index.js",
|
|
20
23
|
"./template": "./template.js",
|
|
24
|
+
"./events": "./dist/events.js",
|
|
21
25
|
"./ZenLink.zen": "./dist/ZenLink.zen"
|
|
22
26
|
},
|
|
23
27
|
"keywords": [
|