|
1 | 1 | import type { Expression, EnsembleAction } from "@ensembleui/react-framework"; |
2 | 2 | import { useRegisterBindings, unwrapWidget } from "@ensembleui/react-framework"; |
3 | 3 | import { useMemo, useCallback } from "react"; |
4 | | -import { Link as RouterLink } from "react-router-dom"; |
| 4 | +import { Link as RouterLink, useNavigate } from "react-router-dom"; |
5 | 5 | import { cloneDeep } from "lodash-es"; |
6 | 6 | import { WidgetRegistry } from "../registry"; |
7 | 7 | import type { EnsembleWidgetProps } from "../shared/types"; |
@@ -41,6 +41,7 @@ export type LinkProps = { |
41 | 41 |
|
42 | 42 | export const Link: React.FC<LinkProps> = ({ id, onTap, widget, ...rest }) => { |
43 | 43 | const action = useEnsembleAction(onTap); |
| 44 | + const navigate = useNavigate(); |
44 | 45 |
|
45 | 46 | const { values, rootRef } = useRegisterBindings({ ...rest, widgetName }, id); |
46 | 47 |
|
@@ -92,6 +93,25 @@ export const Link: React.FC<LinkProps> = ({ id, onTap, widget, ...rest }) => { |
92 | 93 | ); |
93 | 94 | }, [values?.url]); |
94 | 95 |
|
| 96 | + // Intercept normal left-clicks (no modifiers) during capture phase |
| 97 | + // This ensures navigation is handled client-side even if the child (e.g., Button) |
| 98 | + // calls stopPropagation in its onClick. Right/middle clicks remain native. |
| 99 | + const onClickCapture = useCallback( |
| 100 | + (e: React.MouseEvent) => { |
| 101 | + if (!values?.url || isExternalUrl) return; |
| 102 | + // only handle left click without modifiers |
| 103 | + if (e.button !== 0) return; |
| 104 | + if (e.metaKey || e.ctrlKey || e.altKey || e.shiftKey) return; |
| 105 | + |
| 106 | + e.preventDefault(); |
| 107 | + navigate(values.url, { |
| 108 | + replace: Boolean(values.replace), |
| 109 | + state: values.inputs, |
| 110 | + }); |
| 111 | + }, |
| 112 | + [navigate, values?.url, values?.replace, values?.inputs, isExternalUrl], |
| 113 | + ); |
| 114 | + |
95 | 115 | if (!values?.url) { |
96 | 116 | return ( |
97 | 117 | <span ref={rootRef} style={linkStyles}> |
@@ -130,6 +150,7 @@ export const Link: React.FC<LinkProps> = ({ id, onTap, widget, ...rest }) => { |
130 | 150 | // For internal navigation, use React Router Link |
131 | 151 | return ( |
132 | 152 | <RouterLink |
| 153 | + onClickCapture={onClickCapture} |
133 | 154 | onClick={handleClick} |
134 | 155 | onMouseEnter={(e): void => { |
135 | 156 | if (hoverStyles.color) e.currentTarget.style.color = hoverStyles.color; |
|
0 commit comments