Skip to content

Commit dae52c7

Browse files
committed
fix: add global click handler for navigation
When using React router, clicks on anchors are intercepted only if Flow client has been initialized. In Hilla or hybrid application, if a Flow view is never navigated, clicking on such links cause the browser to reload the page instead of navigating to the expected view. This change registers a global click handler that intercepts click events and triggers a router navigation if necessary. The new behavior is aligned with vaadin-router. Fixes #20939
1 parent 6fe93c4 commit dae52c7

File tree

3 files changed

+22
-26
lines changed
  • flow-plugins/flow-maven-plugin/src/it/flow-addon/src/main/fake-resources/com/vaadin/flow/server/frontend
  • flow-server/src/main/resources/com/vaadin/flow/server/frontend

3 files changed

+22
-26
lines changed

flow-plugins/flow-maven-plugin/src/it/flow-addon/src/main/fake-resources/com/vaadin/flow/server/frontend/Flow.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@
1515
*/
1616

1717
// Resource loaded from project dependency
18-
export const serverSideRoutes = []
18+
export const serverSideRoutes = [];
19+
export const registerGlobalClickHandler = (router: any) => {};

flow-server/src/main/resources/com/vaadin/flow/server/frontend/Flow.tsx

+17-24
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
/// <reference lib="es2018" />
1717
import { Flow as _Flow } from 'Frontend/generated/jar-resources/Flow.js';
1818
import React, { useCallback, useEffect, useReducer, useRef, useState, type ReactNode } from 'react';
19-
import { matchRoutes, useBlocker, useLocation, useNavigate, type NavigateOptions, useHref } from 'react-router';
19+
import { matchRoutes, useBlocker, useLocation, useNavigate, type NavigateOptions, useHref, type DataRouter } from 'react-router';
2020
import { createPortal } from 'react-dom';
2121

2222
const flow = new _Flow({
@@ -134,6 +134,22 @@ function extractPath(event: MouseEvent): void | string {
134134
return normalizeURL(new URL(anchor.href, anchor.baseURI));
135135
}
136136

137+
export const registerGlobalClickHandler = (router: DataRouter)=> {
138+
window.addEventListener('click', (event: MouseEvent) => {
139+
const path = extractPath(event);
140+
if (!path) {
141+
return;
142+
}
143+
144+
if (event && event.preventDefault) {
145+
event.preventDefault();
146+
}
147+
router.navigate(path);
148+
});
149+
};
150+
151+
152+
137153
/**
138154
* Fire 'vaadin-navigated' event to inform components of navigation.
139155
* @param pathname pathname of navigation
@@ -342,28 +358,6 @@ function Flow() {
342358
[dispatchPortalAction]
343359
);
344360

345-
const navigateEventHandler = useCallback(
346-
(event: MouseEvent) => {
347-
const path = extractPath(event);
348-
if (!path) {
349-
return;
350-
}
351-
352-
if (event && event.preventDefault) {
353-
event.preventDefault();
354-
}
355-
356-
navigated.current = false;
357-
// When navigation is triggered by click on a link, fromAnchor is set to true
358-
// in order to get a server round-trip even when navigating to the same URL again
359-
fromAnchor.current = true;
360-
navigate(path);
361-
// Dispatch close event for overlay drawer on click navigation.
362-
window.dispatchEvent(new CustomEvent('close-overlay-drawer'));
363-
},
364-
[navigate]
365-
);
366-
367361
const vaadinRouterGoEventHandler = useCallback(
368362
(event: CustomEvent<URL>) => {
369363
const url = event.detail;
@@ -533,7 +527,6 @@ function Flow() {
533527
if (outlet && outlet !== container.parentNode) {
534528
outlet.append(container);
535529
container.addEventListener('flow-portal-add', addPortalEventHandler as EventListener);
536-
window.addEventListener('click', navigateEventHandler);
537530
containerRef.current = container;
538531
}
539532
return container.onBeforeEnter?.call(

flow-server/src/main/resources/com/vaadin/flow/server/frontend/vaadin-react.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
import { routes } from "%routesJsImportPath%";
1+
import { router, routes } from "%routesJsImportPath%";
2+
import { registerGlobalClickHandler } from "Frontend/generated/flow/Flow.js";
23

34
(window as any).Vaadin ??= {};
45
(window as any).Vaadin.routesConfig = routes;
6+
registerGlobalClickHandler(router);
57

68
export { routes as forHMROnly };
79

0 commit comments

Comments
 (0)