olova-router 1.0.0 → 1.0.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/olova-router.js +249 -0
- package/dist/router.d.ts +1 -1
- package/package.json +15 -18
- package/README.md +0 -18
- package/dist/router.js +0 -40
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/** @jsx Olova.createElement */
|
|
2
|
+
import Olova from "Olova";
|
|
3
|
+
|
|
4
|
+
const NavigationContext = Olova.createContext({
|
|
5
|
+
basename: "",
|
|
6
|
+
navigator: null,
|
|
7
|
+
static: false,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const LocationContext = Olova.createContext({
|
|
11
|
+
location: {
|
|
12
|
+
pathname: window.location.pathname,
|
|
13
|
+
search: window.location.search,
|
|
14
|
+
hash: window.location.hash,
|
|
15
|
+
state: null,
|
|
16
|
+
key: "",
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const RouteContext = Olova.createContext({
|
|
21
|
+
params: {},
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
function createLocation(path) {
|
|
25
|
+
const [pathname, search] = path.split("?");
|
|
26
|
+
return {
|
|
27
|
+
pathname: pathname || "/",
|
|
28
|
+
search: search ? `?${search}` : "",
|
|
29
|
+
hash: window.location.hash || "",
|
|
30
|
+
state: null,
|
|
31
|
+
key: Math.random().toString(36).slice(2),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function BrowserRouter({ children, basename = "" }) {
|
|
36
|
+
const [location, setLocation] = Olova.State(
|
|
37
|
+
createLocation(
|
|
38
|
+
window.location.pathname + window.location.search + window.location.hash
|
|
39
|
+
)
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const navigator = {
|
|
43
|
+
push(to) {
|
|
44
|
+
const newLocation = createLocation(to);
|
|
45
|
+
window.history.pushState(null, "", to);
|
|
46
|
+
setLocation(newLocation);
|
|
47
|
+
},
|
|
48
|
+
replace(to) {
|
|
49
|
+
const newLocation = createLocation(to);
|
|
50
|
+
window.history.replaceState(null, "", to);
|
|
51
|
+
setLocation(newLocation);
|
|
52
|
+
},
|
|
53
|
+
go(delta) {
|
|
54
|
+
window.history.go(delta);
|
|
55
|
+
},
|
|
56
|
+
back() {
|
|
57
|
+
window.history.back();
|
|
58
|
+
},
|
|
59
|
+
forward() {
|
|
60
|
+
window.history.forward();
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
Olova.Effect(() => {
|
|
65
|
+
const handlePopState = () => {
|
|
66
|
+
setLocation(
|
|
67
|
+
createLocation(
|
|
68
|
+
window.location.pathname +
|
|
69
|
+
window.location.search +
|
|
70
|
+
window.location.hash
|
|
71
|
+
)
|
|
72
|
+
);
|
|
73
|
+
};
|
|
74
|
+
window.addEventListener("popstate", handlePopState);
|
|
75
|
+
return () => window.removeEventListener("popstate", handlePopState);
|
|
76
|
+
}, []);
|
|
77
|
+
|
|
78
|
+
const navigationValue = Olova.Memo(
|
|
79
|
+
() => ({ navigator, basename }),
|
|
80
|
+
[navigator, basename]
|
|
81
|
+
);
|
|
82
|
+
const locationValue = Olova.Memo(() => ({ location }), [location]);
|
|
83
|
+
|
|
84
|
+
return Olova.createElement(
|
|
85
|
+
NavigationContext.Provider,
|
|
86
|
+
{ value: navigationValue },
|
|
87
|
+
Olova.createElement(
|
|
88
|
+
LocationContext.Provider,
|
|
89
|
+
{ value: locationValue },
|
|
90
|
+
children
|
|
91
|
+
)
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function Routes({ children }) {
|
|
96
|
+
const { location } = Olova.Context(LocationContext);
|
|
97
|
+
const { basename } = Olova.Context(NavigationContext);
|
|
98
|
+
|
|
99
|
+
let element = null;
|
|
100
|
+
let matchParams = {};
|
|
101
|
+
|
|
102
|
+
const childrenArray = Array.isArray(children) ? children : [children];
|
|
103
|
+
const validChildren = childrenArray.filter((child) => child != null);
|
|
104
|
+
|
|
105
|
+
for (let i = 0; i < validChildren.length; i++) {
|
|
106
|
+
const child = validChildren[i];
|
|
107
|
+
if (child.props) {
|
|
108
|
+
const path = basename + (child.props.path || "");
|
|
109
|
+
const match = matchPath(path, location.pathname);
|
|
110
|
+
if (match) {
|
|
111
|
+
matchParams = match.params;
|
|
112
|
+
element =
|
|
113
|
+
typeof child.props.element === "function"
|
|
114
|
+
? Olova.createElement(child.props.element, { params: match.params })
|
|
115
|
+
: child.props.element;
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return element;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function Route({ path, element }) {
|
|
125
|
+
return Olova.createElement("route", { path, element });
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function Link({
|
|
129
|
+
to,
|
|
130
|
+
children,
|
|
131
|
+
className = "",
|
|
132
|
+
activeClassName = "",
|
|
133
|
+
...props
|
|
134
|
+
}) {
|
|
135
|
+
const { navigator, basename } = Olova.Context(NavigationContext);
|
|
136
|
+
const { location } = Olova.Context(LocationContext);
|
|
137
|
+
|
|
138
|
+
const targetPath = basename + to;
|
|
139
|
+
const isActive = location.pathname === targetPath;
|
|
140
|
+
const finalClassName = isActive
|
|
141
|
+
? `${className} ${activeClassName}`.trim()
|
|
142
|
+
: className;
|
|
143
|
+
|
|
144
|
+
const handleClick = (event) => {
|
|
145
|
+
event.preventDefault();
|
|
146
|
+
navigator.push(targetPath);
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
return Olova.createElement(
|
|
150
|
+
"a",
|
|
151
|
+
{
|
|
152
|
+
href: targetPath,
|
|
153
|
+
onClick: handleClick,
|
|
154
|
+
className: finalClassName,
|
|
155
|
+
...props,
|
|
156
|
+
},
|
|
157
|
+
children
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function matchPath(pattern, pathname) {
|
|
162
|
+
if (pattern === pathname || pattern === "*") return { params: {} };
|
|
163
|
+
if (pattern === "/" && (pathname === "" || pathname === "/"))
|
|
164
|
+
return { params: {} };
|
|
165
|
+
|
|
166
|
+
const patternSegments = pattern.split("/").filter(Boolean);
|
|
167
|
+
const pathnameSegments = pathname.split("/").filter(Boolean);
|
|
168
|
+
|
|
169
|
+
if (patternSegments.length !== pathnameSegments.length) return null;
|
|
170
|
+
|
|
171
|
+
const params = {};
|
|
172
|
+
|
|
173
|
+
for (let i = 0; i < patternSegments.length; i++) {
|
|
174
|
+
const patternSegment = patternSegments[i];
|
|
175
|
+
const pathnameSegment = pathnameSegments[i];
|
|
176
|
+
|
|
177
|
+
if (patternSegment.startsWith(":")) {
|
|
178
|
+
const paramName = patternSegment.slice(1);
|
|
179
|
+
params[paramName] = decodeURIComponent(pathnameSegment);
|
|
180
|
+
} else if (patternSegment !== pathnameSegment) {
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return { params };
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export function useSearchParams() {
|
|
189
|
+
const { location } = useLocation();
|
|
190
|
+
const searchParams = new URLSearchParams(location.search);
|
|
191
|
+
|
|
192
|
+
const setSearchParams = (newParams) => {
|
|
193
|
+
const navigate = useNavigate();
|
|
194
|
+
const newSearch = new URLSearchParams(newParams).toString();
|
|
195
|
+
navigate(`${location.pathname}?${newSearch}${location.hash}`);
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
return [searchParams, setSearchParams];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export function useNavigate() {
|
|
202
|
+
const { navigator } = Olova.Context(NavigationContext);
|
|
203
|
+
return Olova.Callback(
|
|
204
|
+
(to, options = {}) => {
|
|
205
|
+
if (options.replace) {
|
|
206
|
+
navigator.replace(to);
|
|
207
|
+
} else {
|
|
208
|
+
navigator.push(to);
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
[navigator]
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export function useLocation() {
|
|
216
|
+
const { location } = Olova.Context(LocationContext);
|
|
217
|
+
return location;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export function useParams() {
|
|
221
|
+
const { params } = Olova.Context(RouteContext);
|
|
222
|
+
return params;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export function Navigate({ to, replace = false }) {
|
|
226
|
+
const navigate = useNavigate();
|
|
227
|
+
Olova.Effect(() => {
|
|
228
|
+
navigate(to, { replace });
|
|
229
|
+
}, [navigate, to, replace]);
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export function Outlet() {
|
|
234
|
+
const { outlet } = Olova.Context(RouteContext);
|
|
235
|
+
return outlet || null;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export default {
|
|
239
|
+
BrowserRouter,
|
|
240
|
+
Routes,
|
|
241
|
+
Route,
|
|
242
|
+
Link,
|
|
243
|
+
Navigate,
|
|
244
|
+
Outlet,
|
|
245
|
+
useNavigate,
|
|
246
|
+
useLocation,
|
|
247
|
+
useParams,
|
|
248
|
+
useSearchParams,
|
|
249
|
+
};
|
package/dist/router.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
declare module "router";
|
|
1
|
+
declare module "olova-router";
|
package/package.json
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "olova-router",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
|
|
16
|
-
"olova": "latest"
|
|
17
|
-
}
|
|
18
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "olova-router",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"main": "dist/olova-router.js",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"javascript",
|
|
7
|
+
"framework",
|
|
8
|
+
"router",
|
|
9
|
+
"olova-router",
|
|
10
|
+
"olovajs"
|
|
11
|
+
],
|
|
12
|
+
"author": "Nazmul Hossain",
|
|
13
|
+
"license": "ISC",
|
|
14
|
+
"description": "olova-router for olovaJs"
|
|
15
|
+
}
|
package/README.md
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
# olova
|
|
2
|
-
|
|
3
|
-
```html
|
|
4
|
-
<div id="app">
|
|
5
|
-
<template>
|
|
6
|
-
<div i-data="{count : 0}">
|
|
7
|
-
<div>{ count }</div>
|
|
8
|
-
<button @click="count++">Increment</button>
|
|
9
|
-
</div>
|
|
10
|
-
</template>
|
|
11
|
-
</div>
|
|
12
|
-
|
|
13
|
-
<script type="module">
|
|
14
|
-
import { createApp } from "//unpkg.com/olova";
|
|
15
|
-
const app = createApp();
|
|
16
|
-
app.mount("#app");
|
|
17
|
-
</script>
|
|
18
|
-
```
|
package/dist/router.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { createApp } from "olova";
|
|
2
|
-
class Router {
|
|
3
|
-
constructor() {
|
|
4
|
-
(this.routes = new Map()), (this.currentApp = null), this.init();
|
|
5
|
-
}
|
|
6
|
-
init() {
|
|
7
|
-
window.addEventListener("popstate", () => this.handleRoute()),
|
|
8
|
-
document.addEventListener("click", (t) => {
|
|
9
|
-
if (t.target.matches("a")) {
|
|
10
|
-
t.preventDefault();
|
|
11
|
-
const e = t.target.getAttribute("href");
|
|
12
|
-
this.navigate(e);
|
|
13
|
-
}
|
|
14
|
-
}),
|
|
15
|
-
window.addEventListener("load", () => {
|
|
16
|
-
this.handleRoute();
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
add(t, e) {
|
|
20
|
-
return this.routes.set(t, e), this;
|
|
21
|
-
}
|
|
22
|
-
navigate(t) {
|
|
23
|
-
window.history.pushState(null, "", t), this.handleRoute();
|
|
24
|
-
}
|
|
25
|
-
handleRoute() {
|
|
26
|
-
const t = window.location.pathname,
|
|
27
|
-
e = this.routes.get(t),
|
|
28
|
-
n = document.querySelector("[i-view]");
|
|
29
|
-
if (n)
|
|
30
|
-
if (e) {
|
|
31
|
-
this.currentApp && (n.innerHTML = "");
|
|
32
|
-
const t = document.createElement("div");
|
|
33
|
-
(t.id = "route-container"),
|
|
34
|
-
n.appendChild(t),
|
|
35
|
-
(this.currentApp = createApp({ ...e })),
|
|
36
|
-
this.currentApp.mount("#route-container");
|
|
37
|
-
} else n.innerHTML = "<h1>404 Not Found</h1>";
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
export const router = new Router();
|