Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/prs/angular/src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@
label="3607 Radio and Checkbox Interaction Area"
url="/bugs/3607"
></goabx-work-side-menu-item>
<goabx-work-side-menu-item label="3505 Link Icon Click" url="/bugs/3505"></goabx-work-side-menu-item>
</goabx-work-side-menu-group>
<goabx-work-side-menu-group icon="star" heading="Features">
<goabx-work-side-menu-item
Expand Down
2 changes: 2 additions & 0 deletions apps/prs/angular/src/app/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import { Bug3450Component } from "../routes/bugs/3450/bug3450.component";
import { Bug3497Component } from "../routes/bugs/3497/bug3497.component";
import { Bug3498Component } from "../routes/bugs/3498/bug3498.component";
import { Bug3607Component } from "../routes/bugs/3607/bug3607.component";
import { Bug3505Component } from "../routes/bugs/3505/bug3505.component";

import { Feat1328Component } from "../routes/features/feat1328/feat1328.component";
import { Feat1383Component } from "../routes/features/feat1383/feat1383.component";
Expand Down Expand Up @@ -140,6 +141,7 @@ export const appRoutes: Route[] = [
{ path: "bugs/3498", component: Bug3498Component },
{ path: "bugs/3607", component: Bug3607Component },

{ path: "bugs/3505", component: Bug3505Component },
// Feature routes
{ path: "features/1328", component: Feat1328Component },
{ path: "features/1383", component: Feat1383Component },
Expand Down
17 changes: 17 additions & 0 deletions apps/prs/angular/src/routes/bugs/3505/bug3505.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<goab-block direction="column" gap="l">
<goab-text tag="h1">Bug 3505 - Link icon click behavior</goab-text>

<goab-text tag="p">
Click the leading icon, trailing icon, or link text. All should open the same target.
</goab-text>

<goab-text tag="p">
Press Tab to move focus to the link. The link should show a single outer focus
outline on the component, and the internal anchor text should not show its own
separate focus outline.
</goab-text>

<goab-link leadingIcon="home" trailingIcon="open">
<a href="https://www.alberta.ca" target="_blank" rel="noreferrer noopener">Alberta.ca (icon click test)</a>
</goab-link>
</goab-block>
10 changes: 10 additions & 0 deletions apps/prs/angular/src/routes/bugs/3505/bug3505.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Component } from "@angular/core";
import { GoabBlock, GoabLink, GoabText } from "@abgov/angular-components";

@Component({
standalone: true,
selector: "abgov-bug3505",
templateUrl: "./bug3505.component.html",
imports: [GoabBlock, GoabLink, GoabText],
})
export class Bug3505Component {}
4 changes: 4 additions & 0 deletions apps/prs/react/src/app/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,10 @@ export function App() {
label="3607 Radio and Checkbox Interaction Area"
url="/bugs/3607"
/>
<GoabxWorkSideMenuItem
label="3505 Link Icon Click"
url="/bugs/3505"
/>
</GoabxWorkSideMenuGroup>

<GoabxWorkSideMenuGroup icon="star" heading="Features">
Expand Down
2 changes: 2 additions & 0 deletions apps/prs/react/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import { Bug3450Route } from "./routes/bugs/bug3450";
import { Bug3497Route } from "./routes/bugs/bug3497";
import { Bug3498Route } from "./routes/bugs/bug3498";
import { Bug3607Route } from "./routes/bugs/bug3607";
import { Bug3505Route } from "./routes/bugs/bug3505";

import { EverythingRoute } from "./routes/everything";
import { EverythingBRoute } from "./routes/everything-b";
Expand Down Expand Up @@ -149,6 +150,7 @@ root.render(
<Route path="bugs/3497" element={<Bug3497Route />} />
<Route path="bugs/3498" element={<Bug3498Route />} />
<Route path="bugs/3607" element={<Bug3607Route />} />
<Route path="bugs/3505" element={<Bug3505Route />} />

<Route path="features/1383" element={<Feat1383Route />} />
<Route path="features/1547" element={<Feat1547Route />} />
Expand Down
28 changes: 28 additions & 0 deletions apps/prs/react/src/routes/bugs/bug3505.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { GoabBlock, GoabLink, GoabText } from "@abgov/react-components";

export function Bug3505Route() {
return (
<GoabBlock direction="column" gap="l">
<GoabText tag="h1">Bug 3505 - Link icon click behavior</GoabText>

<GoabText tag="p">
Click the leading icon, trailing icon, or link text. All should open the same
target.
</GoabText>

<GoabText tag="p">
Press Tab to move focus to the link. The link should show a single outer focus
outline on the component, and the internal anchor text should not show its own
separate focus outline.
</GoabText>

<GoabLink leadingIcon="home" trailingIcon="open">
<a href="https://www.alberta.ca" target="_blank" rel="noreferrer noopener">
Alberta.ca (icon click test)
</a>
</GoabLink>
</GoabBlock>
);
}

export default Bug3505Route;
51 changes: 51 additions & 0 deletions libs/react-components/specs/link.browser.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,55 @@ describe("Link", () => {
expect(spy).toBeCalledWith({foo: "bar"});
})
})

it("should trigger the anchor when the leading icon is clicked", async () => {
const Component = () => {
return (
<GoabLink testId={"link"} leadingIcon={"home"}>
<a href="#test-anchor" data-testid="anchor">Link text</a>
</GoabLink>
);
};

const result = render(<Component />);
const link = result.getByTestId("link");
const leadingIcon = link.getByTestId("leading-icon");

const spy = vi.fn();

const anchor = result.getByTestId("anchor");
anchor.element().addEventListener("click", spy);

await leadingIcon.click();

await vi.waitFor(() => {
expect(spy).toHaveBeenCalled();
});
});

it("should trigger the anchor when the trailing icon is clicked", async () => {
const Component = () => {
return (
<GoabLink testId={"link"} trailingIcon={"home"}>
<a href="#test-anchor" data-testid="anchor">Link text</a>
</GoabLink>
);
};

const result = render(<Component />);
const link = result.getByTestId("link");
const trailingIcon = link.getByTestId("trailing-icon");

const spy = vi.fn();

const anchor = result.getByTestId("anchor");
anchor.element().addEventListener("click", spy);


await trailingIcon.click();

await vi.waitFor(() => {
expect(spy).toHaveBeenCalled();
});
});
})
27 changes: 23 additions & 4 deletions libs/web-components/src/components/link/Link.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@
e.preventDefault();
dispatch(e.target as Element, action, actionArg || actionArgs, { bubbles: true });
}

function handleIconClick() {
if (action) return; // Let click bubble to the container action handler
const host = (_rootEl.getRootNode() as ShadowRoot)?.host as HTMLElement;
host?.querySelector("a")?.click();
}
</script>

<div
Expand All @@ -75,9 +81,18 @@
style={styles(calculateMargin(mt, mr, mb, ml))}
data-testid={testid}
>
{#if leadingicon}<goa-icon data-testid="leading-icon" type={leadingicon} size={_iconSize} />{/if}

{#if leadingicon}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<goa-icon data-testid="leading-icon" type={leadingicon} size={_iconSize} on:click={handleIconClick} />
{/if}
<slot />
{#if trailingicon}<goa-icon data-testid="trailing-icon" type={trailingicon} size={_iconSize} />{/if}
{#if trailingicon}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<goa-icon data-testid="trailing-icon" type={trailingicon} size={_iconSize} on:click={handleIconClick} />
{/if}
</div>

<style>
Expand Down Expand Up @@ -186,7 +201,11 @@
outline-offset: var(--goa-link-focus-offset, var(--goa-space-3xs));
}

.link :global(::slotted(a:focus-visible)) {
outline: none;
.link :global(::slotted(a:focus-visible)),
.link :global(::slotted(a:focus-within)),
.link :global(::slotted(a:focus)) {
outline: none !important;
outline-offset: 0 !important;
box-shadow: none !important;
}
</style>
Loading