Skip to content

Commit 3fd72e2

Browse files
committed
feat(#3340): add click handling to work side menu item
1 parent b91c3c7 commit 3fd72e2

10 files changed

Lines changed: 189 additions & 19 deletions

File tree

apps/prs/angular/src/app/app.routes.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ import { Feat3241Component } from "../routes/features/feat3241/feat3241.componen
6262
import { FeatV2IconsComponent } from "../routes/features/featV2Icons/feat-v2-icons.component";
6363
import { Feat3137Component } from "../routes/features/feat3137/feat3137.component";
6464
import { Feat3306Component } from "../routes/features/feat3306/feat3306.component";
65+
import { Feat3340Component } from "../routes/features/feat3340/feat3340.component";
6566

6667
export const appRoutes: Route[] = [
6768
{ path: "everything", component: EverythingComponent },
@@ -128,4 +129,5 @@ export const appRoutes: Route[] = [
128129
{ path: "features/3137", component: Feat3137Component },
129130
{ path: "features/1908", component: Feat1908Component },
130131
{ path: "features/3306", component: Feat3306Component },
132+
{ path: "features/3340", component: Feat3340Component },
131133
];

apps/prs/angular/src/routes/features/feat3340/feat3340.component.css

Whitespace-only changes.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<h1>Feature 3340: Work Side Menu Item Click Handling</h1>
2+
3+
<p>
4+
This demonstrates handling click events on items within a
5+
<code>goabx-work-side-menu</code> component.
6+
</p>
7+
8+
<p>
9+
Total item clicks:
10+
<strong>{{ itemClicks }}</strong>
11+
</p>
12+
13+
<goabx-work-side-menu
14+
heading="Menu heading"
15+
url="#"
16+
[primaryContent]="primaryTemplate"
17+
[open]="true"
18+
>
19+
</goabx-work-side-menu>
20+
21+
<ng-template #primaryTemplate>
22+
<goabx-work-side-menu-item label="Menu item 1" icon="star" (click)="onItemClick()" />
23+
<goabx-work-side-menu-item label="Menu item 2" icon="star" (click)="onItemClick()" />
24+
<goabx-work-side-menu-item label="Menu item 3" icon="star" (click)="onItemClick()" />
25+
</ng-template>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { CommonModule } from "@angular/common";
2+
import { Component } from "@angular/core";
3+
import {
4+
GoabxWorkSideMenu,
5+
GoabxWorkSideMenuGroup,
6+
GoabxWorkSideMenuItem,
7+
} from "@abgov/angular-components";
8+
9+
@Component({
10+
standalone: true,
11+
selector: "abgov-feat3340",
12+
templateUrl: "./feat3340.component.html",
13+
styleUrls: ["./feat3340.component.css"],
14+
imports: [
15+
CommonModule,
16+
GoabxWorkSideMenu,
17+
GoabxWorkSideMenuGroup,
18+
GoabxWorkSideMenuItem,
19+
],
20+
})
21+
export class Feat3340Component {
22+
itemClicks = 0;
23+
24+
onItemClick(): void {
25+
this.itemClicks += 1;
26+
}
27+
}

apps/prs/react/src/app/app.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ export function App() {
8888
<Link to="/features/v2-icons">v2 header icons</Link>
8989
<Link to="/features/3137">3137 Work Side Menu Group</Link>
9090
<Link to="/features/3306">3306 Custom slug value for tabs</Link>
91+
<Link to="/features/3340">3340 Work Side Menu Item Click</Link>
9192
</GoabSideMenuGroup>
9293
<GoabSideMenuGroup heading="Everything">
9394
<Link to="/everything">A</Link>

apps/prs/react/src/main.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ import { Feat3241Route } from "./routes/features/feat3241";
6767
import { FeatV2IconsRoute } from "./routes/features/featV2Icons";
6868
import { Feat3137Route } from "./routes/features/feat3137";
6969
import Feat3306Route from "./routes/features/feat3306";
70+
import Feat3340Route from "./routes/features/feat3340";
7071

7172
const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement);
7273

@@ -142,6 +143,7 @@ root.render(
142143
<Route path="features/3137" element={<Feat3137Route />} />
143144
<Route path="features/1908" element={<Feat1908Route />} />
144145
<Route path="features/3306" element={<Feat3306Route />} />
146+
<Route path="features/3340" element={<Feat3340Route />} />
145147
</Route>
146148
</Routes>
147149
</BrowserRouter>
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import React, { useCallback, useMemo, useState } from "react";
2+
import { GoabButton, GoabContainer, GoabText } from "@abgov/react-components";
3+
import {
4+
GoabxWorkSideMenu,
5+
GoabxWorkSideMenuGroup,
6+
GoabxWorkSideMenuItem,
7+
} from "@abgov/react-components/experimental";
8+
9+
export function Feat3340Route() {
10+
const [itemClicks, setItemClicks] = useState(0);
11+
12+
const onItemClick = function () {
13+
console.log("Menu item clicked");
14+
setItemClicks((prev) => prev + 1);
15+
};
16+
return (
17+
<div
18+
style={{
19+
display: "flex",
20+
flexDirection: "column",
21+
gap: "var(--goa-spacing-xl)",
22+
}}
23+
>
24+
<h1>Feature 3340: Work Side Menu Item Click Handling</h1>
25+
26+
<p>
27+
This demonstrates handling click events on items within a
28+
<code>goabx-work-side-menu</code> component.
29+
</p>
30+
31+
<GoabText as="p" size="body-m">
32+
Total item clicks: <strong>{itemClicks}</strong>
33+
</GoabText>
34+
35+
<GoabxWorkSideMenu
36+
heading="Menu heading"
37+
url="#"
38+
open={true}
39+
primaryContent={
40+
<>
41+
<GoabxWorkSideMenuItem
42+
label="Menu item 1"
43+
icon="star"
44+
onClick={onItemClick}
45+
/>
46+
<GoabxWorkSideMenuItem
47+
label="Menu item 2"
48+
icon="star"
49+
onClick={onItemClick}
50+
/>
51+
<GoabxWorkSideMenuItem
52+
label="Menu item 3"
53+
icon="star"
54+
onClick={onItemClick}
55+
/>
56+
</>
57+
}
58+
/>
59+
</div>
60+
);
61+
}
62+
63+
export default Feat3340Route;

libs/angular-components/src/experimental/work-side-menu-item/work-side-menu-item.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import {
33
CUSTOM_ELEMENTS_SCHEMA,
44
Component,
55
Input,
6+
Output,
7+
EventEmitter,
68
OnInit,
79
ChangeDetectorRef,
810
} from "@angular/core";
@@ -23,6 +25,7 @@ import { CommonModule } from "@angular/common";
2325
[attr.icon]="icon"
2426
[attr.testid]="testId"
2527
[attr.type]="type"
28+
(_click)="_onClick()"
2629
>
2730
<ng-content />
2831
</goa-work-side-menu-item>
@@ -31,14 +34,16 @@ import { CommonModule } from "@angular/common";
3134
})
3235
export class GoabxWorkSideMenuItem implements OnInit {
3336
@Input({ required: true }) label!: string;
34-
@Input({ required: true }) url!: string;
37+
@Input() url?: string;
3538
@Input() badge?: string;
3639
@Input() current?: boolean;
3740
@Input() divider?: boolean;
3841
@Input() icon?: string;
3942
@Input() testId?: string;
4043
@Input() type?: GoabWorkSideMenuItemType = "normal";
4144

45+
@Output() onClick = new EventEmitter();
46+
4247
isReady = false;
4348

4449
constructor(private cdr: ChangeDetectorRef) {}
@@ -51,4 +56,8 @@ export class GoabxWorkSideMenuItem implements OnInit {
5156
this.cdr.detectChanges();
5257
}, 0);
5358
}
59+
60+
_onClick() {
61+
this.onClick.emit();
62+
}
5463
}

libs/react-components/src/experimental/work-side-menu-item/work-side-menu-item.tsx

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { type JSX } from "react";
1+
import { useEffect, useRef, type JSX } from "react";
22
import { GoabWorkSideMenuItemType } from "@abgov/ui-components-common";
33
interface WCProps {
44
label: string;
5-
url: string;
5+
url?: string;
66
badge?: string;
77
current?: string;
88
divider?: string;
@@ -15,36 +15,68 @@ declare module "react" {
1515
// eslint-disable-next-line @typescript-eslint/no-namespace
1616
namespace JSX {
1717
interface IntrinsicElements {
18-
"goa-work-side-menu-item": WCProps & React.HTMLAttributes<HTMLElement>;
18+
"goa-work-side-menu-item": WCProps &
19+
React.HTMLAttributes<HTMLElement> & {
20+
ref: React.RefObject<HTMLElement | null>;
21+
};
1922
}
2023
}
2124
}
2225

2326
export interface GoabWorkSideMenuItemProps {
2427
label: string;
25-
url: string;
28+
url?: string;
2629
badge?: string;
2730
current?: boolean;
2831
divider?: boolean;
2932
icon?: string;
3033
testId?: string;
3134
type?: GoabWorkSideMenuItemType;
3235
children?: React.ReactNode;
36+
onCLick?: () => void;
3337
}
3438

35-
export function GoabxWorkSideMenuItem(props: GoabWorkSideMenuItemProps): JSX.Element {
39+
export function GoabxWorkSideMenuItem({
40+
label,
41+
url,
42+
badge,
43+
current,
44+
divider,
45+
icon,
46+
testId,
47+
type,
48+
children,
49+
onClick,
50+
}: GoabWorkSideMenuItemProps): JSX.Element {
51+
const el = useRef<HTMLElement>(null);
52+
53+
useEffect(() => {
54+
if (!el.current) return;
55+
if (!onClick) return;
56+
const current = el.current;
57+
const listener = () => {
58+
onClick?.();
59+
};
60+
61+
current.addEventListener("_click", listener);
62+
return () => {
63+
current.removeEventListener("_click", listener);
64+
};
65+
}, [el, onClick]);
66+
3667
return (
3768
<goa-work-side-menu-item
38-
label={props.label}
39-
url={props.url}
40-
badge={props.badge}
41-
current={props.current ? "true" : undefined}
42-
divider={props.divider ? "true" : undefined}
43-
icon={props.icon}
44-
testid={props.testId}
45-
type={props.type}
69+
ref={el}
70+
label={label}
71+
url={url}
72+
badge={badge}
73+
current={current ? "true" : undefined}
74+
divider={divider ? "true" : undefined}
75+
icon={icon}
76+
testid={testId}
77+
type={type}
4678
>
47-
{props.children}
79+
{children}
4880
</goa-work-side-menu-item>
4981
);
5082
}

libs/web-components/src/components/work-side-menu/WorkSideMenuItem.svelte

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
/** The text label displayed for the menu item. */
1414
export let label: string;
1515
/** The URL the menu item links to. */
16-
export let url: string;
16+
export let url: string = "";
1717
1818
// optional
1919
/** Badge text displayed alongside the menu item (e.g., notification count). */
@@ -61,8 +61,9 @@
6161
// Functions
6262
// *********
6363
64-
function handleClick() {
64+
function handleClick(e: Event) {
6565
dispatch(_rootEl, "_update", {}, { bubbles: true });
66+
dispatch(_rootEl, "_click", {}, { bubbles: true });
6667
}
6768
6869
function handleUpdateItem(e: CustomEvent) {
@@ -104,7 +105,8 @@
104105
on:mouseenter={handleMouseEnter}
105106
bind:this={_rootEl}
106107
>
107-
<a
108+
<svelte:element
109+
this={url ? "a" : "button"}
108110
class="menu-item"
109111
class:current
110112
aria-current={current ? "page" : undefined}
@@ -138,7 +140,7 @@
138140
{badge}
139141
</div>
140142
{/if}
141-
</a>
143+
</svelte:element>
142144
</div>
143145

144146
<style>
@@ -196,6 +198,13 @@
196198
margin-top: var(--goa-space-3xs);
197199
}
198200
201+
button.menu-item {
202+
border: none;
203+
width: 100%;
204+
text-align: left;
205+
background-color: transparent;
206+
}
207+
199208
/* Divider */
200209
.divider {
201210
padding-bottom: var(--goa-space-s);

0 commit comments

Comments
 (0)