fix(vue): pass router-link value to href to properly render clickable elements (#29745)

Issue number: N/A

---------

## What is the current behavior?
Ionic Framework Vue components using `router-link` do not apply an
`href` property which causes components to render `div` or `button`
elements when they should render an `a`. This is inconsistent with the
way Angular and Vue handle router link.

## What is the new behavior?
Updates `@stencil/vue-output-target` to latest which adds the code from
the following PR:
https://github.com/ionic-team/stencil-ds-output-targets/pull/446

The update in vue output target checks if `router-link` and `navManager`
are defined so this fix only applies to Ionic Framework components. If
both are defined then it adds the `href` property to the element with
the value of `router-link`.

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

## Other information

Dev build: `8.2.7-dev.11722629362.1ac136c4`
This commit is contained in:
Brandy Carney
2024-08-05 17:35:26 -04:00
committed by GitHub
parent a9f278ad67
commit ab4f2791c1
10 changed files with 77 additions and 38 deletions

View File

@ -91,8 +91,17 @@ export const defineContainer = <Props, VModelType = string | number | boolean>(
const eventsNames = Array.isArray(modelUpdateEvent) ? modelUpdateEvent : [modelUpdateEvent];
eventsNames.forEach((eventName: string) => {
el.addEventListener(eventName.toLowerCase(), (e: Event) => {
modelPropValue = (e?.target as any)[modelProp];
emit(UPDATE_VALUE_EVENT, modelPropValue);
/**
* Only update the v-model binding if the event's target is the element we are
* listening on. For example, Component A could emit ionChange, but it could also
* have a descendant Component B that also emits ionChange. We only want to update
* the v-model for Component A when ionChange originates from that element and not
* when ionChange bubbles up from Component B.
*/
if (e.target.tagName === el.tagName) {
modelPropValue = (e?.target as any)[modelProp];
emit(UPDATE_VALUE_EVENT, modelPropValue);
}
});
});
},
@ -106,6 +115,16 @@ export const defineContainer = <Props, VModelType = string | number | boolean>(
if (routerLink === EMPTY_PROP) return;
if (navManager !== undefined) {
/**
* This prevents the browser from
* performing a page reload when pressing
* an Ionic component with routerLink.
* The page reload interferes with routing
* and causes ion-back-button to disappear
* since the local history is wiped on reload.
*/
ev.preventDefault();
let navigationPayload: any = { event: ev };
for (const key in props) {
const value = props[key];
@ -176,6 +195,17 @@ export const defineContainer = <Props, VModelType = string | number | boolean>(
}
}
// If router link is defined, add href to props
// in order to properly render an anchor tag inside
// of components that should become activatable and
// focusable with router link.
if (props[ROUTER_LINK_VALUE] !== EMPTY_PROP) {
propsToAdd = {
...propsToAdd,
href: props[ROUTER_LINK_VALUE],
};
}
/**
* vModelDirective is only needed on components that support v-model.
* As a result, we conditionally call withDirectives with v-model components.