Skip to content

Commit aa1db09

Browse files
committed
Enhance x-router:link
Allow x-router:link to be used on parent elements while the actual link is declared in child elements.
1 parent 941bb37 commit aa1db09

File tree

1 file changed

+71
-18
lines changed

1 file changed

+71
-18
lines changed

src/plugins/router/router.js

Lines changed: 71 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -126,24 +126,29 @@ export default function({ directive, magic, reactive }) {
126126
}
127127

128128
function process_link() {
129-
const is_blank = (el.getAttribute("target") ?? "").indexOf("_blank") >= 0;
130-
const unsubscribe = listen(el, "click", e => {
131-
if (e.metaKey
132-
|| e.altKey
133-
|| e.ctrlKey
134-
|| e.shiftKey
135-
|| e.defaultPrevented
136-
|| e.button > 0
137-
|| is_blank) {
138-
return;
139-
}
129+
let link = get_anchor_element(el);
130+
if (link) {
131+
el._r_routerlink = link;
132+
133+
const is_blank = (link.getAttribute("target") ?? "").indexOf("_blank") >= 0;
134+
const unsubscribe = listen(link, "click", e => {
135+
if (e.metaKey
136+
|| e.altKey
137+
|| e.ctrlKey
138+
|| e.shiftKey
139+
|| e.defaultPrevented
140+
|| e.button > 0
141+
|| is_blank) {
142+
return;
143+
}
140144

141-
e.preventDefault();
145+
e.preventDefault();
142146

143-
router.navigate(`${ el.pathname }${ el.search }${ el.hash }`);
144-
});
147+
router.navigate(`${ link.pathname }${ link.search }${ link.hash }`);
148+
});
145149

146-
cleanup(unsubscribe);
150+
cleanup(unsubscribe);
151+
}
147152
}
148153

149154
function process_outlet() {
@@ -161,11 +166,59 @@ export default function({ directive, magic, reactive }) {
161166

162167
magic("active", el => {
163168
const router = closest(el, node => node._r_router)?._r_router;
169+
if (is_nullish(router)) {
170+
warn("No x-router directive found");
171+
return false;
172+
}
164173

165-
if (!is_nullish(router)) {
166-
return router.history.resolve(el.href) === router.values.path;
174+
//
175+
// Create a dependency on router.values
176+
//
177+
JSON.stringify(router.values);
178+
179+
const link = is_anchor_element(el) ? el : closest(el, node => node._r_routerlink)?._r_routerlink;
180+
181+
//
182+
// The issue is that the router:link directive is processed later than x-bind,
183+
// and if $active is used in x-bind, we won’t find node._r_routerlink.
184+
// Therefore, we delay execution and try again.
185+
//
186+
// <div x-router:link :class="{ active: $active }">
187+
// ...
188+
// </div>
189+
//
190+
191+
if (link) {
192+
return router.history.resolve(link.href) === router.values.path;
167193
}
168194

169-
warn("No x-router directive found");
195+
if (el._r_routerlink_init) {
196+
warn(`x-router:link directive not found`, el);
197+
}
198+
else {
199+
queueMicrotask(() => {
200+
el._r_routerlink_init = true;
201+
//
202+
// Force an upate
203+
//
204+
router.values.path = router.values.path;
205+
});
206+
}
207+
208+
return false;
170209
});
171210
}
211+
212+
function is_anchor_element(el) {
213+
return el.tagName.toUpperCase() === "A";
214+
}
215+
216+
function get_anchor_element(el) {
217+
if (is_anchor_element(el)) {
218+
return el;
219+
}
220+
221+
const links = el.querySelectorAll("a");
222+
links.length !== 1 && warn(`Expected exactly one link, but found ${links.length}`);
223+
return links[0];
224+
}

0 commit comments

Comments
 (0)