Initial version

This commit is contained in:
trading_peter 2022-03-16 23:45:06 +01:00
parent 0625869d76
commit 69690793be
5 changed files with 220 additions and 40 deletions

View File

@ -1 +1 @@
# tp-element # tp-popup

13
package-lock.json generated Normal file
View File

@ -0,0 +1,13 @@
{
"name": "@tp/tp-popup",
"version": "0.0.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@tp/helpers": {
"version": "1.0.1",
"resolved": "https://verdaccio.codeblob.work/@tp%2fhelpers/-/helpers-1.0.1.tgz",
"integrity": "sha512-f6pDPw4QpjWnmVkYgOHjMXQXtGB4vbA45eZV9DjCF9OoCXsa+Pz32H2rLQRKbdpsfFllywOBI+GMGPYDJyrG/Q=="
}
}
}

View File

@ -1,18 +1,19 @@
{ {
"name": "@tp/tp-element", "name": "@tp/tp-popup",
"version": "0.0.1", "version": "1.0.0",
"description": "", "description": "",
"main": "tp-element.js", "main": "tp-popup.js",
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://gitea.codeblob.work/tp-elements/tp-element.git" "url": "https://gitea.codeblob.work/tp-elements/tp-popup.git"
}, },
"author": "trading_peter", "author": "trading_peter",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@tp/helpers": "^1.0.1",
"lit": "^2.2.0" "lit": "^2.2.0"
} }
} }

View File

@ -1,35 +0,0 @@
/**
@license
Copyright (c) 2022 trading_peter
This program is available under Apache License Version 2.0
*/
import { LitElement, html, css } from 'lit';
class TpElement extends LitElement {
static get styles() {
return [
css`
:host {
display: block;
}
`
];
}
render() {
const { } = this;
return html`
`;
}
static get properties() {
return { };
}
}
window.customElements.define('tp-element', TpElement);

201
tp-popup.js Normal file
View File

@ -0,0 +1,201 @@
/**
@license
Copyright (c) 2022 trading_peter
This program is available under Apache License Version 2.0
*/
import { LitElement, html, css } from 'lit';
import { DomQuery } from '@tp/helpers/dom-query.js';
import { Position } from '@tp/helpers/position.js';
import { EventHelpers } from '@tp/helpers/event-helpers.js';
import { closest } from '@tp/helpers/closest.js';
class TpPopup extends EventHelpers(Position(DomQuery(LitElement))) {
static get styles() {
return [
css`
:host {
display: inline-block;
position: relative;
outline: 0;
}
.toggle {
cursor: pointer;
}
#content {
pointer-events: none;
position: fixed;
z-index: 1;
margin-top: 5px;
transition: opacity 180ms;
opacity: 0;
border-radius: 2px;
box-shadow: var(--tp-popup-shadow, none);
}
#content[open] {
pointer-events: all;
opacity: 1;
background: var(--tp-popup-background, #F5F5F5);
}
#content .content-wrap {
padding: var(--tp-popup-content-padding, 10px);
}
@media all and (min-width: 0) and (max-width: 480px) {
:host(:not([not-responsive])) #content {
bottom: 0 !important;
top: auto !important;
right: 0 !important;
left: 0 !important;
margin-top: 0;
transition: transform 0.3s, opacity 0.3s;
transform: translateY(100%);
max-height: 80%;
overflow: hidden;
overflow-y: auto;
box-shadow: var(--tp-popup-shadow-responsive, none);
}
:host(:not([not-responsive])) #content[open] {
transform: translateY(0%);
}
}
`
];
}
render() {
const { isOpen } = this;
return html`
<div class="wrap">
<div class="toggle">
<slot id="toggleContent" name="toggle"></slot>
</div>
<div id="content" ?open=${isOpen}>
<div class="content-wrap">
<slot id="contentSlot" name="content"></slot>
</div>
</div>
</div>
`;
}
static get properties() {
return {
isOpen: { type: Boolean, reflect: true },
alwaysToggle: { type: Boolean, reflect: true },
halign: { type: String },
valign: { type: String },
scrollTarget: { type: Object }
};
}
constructor() {
super();
this.isOpen = false;
this.alwaysToggle = false;
this.halign = 'middle';
this.valign = 'bottom';
this.scrollTarget = document;
this.fit = this.fit.bind(this);
this._onDocClickHandler = () => this.close();
}
get toggleEl() {
if (!this._toggleEl) {
this._toggleEl = this.querySelector('[slot="toggle"]');
}
return this._toggleEl;
}
firstUpdated() {
super.firstUpdated();
this.listen(this, 'click', '_onClick');
}
disconnectedCallback() {
super.disconnectedCallback();
this._cleanupEvents();
}
close() {
this.isOpen = false;
this._cleanupEvents();
}
open() {
this.updateComplete.then(() => {
this.fit();
});
this.isOpen = true;
this._registerEvents();
const autofocusEl = this.querySelector('[autofocus]');
if (autofocusEl) {
autofocusEl.focus();
}
}
toggle() {
if (!this.isOpen) {
this.open();
} else {
this.isOpen = false;
this._cleanupEvents();
}
}
/**
* Set correct position on the popup to fit into the window.
*/
fit() {
this._posFixed(this.shadowRoot.querySelector('.toggle'), this.$.content, {
valign: this.valign || 'bottom',
halign: this.halign || 'middle',
spacing: 5
});
}
_docClick(e) {
const isThisPopover = e.composedPath().indexOf(this) > -1;
if (!isThisPopover && this.isOpen) {
this.close();
}
}
_onClick(e) {
const toggle = closest(e.composedPath()[0], '[slot="toggle"]', true) === this.toggleEl;
const closePopover = closest(e.composedPath()[0], '[close-popover]', true);
if (toggle && this.toggleEl.hasAttribute('disabled')) return;
if (toggle || this.alwaysToggle) {
this.toggle();
}
if (closePopover) {
this.close();
}
}
_registerEvents() {
this._cleanupEvents();
this.listen(document, 'mousedown', '_docClick');
this.scrollTarget.addEventListener('scroll', this.fit, { passive: true });
}
_cleanupEvents() {
this.unlisten(document, 'mousedown', '_docClick');
this.scrollTarget.removeEventListener('scroll', this.fit, { passive: true });
}
}
window.customElements.define('tp-popup', TpPopup);