olova-router 1.0.1 → 1.0.2
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 +30 -228
- package/package.json +1 -1
package/dist/olova-router.js
CHANGED
|
@@ -1,249 +1,51 @@
|
|
|
1
|
-
|
|
2
|
-
import Olova from "Olova";
|
|
1
|
+
import { State, Effect, Component, h, Memo } from "olova";
|
|
3
2
|
|
|
4
|
-
const
|
|
5
|
-
basename: "",
|
|
6
|
-
navigator: null,
|
|
7
|
-
static: false,
|
|
8
|
-
});
|
|
3
|
+
const [currentRoute, setCurrentRoute] = State(window.location.pathname);
|
|
9
4
|
|
|
10
|
-
|
|
11
|
-
|
|
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(() => {
|
|
5
|
+
function Router(props) {
|
|
6
|
+
Effect(() => {
|
|
65
7
|
const handlePopState = () => {
|
|
66
|
-
|
|
67
|
-
createLocation(
|
|
68
|
-
window.location.pathname +
|
|
69
|
-
window.location.search +
|
|
70
|
-
window.location.hash
|
|
71
|
-
)
|
|
72
|
-
);
|
|
8
|
+
setCurrentRoute(window.location.pathname);
|
|
73
9
|
};
|
|
10
|
+
|
|
74
11
|
window.addEventListener("popstate", handlePopState);
|
|
75
12
|
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]);
|
|
13
|
+
});
|
|
83
14
|
|
|
84
|
-
return
|
|
85
|
-
NavigationContext.Provider,
|
|
86
|
-
{ value: navigationValue },
|
|
87
|
-
Olova.createElement(
|
|
88
|
-
LocationContext.Provider,
|
|
89
|
-
{ value: locationValue },
|
|
90
|
-
children
|
|
91
|
-
)
|
|
92
|
-
);
|
|
15
|
+
return h("div", { class: "router" }, props?.children);
|
|
93
16
|
}
|
|
94
17
|
|
|
95
|
-
|
|
96
|
-
const
|
|
97
|
-
|
|
18
|
+
function Route({ path, component: RouteComponent }) {
|
|
19
|
+
const matches = Memo(() => {
|
|
20
|
+
return currentRoute() === path;
|
|
21
|
+
});
|
|
98
22
|
|
|
99
|
-
|
|
100
|
-
let matchParams = {};
|
|
23
|
+
const routeContent = document.createElement("div");
|
|
101
24
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
-
}
|
|
25
|
+
Effect(() => {
|
|
26
|
+
if (matches()) {
|
|
27
|
+
routeContent.innerHTML = "";
|
|
28
|
+
routeContent.appendChild(h(RouteComponent, null));
|
|
29
|
+
} else {
|
|
30
|
+
routeContent.innerHTML = "";
|
|
118
31
|
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return element;
|
|
122
|
-
}
|
|
32
|
+
});
|
|
123
33
|
|
|
124
|
-
|
|
125
|
-
return Olova.createElement("route", { path, element });
|
|
34
|
+
return routeContent;
|
|
126
35
|
}
|
|
127
36
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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);
|
|
37
|
+
function Link({ to, children }) {
|
|
38
|
+
const handleClick = (e) => {
|
|
39
|
+
e.preventDefault();
|
|
40
|
+
navigate(to);
|
|
147
41
|
};
|
|
148
42
|
|
|
149
|
-
return
|
|
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;
|
|
43
|
+
return h("a", { href: to, onClick: handleClick }, children);
|
|
231
44
|
}
|
|
232
45
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
46
|
+
function navigate(to) {
|
|
47
|
+
window.history.pushState({}, "", to);
|
|
48
|
+
setCurrentRoute(to);
|
|
236
49
|
}
|
|
237
50
|
|
|
238
|
-
export
|
|
239
|
-
BrowserRouter,
|
|
240
|
-
Routes,
|
|
241
|
-
Route,
|
|
242
|
-
Link,
|
|
243
|
-
Navigate,
|
|
244
|
-
Outlet,
|
|
245
|
-
useNavigate,
|
|
246
|
-
useLocation,
|
|
247
|
-
useParams,
|
|
248
|
-
useSearchParams,
|
|
249
|
-
};
|
|
51
|
+
export { Router, Route, Link, navigate };
|