Skip to content

Commit b3014dd

Browse files
2nd approach
1 parent 8d19761 commit b3014dd

4 files changed

Lines changed: 130 additions & 142 deletions

File tree

apps/prs/react/src/routes/features/feat2885.tsx

Lines changed: 34 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -148,15 +148,15 @@ export function Feat2885Route() {
148148
prev.map((notif) =>
149149
notif.id === id && notif.readStatus === "unread"
150150
? { ...notif, readStatus: "read" as const }
151-
: notif
152-
)
151+
: notif,
152+
),
153153
);
154154
};
155155

156156
const handleMarkAllRead = () => {
157157
console.log("Mark all as read clicked");
158158
setNotifications((prev) =>
159-
prev.map((notif) => ({ ...notif, readStatus: "read" as const }))
159+
prev.map((notif) => ({ ...notif, readStatus: "read" as const })),
160160
);
161161
};
162162

@@ -176,11 +176,7 @@ export function Feat2885Route() {
176176
onToggle={() => setMenuOpen((prev) => !prev)}
177177
primaryContent={
178178
<>
179-
<GoabxWorkSideMenuItem
180-
icon="grid"
181-
label="Dashboard"
182-
url="/features/2885"
183-
/>
179+
<GoabxWorkSideMenuItem icon="grid" label="Dashboard" url="/features/2885" />
184180
<GoabxWorkSideMenuItem
185181
icon="search"
186182
label="Search"
@@ -211,11 +207,15 @@ export function Feat2885Route() {
211207
<h3 style={{ margin: "0 0 0.5rem 0", fontSize: "1rem" }}>
212208
Custom Popover Content
213209
</h3>
214-
<p style={{ margin: "0 0 1rem 0", color: "#666", fontSize: "0.875rem" }}>
215-
This demonstrates that <code>popoverContent</code> accepts any React node,
216-
not just <code>GoabxWorkSideNotificationPanel</code>.
210+
<p
211+
style={{ margin: "0 0 1rem 0", color: "#666", fontSize: "0.875rem" }}
212+
>
213+
This demonstrates that <code>popoverContent</code> accepts any React
214+
node, not just <code>GoabxWorkSideNotificationPanel</code>.
217215
</p>
218-
<ul style={{ margin: "0", paddingLeft: "1.25rem", fontSize: "0.875rem" }}>
216+
<ul
217+
style={{ margin: "0", paddingLeft: "1.25rem", fontSize: "0.875rem" }}
218+
>
219219
<li>Custom alerts</li>
220220
<li>Quick actions</li>
221221
<li>Mini dashboards</li>
@@ -274,11 +274,7 @@ export function Feat2885Route() {
274274
label="Settings"
275275
url="/features/2885/settings"
276276
/>
277-
<GoabxWorkSideMenuItem
278-
icon="log-out"
279-
label="Log out"
280-
url="/logout"
281-
/>
277+
<GoabxWorkSideMenuItem icon="log-out" label="Log out" url="/logout" />
282278
</>
283279
}
284280
/>
@@ -293,11 +289,7 @@ export function Feat2885Route() {
293289
>
294290
{/* Mobile menu toggle button */}
295291
<div className="mobile-menu-toggle">
296-
<GoabIconButton
297-
icon="menu"
298-
variant="dark"
299-
onClick={() => setMenuOpen(true)}
300-
/>
292+
<GoabIconButton icon="menu" variant="dark" onClick={() => setMenuOpen(true)} />
301293
</div>
302294
<style>{`
303295
.mobile-menu-toggle {
@@ -316,28 +308,28 @@ export function Feat2885Route() {
316308

317309
<h1>Feature #2885: Work Side Menu with Notification Popover</h1>
318310
<p>
319-
This demonstrates the <code>GoabxWorkSideMenu</code> with the new
320-
notification popover feature.
311+
This demonstrates the <code>GoabxWorkSideMenu</code> with the new notification
312+
popover feature.
321313
</p>
322314

323315
<h2>New Features</h2>
324316
<ul>
325317
<li>
326-
<strong>Notification Popover</strong> - Click the "Notifications"
327-
menu item to see the popover panel
318+
<strong>Notification Popover</strong> - Click the "Notifications" menu item to
319+
see the popover panel
328320
</li>
329321
<li>
330-
<strong>Custom Popover Content</strong> - Click the "Alerts"
331-
menu item to see a custom div, demonstrating that{" "}
332-
<code>popoverContent</code> accepts any React node
322+
<strong>Custom Popover Content</strong> - Click the "Alerts" menu item to see
323+
a custom div, demonstrating that <code>popoverContent</code> accepts any React
324+
node
333325
</li>
334326
<li>
335-
<strong>GoabxWorkSideNotificationPanel</strong> - Panel with tabs
336-
(Unread, Urgent, All)
327+
<strong>GoabxWorkSideNotificationPanel</strong> - Panel with tabs (Unread,
328+
Urgent, All)
337329
</li>
338330
<li>
339-
<strong>GoabxWorkSideNotificationItem</strong> - Individual
340-
notification cards with:
331+
<strong>GoabxWorkSideNotificationItem</strong> - Individual notification cards
332+
with:
341333
<ul>
342334
<li>Title and description</li>
343335
<li>Smart timestamp formatting (e.g., "5 min ago", "2 h ago")</li>
@@ -347,16 +339,15 @@ export function Feat2885Route() {
347339
</ul>
348340
</li>
349341
<li>
350-
<strong>Footer actions</strong> - "View all" and "Mark all as read"
351-
buttons
342+
<strong>Footer actions</strong> - "View all" and "Mark all as read" buttons
352343
</li>
353344
</ul>
354345

355346
<h2>Existing Features</h2>
356347
<ul>
357348
<li>
358-
<strong>Collapsible menu</strong> - Click the toggle button at the
359-
bottom to expand/collapse
349+
<strong>Collapsible menu</strong> - Click the toggle button at the bottom to
350+
expand/collapse
360351
</li>
361352
<li>
362353
<strong>Primary content slot</strong> - Main navigation items
@@ -366,12 +357,12 @@ export function Feat2885Route() {
366357
(notifications, help)
367358
</li>
368359
<li>
369-
<strong>Account content slot</strong> - User account menu (click
370-
profile to show)
360+
<strong>Account content slot</strong> - User account menu (click profile to
361+
show)
371362
</li>
372363
<li>
373-
<strong>Badges</strong> - Notification counts with different types
374-
(success, emergency)
364+
<strong>Badges</strong> - Notification counts with different types (success,
365+
emergency)
375366
</li>
376367
<li>
377368
<strong>Dividers</strong> - Visual separation between menu groups
@@ -397,8 +388,8 @@ export function Feat2885Route() {
397388

398389
<h2>Console Output</h2>
399390
<p>
400-
Open the browser console to see events when clicking notifications or
401-
footer actions.
391+
Open the browser console to see events when clicking notifications or footer
392+
actions.
402393
</p>
403394
</main>
404395
</div>

libs/web-components/src/components/badge/Badge.svelte

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
type BadgeType = (typeof Types)[number];
7878
type BadgeSize = (typeof badgeSizes)[number];
7979
type BadgeVersion = (typeof versions)[number];
80+
type BadgeJustifyContent = "center" | "flex-start" | "flex-end" | "space-between";
8081
8182
/** Defines the context and colour of the badge. */
8283
export let type: BadgeType;
@@ -110,8 +111,8 @@
110111
111112
/** min-width value for the badge container (e.g. "20px", "var(--goa-space-m)"). */
112113
export let minWidth: string = "";
113-
/** justify-content value for the badge container (e.g. "center", "flex-start"). */
114-
export let justifyContent: string = "";
114+
/** justify-content value for the badge container. */
115+
export let justifyContent: BadgeJustifyContent | "" = "";
115116
116117
// private
117118
// Show icon unless explicitly disabled, when either icon=true or icontype is provided

libs/web-components/src/components/popover/Popover.svelte

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
tag: "goa-popover",
44
props: {
55
open: { reflect: true, type: "String" },
6-
targetWidth: { type: "String", attribute: "target-width" },
7-
targetTextAlign: { type: "String", attribute: "target-text-align" },
86
},
97
}}
108
/>
@@ -26,7 +24,7 @@
2624
/** Sets a data-testid attribute for automated testing. */
2725
export let testid: string = "popover";
2826
/** Provides control to where the popover content is positioned. */
29-
export let position: "above" | "below" | "auto" | "right" = "auto";
27+
export let position: "above" | "below" | "right" | "auto" = "auto";
3028
/** Sets the maximum width of the popover container. */
3129
export let maxwidth: string | "none" = "320px";
3230
/** Sets the minimum width of the popover container. */
@@ -63,10 +61,6 @@
6361
export let focusborderwidth = "var(--goa-border-width-l)";
6462
/** Border radius of the popover window. */
6563
export let borderradius = "var(--goa-border-radius-m)";
66-
/** Width of the popover target button. */
67-
export let targetWidth = "";
68-
/** Text alignment of the popover target button. */
69-
export let targetTextAlign = "";
7064
/** Indicates the popover is used within a filterable context like a combobox. */
7165
export let filterablecontext: string = "false";
7266
@@ -209,11 +203,11 @@
209203
// Dispatch _open/_close events for consumer components
210204
// (MenuButton, AppHeader, AppHeaderMenu, Dropdown)
211205
if (_isOpen) {
212-
dispatch(_rootEl, "_open");
213-
requestAnimationFrame(updateAutoPosition); // same vs await tick(), make sure popover element is fully rendered before we measure its dimension
206+
dispatch(_rootEl, "_open", {}, { bubbles: true });
207+
requestAnimationFrame(() => requestAnimationFrame(updateAutoPosition)); // double rAF: give slot content (web components) one extra frame to render before measuring height
214208
} else {
215209
_targetEl.focus();
216-
dispatch(_rootEl, "_close");
210+
dispatch(_rootEl, "_close", {}, { bubbles: true });
217211
}
218212
}
219213
@@ -235,12 +229,16 @@
235229
} else {
236230
_popoverEl.showPopover();
237231
_isOpen = true;
238-
requestAnimationFrame(updateAutoPosition);
232+
requestAnimationFrame(() => requestAnimationFrame(updateAutoPosition));
239233
}
240234
}
241235
242236
function updateAutoPosition() {
243-
if (position !== "auto" || !_isOpen || !_targetEl || !_popoverEl) {
237+
if (!_isOpen || !_targetEl || !_popoverEl) {
238+
return;
239+
}
240+
241+
if (position !== "auto") {
244242
return;
245243
}
246244
@@ -260,8 +258,7 @@
260258
bind:this={_rootEl}
261259
data-testid={testid}
262260
style={styles(
263-
// Use block display when targetWidth is customized so width property works
264-
targetWidth ? "display: block" : "display: inline-block",
261+
"display: inline-block",
265262
height === "full" && "height: 100%;",
266263
calculateMargin(mt, mr, mb, ml),
267264
style("--offset-top", voffset),
@@ -270,9 +267,7 @@
270267
style("--offset-right", hoffset),
271268
style("--focus-border-width", focusborderwidth),
272269
style("--border-radius", borderradius),
273-
targetWidth && style("--target-width", targetWidth),
274-
targetTextAlign && style("--target-text-align", targetTextAlign),
275-
!targetWidth && style("width", width),
270+
style("width", width),
276271
)}
277272
>
278273
<button
@@ -304,9 +299,9 @@
304299
(position === "auto" && _autoPosition === "below")}
305300
class:position-right={position === "right"}
306301
style={styles(
307-
style("width", width),
302+
style("width", position !== "right" ? width : undefined),
308303
style("min-width", minwidth),
309-
style("max-width", width ? `max(${width}, ${maxwidth})` : maxwidth),
304+
style("max-width", position !== "right" && width ? `max(${width}, ${maxwidth})` : maxwidth),
310305
style("padding", _padded ? "var(--goa-space-m)" : "0"),
311306
)}
312307
>
@@ -336,8 +331,8 @@
336331
border: none;
337332
padding: 0;
338333
background-color: transparent;
339-
width: var(--target-width, inherit);
340-
text-align: var(--target-text-align, inherit);
334+
width: inherit;
335+
text-align: inherit;
341336
anchor-name: --goa-popover-target;
342337
}
343338
@@ -381,11 +376,12 @@
381376
}
382377
383378
.popover-content.position-right {
384-
inset-block-start: anchor(top);
379+
inset-block-start: unset;
380+
inset-block-end: anchor(bottom);
385381
inset-inline-start: anchor(right);
386-
--popover-translate-x: var(--offset-left, 0);
387-
--popover-translate-y: var(--offset-top, 0);
388-
position-try-fallbacks: flip-inline;
382+
--popover-translate-x: var(--offset-left, 8px);
383+
--popover-translate-y: 0;
384+
position-try-fallbacks: none;
389385
}
390386
391387
:global(::slotted(ul)) {

0 commit comments

Comments
 (0)