1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-10 05:13:29 +00:00

[CL-753] Update popover styles (#15838)

This commit is contained in:
Vicki League
2025-08-11 15:04:53 -04:00
committed by GitHub
parent f4d3f36c56
commit 943cdc2fbd
6 changed files with 263 additions and 171 deletions

View File

@@ -1,6 +1,6 @@
import { ConnectedPosition } from "@angular/cdk/overlay";
const ORIGIN_OFFSET_PX = 6;
const ORIGIN_OFFSET_PX = 14;
const OVERLAY_OFFSET_PX = 24;
export type PositionIdentifier =

View File

@@ -1,13 +1,13 @@
.bit-popover-arrow {
@apply tw-absolute tw-z-10 tw-h-4 tw-w-4 tw-rotate-45 tw-border-solid tw-bg-background;
@apply tw-absolute tw-z-10 tw-size-4 tw-rotate-45 tw-bg-primary-100 tw-shadow-lg;
}
.bit-popover-right .bit-popover-arrow {
@apply tw-left-1 -tw-translate-x-1/2 tw-rounded-bl-sm tw-border-b tw-border-l tw-border-b-secondary-300 tw-border-l-secondary-300;
@apply tw-left-1 -tw-translate-x-3/4 tw-rounded-bl-sm;
}
.bit-popover-left .bit-popover-arrow {
@apply tw-right-1 tw-translate-x-1/2 tw-rounded-tr-sm tw-border-r tw-border-t tw-border-r-secondary-300 tw-border-t-secondary-300;
@apply tw-right-1 tw-translate-x-3/4 tw-rounded-tr-sm;
}
.bit-popover-right-start .bit-popover-arrow,
@@ -26,11 +26,11 @@
}
.bit-popover-below .bit-popover-arrow {
@apply tw-top-1 -tw-translate-y-1/2 tw-rounded-tl-sm tw-border-l tw-border-t tw-border-l-secondary-300 tw-border-t-secondary-300;
@apply tw-top-1 -tw-translate-y-3/4 tw-rounded-tl-sm;
}
.bit-popover-above .bit-popover-arrow {
@apply tw-bottom-1 tw-translate-y-1/2 tw-rounded-br-sm tw-border-b tw-border-r tw-border-b-secondary-300 tw-border-r-secondary-300;
@apply tw-bottom-1 tw-translate-y-3/4 tw-rounded-br-sm;
}
.bit-popover-below-start .bit-popover-arrow,

View File

@@ -1,8 +1,15 @@
<ng-template>
<section cdkTrapFocus cdkTrapFocusAutoCapture class="tw-relative" role="dialog" aria-modal="true">
<div class="tw-overflow-hidden tw-rounded-xl tw-border tw-border-solid tw-border-secondary-300">
<section
cdkTrapFocus
cdkTrapFocusAutoCapture
class="tw-relative"
role="dialog"
aria-modal="true"
[attr.aria-label]="title()"
>
<div class="tw-overflow-hidden tw-rounded-xl tw-shadow-lg">
<div
class="tw-relative tw-z-20 tw-w-72 tw-break-words tw-bg-background tw-pb-4 tw-pt-2 tw-text-main"
class="tw-relative tw-z-20 tw-w-72 tw-break-words tw-bg-primary-100 tw-pb-4 tw-pt-2 tw-text-main"
>
<div class="tw-me-2 tw-flex tw-items-start tw-justify-between tw-gap-4 tw-ps-4">
<h2 bitTypography="h5" class="tw-font-semibold tw-mt-1">

View File

@@ -26,6 +26,13 @@ page.
<Primary />
## Implementation Notes
The popover should have even spacing above and below the content. If you are using element(s) inside
the popover that have built-in bottom margin, please remove the bottom margin on the last element.
<Canvas of={stories.OpenLongTitle} />
## Open on Page Load
A Popover can be set to initially open on page load by setting `[popoverOpen]="true"` on the trigger

View File

@@ -1,4 +1,5 @@
import { Meta, StoryObj, moduleMetadata } from "@storybook/angular";
import { getByRole, userEvent } from "@storybook/test";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
@@ -76,14 +77,15 @@ export const Default: Story = {
render: (args) => ({
props: args,
template: /*html*/ `
<div class="tw-mt-56">
<div class="tw-mt-44 tw-h-[400px]">
<button
type="button"
class="tw-border-none tw-bg-transparent tw-text-primary-600"
class="tw-border-none tw-bg-transparent tw-text-primary-600 tw-p-0"
[bitPopoverTriggerFor]="myPopover"
#triggerRef="popoverTrigger"
aria-label="Open popover"
title="Open popover"
bitLink
>
<i class="bwi bwi-question-circle"></i>
</button>
@@ -91,74 +93,48 @@ export const Default: Story = {
${popoverContent}
`,
}),
};
play: async (context) => {
const canvasEl = context.canvasElement;
const button = getByRole(canvasEl, "button");
export const Open: Story = {
render: (args) => ({
props: args,
template: /*html*/ `
<bit-popover [title]="'Example Title'" #myPopover="popoverComponent">
<div>Lorem ipsum dolor <a href="#" bitLink>adipisicing elit</a>.</div>
<ul class="tw-mt-2 tw-mb-0 tw-ps-4">
<li>Dolor sit amet consectetur</li>
<li>Esse labore veniam tempora</li>
<li>Adipisicing elit ipsum <a href="#" bitLink>iustolaborum</a></li>
</ul>
</bit-popover>
<div class="tw-h-40">
<div class="cdk-overlay-pane bit-popover-right bit-popover-right-start">
<ng-container *ngTemplateOutlet="myPopover.templateRef"></ng-container>
</div>
</div>
`,
}),
await userEvent.click(button);
},
};
export const OpenLongTitle: Story = {
render: (args) => ({
props: args,
template: /*html*/ `
<bit-popover [title]="'Example Title that is really long it wraps 2 lines'" #myPopover="popoverComponent">
<div>Lorem ipsum dolor <a href="#" bitLink>adipisicing elit</a>.</div>
<ul class="tw-mt-2 tw-mb-0 tw-ps-4">
<li>Dolor sit amet consectetur</li>
<li>Esse labore veniam tempora</li>
<li>Adipisicing elit ipsum <a href="#" bitLink>iustolaborum</a></li>
</ul>
</bit-popover>
<div class="tw-h-40">
<div class="cdk-overlay-pane bit-popover-right bit-popover-right-start">
<ng-container *ngTemplateOutlet="myPopover.templateRef"></ng-container>
</div>
</div>
`,
}),
};
export const InitiallyOpen: Story = {
render: (args) => ({
props: args,
template: /*html*/ `
<div class="tw-mt-56">
<div class="tw-h-[400px] tw-mt-44">
<button
type="button"
class="tw-border-none tw-bg-transparent tw-text-primary-600"
[bitPopoverTriggerFor]="myPopover"
[popoverOpen]="true"
#triggerRef="popoverTrigger"
aria-label="Open popover"
title="Open popover"
bitLink
>
<i class="bwi bwi-question-circle"></i>
</button>
</div>
${popoverContent}
<bit-popover [title]="'Example Title that is really long it wraps 2 lines'" #myPopover>
<div>Lorem ipsum dolor <a href="#" bitLink>adipisicing elit</a>.</div>
<ul class="tw-mt-2 tw-ps-4">
<li>Dolor sit amet consectetur</li>
<li>Esse labore veniam tempora</li>
<li>Adipisicing elit ipsum <a href="#" bitLink>iustolaborum</a></li>
</ul>
<p class="tw-mb-0">Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p>
</bit-popover>
`,
}),
parameters: {
chromatic: { disableSnapshot: true },
play: async (context) => {
const canvasEl = context.canvasElement;
const button = getByRole(canvasEl, "button");
await userEvent.click(button);
},
};
@@ -169,7 +145,7 @@ export const RightStart: Story = {
render: (args) => ({
props: args,
template: /*html*/ `
<div class="tw-mt-56">
<div class="tw-h-[400px] tw-mt-44">
<button
type="button"
class="tw-border-none tw-bg-transparent tw-text-primary-600"
@@ -178,6 +154,7 @@ export const RightStart: Story = {
[position]="'${args.position}'"
aria-label="Open popover"
title="Open popover"
bitLink
>
<i class="bwi bwi-question-circle"></i>
</button>
@@ -185,6 +162,12 @@ export const RightStart: Story = {
${popoverContent}
`,
}),
play: async (context) => {
const canvasEl = context.canvasElement;
const button = getByRole(canvasEl, "button");
await userEvent.click(button);
},
};
export const RightCenter: Story = {
@@ -194,7 +177,7 @@ export const RightCenter: Story = {
render: (args) => ({
props: args,
template: /*html*/ `
<div class="tw-mt-56">
<div class="tw-h-[400px] tw-mt-44">
<button
type="button"
class="tw-border-none tw-bg-transparent tw-text-primary-600"
@@ -203,6 +186,7 @@ export const RightCenter: Story = {
[position]="'${args.position}'"
aria-label="Open popover"
title="Open popover"
bitLink
>
<i class="bwi bwi-question-circle"></i>
</button>
@@ -210,6 +194,12 @@ export const RightCenter: Story = {
${popoverContent}
`,
}),
play: async (context) => {
const canvasEl = context.canvasElement;
const button = getByRole(canvasEl, "button");
await userEvent.click(button);
},
};
export const RightEnd: Story = {
@@ -219,7 +209,7 @@ export const RightEnd: Story = {
render: (args) => ({
props: args,
template: /*html*/ `
<div class="tw-mt-56">
<div class="tw-h-[400px] tw-mt-44">
<button
type="button"
class="tw-border-none tw-bg-transparent tw-text-primary-600"
@@ -228,6 +218,7 @@ export const RightEnd: Story = {
[position]="'${args.position}'"
aria-label="Open popover"
title="Open popover"
bitLink
>
<i class="bwi bwi-question-circle"></i>
</button>
@@ -235,6 +226,12 @@ export const RightEnd: Story = {
${popoverContent}
`,
}),
play: async (context) => {
const canvasEl = context.canvasElement;
const button = getByRole(canvasEl, "button");
await userEvent.click(button);
},
};
export const LeftStart: Story = {
@@ -244,22 +241,31 @@ export const LeftStart: Story = {
render: (args) => ({
props: args,
template: /*html*/ `
<div class="tw-mt-56 tw-flex tw-justify-end">
<button
type="button"
class="tw-border-none tw-bg-transparent tw-text-primary-600"
[bitPopoverTriggerFor]="myPopover"
#triggerRef="popoverTrigger"
[position]="'${args.position}'"
aria-label="Open popover"
title="Open popover"
>
<i class="bwi bwi-question-circle"></i>
</button>
<div class="tw-h-[400px] tw-mt-44">
<div class="tw-flex tw-justify-end">
<button
type="button"
class="tw-border-none tw-bg-transparent tw-text-primary-600"
[bitPopoverTriggerFor]="myPopover"
#triggerRef="popoverTrigger"
[position]="'${args.position}'"
aria-label="Open popover"
title="Open popover"
bitLink
>
<i class="bwi bwi-question-circle"></i>
</button>
</div>
</div>
${popoverContent}
`,
}),
play: async (context) => {
const canvasEl = context.canvasElement;
const button = getByRole(canvasEl, "button");
await userEvent.click(button);
},
};
export const LeftCenter: Story = {
@@ -269,22 +275,31 @@ export const LeftCenter: Story = {
render: (args) => ({
props: args,
template: /*html*/ `
<div class="tw-mt-56 tw-flex tw-justify-end">
<button
type="button"
class="tw-border-none tw-bg-transparent tw-text-primary-600"
[bitPopoverTriggerFor]="myPopover"
#triggerRef="popoverTrigger"
[position]="'${args.position}'"
aria-label="Open popover"
title="Open popover"
>
<i class="bwi bwi-question-circle"></i>
</button>
<div class="tw-h-[400px] tw-mt-44">
<div class="tw-flex tw-justify-end">
<button
type="button"
class="tw-border-none tw-bg-transparent tw-text-primary-600"
[bitPopoverTriggerFor]="myPopover"
#triggerRef="popoverTrigger"
[position]="'${args.position}'"
aria-label="Open popover"
title="Open popover"
bitLink
>
<i class="bwi bwi-question-circle"></i>
</button>
</div>
</div>
${popoverContent}
`,
}),
play: async (context) => {
const canvasEl = context.canvasElement;
const button = getByRole(canvasEl, "button");
await userEvent.click(button);
},
};
export const LeftEnd: Story = {
args: {
@@ -293,22 +308,31 @@ export const LeftEnd: Story = {
render: (args) => ({
props: args,
template: /*html*/ `
<div class="tw-mt-56 tw-flex tw-justify-end">
<button
type="button"
class="tw-border-none tw-bg-transparent tw-text-primary-600"
[bitPopoverTriggerFor]="myPopover"
#triggerRef="popoverTrigger"
[position]="'${args.position}'"
aria-label="Open popover"
title="Open popover"
>
<i class="bwi bwi-question-circle"></i>
</button>
<div class="tw-h-[400px] tw-mt-44">
<div class="tw-flex tw-justify-end">
<button
type="button"
class="tw-border-none tw-bg-transparent tw-text-primary-600"
[bitPopoverTriggerFor]="myPopover"
#triggerRef="popoverTrigger"
[position]="'${args.position}'"
aria-label="Open popover"
title="Open popover"
bitLink
>
<i class="bwi bwi-question-circle"></i>
</button>
</div>
</div>
${popoverContent}
`,
}),
play: async (context) => {
const canvasEl = context.canvasElement;
const button = getByRole(canvasEl, "button");
await userEvent.click(button);
},
};
export const BelowStart: Story = {
@@ -318,22 +342,31 @@ export const BelowStart: Story = {
render: (args) => ({
props: args,
template: /*html*/ `
<div class="tw-mt-56 tw-flex tw-justify-center">
<button
type="button"
class="tw-border-none tw-bg-transparent tw-text-primary-600"
[bitPopoverTriggerFor]="myPopover"
#triggerRef="popoverTrigger"
[position]="'${args.position}'"
aria-label="Open popover"
title="Open popover"
>
<i class="bwi bwi-question-circle"></i>
</button>
<div class="tw-h-[400px] tw-mt-44">
<div class="tw-flex tw-justify-center">
<button
type="button"
class="tw-border-none tw-bg-transparent tw-text-primary-600"
[bitPopoverTriggerFor]="myPopover"
#triggerRef="popoverTrigger"
[position]="'${args.position}'"
aria-label="Open popover"
title="Open popover"
bitLink
>
<i class="bwi bwi-question-circle"></i>
</button>
</div>
</div>
${popoverContent}
`,
}),
play: async (context) => {
const canvasEl = context.canvasElement;
const button = getByRole(canvasEl, "button");
await userEvent.click(button);
},
};
export const BelowCenter: Story = {
@@ -343,22 +376,31 @@ export const BelowCenter: Story = {
render: (args) => ({
props: args,
template: /*html*/ `
<div class="tw-mt-56 tw-flex tw-justify-center">
<button
type="button"
class="tw-border-none tw-bg-transparent tw-text-primary-600"
[bitPopoverTriggerFor]="myPopover"
#triggerRef="popoverTrigger"
[position]="'${args.position}'"
aria-label="Open popover"
title="Open popover"
>
<i class="bwi bwi-question-circle"></i>
</button>
<div class="tw-h-[400px] tw-mt-44">
<div class="tw-flex tw-justify-center">
<button
type="button"
class="tw-border-none tw-bg-transparent tw-text-primary-600"
[bitPopoverTriggerFor]="myPopover"
#triggerRef="popoverTrigger"
[position]="'${args.position}'"
aria-label="Open popover"
title="Open popover"
bitLink
>
<i class="bwi bwi-question-circle"></i>
</button>
</div>
</div>
${popoverContent}
`,
}),
play: async (context) => {
const canvasEl = context.canvasElement;
const button = getByRole(canvasEl, "button");
await userEvent.click(button);
},
};
export const BelowEnd: Story = {
@@ -368,22 +410,31 @@ export const BelowEnd: Story = {
render: (args) => ({
props: args,
template: /*html*/ `
<div class="tw-mt-56 tw-flex tw-justify-center">
<button
type="button"
class="tw-border-none tw-bg-transparent tw-text-primary-600"
[bitPopoverTriggerFor]="myPopover"
#triggerRef="popoverTrigger"
[position]="'${args.position}'"
aria-label="Open popover"
title="Open popover"
>
<i class="bwi bwi-question-circle"></i>
</button>
<div class="tw-h-[400px] tw-mt-44">
<div class="tw-flex tw-justify-center">
<button
type="button"
class="tw-border-none tw-bg-transparent tw-text-primary-600"
[bitPopoverTriggerFor]="myPopover"
#triggerRef="popoverTrigger"
[position]="'${args.position}'"
aria-label="Open popover"
title="Open popover"
bitLink
>
<i class="bwi bwi-question-circle"></i>
</button>
</div>
</div>
${popoverContent}
`,
}),
play: async (context) => {
const canvasEl = context.canvasElement;
const button = getByRole(canvasEl, "button");
await userEvent.click(button);
},
};
export const AboveStart: Story = {
@@ -393,22 +444,31 @@ export const AboveStart: Story = {
render: (args) => ({
props: args,
template: /*html*/ `
<div class="tw-mt-56 tw-flex tw-justify-center">
<button
type="button"
class="tw-border-none tw-bg-transparent tw-text-primary-600"
[bitPopoverTriggerFor]="myPopover"
#triggerRef="popoverTrigger"
[position]="'${args.position}'"
aria-label="Open popover"
title="Open popover"
>
<i class="bwi bwi-question-circle"></i>
</button>
<div class="tw-h-[400px] tw-mt-44">
<div class="tw-flex tw-justify-center">
<button
type="button"
class="tw-border-none tw-bg-transparent tw-text-primary-600"
[bitPopoverTriggerFor]="myPopover"
#triggerRef="popoverTrigger"
[position]="'${args.position}'"
aria-label="Open popover"
title="Open popover"
bitLink
>
<i class="bwi bwi-question-circle"></i>
</button>
</div>
</div>
${popoverContent}
`,
}),
play: async (context) => {
const canvasEl = context.canvasElement;
const button = getByRole(canvasEl, "button");
await userEvent.click(button);
},
};
export const AboveCenter: Story = {
@@ -418,22 +478,31 @@ export const AboveCenter: Story = {
render: (args) => ({
props: args,
template: /*html*/ `
<div class="tw-mt-56 tw-flex tw-justify-center">
<button
type="button"
class="tw-border-none tw-bg-transparent tw-text-primary-600"
[bitPopoverTriggerFor]="myPopover"
#triggerRef="popoverTrigger"
[position]="'${args.position}'"
aria-label="Open popover"
title="Open popover"
>
<i class="bwi bwi-question-circle"></i>
</button>
<div class="tw-h-[400px] tw-mt-44">
<div class="tw-flex tw-justify-center">
<button
type="button"
class="tw-border-none tw-bg-transparent tw-text-primary-600"
[bitPopoverTriggerFor]="myPopover"
#triggerRef="popoverTrigger"
[position]="'${args.position}'"
aria-label="Open popover"
title="Open popover"
bitLink
>
<i class="bwi bwi-question-circle"></i>
</button>
</div>
</div>
${popoverContent}
`,
}),
play: async (context) => {
const canvasEl = context.canvasElement;
const button = getByRole(canvasEl, "button");
await userEvent.click(button);
},
};
export const AboveEnd: Story = {
@@ -443,20 +512,29 @@ export const AboveEnd: Story = {
render: (args) => ({
props: args,
template: /*html*/ `
<div class="tw-mt-56 tw-flex tw-justify-center">
<button
type="button"
class="tw-border-none tw-bg-transparent tw-text-primary-600"
[bitPopoverTriggerFor]="myPopover"
#triggerRef="popoverTrigger"
[position]="'${args.position}'"
aria-label="Open popover"
title="Open popover"
>
<i class="bwi bwi-question-circle"></i>
</button>
<div class="tw-h-[400px] tw-mt-44">
<div class="tw-flex tw-justify-center">
<button
type="button"
class="tw-border-none tw-bg-transparent tw-text-primary-600"
[bitPopoverTriggerFor]="myPopover"
#triggerRef="popoverTrigger"
[position]="'${args.position}'"
aria-label="Open popover"
title="Open popover"
bitLink
>
<i class="bwi bwi-question-circle"></i>
</button>
</div>
</div>
${popoverContent}
`,
}),
play: async (context) => {
const canvasEl = context.canvasElement;
const button = getByRole(canvasEl, "button");
await userEvent.click(button);
},
};

View File

@@ -87,7 +87,7 @@
--color-background-alt3: 48 57 70;
--color-background-alt4: 18 26 39;
--color-primary-100: 26 39 78;
--color-primary-100: 29 46 99;
--color-primary-300: 26 65 172;
--color-primary-600: 101 171 255;
--color-primary-700: 170 195 239;