vite-plugin-vanjs 0.1.14 → 0.1.16
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/client/index.mjs +3 -77
- package/meta/helpers.mjs +1 -0
- package/meta/tags.mjs +6 -22
- package/meta/types.d.ts +6 -1
- package/package.json +9 -9
- package/plugin/helpers.mjs +1 -0
- package/router/global.d.ts +8 -3
- package/router/helpers.mjs +1 -1
- package/router/router.mjs +103 -121
- package/router/state.mjs +71 -8
- package/router/types.d.ts +5 -4
package/client/index.mjs
CHANGED
|
@@ -133,13 +133,6 @@ export function elementsMatch(el1, el2, deep) {
|
|
|
133
133
|
: true;
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
/** @type {<E extends Element = Element, T extends keyof HTMLElementTagNameMap>(target: E, ...tagNames: T[]) => boolean} */
|
|
137
|
-
const isTag = (target, ...tagNames) => {
|
|
138
|
-
return tagNames.some((tag) =>
|
|
139
|
-
target.tagName.toLowerCase() === tag.toLowerCase()
|
|
140
|
-
);
|
|
141
|
-
};
|
|
142
|
-
|
|
143
136
|
function createHydrationContext() {
|
|
144
137
|
/** @type {WeakMap<Element, Element>} */
|
|
145
138
|
const parentCache = new WeakMap();
|
|
@@ -250,31 +243,15 @@ export const hydrate = (target, content) => {
|
|
|
250
243
|
const currentChildren = Array.from(target.children);
|
|
251
244
|
const newChildren = Array.from(wrapper.children);
|
|
252
245
|
|
|
253
|
-
if (
|
|
246
|
+
if (target.tagName.toLowerCase() === "head") {
|
|
254
247
|
// Keep current tags on first hydration
|
|
255
248
|
if (!target.hasAttribute("data-h")) {
|
|
256
249
|
target.setAttribute("data-h", "");
|
|
257
250
|
return target;
|
|
258
251
|
}
|
|
259
252
|
|
|
260
|
-
//
|
|
261
|
-
|
|
262
|
-
!isTag(child, "style", "link")
|
|
263
|
-
);
|
|
264
|
-
|
|
265
|
-
// Handle style/link tags separately
|
|
266
|
-
const styleTags = newChildren.filter((child) =>
|
|
267
|
-
isTag(child, "style", "link")
|
|
268
|
-
);
|
|
269
|
-
|
|
270
|
-
// Create maps for existing tags
|
|
271
|
-
const existingStyles = new Map(
|
|
272
|
-
currentChildren.filter((child) => isTag(child, "style", "link"))
|
|
273
|
-
.map((child) => [getTagKey(child), child]),
|
|
274
|
-
);
|
|
275
|
-
|
|
276
|
-
// Process regular tags normally
|
|
277
|
-
regularTags.forEach((newChild) => {
|
|
253
|
+
// Replace all tags uniformly - styles/scripts are handled via imports
|
|
254
|
+
newChildren.forEach((newChild) => {
|
|
278
255
|
const key = getTagKey(newChild);
|
|
279
256
|
const existing = currentChildren.find((child) =>
|
|
280
257
|
getTagKey(child) === key
|
|
@@ -285,57 +262,6 @@ export const hydrate = (target, content) => {
|
|
|
285
262
|
target.appendChild(newChild);
|
|
286
263
|
}
|
|
287
264
|
});
|
|
288
|
-
|
|
289
|
-
// Process style tags with special handling
|
|
290
|
-
styleTags.forEach((newChild) => {
|
|
291
|
-
const key = getTagKey(newChild);
|
|
292
|
-
const existing = existingStyles.get(key);
|
|
293
|
-
|
|
294
|
-
// Skip if tag already exists with same content+id/href
|
|
295
|
-
if (existing) {
|
|
296
|
-
// istanbul ignore next - try again later
|
|
297
|
-
if (isTag(existing, "style") && isTag(newChild, "style")) {
|
|
298
|
-
if (
|
|
299
|
-
existing.textContent === newChild.textContent &&
|
|
300
|
-
existing.id === newChild.id
|
|
301
|
-
) return;
|
|
302
|
-
}
|
|
303
|
-
// istanbul ignore next - try again later
|
|
304
|
-
if (isTag(existing, "link") && isTag(newChild, "link")) {
|
|
305
|
-
if (existing.href === newChild.href) return;
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
// For link tags, add with disabled state first
|
|
310
|
-
// istanbul ignore else - try again later
|
|
311
|
-
if (isTag(newChild, "link")) {
|
|
312
|
-
const temp = newChild.cloneNode();
|
|
313
|
-
temp.disabled = true;
|
|
314
|
-
|
|
315
|
-
const originalRel = temp.rel;
|
|
316
|
-
temp.rel = "preload";
|
|
317
|
-
temp.as = "style";
|
|
318
|
-
// istanbul ignore next
|
|
319
|
-
temp.onload = () => {
|
|
320
|
-
temp.rel = originalRel;
|
|
321
|
-
temp.removeAttribute("as");
|
|
322
|
-
temp.disabled = false;
|
|
323
|
-
if (existing && existing.parentNode === target) {
|
|
324
|
-
existing.remove();
|
|
325
|
-
}
|
|
326
|
-
};
|
|
327
|
-
|
|
328
|
-
target.appendChild(temp);
|
|
329
|
-
} // For style tags, add new one first
|
|
330
|
-
else if (isTag(newChild, "style")) {
|
|
331
|
-
target.appendChild(newChild);
|
|
332
|
-
// istanbul ignore next - try again later
|
|
333
|
-
if (existing && existing.parentNode === target) {
|
|
334
|
-
// Remove old one in next frame
|
|
335
|
-
existing.remove();
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
});
|
|
339
265
|
} else {
|
|
340
266
|
if (!target.hasAttribute("data-h")) {
|
|
341
267
|
const { diffAndHydrate } = createHydrationContext();
|
package/meta/helpers.mjs
CHANGED
package/meta/tags.mjs
CHANGED
|
@@ -25,31 +25,15 @@ export const Meta = (props) => {
|
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
* Add a new `<link>` tag
|
|
28
|
+
* Add a new `<link>` tag, not to be used for stylesheets
|
|
29
29
|
* @type {(props: PropsWithKnownKeys<HTMLLinkElement>) => null}
|
|
30
30
|
*/
|
|
31
31
|
export const Link = (props) => {
|
|
32
32
|
const { link } = van.tags;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
* Add a new `<script>` tag
|
|
39
|
-
* @type {(props: PropsWithKnownKeys<HTMLScriptElement>, content?: string) => null}
|
|
40
|
-
*/
|
|
41
|
-
export const Script = (props, content) => {
|
|
42
|
-
const { script } = van.tags;
|
|
43
|
-
addMeta(script(props, content));
|
|
44
|
-
return null;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Add a new `<style>` tag
|
|
49
|
-
* @type {(props: PropsWithKnownKeys<HTMLStyleElement>, content: string) => null}
|
|
50
|
-
*/
|
|
51
|
-
export const Style = (props, content) => {
|
|
52
|
-
const { style } = van.tags;
|
|
53
|
-
addMeta(style(props, content));
|
|
33
|
+
if (props.rel === "stylesheet") {
|
|
34
|
+
console.warn("Link doesn't support stylesheets.");
|
|
35
|
+
} else {
|
|
36
|
+
addMeta(link(props));
|
|
37
|
+
}
|
|
54
38
|
return null;
|
|
55
39
|
};
|
package/meta/types.d.ts
CHANGED
|
@@ -13,6 +13,11 @@ export const resetHeadTags: () => void;
|
|
|
13
13
|
export const initializeHeadTags: () => void | (() => Promise<void>);
|
|
14
14
|
|
|
15
15
|
export type SupportedTags =
|
|
16
|
+
| HTMLTitleElement
|
|
17
|
+
| HTMLLinkElement
|
|
18
|
+
| HTMLMetaElement;
|
|
19
|
+
|
|
20
|
+
export type AllHeadTags =
|
|
16
21
|
| HTMLTitleElement
|
|
17
22
|
| HTMLMetaElement
|
|
18
23
|
| HTMLScriptElement
|
|
@@ -21,7 +26,7 @@ export type SupportedTags =
|
|
|
21
26
|
|
|
22
27
|
export type TagProps = SupportedTags | PropsWithKnownKeys<SupportedTags>;
|
|
23
28
|
|
|
24
|
-
export type HeadTags =
|
|
29
|
+
export type HeadTags = AllHeadTags[] | TagFunc[];
|
|
25
30
|
|
|
26
31
|
export const addMeta = (_tag: string | TagProps) => null;
|
|
27
32
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-vanjs",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"author": "thednp",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "A mini meta-framework for VanJS powered by Vite",
|
|
@@ -87,14 +87,14 @@
|
|
|
87
87
|
"vanjs-ext": "^0.6.3"
|
|
88
88
|
},
|
|
89
89
|
"devDependencies": {
|
|
90
|
-
"@types/node": "^25.
|
|
91
|
-
"@vitest/browser": "^4.1.
|
|
92
|
-
"@vitest/coverage-istanbul": "^4.1.
|
|
93
|
-
"@vitest/ui": "^4.1.
|
|
94
|
-
"happy-dom": "^20.
|
|
95
|
-
"typescript": "6.0.
|
|
96
|
-
"vite": "^8.0.
|
|
97
|
-
"vitest": "^4.1.
|
|
90
|
+
"@types/node": "^25.6.0",
|
|
91
|
+
"@vitest/browser": "^4.1.5",
|
|
92
|
+
"@vitest/coverage-istanbul": "^4.1.5",
|
|
93
|
+
"@vitest/ui": "^4.1.5",
|
|
94
|
+
"happy-dom": "^20.9.0",
|
|
95
|
+
"typescript": "6.0.3",
|
|
96
|
+
"vite": "^8.0.9",
|
|
97
|
+
"vitest": "^4.1.5"
|
|
98
98
|
},
|
|
99
99
|
"engines": {
|
|
100
100
|
"node": ">=20",
|
package/plugin/helpers.mjs
CHANGED
|
@@ -48,6 +48,7 @@ export const globFiles = async (dir, extensions) => {
|
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
50
50
|
const entries = await readdir(directory, { withFileTypes: true });
|
|
51
|
+
// istanbul ignore if
|
|
51
52
|
if (!entries.length) {
|
|
52
53
|
// console.warn('🍦 @vanjs/router: the "routes" folder is empty.');
|
|
53
54
|
return;
|
package/router/global.d.ts
CHANGED
|
@@ -185,10 +185,15 @@ declare module "@vanjs/router" {
|
|
|
185
185
|
* A reactive object that holds the current router state.
|
|
186
186
|
* This state is maintained by both server and client.
|
|
187
187
|
*/
|
|
188
|
+
// export const routerState: {
|
|
189
|
+
// pathname: State<RouterState.pathname>;
|
|
190
|
+
// searchParams: State<RouterState.searchParams>;
|
|
191
|
+
// params?: State<RouterState.params>;
|
|
192
|
+
// };
|
|
188
193
|
export const routerState: {
|
|
189
|
-
pathname:
|
|
190
|
-
searchParams:
|
|
191
|
-
params?:
|
|
194
|
+
pathname: RouterState["pathname"];
|
|
195
|
+
searchParams: RouterState["searchParams"];
|
|
196
|
+
params?: RouterState["params"];
|
|
192
197
|
};
|
|
193
198
|
|
|
194
199
|
/**
|
package/router/helpers.mjs
CHANGED
package/router/router.mjs
CHANGED
|
@@ -9,136 +9,118 @@ import { Head, initializeHeadTags } from "../meta/index.mjs";
|
|
|
9
9
|
|
|
10
10
|
import "virtual:@vanjs/routes";
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
/** @typedef {import("./types.d.ts").ComponentModule} ComponentModule */
|
|
13
|
+
/** @typedef {import("./types.d.ts").RouteEntry} RouteEntry */
|
|
14
|
+
/** @typedef {import("./types.d.ts").VanNode} VanNode */
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Resolve component children from a module
|
|
18
|
+
* @param {ComponentModule | Element | Element[] | any} module
|
|
19
|
+
* @returns {VanNode[]}
|
|
20
|
+
*/
|
|
21
|
+
const resolveChildren = (module) => {
|
|
22
|
+
const isElement = typeof Element !== "undefined" && module instanceof Element;
|
|
23
|
+
const cp = (Array.isArray(module) || isElement)
|
|
24
|
+
? module
|
|
25
|
+
: typeof module.component === "function"
|
|
26
|
+
? module.component()
|
|
27
|
+
: module.component;
|
|
28
|
+
return cp ? Array.from(unwrap(cp).children) : /* istanbul ignore next */ [];
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Update head tags
|
|
33
|
+
*/
|
|
34
|
+
const updateHead = () => {
|
|
35
|
+
// istanbul ignore else
|
|
36
|
+
if (document.head) {
|
|
37
|
+
van.hydrate(document.head, (head) => hydrate(head, Head()));
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Initialize client-side router (Head + popstate listener)
|
|
43
|
+
*/
|
|
44
|
+
let _initialized = false;
|
|
45
|
+
const initClient = () => {
|
|
46
|
+
// istanbul ignore if - already initialized
|
|
47
|
+
if (_initialized) return;
|
|
48
|
+
|
|
49
|
+
initializeHeadTags();
|
|
50
|
+
globalThis.addEventListener(
|
|
51
|
+
"popstate",
|
|
52
|
+
/** @param {Event & {target: globalThis}} e */
|
|
53
|
+
(e) => {
|
|
54
|
+
const location = e.target.location;
|
|
55
|
+
const oldPath = routerState.pathname;
|
|
56
|
+
// istanbul ignore next - cannot test
|
|
57
|
+
if (location.pathname !== oldPath) {
|
|
58
|
+
setRouterState(location.pathname, location.search);
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
);
|
|
62
|
+
_initialized = true;
|
|
63
|
+
};
|
|
13
64
|
|
|
14
65
|
export const Router = (initialProps = /* istanbul ignore next */ {}) => {
|
|
15
66
|
const { div, main } = van.tags;
|
|
16
67
|
|
|
17
|
-
/* istanbul ignore next - try again later */
|
|
18
68
|
const props = Object.fromEntries(
|
|
19
69
|
Object.entries(initialProps).filter(([_, val]) => val !== undefined),
|
|
20
70
|
);
|
|
21
71
|
const wrapper = main({ ...props, "data-root": true });
|
|
22
|
-
const mainLayout = () => {
|
|
23
|
-
const route = matchRoute(routerState.pathname.val);
|
|
24
|
-
/* istanbul ignore else */
|
|
25
|
-
if (!route) return van.add(wrapper, div("No Route Found"));
|
|
26
|
-
|
|
27
|
-
routerState.params.val = route.params || {};
|
|
28
|
-
// Server-side or async component: use renderComponent
|
|
29
|
-
if (isServer) {
|
|
30
|
-
const renderComponent = async () => {
|
|
31
|
-
try {
|
|
32
|
-
const module = await route.component();
|
|
33
|
-
const component = typeof module.component === "function"
|
|
34
|
-
? module.component()
|
|
35
|
-
: /* istanbul ignore next */ module.component;
|
|
36
|
-
|
|
37
|
-
await executeLifecycle(module, route.params);
|
|
38
|
-
return van.add(wrapper, unwrap(component).children);
|
|
39
|
-
} catch (error) {
|
|
40
|
-
/* istanbul ignore next */
|
|
41
|
-
console.error("Router error:", error);
|
|
42
|
-
/* istanbul ignore next */
|
|
43
|
-
return van.add(wrapper, div("Error loading page"));
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
return renderComponent();
|
|
48
|
-
}
|
|
49
72
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
)
|
|
67
|
-
|
|
73
|
+
// Initialize Head BEFORE any route matching or lifecycle execution
|
|
74
|
+
if (!isServer) initClient();
|
|
75
|
+
|
|
76
|
+
const route = matchRoute(routerState.pathname);
|
|
77
|
+
/* istanbul ignore else */
|
|
78
|
+
if (!route) return van.add(wrapper, div("No Route Found"));
|
|
79
|
+
|
|
80
|
+
Object.assign(routerState.params, route.params || {});
|
|
81
|
+
|
|
82
|
+
// Server-side rendering
|
|
83
|
+
if (isServer) {
|
|
84
|
+
return (async () => {
|
|
85
|
+
try {
|
|
86
|
+
const module = await route.component();
|
|
87
|
+
await executeLifecycle(module, route.params);
|
|
88
|
+
return van.add(wrapper, ...resolveChildren(module));
|
|
89
|
+
} catch (error) {
|
|
90
|
+
/* istanbul ignore next */
|
|
91
|
+
console.error("Router error:", error);
|
|
92
|
+
/* istanbul ignore next */
|
|
93
|
+
return van.add(wrapper, div("Error loading page"));
|
|
94
|
+
}
|
|
95
|
+
})();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Client-side: check if hydrating SSR content or SPA
|
|
99
|
+
const root = document.querySelector("[data-root]");
|
|
68
100
|
|
|
69
|
-
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const kids = () => cp ? Array.from(unwrap(cp).children) : [];
|
|
84
|
-
const kudos = kids();
|
|
85
|
-
|
|
86
|
-
isConnected = true;
|
|
87
|
-
// istanbul ignore else
|
|
88
|
-
if (document.head) {
|
|
89
|
-
van.hydrate(document.head, (head) => hydrate(head, Head()));
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return kudos;
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
return van.add(wrapper, ...children());
|
|
101
|
+
if (root) {
|
|
102
|
+
// Hydration path - root exists from SSR
|
|
103
|
+
const module = route.component();
|
|
104
|
+
executeLifecycle(module, route.params);
|
|
105
|
+
updateHead();
|
|
106
|
+
return van.add(wrapper, ...resolveChildren(module));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// SPA path - reactive routing
|
|
110
|
+
van.derive(() => {
|
|
111
|
+
const r = matchRoute(routerState.pathname);
|
|
112
|
+
if (!r) {
|
|
113
|
+
wrapper.replaceChildren(div("No Route Found"));
|
|
114
|
+
return;
|
|
96
115
|
}
|
|
97
|
-
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
const md = route.component();
|
|
108
|
-
executeLifecycle(md, route.params);
|
|
109
|
-
// istanbul ignore next - cannot test all cases
|
|
110
|
-
const cp = (Array.isArray(md) || md instanceof Element)
|
|
111
|
-
? md
|
|
112
|
-
: typeof md.component === "function"
|
|
113
|
-
? md.component()
|
|
114
|
-
: md.component;
|
|
115
|
-
return cp
|
|
116
|
-
? Array.from(unwrap(cp).children)
|
|
117
|
-
: /* istanbul ignore next */ [];
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
const component = () => {
|
|
121
|
-
const kids = () => children.val;
|
|
122
|
-
const result = () => {
|
|
123
|
-
return van.derive(() =>
|
|
124
|
-
van.hydrate(wrapper, (el) => {
|
|
125
|
-
const kudos = kids();
|
|
126
|
-
isConnected = true;
|
|
127
|
-
// istanbul ignore else
|
|
128
|
-
if (document.head) {
|
|
129
|
-
van.hydrate(document.head, (head) => hydrate(head, Head()));
|
|
130
|
-
}
|
|
131
|
-
return hydrate(el, kudos);
|
|
132
|
-
})
|
|
133
|
-
).val;
|
|
134
|
-
};
|
|
135
|
-
return result();
|
|
136
|
-
};
|
|
137
|
-
const finalResult = component();
|
|
138
|
-
return finalResult
|
|
139
|
-
? /* istanbul ignore next*/ van.add(wrapper, finalResult)
|
|
140
|
-
: wrapper;
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
return mainLayout();
|
|
116
|
+
|
|
117
|
+
const module = r.component();
|
|
118
|
+
executeLifecycle(module, r.params);
|
|
119
|
+
const children = resolveChildren(module);
|
|
120
|
+
|
|
121
|
+
wrapper.replaceChildren(...children);
|
|
122
|
+
updateHead();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
return wrapper;
|
|
144
126
|
};
|
package/router/state.mjs
CHANGED
|
@@ -18,23 +18,86 @@ export const fixRouteUrl = (url) => {
|
|
|
18
18
|
const initialPath = !isServer ? globalThis.location.pathname : "/";
|
|
19
19
|
const initialSearch = !isServer ? globalThis.location.search : "";
|
|
20
20
|
|
|
21
|
+
const STATE_PROXY = "_proxy";
|
|
22
|
+
const proxyProps = {
|
|
23
|
+
value: 1,
|
|
24
|
+
enumerable: false,
|
|
25
|
+
configurable: false,
|
|
26
|
+
writable: false,
|
|
27
|
+
};
|
|
28
|
+
|
|
21
29
|
/**
|
|
22
|
-
* @
|
|
30
|
+
* @param {number | Omit<keyof T, "symbol">} key
|
|
31
|
+
* @param {T[keyof T]} value
|
|
32
|
+
* @param {Record<string, string | number>} target
|
|
33
|
+
* @returns {T}
|
|
23
34
|
*/
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
35
|
+
const defineProxy = (key, value, target) => {
|
|
36
|
+
const stateObj = van.state(value);
|
|
37
|
+
|
|
38
|
+
const getter = () => stateObj.val;
|
|
39
|
+
const setter = (newVal) => {
|
|
40
|
+
stateObj.val = newVal;
|
|
41
|
+
};
|
|
42
|
+
stateObj.val = value;
|
|
43
|
+
|
|
44
|
+
Object.defineProperties(target, {
|
|
45
|
+
[STATE_PROXY]: proxyProps,
|
|
46
|
+
[key]: {
|
|
47
|
+
get: getter,
|
|
48
|
+
set: setter,
|
|
49
|
+
enumerable: true,
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return stateObj;
|
|
28
54
|
};
|
|
29
55
|
|
|
56
|
+
/**
|
|
57
|
+
* @param {T extends Record<string, unknown>} init
|
|
58
|
+
* @returns {T}
|
|
59
|
+
*/
|
|
60
|
+
export function miniStore(init) {
|
|
61
|
+
const target = {};
|
|
62
|
+
for (const [prop, value] of Object.entries(init)) {
|
|
63
|
+
if (
|
|
64
|
+
value && typeof value === "object" &&
|
|
65
|
+
Object.getPrototypeOf(value) === Object
|
|
66
|
+
) {
|
|
67
|
+
for (const [sp, sv] of Object.entries(value)) {
|
|
68
|
+
target[prop] = defineProxy(sp, sv, {});
|
|
69
|
+
}
|
|
70
|
+
} else if (!Array.isArray(value)) {
|
|
71
|
+
defineProxy(prop, value, target);
|
|
72
|
+
} else {
|
|
73
|
+
console.warn(typeof value + " is not supported.");
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return target;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @type {typeof import("./types.d.ts").routerState}
|
|
81
|
+
*/
|
|
82
|
+
// export const routerState = {
|
|
83
|
+
// pathname: van.state(initialPath),
|
|
84
|
+
// searchParams: van.state(new URLSearchParams(initialSearch)),
|
|
85
|
+
// params: van.state({}),
|
|
86
|
+
// };
|
|
87
|
+
export const routerState = miniStore({
|
|
88
|
+
pathname: initialPath,
|
|
89
|
+
searchParams: new URLSearchParams(initialSearch),
|
|
90
|
+
params: {},
|
|
91
|
+
});
|
|
92
|
+
|
|
30
93
|
/**
|
|
31
94
|
* @type {typeof import("./types.d.ts").setRouterState}
|
|
32
95
|
*/
|
|
33
96
|
export const setRouterState = (path, search = undefined, params) => {
|
|
34
97
|
const [pathname, searchParams] = fixRouteUrl(path).split("?");
|
|
35
|
-
routerState.pathname
|
|
36
|
-
routerState.searchParams
|
|
98
|
+
routerState.pathname = pathname;
|
|
99
|
+
routerState.searchParams = new URLSearchParams(
|
|
37
100
|
search || searchParams || "",
|
|
38
101
|
);
|
|
39
|
-
routerState.params
|
|
102
|
+
Object.assign(routerState.params, params || {});
|
|
40
103
|
};
|
package/router/types.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/// <reference path="global.d.ts" />
|
|
2
|
+
|
|
2
3
|
import type {
|
|
3
4
|
Element as VElement,
|
|
4
5
|
TagFunc as IsoTagFunc,
|
|
5
6
|
} from "mini-van-plate/van-plate";
|
|
6
|
-
import van from "vanjs-core";
|
|
7
|
+
// import van from "vanjs-core";
|
|
7
8
|
import type {
|
|
8
9
|
ChildDom,
|
|
9
10
|
Primitive,
|
|
@@ -202,9 +203,9 @@ export type RouterState = {
|
|
|
202
203
|
* This state is maintained by both server and client.
|
|
203
204
|
*/
|
|
204
205
|
export const routerState: {
|
|
205
|
-
pathname:
|
|
206
|
-
searchParams:
|
|
207
|
-
params?:
|
|
206
|
+
pathname: RouterState["pathname"];
|
|
207
|
+
searchParams: RouterState["searchParams"];
|
|
208
|
+
params?: RouterState["params"];
|
|
208
209
|
};
|
|
209
210
|
|
|
210
211
|
/**
|