UNPKG

@teipublisher/pb-components

Version:
212 lines (191 loc) 6.89 kB
import { LitElement, html, css } from 'lit-element'; import { pbMixin } from './pb-mixin.js'; import './pb-view.js'; import '@polymer/paper-dropdown-menu/paper-dropdown-menu.js'; import '@polymer/paper-listbox'; import '@polymer/paper-item'; import '@polymer/app-layout'; /** * A container for different views. Only one view will be shown at a time. * Provides a dropdown for the user to switch between views. Views are * lazy loaded and should be provided as one or more `<template>` elements. * Each `<template>` may have a title attribute to specify the title to be shown * for it in the dropdown. * * @slot - unnamed default slot for content * @slot toolbar - toolbar area * @fires pb-panel - Fired whenever the component switches to a different content panel. Used by `pb-grid` to update its state. * @fires pb-refresh - Fired after a new content panel is shown to allow connected components to refresh. * @cssprop --pb-panel-max-height - The max height of the panel content. Set to enable scrolling. */ export class PbPanel extends pbMixin(LitElement) { static get properties() { return { ...super.properties, /** * the index of the active view */ active: { type: Number, reflect: true }, /** * the label displayed above the dropdown for selecting the view to show */ label: { type: String }, /** * a name for each available panel, to be displayed in the dropdown. If not set, * each template will be checked for a title attribute, which will be taken as name. */ panels: { type: Array, reflect: true }, /** * if set, the panel can be dragged to another position in the grid. A button will * be added to the toolbar to allow dragging. */ draggable: { type: Boolean } }; } constructor() { super(); this.active = 0; this.label = 'View'; this.panels = null; this.position = -1; this.draggable = false; } connectedCallback() { super.connectedCallback(); if (!this.panels) { const titles = []; this.querySelectorAll('template').forEach(template => titles.push(template.title)); this.panels = titles; } this._show(); } firstUpdated() { const dragHandle = this.shadowRoot.getElementById('drag-handle'); let initiator = null; if (this.draggable) { dragHandle.addEventListener('dragstart', (ev) => { ev.dataTransfer.setDragImage(this, 10, 10); ev.dataTransfer.setData("text", this.position); initiator = this; }); } this.addEventListener('dragover', (ev) => { ev.preventDefault(); }); document.addEventListener('dragenter', (ev) => { ev.stopPropagation(); ev.preventDefault(); if (initiator === this) { return; } if (this.contains(ev.target)) { this.classList.add('dragover'); } else { this.classList.remove('dragover'); } }); this.addEventListener('drop', (ev) => { ev.stopPropagation(); ev.preventDefault(); initiator = null; this.dispatchEvent(new CustomEvent('pb-drop', { detail: { panel: ev.dataTransfer.getData("text"), target: this }, bubbles: true, composed: true })); }); } render() { return html` <app-toolbar id="toolbar"> <paper-dropdown-menu id="menu" label="${this.label}"> <paper-listbox id="panels" slot="dropdown-content" class="dropdown-content" selected="${this.active}" @selected-item-changed="${this._update}"> ${this.panels.map((item) => html`<paper-item>${item}</paper-item>`)} </paper-listbox> </paper-dropdown-menu> ${this.draggable ? html`<paper-icon-button id="drag-handle" icon="icons:open-with" draggable="true"></paper-icon-button>` : ''} <slot name="toolbar"></slot> </app-toolbar> <slot></slot> `; } static get styles() { return css` :host { display: block; } app-toolbar { padding: 0; justify-content: space-between; } ::slotted(._pb_panel) { overflow: auto; max-height: calc(var(--pb-panel-max-height) - 72px); } app-toolbar { font-size: 75%; } :host(.dragover) { background-color: var(--pb-grid-highlight-color, var(--pb-highlight-color)); animation: highlight 1s; } @keyframes highlight { from { background-color: transparent; } to { background-color: var(--pb-grid-highlight-color, var(--pb-highlight-color)); } } `; } _update() { const panel = this.shadowRoot.getElementById('panels').selected; if (this.active !== panel) { this.active = panel; this._show(); } } _show() { const templates = this.querySelectorAll('template'); if (this.active >= templates.length) { this.active = templates.length - 1; } console.log('<pb-panel> showing panel %s', this.active); this.querySelectorAll('._pb_panel').forEach(div => div.style.display = 'none'); const existingPanel = this.querySelector('._pb_panel' + this.active); if (existingPanel) { existingPanel.style.display = ''; } else { const template = templates[this.active]; const clone = document.importNode(template.content, true); const div = document.createElement('div'); div.className = '_pb_panel _pb_panel' + this.active; div.appendChild(clone); this.appendChild(div); this.emitTo('pb-panel', { panel: this, active: this.active }); // this.refresh(); } } refresh() { this.emitTo('pb-refresh', null); } } customElements.define('pb-panel', PbPanel);