-
Notifications
You must be signed in to change notification settings - Fork 187
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs: add Popover documentation and live examples (#3587)
- Loading branch information
1 parent
6b6b6d5
commit fd2e1e3
Showing
29 changed files
with
2,546 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
--- | ||
title: Styling | ||
description: Styling API reference for the Popover component. | ||
order: 50 | ||
--- | ||
= Styling | ||
|
||
|
||
include::../_styling-section-theming-props.adoc[tag=style-properties] | ||
|
||
[cols="1,2,2"] | ||
|=== | ||
| Feature | Property | Default Value | ||
|
||
|Arrow size | ||
|`--vaadin-popover-arrow-size` | ||
|`0.5rem` | ||
|
||
|Top offset | ||
|`--vaadin-popover-offset-top` | ||
|`var(--lumo-space-xs)` | ||
|
||
|Bottom offset | ||
|`--vaadin-popover-offset-bottom` | ||
|`var(--lumo-space-xs)` | ||
|
||
|Start offset | ||
|`--vaadin-popover-offset-start` | ||
|`var(--lumo-space-xs)` | ||
|
||
|End offset | ||
|`--vaadin-popover-offset-end` | ||
|`var(--lumo-space-xs)` | ||
|
||
|=== | ||
|
||
|
||
include::../_styling-section-intros.adoc[tag=selectors] | ||
|
||
|
||
Root element:: `vaadin-popover-overlay` | ||
|
||
|
||
=== States | ||
|
||
Non-modal:: `vaadin-popover-overlay+++<wbr>+++**[modeless]**` | ||
|
||
|
||
=== Parts | ||
|
||
Modality curtain (backdrop):: `vaadin-popover-overlay+++<wbr>+++**::part(backdrop)**` | ||
Popover surface:: `vaadin-popover-overlay+++<wbr>+++**::part(overlay)**` | ||
Content wrapper:: `vaadin-popover-overlay+++<wbr>+++**::part(content)**` | ||
Arrow element:: `vaadin-popover-overlay+++<wbr>+++**::part(arrow)**` | ||
|
||
=== Style Variants | ||
|
||
Arrow:: `vaadin-popover+++<wbr>+++**[theme~="arrow"]**` |
125 changes: 125 additions & 0 deletions
125
frontend/demo/component/popover/popover-anchored-dialog.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
import 'Frontend/demo/init'; // hidden-source-line | ||
|
||
import { html, LitElement } from 'lit'; | ||
import { customElement, state } from 'lit/decorators.js'; | ||
import '@vaadin/button'; | ||
import '@vaadin/checkbox-group'; | ||
import '@vaadin/grid'; | ||
import '@vaadin/horizontal-layout'; | ||
import '@vaadin/icon'; | ||
import '@vaadin/icons'; | ||
import '@vaadin/popover'; | ||
import type { CheckboxChangeEvent } from '@vaadin/checkbox'; | ||
import { popoverRenderer } from '@vaadin/popover/lit.js'; | ||
import { getPeople } from 'Frontend/demo/domain/DataService'; | ||
import type Person from 'Frontend/generated/com/vaadin/demo/domain/Person'; | ||
import { applyTheme } from 'Frontend/generated/theme'; | ||
|
||
const DEFAULT_COLUMNS = [ | ||
{ label: 'First name', key: 'firstName', visible: true }, | ||
{ label: 'Last name', key: 'lastName', visible: true }, | ||
{ label: 'Email', key: 'email', visible: true }, | ||
{ label: 'Phone', key: 'address.phone', visible: false }, | ||
{ label: 'Birthday', key: 'birthday', visible: false }, | ||
{ label: 'Profession', key: 'profession', visible: true }, | ||
]; | ||
|
||
@customElement('popover-anchored-dialog') | ||
export class Example extends LitElement { | ||
protected override createRenderRoot() { | ||
const root = super.createRenderRoot(); | ||
// Apply custom theme (only supported if your app uses one) | ||
applyTheme(root); | ||
return root; | ||
} | ||
|
||
// tag::snippet[] | ||
@state() | ||
private items: Person[] = []; | ||
|
||
@state() | ||
private gridColumns = [...DEFAULT_COLUMNS]; | ||
|
||
protected override async firstUpdated() { | ||
const { people } = await getPeople(); | ||
this.items = people; | ||
} | ||
|
||
protected override render() { | ||
return html` | ||
<!-- tag::snippet[] --> | ||
<vaadin-horizontal-layout style="align-items: baseline"> | ||
<strong style="flex: 1;">Employees</strong> | ||
<vaadin-button id="toggle-columns" theme="icon" aria-label="Show / hide columns"> | ||
<vaadin-icon icon="vaadin:grid-h"></vaadin-icon> | ||
</vaadin-button> | ||
</vaadin-horizontal-layout> | ||
<vaadin-popover | ||
for="toggle-columns" | ||
modal | ||
with-backdrop | ||
position="bottom-end" | ||
${popoverRenderer(this.popoverRenderer, [this.gridColumns])} | ||
></vaadin-popover> | ||
<!-- end::snippet[] --> | ||
<vaadin-grid .items="${this.items}"> | ||
${this.gridColumns.map( | ||
(column) => html` | ||
<vaadin-grid-column | ||
path="${column.key}" | ||
.hidden="${!column.visible}" | ||
></vaadin-grid-column> | ||
` | ||
)} | ||
</vaadin-grid> | ||
`; | ||
} | ||
|
||
// tag::snippet[] | ||
popoverRenderer() { | ||
const visibleColumns = this.gridColumns | ||
.filter((column) => column.visible) | ||
.map((column) => column.key); | ||
|
||
return html` | ||
<h4 style="margin: 0">Configure columns</h4> | ||
<vaadin-checkbox-group theme="vertical" .value="${visibleColumns}"> | ||
${this.gridColumns.map( | ||
(column) => html` | ||
<vaadin-checkbox | ||
.label="${column.label}" | ||
.value="${column.key}" | ||
@change="${this.onCheckboxChange}" | ||
></vaadin-checkbox> | ||
` | ||
)} | ||
</vaadin-checkbox-group> | ||
<vaadin-horizontal-layout theme="spacing-xs"> | ||
<vaadin-button @click="${this.showAllColumns}">Show all</vaadin-button> | ||
<vaadin-button @click="${this.resetColumns}">Reset</vaadin-button> | ||
</vaadin-horizontal-layout> | ||
`; | ||
} | ||
// end::snippet[] | ||
|
||
onCheckboxChange(event: CheckboxChangeEvent) { | ||
const idx = this.gridColumns.findIndex(({ key }) => key === event.target.value); | ||
this.gridColumns = this.gridColumns.map((column, index) => ({ | ||
...column, | ||
visible: idx === index ? event.target.checked : column.visible, | ||
})); | ||
} | ||
|
||
showAllColumns() { | ||
this.gridColumns = this.gridColumns.map((column) => ({ ...column, visible: true })); | ||
} | ||
|
||
resetColumns() { | ||
this.gridColumns = this.gridColumns.map((column, idx) => ({ | ||
...column, | ||
visible: DEFAULT_COLUMNS[idx].visible, | ||
})); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import 'Frontend/demo/init'; // hidden-source-line | ||
|
||
import { html, LitElement } from 'lit'; | ||
import { customElement } from 'lit/decorators.js'; | ||
import '@vaadin/button'; | ||
import '@vaadin/icon'; | ||
import '@vaadin/popover'; | ||
import '@vaadin/vaadin-lumo-styles/vaadin-iconset.js'; | ||
import { popoverRenderer } from '@vaadin/popover/lit.js'; | ||
import { applyTheme } from 'Frontend/generated/theme'; | ||
|
||
@customElement('popover-arrow') | ||
export class Example extends LitElement { | ||
protected override createRenderRoot() { | ||
const root = super.createRenderRoot(); | ||
// Apply custom theme (only supported if your app uses one) | ||
applyTheme(root); | ||
return root; | ||
} | ||
|
||
protected override render() { | ||
return html` | ||
<vaadin-button id="target" aria-label="notifications" theme="icon"> | ||
<vaadin-icon icon="lumo:bell"></vaadin-icon> | ||
</vaadin-button> | ||
<!-- tag::snippet[] --> | ||
<vaadin-popover | ||
for="target" | ||
theme="arrow" | ||
${popoverRenderer(this.popoverRenderer)} | ||
></vaadin-popover> | ||
<!-- end::snippet[] --> | ||
`; | ||
} | ||
|
||
popoverRenderer() { | ||
return html`<div>No new notifications</div>`; | ||
} | ||
} |
157 changes: 157 additions & 0 deletions
157
frontend/demo/component/popover/popover-dropdown-field.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
import 'Frontend/demo/init'; // hidden-source-line | ||
|
||
import { html, LitElement } from 'lit'; | ||
import { customElement, state } from 'lit/decorators.js'; | ||
import '@vaadin/date-picker'; | ||
import '@vaadin/horizontal-layout'; | ||
import '@vaadin/icon'; | ||
import '@vaadin/popover'; | ||
import '@vaadin/select'; | ||
import '@vaadin/text-field'; | ||
import '@vaadin/vaadin-lumo-styles/vaadin-iconset.js'; | ||
import type { DatePickerChangeEvent } from '@vaadin/date-picker'; | ||
import type { PopoverOpenedChangedEvent, PopoverTrigger } from '@vaadin/popover'; | ||
import type { SelectChangeEvent } from '@vaadin/select'; | ||
import { popoverRenderer } from '@vaadin/popover/lit.js'; | ||
import { applyTheme } from 'Frontend/generated/theme'; | ||
import { formatISO, subMonths, subWeeks, subYears } from 'date-fns'; | ||
|
||
@customElement('popover-dropdown-field') | ||
export class Example extends LitElement { | ||
protected override createRenderRoot() { | ||
const root = super.createRenderRoot(); | ||
// Apply custom theme (only supported if your app uses one) | ||
applyTheme(root); | ||
return root; | ||
} | ||
|
||
@state() | ||
range = ''; | ||
|
||
@state() | ||
from = ''; | ||
|
||
@state() | ||
to = ''; | ||
|
||
@state() | ||
opened = false; | ||
|
||
@state() | ||
trigger: PopoverTrigger[] = ['click', 'focus']; | ||
|
||
@state() | ||
presets = [ | ||
{ label: 'Today', value: 'today' }, | ||
{ label: 'Last week', value: 'last-week' }, | ||
{ label: 'Last month', value: 'last-month' }, | ||
{ label: 'Year to date', value: 'year-to-date' }, | ||
{ label: 'Last year', value: 'last-year' }, | ||
{ label: 'Past 5 years', value: 'past-5-years' }, | ||
]; | ||
|
||
protected override render() { | ||
return html` | ||
<vaadin-text-field | ||
id="range-field" | ||
label="Search date range" | ||
style="width: 340px" | ||
.value="${this.from && this.to ? `${this.from} − ${this.to}` : ''}" | ||
> | ||
<vaadin-icon icon="lumo:dropdown" slot="suffix"></vaadin-icon> | ||
</vaadin-text-field> | ||
<!-- tag::snippet[] --> | ||
<vaadin-popover | ||
for="range-field" | ||
.trigger="${this.trigger}" | ||
focus-delay="0" | ||
modal | ||
content-width="325px" | ||
position="bottom-start" | ||
accessible-name="Select a date range" | ||
.opened="${this.opened}" | ||
@opened-changed="${this.onOpenedChanged}" | ||
${popoverRenderer(this.popoverRenderer, [this.from, this.to])} | ||
></vaadin-popover> | ||
<!-- end::snippet[] --> | ||
`; | ||
} | ||
|
||
// tag::snippet[] | ||
popoverRenderer() { | ||
return html` | ||
<vaadin-select | ||
label="Common ranges" | ||
.items="${this.presets}" | ||
placeholder="Select preset" | ||
style="width: 100%" | ||
.value="${this.range}" | ||
@change="${this.onRangeChange}" | ||
></vaadin-select> | ||
<vaadin-horizontal-layout theme="spacing-s" style="align-items: baseline"> | ||
<vaadin-date-picker | ||
label="From" | ||
style="width: 150px" | ||
.value="${this.from}" | ||
@change="${this.onFromChange}" | ||
></vaadin-date-picker> | ||
<div>−</div> | ||
<vaadin-date-picker | ||
label="To" | ||
style="width: 150px" | ||
.value="${this.to}" | ||
@change="${this.onToChange}" | ||
></vaadin-date-picker> | ||
</vaadin-horizontal-layout> | ||
`; | ||
} | ||
// end::snippet[] | ||
|
||
onFromChange(event: DatePickerChangeEvent) { | ||
this.range = ''; | ||
this.from = event.target.value; | ||
} | ||
|
||
onToChange(event: DatePickerChangeEvent) { | ||
this.range = ''; | ||
this.to = event.target.value; | ||
} | ||
|
||
onOpenedChanged(event: PopoverOpenedChangedEvent) { | ||
this.opened = event.detail.value; | ||
} | ||
|
||
onRangeChange(event: SelectChangeEvent) { | ||
this.range = event.target.value; | ||
this.to = this.formatDate(new Date()); | ||
|
||
switch (event.target.value) { | ||
case 'today': | ||
this.from = this.formatDate(new Date()); | ||
break; | ||
case 'last-week': | ||
this.from = this.formatDate(subWeeks(new Date(), 1)); | ||
break; | ||
case 'last-month': | ||
this.from = this.formatDate(subMonths(new Date(), 1)); | ||
break; | ||
case 'year-to-date': | ||
this.from = this.formatDate(new Date(new Date().getFullYear(), 0, 1)); | ||
break; | ||
case 'last-year': | ||
this.from = this.formatDate(subYears(new Date(), 1)); | ||
break; | ||
case 'past-5-years': | ||
this.from = this.formatDate(subYears(new Date(), 5)); | ||
break; | ||
default: | ||
// Do nothing | ||
} | ||
|
||
this.opened = false; | ||
} | ||
|
||
formatDate(date: Date) { | ||
return formatISO(date, { representation: 'date' }); | ||
} | ||
} |
Oops, something went wrong.