mirror of
https://github.com/shoelace-style/webawesome.git
synced 2026-01-12 04:09:12 +00:00
Add <wa-popover> (#1012)
* remove redundant styles from template * rotate arrow based on placement so borders show correctly when applied * use actual placement, not preferred * add popover * update changelog * update changelog * use <dialog> for popover * fix arrow border in FF/Safari * update content * add sidebar to plop * add popover
This commit is contained in:
@@ -137,6 +137,7 @@
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="/docs/components/mutation-observer/">Mutation Observer</a></li>
|
||||
<li><a href="/docs/components/popover/">Popover</a></li>
|
||||
<li><a href="/docs/components/popup/">Popup</a></li>
|
||||
<li><a href="/docs/components/progress-bar/">Progress Bar</a></li>
|
||||
<li><a href="/docs/components/progress-ring/">Progress Ring</a></li>
|
||||
@@ -174,6 +175,7 @@
|
||||
<li><a href="/docs/components/tooltip/">Tooltip</a></li>
|
||||
<li><a href="/docs/components/tree/">Tree</a></li>
|
||||
<li><a href="/docs/components/tree-item/">Tree Item</a></li>
|
||||
{# PLOP_NEW_COMPONENT_PLACEHOLDER #}
|
||||
</ul>
|
||||
</wa-details>
|
||||
|
||||
|
||||
143
packages/webawesome/docs/docs/components/popover.md
Normal file
143
packages/webawesome/docs/docs/components/popover.md
Normal file
@@ -0,0 +1,143 @@
|
||||
---
|
||||
title: Popover
|
||||
layout: component
|
||||
---
|
||||
|
||||
Popovers display interactive content when their anchor element is clicked. Unlike [tooltips](/docs/components/tooltip), popovers can contain links, buttons, and form controls. They appear without an overlay and will close when you click outside or press [[Escape]]. Only one popover can be open at a time.
|
||||
|
||||
```html {.example}
|
||||
<wa-popover for="popover__overview">
|
||||
<div style="display: flex; flex-direction: column; gap: 1rem;">
|
||||
<p>This popover contains interactive content that users can engage with directly.</p>
|
||||
<wa-button variant="primary" size="small">Take Action</wa-button>
|
||||
</div>
|
||||
</wa-popover>
|
||||
|
||||
<wa-button id="popover__overview">Show popover</wa-button>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Assigning an Anchor
|
||||
|
||||
Use `<wa-button>` or `<button>` elements as popover anchors. Connect the popover to its anchor by setting the `for` attribute to match the anchor's `id`.
|
||||
|
||||
```html {.example}
|
||||
<wa-button id="popover__anchor-button">Show Popover</wa-button>
|
||||
|
||||
<wa-popover for="popover__anchor-button">
|
||||
I'm anchored to a Web Awesome button.
|
||||
</wa-popover>
|
||||
|
||||
<br><br>
|
||||
|
||||
<button id="popover__anchor-native-button">Show Popover</button>
|
||||
|
||||
<wa-popover for="popover__anchor-native-button">
|
||||
I'm anchored to a native button.
|
||||
</wa-popover>
|
||||
```
|
||||
|
||||
:::warning
|
||||
Make sure the anchor element exists in the DOM before the popover connects. If it doesn't exist, the popover won't attach and you'll see a console warning.
|
||||
:::
|
||||
|
||||
### Opening and Closing
|
||||
|
||||
Popovers show when you click their anchor element. You can also control them programmatically by setting the `open` property to `true` or `false`.
|
||||
|
||||
Use `data-popover="close"` on any button inside a popover to close it automatically.
|
||||
|
||||
```html {.example}
|
||||
<wa-popover for="popover__opening">
|
||||
<p>The button below has <code>data-popover="close"</code> so clicking it will close the popover.</p>
|
||||
<wa-button data-popover="close" variant="primary">Dismiss</wa-button>
|
||||
</wa-popover>
|
||||
|
||||
<wa-button id="popover__opening">Show popover</wa-button>
|
||||
```
|
||||
|
||||
### Placement
|
||||
|
||||
Use the `placement` attribute to set where the popover appears relative to its anchor. The popover will automatically reposition if there isn't enough space in the preferred location. The default placement is `top`.
|
||||
|
||||
```html {.example}
|
||||
<div style="display: flex; gap: 1rem; align-items: center;">
|
||||
<wa-button id="popover__top">Top</wa-button>
|
||||
<wa-popover for="popover__top" placement="top">I'm on the top</wa-popover>
|
||||
|
||||
<wa-button id="popover__bottom">Bottom</wa-button>
|
||||
<wa-popover for="popover__bottom" placement="bottom">I'm on the bottom</wa-popover>
|
||||
|
||||
<wa-button id="popover__left">Left</wa-button>
|
||||
<wa-popover for="popover__left" placement="left">I'm on the left</wa-popover>
|
||||
|
||||
<wa-button id="popover__right">Right</wa-button>
|
||||
<wa-popover for="popover__right" placement="right">I'm on the right</wa-popover>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Distance
|
||||
|
||||
Use the `distance` attribute to control how far the popover appears from its anchor.
|
||||
|
||||
```html {.example}
|
||||
<div style="display: flex; gap: 1rem; align-items: center;">
|
||||
<wa-button id="popover__distance-near">Near</wa-button>
|
||||
<wa-popover for="popover__distance-near" distance="0">I'm very close</wa-popover>
|
||||
|
||||
<wa-button id="popover__distance-far">Far</wa-button>
|
||||
<wa-popover for="popover__distance-far" distance="30">I'm farther away</wa-popover>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Arrow Size
|
||||
|
||||
Use the `--arrow-size` custom property to change the size of the popover's arrow. Set it to `0` to remove the arrow entirely.
|
||||
|
||||
```html {.example}
|
||||
<div style="display: flex; gap: 1rem; align-items: center;">
|
||||
<wa-button id="popover__big-arrow">Big arrow</wa-button>
|
||||
<wa-popover for="popover__big-arrow" style="--arrow-size: 8px;">I have a big arrow</wa-popover>
|
||||
|
||||
<wa-button id="popover__no-arrow">No arrow</wa-button>
|
||||
<wa-popover for="popover__no-arrow" style="--arrow-size: 0;">I don't have an arrow</wa-popover>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Setting a Maximum Width
|
||||
|
||||
Use the `--max-width` custom property to control the maximum width of the popover.
|
||||
|
||||
```html {.example}
|
||||
<wa-button id="popover__max-width">Toggle me</wa-button>
|
||||
<wa-popover for="popover__max-width" style="--max-width: 160px;">
|
||||
Popovers will usually grow to be much wider, but this one has a custom max width that forces text to wrap.
|
||||
</wa-popover>
|
||||
```
|
||||
|
||||
### Setting Focus
|
||||
|
||||
Use the [`autofocus`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autofocus) global attribute to move focus to a specific form control when the popover opens.
|
||||
|
||||
```html {.example}
|
||||
<wa-popover for="popover__autofocus">
|
||||
<div style="display: flex; flex-direction: column; gap: 1rem;">
|
||||
<wa-textarea
|
||||
autofocus
|
||||
placeholder="What's on your mind?"
|
||||
size="small"
|
||||
resize="none"
|
||||
rows="3"
|
||||
></wa-textarea>
|
||||
<wa-button variant="primary" size="small" data-popover="close">
|
||||
Submit
|
||||
</wa-button>
|
||||
</div>
|
||||
</wa-popover>
|
||||
|
||||
<wa-button id="popover__autofocus">
|
||||
<wa-icon name="comment" slot="prefix"></wa-icon>
|
||||
Feedback
|
||||
</wa-button>
|
||||
```
|
||||
@@ -31,6 +31,7 @@ During the alpha period, things might break! We take breaking changes very serio
|
||||
- `<wa-tab-group no-scroll-controls>` => `<wa-tab-group without-scroll-controls>`
|
||||
- `<wa-tag removable>` => `<wa-tag with-remove>`
|
||||
- 🚨 BREAKING: removed the `size` attribute from `<wa-card>`; please set the size of child elements on the children directly
|
||||
- Added a new free component: `<wa-popover>` (#2 of 14 per stretch goals)
|
||||
- Added a `min-block-size` to `<wa-divider orientation="vertical">` to ensure the divider is visible regardless of container height [issue:675]
|
||||
- Fixed a bug in `<wa-radio-group>` that caused radios to uncheck when assigning a numeric value [issue:924]
|
||||
- Fixed `<wa-button-group>` so dividers properly show between buttons
|
||||
|
||||
@@ -50,6 +50,12 @@ export default function (plop) {
|
||||
path: '../../docs/docs/components/{{ tagWithoutPrefix tag }}.md',
|
||||
templateFile: 'templates/component/docs.hbs',
|
||||
},
|
||||
{
|
||||
type: 'modify',
|
||||
path: '../../docs/_includes/sidebar.njk',
|
||||
pattern: /\{# PLOP_NEW_COMPONENT_PLACEHOLDER #\}/,
|
||||
template: `<li><a href="/docs/components/{{ tagWithoutPrefix tag }}">{{ tagToTitle tag }}</a></li>\n {# PLOP_NEW_COMPONENT_PLACEHOLDER #}`,
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import { html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { watch } from '../../internal/watch.js';
|
||||
import WebAwesomeElement from '../../internal/webawesome-element.js';
|
||||
import componentStyles from '../../styles/component/host.css';
|
||||
import styles from './{{ tagWithoutPrefix tag }}.css';
|
||||
|
||||
/**
|
||||
@@ -22,7 +21,7 @@ import styles from './{{ tagWithoutPrefix tag }}.css';
|
||||
*/
|
||||
@customElement("{{ tag }}")
|
||||
export default class {{ properCase tag }} extends WebAwesomeElement {
|
||||
static shadowStyle = [componentStyles, styles];
|
||||
static shadowStyle = styles;
|
||||
|
||||
/** An example attribute. */
|
||||
@property() attr = 'example';
|
||||
|
||||
91
packages/webawesome/src/components/popover/popover.css
Normal file
91
packages/webawesome/src/components/popover/popover.css
Normal file
@@ -0,0 +1,91 @@
|
||||
:host {
|
||||
--arrow-size: 0.375rem;
|
||||
--max-width: 25rem;
|
||||
--show-duration: 100ms;
|
||||
--hide-duration: 100ms;
|
||||
|
||||
/* Internal calculated properties */
|
||||
--arrow-diagonal-size: calc((var(--arrow-size) * sin(45deg)));
|
||||
|
||||
display: contents;
|
||||
|
||||
/** Defaults for inherited CSS properties */
|
||||
font-size: var(--wa-popover-font-size);
|
||||
line-height: var(--wa-popover-line-height);
|
||||
text-align: start;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
/* The native dialog element */
|
||||
.dialog {
|
||||
display: none;
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: transparent;
|
||||
overflow: visible;
|
||||
pointer-events: none;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&[open] {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
/* The <wa-popup> element */
|
||||
.popover {
|
||||
--arrow-size: inherit;
|
||||
--show-duration: inherit;
|
||||
--hide-duration: inherit;
|
||||
|
||||
pointer-events: auto;
|
||||
|
||||
&::part(arrow) {
|
||||
background-color: var(--wa-color-surface-default);
|
||||
border-top: none;
|
||||
border-left: none;
|
||||
border-bottom: solid var(--wa-panel-border-width) var(--wa-color-surface-border);
|
||||
border-right: solid var(--wa-panel-border-width) var(--wa-color-surface-border);
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.popover[placement^='top']::part(popup) {
|
||||
transform-origin: bottom;
|
||||
}
|
||||
|
||||
.popover[placement^='bottom']::part(popup) {
|
||||
transform-origin: top;
|
||||
}
|
||||
|
||||
.popover[placement^='left']::part(popup) {
|
||||
transform-origin: right;
|
||||
}
|
||||
|
||||
.popover[placement^='right']::part(popup) {
|
||||
transform-origin: left;
|
||||
}
|
||||
|
||||
/* Body */
|
||||
.body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: max-content;
|
||||
max-width: var(--max-width);
|
||||
padding: var(--wa-space);
|
||||
background-color: var(--wa-color-surface-default);
|
||||
border: var(--wa-panel-border-width) solid var(--wa-color-surface-border);
|
||||
border-radius: var(--wa-panel-border-radius);
|
||||
border-style: var(--wa-panel-border-style);
|
||||
box-shadow: var(--wa-shadow-s);
|
||||
color: var(--wa-color-text-normal);
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { expect, fixture, html } from '@open-wc/testing';
|
||||
|
||||
describe('<wa-popover>', () => {
|
||||
it('should render a component', async () => {
|
||||
const el = await fixture(html` <wa-popover></wa-popover> `);
|
||||
|
||||
expect(el).to.exist;
|
||||
});
|
||||
});
|
||||
310
packages/webawesome/src/components/popover/popover.ts
Normal file
310
packages/webawesome/src/components/popover/popover.ts
Normal file
@@ -0,0 +1,310 @@
|
||||
import { html } from 'lit';
|
||||
import { customElement, property, query, state } from 'lit/decorators.js';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
import { WaAfterHideEvent } from '../../events/after-hide.js';
|
||||
import { WaAfterShowEvent } from '../../events/after-show.js';
|
||||
import { WaHideEvent } from '../../events/hide.js';
|
||||
import { WaShowEvent } from '../../events/show.js';
|
||||
import { animateWithClass } from '../../internal/animate.js';
|
||||
import { waitForEvent } from '../../internal/event.js';
|
||||
import { uniqueId } from '../../internal/math.js';
|
||||
import { watch } from '../../internal/watch.js';
|
||||
import WebAwesomeElement from '../../internal/webawesome-element.js';
|
||||
import WaPopup from '../popup/popup.js';
|
||||
import styles from './popover.css';
|
||||
|
||||
const openPopovers = new Set<WaPopover>();
|
||||
|
||||
/**
|
||||
* @summary Popovers display contextual content and interactive elements in a floating panel.
|
||||
* @documentation https://backers.webawesome.com/docs/components/popover
|
||||
* @status stable
|
||||
* @since 3.0
|
||||
*
|
||||
* @dependency wa-popup
|
||||
*
|
||||
* @slot - The popover's content. Interactive elements such as buttons and links are supported.
|
||||
*
|
||||
* @event wa-show - Emitted when the popover begins to show. Canceling this event will stop the popover from showing.
|
||||
* @event wa-after-show - Emitted after the popover has shown and all animations are complete.
|
||||
* @event wa-hide - Emitted when the popover begins to hide. Canceling this event will stop the popover from hiding.
|
||||
* @event wa-after-hide - Emitted after the popover has hidden and all animations are complete.
|
||||
*
|
||||
* @csspart dialog - The native dialog element that contains the popover content.
|
||||
* @csspart body - The popover's body where its content is rendered.
|
||||
* @csspart popup - The internal `<wa-popup>` element that positions the popover.
|
||||
* @csspart popup__popup - The popup's exported `popup` part. Use this to target the popover's popup container.
|
||||
* @csspart popup__arrow - The popup's exported `arrow` part. Use this to target the popover's arrow.
|
||||
*
|
||||
* @cssproperty [--arrow-size=0.375rem] - The size of the tiny arrow that points to the popover (set to zero to remove).
|
||||
* @cssproperty [--max-width=25rem] - The maximum width of the popover's body content.
|
||||
* @cssproperty [--show-duration=100ms] - The speed of the show animation.
|
||||
* @cssproperty [--hide-duration=100ms] - The speed of the hide animation.
|
||||
*/
|
||||
@customElement('wa-popover')
|
||||
export default class WaPopover extends WebAwesomeElement {
|
||||
static shadowStyle = styles;
|
||||
static dependencies = { 'wa-popup': WaPopup };
|
||||
|
||||
@query('dialog') dialog: HTMLDialogElement;
|
||||
@query('.body') body: HTMLElement;
|
||||
@query('wa-popup') popup: WaPopup;
|
||||
|
||||
@state() anchor: null | Element = null;
|
||||
|
||||
/**
|
||||
* The preferred placement of the popover. Note that the actual placement may vary as needed to keep the popover
|
||||
* inside of the viewport.
|
||||
*/
|
||||
@property() placement:
|
||||
| 'top'
|
||||
| 'top-start'
|
||||
| 'top-end'
|
||||
| 'right'
|
||||
| 'right-start'
|
||||
| 'right-end'
|
||||
| 'bottom'
|
||||
| 'bottom-start'
|
||||
| 'bottom-end'
|
||||
| 'left'
|
||||
| 'left-start'
|
||||
| 'left-end' = 'top';
|
||||
|
||||
/** Shows or hides the popover. */
|
||||
@property({ type: Boolean, reflect: true }) open = false;
|
||||
|
||||
/** The distance in pixels from which to offset the popover away from its target. */
|
||||
@property({ type: Number }) distance = 8;
|
||||
|
||||
/** The distance in pixels from which to offset the popover along its target. */
|
||||
@property({ type: Number }) skidding = 0;
|
||||
|
||||
/** The ID of the popover's anchor element. This must be an interactive/focusable element such as a button. */
|
||||
@property() for: string | null = null;
|
||||
|
||||
private eventController = new AbortController();
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
|
||||
// If the user doesn't give us an id, generate one.
|
||||
if (!this.id) {
|
||||
this.id = uniqueId('wa-popover-');
|
||||
}
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
|
||||
// Cleanup events in case the popover is removed while open
|
||||
document.removeEventListener('keydown', this.handleDocumentKeyDown);
|
||||
this.eventController.abort();
|
||||
}
|
||||
|
||||
firstUpdated() {
|
||||
// If the popover is visible on init, update its position
|
||||
if (this.open) {
|
||||
this.dialog.show();
|
||||
this.popup.active = true;
|
||||
this.popup.reposition();
|
||||
}
|
||||
}
|
||||
|
||||
private handleAnchorClick = () => {
|
||||
// Clicks on the anchor should toggle the popover
|
||||
this.open = !this.open;
|
||||
};
|
||||
|
||||
private handleBodyClick = (event: PointerEvent) => {
|
||||
const target = event.target as HTMLElement;
|
||||
const button = target.closest('[data-popover="close"]');
|
||||
|
||||
// Watch for [data-popover="close"] clicks
|
||||
if (button) {
|
||||
event.stopPropagation();
|
||||
this.open = false;
|
||||
}
|
||||
};
|
||||
|
||||
private handleDocumentKeyDown = (event: KeyboardEvent) => {
|
||||
// Hide the popover when escape is pressed
|
||||
if (event.key === 'Escape') {
|
||||
event.preventDefault();
|
||||
this.open = false;
|
||||
if (this.anchor && typeof (this.anchor as any).focus === 'function') {
|
||||
(this.anchor as any).focus();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private handleDocumentClick = (event: PointerEvent) => {
|
||||
const target = event.target as HTMLElement;
|
||||
|
||||
// Ignore clicks on the anchor so it will be closed by the anchor's click handler
|
||||
if (this.anchor && event.composedPath().includes(this.anchor)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Detect when clicks occur outside the popover
|
||||
if (target.closest('wa-popover') !== this) {
|
||||
this.open = false;
|
||||
}
|
||||
};
|
||||
|
||||
@watch('open', { waitUntilFirstUpdate: true })
|
||||
async handleOpenChange() {
|
||||
if (this.open) {
|
||||
// Show
|
||||
const waShowEvent = new WaShowEvent();
|
||||
this.dispatchEvent(waShowEvent);
|
||||
if (waShowEvent.defaultPrevented) {
|
||||
this.open = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Close other popovers that are open
|
||||
openPopovers.forEach(popover => (popover.open = false));
|
||||
|
||||
document.addEventListener('keydown', this.handleDocumentKeyDown, { signal: this.eventController.signal });
|
||||
document.addEventListener('click', this.handleDocumentClick, { signal: this.eventController.signal });
|
||||
|
||||
// Show the dialog non-modally
|
||||
this.dialog.show();
|
||||
this.popup.active = true;
|
||||
openPopovers.add(this);
|
||||
|
||||
// Autofocus the first element with the autofocus attribute
|
||||
requestAnimationFrame(() => {
|
||||
const elementToFocus = this.querySelector<HTMLElement>('[autofocus]');
|
||||
if (elementToFocus && typeof elementToFocus.focus === 'function') {
|
||||
elementToFocus.focus();
|
||||
} else {
|
||||
// Fall back to setting focus on the dialog
|
||||
this.dialog.focus();
|
||||
}
|
||||
});
|
||||
|
||||
await animateWithClass(this.popup.popup, 'show-with-scale');
|
||||
this.popup.reposition();
|
||||
|
||||
this.dispatchEvent(new WaAfterShowEvent());
|
||||
} else {
|
||||
// Hide
|
||||
const waHideEvent = new WaHideEvent();
|
||||
this.dispatchEvent(waHideEvent);
|
||||
if (waHideEvent.defaultPrevented) {
|
||||
this.open = true;
|
||||
return;
|
||||
}
|
||||
|
||||
document.removeEventListener('keydown', this.handleDocumentKeyDown);
|
||||
document.removeEventListener('click', this.handleDocumentClick);
|
||||
|
||||
openPopovers.delete(this);
|
||||
|
||||
await animateWithClass(this.popup.popup, 'hide-with-scale');
|
||||
this.popup.active = false;
|
||||
this.dialog.close();
|
||||
|
||||
this.dispatchEvent(new WaAfterHideEvent());
|
||||
}
|
||||
}
|
||||
|
||||
@watch('for')
|
||||
handleForChange() {
|
||||
const rootNode = this.getRootNode() as Document | ShadowRoot | null;
|
||||
|
||||
if (!rootNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newAnchor = this.for ? rootNode.querySelector(`#${this.for}`) : null;
|
||||
const oldAnchor = this.anchor;
|
||||
|
||||
if (newAnchor === oldAnchor) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { signal } = this.eventController;
|
||||
|
||||
if (newAnchor) {
|
||||
newAnchor.addEventListener('click', this.handleAnchorClick, { signal });
|
||||
}
|
||||
|
||||
if (oldAnchor) {
|
||||
oldAnchor.removeEventListener('click', this.handleAnchorClick);
|
||||
}
|
||||
|
||||
this.anchor = newAnchor;
|
||||
|
||||
if (this.for && !newAnchor) {
|
||||
console.warn(
|
||||
`A popover was assigned to an element with an ID of "${this.for}" but the element could not be found.`,
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@watch(['distance', 'placement', 'skidding'])
|
||||
async handleOptionsChange() {
|
||||
if (this.hasUpdated) {
|
||||
await this.updateComplete;
|
||||
this.popup.reposition();
|
||||
}
|
||||
}
|
||||
|
||||
/** Shows the popover. */
|
||||
async show() {
|
||||
if (this.open) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
this.open = true;
|
||||
return waitForEvent(this, 'wa-after-show');
|
||||
}
|
||||
|
||||
/** Hides the popover. */
|
||||
async hide() {
|
||||
if (!this.open) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
this.open = false;
|
||||
return waitForEvent(this, 'wa-after-hide');
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<dialog part="dialog" class="dialog">
|
||||
<wa-popup
|
||||
part="popup"
|
||||
exportparts="
|
||||
popup:popup__popup,
|
||||
arrow:popup__arrow
|
||||
"
|
||||
class=${classMap({
|
||||
popover: true,
|
||||
'popover-open': this.open,
|
||||
})}
|
||||
placement=${this.placement}
|
||||
distance=${this.distance}
|
||||
skidding=${this.skidding}
|
||||
flip
|
||||
shift
|
||||
arrow
|
||||
.anchor=${this.anchor}
|
||||
>
|
||||
<div part="body" class="body" @click=${this.handleBodyClick}>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</wa-popup>
|
||||
</dialog>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'wa-popover': WaPopover;
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,19 @@
|
||||
height: calc(var(--arrow-size-diagonal) * 2);
|
||||
rotate: 45deg;
|
||||
background: var(--arrow-color);
|
||||
z-index: -1;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
:host([data-current-placement~='left']) .arrow {
|
||||
rotate: -45deg;
|
||||
}
|
||||
|
||||
:host([data-current-placement~='right']) .arrow {
|
||||
rotate: 135deg;
|
||||
}
|
||||
|
||||
:host([data-current-placement~='bottom']) .arrow {
|
||||
rotate: 225deg;
|
||||
}
|
||||
|
||||
/* Hover bridge */
|
||||
|
||||
Reference in New Issue
Block a user