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.
Files changed (2) hide show
  1. package/dist/olova-router.js +30 -228
  2. package/package.json +1 -1
@@ -1,249 +1,51 @@
1
- /** @jsx Olova.createElement */
2
- import Olova from "Olova";
1
+ import { State, Effect, Component, h, Memo } from "olova";
3
2
 
4
- const NavigationContext = Olova.createContext({
5
- basename: "",
6
- navigator: null,
7
- static: false,
8
- });
3
+ const [currentRoute, setCurrentRoute] = State(window.location.pathname);
9
4
 
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(() => {
5
+ function Router(props) {
6
+ Effect(() => {
65
7
  const handlePopState = () => {
66
- setLocation(
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 Olova.createElement(
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
- export function Routes({ children }) {
96
- const { location } = Olova.Context(LocationContext);
97
- const { basename } = Olova.Context(NavigationContext);
18
+ function Route({ path, component: RouteComponent }) {
19
+ const matches = Memo(() => {
20
+ return currentRoute() === path;
21
+ });
98
22
 
99
- let element = null;
100
- let matchParams = {};
23
+ const routeContent = document.createElement("div");
101
24
 
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
- }
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
- export function Route({ path, element }) {
125
- return Olova.createElement("route", { path, element });
34
+ return routeContent;
126
35
  }
127
36
 
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);
37
+ function Link({ to, children }) {
38
+ const handleClick = (e) => {
39
+ e.preventDefault();
40
+ navigate(to);
147
41
  };
148
42
 
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;
43
+ return h("a", { href: to, onClick: handleClick }, children);
231
44
  }
232
45
 
233
- export function Outlet() {
234
- const { outlet } = Olova.Context(RouteContext);
235
- return outlet || null;
46
+ function navigate(to) {
47
+ window.history.pushState({}, "", to);
48
+ setCurrentRoute(to);
236
49
  }
237
50
 
238
- export default {
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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "olova-router",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "main": "dist/olova-router.js",
5
5
  "keywords": [
6
6
  "javascript",