devex: Create btrix-popover component (#2632)

Add and documents new `btrix-popover` component.
This commit is contained in:
sua yoo 2025-05-28 18:29:30 -07:00 committed by GitHub
parent 7e3e8a594f
commit 9f17264aa9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 179 additions and 0 deletions

View File

@ -30,6 +30,7 @@ import("./numbered-list");
import("./overflow-dropdown");
import("./overflow-scroll");
import("./pagination");
import("./popover");
import("./pw-strength-alert");
import("./relative-duration");
import("./search-combobox");

View File

@ -0,0 +1,70 @@
import { localized } from "@lit/localize";
import SlTooltip from "@shoelace-style/shoelace/dist/components/tooltip/tooltip.component.js";
import slTooltipStyles from "@shoelace-style/shoelace/dist/components/tooltip/tooltip.styles.js";
import { css } from "lit";
import { customElement, property } from "lit/decorators.js";
/**
* Popovers are used to reveal supplementary information, like additional context or details.
* They're hidden until an anchor is activated, e.g. on hover.
*
* Popovers should be used to convey information in full sentences or complex HTML.
* To display titles, labels, and expand truncated text on hover, use `<sl-tooltip>`.
*
* @attr {String} content
* @attr {String} placement
* @attr {String} trigger
* @attr {Boolean} open
*/
@customElement("btrix-popover")
@localized()
export class Popover extends SlTooltip {
@property({ type: Boolean, reflect: true })
hoist = true;
@property({ type: String, reflect: true })
placement: SlTooltip["placement"] = "bottom";
static styles = [
slTooltipStyles,
css`
:host {
--btrix-border: 1px solid var(--sl-panel-border-color);
--sl-tooltip-background-color: var(--sl-color-neutral-0);
--sl-tooltip-color: var(--sl-color-neutral-700);
--sl-tooltip-font-size: var(--sl-font-size-x-small);
--sl-tooltip-padding: var(--sl-spacing-small);
--sl-tooltip-line-height: var(--sl-line-height-dense);
}
::part(body) {
border: var(--btrix-border);
box-shadow: var(--sl-shadow-medium);
}
::part(arrow) {
z-index: 1;
}
[placement^="bottom"]::part(arrow),
[placement^="left"]::part(arrow) {
border-top: var(--btrix-border);
}
[placement^="bottom"]::part(arrow),
[placement^="right"]::part(arrow) {
border-left: var(--btrix-border);
}
[placement^="top"]::part(arrow),
[placement^="right"]::part(arrow) {
border-bottom: var(--btrix-border);
}
[placement^="top"]::part(arrow),
[placement^="left"]::part(arrow) {
border-right: var(--btrix-border);
}
`,
];
}

View File

@ -0,0 +1,74 @@
import type { Meta, StoryObj } from "@storybook/web-components";
import { html } from "lit";
import { renderComponent, type RenderProps } from "./Popover";
const meta = {
title: "Components/Popover",
component: "btrix-popover",
tags: ["autodocs"],
decorators: (story) =>
html` <div class="px-20 py-10 text-center">${story()}</div>`,
render: renderComponent,
argTypes: {
anchor: { table: { disable: true } },
slottedContent: { table: { disable: true } },
},
args: {
content: "Popover content",
anchor: html`<btrix-badge>Hover me</btrix-badge>`,
},
} satisfies Meta<RenderProps>;
export default meta;
type Story = StoryObj<RenderProps>;
export const Basic: Story = {
args: {},
};
export const Open: Story = {
args: {
open: true,
anchor: html`<btrix-badge>Always open</btrix-badge>`,
},
};
export const TopPlacement: Story = {
args: {
open: true,
placement: "top",
anchor: html`<btrix-badge>Popover displays below</btrix-badge>`,
},
};
export const LeftPlacement: Story = {
args: {
open: true,
placement: "left",
anchor: html`<btrix-badge>Popover displays left</btrix-badge>`,
},
};
export const RightPlacement: Story = {
args: {
open: true,
placement: "right",
anchor: html`<btrix-badge>Popover displays right</btrix-badge>`,
},
};
export const HTMLContent: Story = {
args: {
open: true,
anchor: html`<btrix-badge>HTML Content</btrix-badge>`,
slottedContent: html`
<header class="font-medium leading-none">Popover Title</header>
<hr class="my-2" />
<p>
This popover has HTML content for displaying informative text or
additional details when the anchor is activated.
</p>
`,
},
};

View File

@ -0,0 +1,33 @@
import { html, nothing, type TemplateResult } from "lit";
import { ifDefined } from "lit/directives/if-defined.js";
import type { Popover } from "@/components/ui/popover";
import "@/components/ui/popover";
export type RenderProps = Popover & {
anchor: TemplateResult;
slottedContent: TemplateResult;
};
export const renderComponent = ({
content,
placement,
open,
anchor,
slottedContent,
}: Partial<RenderProps>) => {
return html`
<btrix-popover
content=${ifDefined(content)}
placement=${ifDefined(placement)}
trigger=${open ? "manual" : "hover"}
?open=${open}
>
${anchor}
${slottedContent
? html`<div slot="content">${slottedContent}</div>`
: nothing}
</btrix-popover>
`;
};

View File

@ -258,6 +258,7 @@
}
/* Style tooltip with white background */
/* TODO Replace instances with `<btrix-popover>` */
sl-tooltip.invert-tooltip {
--sl-tooltip-arrow-size: 0;
--sl-tooltip-background-color: var(--sl-color-neutral-50);