Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@operato/popup

Package Overview
Dependencies
Maintainers
4
Versions
326
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@operato/popup - npm Package Compare versions

Comparing version 0.2.35 to 0.2.36

19

CHANGELOG.md

@@ -6,2 +6,21 @@ # Change Log

### [0.2.36](https://github.com/hatiolab/operato/compare/v0.2.35...v0.2.36) (2021-12-06)
### :bug: Bug Fix
* apply class name prefix Ox for operato/popup ([d528848](https://github.com/hatiolab/operato/commit/d5288486ea0e1bec84fff3c5b6bac696eb701e5d))
* operato/input to support formfield ([21b4d46](https://github.com/hatiolab/operato/commit/21b4d46d750ba833c571b5caeed27eebd8aa03ca))
* operato/input to support formfield ([544bf92](https://github.com/hatiolab/operato/commit/544bf928946d878aa967f33b20efdf90eb8e82f5))
* operato/ox-popup-list rewritten ([f78b3e9](https://github.com/hatiolab/operato/commit/f78b3e9623faac5ea653442ced653173d630d9e6))
* operato/popup, input sample ([116b037](https://github.com/hatiolab/operato/commit/116b0371446cb24d8863c2bdea876b97f6e11dfd))
* operato/popup, input sample ([31fb99f](https://github.com/hatiolab/operato/commit/31fb99fc4e37a26c38826dd3554f92ded0632e82))
### :rocket: New Features
* adding filter options for data-grist ([3620e8b](https://github.com/hatiolab/operato/commit/3620e8b5c39e7e66f8e7ab39b2ae7200f7f7afb5))
### [0.2.35](https://github.com/hatiolab/operato/compare/v0.2.34...v0.2.35) (2021-12-03)

@@ -8,0 +27,0 @@

30

dist/src/ox-popup-list.d.ts
import { PropertyValues } from 'lit';
import { Popup } from './ox-popup';
export declare class PopupList extends Popup {
import { OxPopup } from './ox-popup';
export declare class OxPopupList extends OxPopup {
static styles: import("lit").CSSResult[];
activeIndex: number;
multiple: boolean;
attrSelected?: string;
activeIndex?: number;
render(): import("lit-html").TemplateResult<1>;

@@ -11,15 +13,25 @@ protected _onkeydown: (e: KeyboardEvent) => void;

updated(changes: PropertyValues<this>): void;
select(option: Element): void;
setActive(active: number | Element | null): void;
select(): Promise<void>;
setActive(active: number | Element | null, withSelect?: boolean): void;
open(params: {
left?: number;
top?: number;
right?: number;
bottom?: number;
silent?: boolean;
}): void;
close(): void;
/**
* Open Popup
* Open OxPopup
*
* @param {PopupOpenOptions}
*/
static open({ template, top, left, parent }: {
static open({ template, top, left, right, bottom, parent }: {
template: unknown;
top: number;
left: number;
top?: number;
left?: number;
right?: number;
bottom?: number;
parent?: Element | null;
}): void;
}
import { __decorate } from "tslib";
import { css, html } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { Popup } from './ox-popup';
import { customElement, property, state } from 'lit/decorators.js';
import { OxPopup } from './ox-popup';
import { render } from 'lit-html';
function focusClosest(element) {
/* Find the closest focusable element. */
function guaranteeFocus(element) {
// 1. 옵션 엘리먼트의 하위 첫번째 focusible 엘리먼트에 focus 기회를 준다.
const focusible = element.querySelector('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
if (focusible) {
;
focusible.focus();
return;
}
// 2. 자신을 포함해서 가장 가까운 부모에게 focus 기회를 준다.
const closest = element.closest('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
closest === null || closest === void 0 ? void 0 : closest.focus();
return closest;
}
let PopupList = class PopupList extends Popup {
let OxPopupList = class OxPopupList extends OxPopup {
constructor() {
super(...arguments);
this.activeIndex = 0;
this.multiple = false;
this._onkeydown = function (e) {
var _a;
e.stopPropagation();

@@ -37,7 +42,6 @@ switch (e.key) {

case 'Enter':
e.stopPropagation();
var option = (_a = e.target) === null || _a === void 0 ? void 0 : _a.closest('[option]');
if (option) {
this.select(option);
}
case ' ':
case 'Spacebar': // for old firefox
this.setActive(this.activeIndex, true);
this.select();
break;

@@ -47,17 +51,8 @@ }

this._onfocusout = function (e) {
const target = e.target;
const to = e.relatedTarget;
const from = target.closest('ox-popup-list');
if (!to && from !== this) {
e.stopPropagation();
/* "하위의 ox-popup-list 엘리먼트가 포커스를 잃었지만, 그 포커스를 받은 엘리먼트가 없다."는 의미는 그 서브메뉴가 클로즈된 것을 의미한다. */
this.setActive(this.activeIndex);
if (!this.contains(to)) {
/* 분명히 내 범위가 아닌 엘리먼트로 포커스가 옮겨졌다면, ox-popup-list는 닫혀야 한다. */
// @ts-ignore for debug
!window.POPUP_DEBUG && this.close();
}
else {
if (!this.contains(to)) {
/* 분명히 내 범위가 아닌 엘리먼트로 포커스가 옮겨졌다면, ox-popup-list는 닫혀야 한다. */
// @ts-ignore for debug
!window.POPUP_DEBUG && this.close();
}
}
}.bind(this);

@@ -69,4 +64,4 @@ this._onclick = function (e) {

if (option) {
this.setActive(option);
this.select(option);
this.setActive(option, true);
this.select();
}

@@ -76,43 +71,89 @@ }.bind(this);

render() {
return html ` <slot> </slot> `;
return html `
<slot
@change=${(e) => {
e.stopPropagation();
}}
>
</slot>
`;
}
updated(changes) {
if (changes.has('activeIndex')) {
this.setActive(this.activeIndex);
this.activeIndex !== undefined && this.setActive(this.activeIndex);
}
}
select(option) {
option.dispatchEvent(new CustomEvent('selected', { bubbles: true, composed: true, detail: this }));
if (!option.hasAttribute('alive-on-select') && !this.hasAttribute('alive-on-select')) {
async select() {
await this.updateComplete;
const options = Array.from(this.querySelectorAll(':scope > [option]'));
const selected = options
.filter(option => option.hasAttribute('value') && option.hasAttribute(this.attrSelected || 'selected'))
.map(option => option.getAttribute('value'));
this.dispatchEvent(new CustomEvent('select', {
bubbles: true,
composed: true,
detail: this.multiple ? selected : selected[0]
}));
const option = options[this.activeIndex];
if (!option.hasAttribute('alive-on-select') && !this.hasAttribute('multiple')) {
this.close();
}
}
setActive(active) {
const options = Array.from(this.querySelectorAll(':scope > [option]'));
options.map(async (option, index) => {
setActive(active, withSelect) {
const options = Array.from(this.querySelectorAll('[option]'));
if (active instanceof Element) {
const index = options.findIndex(option => option === active);
this.setActive(index === -1 ? 0 : index, withSelect);
return;
}
options.forEach(async (option, index) => {
if (typeof active === 'number' && index === (active + options.length) % options.length) {
option.setAttribute('active', '');
focusClosest(option);
if (withSelect && !this.attrSelected) {
this.multiple ? option.toggleAttribute('selected') : option.setAttribute('selected', '');
}
guaranteeFocus(option);
this.activeIndex = index;
}
else if (active === option) {
this.activeIndex = index;
}
else {
option.removeAttribute('active');
!this.attrSelected && !this.multiple && withSelect && option.removeAttribute('selected');
}
});
}
open(params) {
super.open(params);
if (this.activeIndex === undefined) {
this.activeIndex = 0;
}
else {
this.setActive(this.activeIndex);
}
}
close() {
if (this.hasAttribute('active')) {
this.dispatchEvent(new CustomEvent('close', {
bubbles: true,
composed: true
}));
}
super.close();
}
/**
* Open Popup
* Open OxPopup
*
* @param {PopupOpenOptions}
*/
static open({ template, top, left, parent }) {
static open({ template, top, left, right, bottom, parent }) {
const owner = parent || document.body;
const target = document.createElement('ox-popup-list');
render(template, target);
target.style.left = `${left}px`;
target.style.top = `${top}px`;
target.setAttribute('active', '');
if (left !== undefined)
target.style.left = `${left}px`;
if (top !== undefined)
target.style.top = `${top}px`;
if (right !== undefined)
target.style.right = `${right}px`;
if (bottom !== undefined)
target.style.bottom = `${bottom}px`;
target._parent = owner;

@@ -122,4 +163,4 @@ owner.appendChild(target);

};
PopupList.styles = [
...Popup.styles,
OxPopupList.styles = [
...OxPopup.styles,
css `

@@ -147,2 +188,6 @@ :host {

::slotted([option]) {
white-space: nowrap;
}
::slotted(*) {

@@ -166,2 +211,7 @@ margin: 1px 0;

::slotted([option][selected]) {
background-color: red;
cursor: pointer;
}
::slotted([separator]) {

@@ -179,8 +229,14 @@ height: 1px;

__decorate([
property({ type: Number })
], PopupList.prototype, "activeIndex", void 0);
PopupList = __decorate([
property({ type: Boolean })
], OxPopupList.prototype, "multiple", void 0);
__decorate([
property({ type: String, attribute: 'attr-selected' })
], OxPopupList.prototype, "attrSelected", void 0);
__decorate([
state()
], OxPopupList.prototype, "activeIndex", void 0);
OxPopupList = __decorate([
customElement('ox-popup-list')
], PopupList);
export { PopupList };
], OxPopupList);
export { OxPopupList };
//# sourceMappingURL=ox-popup-list.js.map
import { PropertyValues } from 'lit';
import { Popup } from './ox-popup';
export declare class PopupMenu extends Popup {
import { OxPopup } from './ox-popup';
export declare class OxPopupMenu extends OxPopup {
static styles: import("lit").CSSResult[];

@@ -5,0 +5,0 @@ activeIndex: number;

import { __decorate } from "tslib";
import { css, html } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { Popup } from './ox-popup';
import { OxPopup } from './ox-popup';
import { render } from 'lit-html';

@@ -12,3 +12,3 @@ function focusClosest(element) {

}
let PopupMenu = class PopupMenu extends Popup {
let OxPopupMenu = class OxPopupMenu extends OxPopup {
constructor() {

@@ -82,3 +82,3 @@ super(...arguments);

select(menu) {
menu.dispatchEvent(new CustomEvent('selected'));
menu.dispatchEvent(new CustomEvent('select'));
if (!menu.hasAttribute('alive-on-select')) {

@@ -126,4 +126,4 @@ this.dispatchEvent(new CustomEvent('ox-close', { bubbles: true, composed: true, detail: this }));

};
PopupMenu.styles = [
...Popup.styles,
OxPopupMenu.styles = [
...OxPopup.styles,
css `

@@ -184,7 +184,7 @@ :host {

property({ type: Number })
], PopupMenu.prototype, "activeIndex", void 0);
PopupMenu = __decorate([
], OxPopupMenu.prototype, "activeIndex", void 0);
OxPopupMenu = __decorate([
customElement('ox-popup-menu')
], PopupMenu);
export { PopupMenu };
], OxPopupMenu);
export { OxPopupMenu };
//# sourceMappingURL=ox-popup-menu.js.map
import { LitElement, PropertyValues } from 'lit';
import { PopupMenu } from './ox-popup-menu';
export declare class PopupMenuItem extends LitElement {
import { OxPopupMenu } from './ox-popup-menu';
export declare class OxPopupMenuItem extends LitElement {
static styles: import("lit").CSSResult[];
active: boolean;
label: string;
_submenu?: PopupMenu;
_submenu?: OxPopupMenu;
render(): import("lit-html").TemplateResult<1>;

@@ -9,0 +9,0 @@ firstUpdated(): void;

import { __decorate } from "tslib";
import { LitElement, css, html } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
let PopupMenuItem = class PopupMenuItem extends LitElement {
let OxPopupMenuItem = class OxPopupMenuItem extends LitElement {
constructor() {

@@ -17,3 +17,3 @@ super(...arguments);

}
this.dispatchEvent(new CustomEvent('selected'));
this.dispatchEvent(new CustomEvent('select'));
requestAnimationFrame(() => {

@@ -96,3 +96,3 @@ this.expand(false);

};
PopupMenuItem.styles = [
OxPopupMenuItem.styles = [
css `

@@ -142,13 +142,13 @@ :host {

property({ type: Boolean })
], PopupMenuItem.prototype, "active", void 0);
], OxPopupMenuItem.prototype, "active", void 0);
__decorate([
property({ type: String })
], PopupMenuItem.prototype, "label", void 0);
], OxPopupMenuItem.prototype, "label", void 0);
__decorate([
state()
], PopupMenuItem.prototype, "_submenu", void 0);
PopupMenuItem = __decorate([
], OxPopupMenuItem.prototype, "_submenu", void 0);
OxPopupMenuItem = __decorate([
customElement('ox-popup-menuitem')
], PopupMenuItem);
export { PopupMenuItem };
], OxPopupMenuItem);
export { OxPopupMenuItem };
//# sourceMappingURL=ox-popup-menuitem.js.map
import { LitElement } from 'lit';
export declare class Popup extends LitElement {
export declare class OxPopup extends LitElement {
static styles: import("lit").CSSResult[];

@@ -28,11 +28,15 @@ _parent?: Element;

*/
static open({ template, top, left, parent }: {
static open({ template, top, left, right, bottom, parent }: {
template: unknown;
top: number;
left: number;
top?: number;
left?: number;
right?: number;
bottom?: number;
parent?: Element | null;
}): void;
open({ left, top, silent }: {
open({ left, top, right, bottom, silent }: {
left?: number;
top?: number;
right?: number;
bottom?: number;
silent?: boolean;

@@ -39,0 +43,0 @@ }): void;

import { __decorate } from "tslib";
import { LitElement, css, html } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import { ScrollbarStyles } from '@operato/styles';
import { render } from 'lit-html';
let Popup = class Popup extends LitElement {
let OxPopup = class OxPopup extends LitElement {
constructor() {

@@ -54,4 +55,2 @@ super(...arguments);

this.addEventListener('ox-collapse', this._oncollapse);
/* When the window is out of focus, all pop-ups should disappear. */
window.addEventListener('blur', this._onwindowblur);
this.setAttribute('tabindex', '0'); // make this element focusable

@@ -74,17 +73,23 @@ this.guaranteeFocus();

*/
static open({ template, top, left, parent }) {
static open({ template, top, left, right, bottom, parent }) {
const owner = parent || document.body;
const target = document.createElement('ox-popup');
render(template, target);
target.style.left = `${left}px`;
target.style.top = `${top}px`;
target.setAttribute('active', '');
target._parent = owner;
owner.appendChild(target);
target.open({ top, left, right, bottom });
}
open({ left = 0, top = 0, silent = false }) {
this.style.left = `${left}px`;
this.style.top = `${top}px`;
open({ left, top, right, bottom, silent = false }) {
if (left !== undefined)
this.style.left = `${left}px`;
if (top !== undefined)
this.style.top = `${top}px`;
if (right !== undefined)
this.style.right = `${right}px`;
if (bottom !== undefined)
this.style.bottom = `${bottom}px`;
this.setAttribute('active', '');
!silent && this.guaranteeFocus();
/* When the window is out of focus, all pop-ups should disappear. */
window.addEventListener('blur', this._onwindowblur);
}

@@ -103,4 +108,5 @@ guaranteeFocus() {

this.removeAttribute('active');
window.removeEventListener('blur', this._onwindowblur);
if (this._parent) {
/* this case is when the popup is opened by Popup.open(...) */
/* this case is when the popup is opened by OxPopup.open(...) */
this.removeEventListener('focusout', this._onfocusout);

@@ -112,3 +118,2 @@ this.removeEventListener('keydown', this._onkeydown);

this.removeEventListener('ox-collapse', this._oncollapse);
window.removeEventListener('blur', this._onwindowblur);
this._parent.removeChild(this);

@@ -119,3 +124,4 @@ delete this._parent;

};
Popup.styles = [
OxPopup.styles = [
ScrollbarStyles,
css `

@@ -127,2 +133,4 @@ :host {

z-index: 100;
box-sizing: border-box;
min-width: fit-content;
}

@@ -141,7 +149,7 @@

state()
], Popup.prototype, "_parent", void 0);
Popup = __decorate([
], OxPopup.prototype, "_parent", void 0);
OxPopup = __decorate([
customElement('ox-popup')
], Popup);
export { Popup };
], OxPopup);
export { OxPopup };
//# sourceMappingURL=ox-popup.js.map
import '../src/ox-popup-menu';
import { expect, fixture } from '@open-wc/testing';
import { html } from 'lit';
import { expect, fixture } from '@open-wc/testing';
describe('PopupMenu', () => {
describe('OxPopupMenu', () => {
it('has a default title "Hey there" and counter 5', async () => {

@@ -6,0 +6,0 @@ const el = await fixture(html `<ox-popup-menu></ox-popup-menu>`);

import '../src/ox-popup';
import { expect, fixture } from '@open-wc/testing';
import { html } from 'lit';
import { expect, fixture } from '@open-wc/testing';
describe('Popup', () => {

@@ -5,0 +5,0 @@ it('has a default title "Hey there" and counter 5', async () => {

@@ -6,3 +6,3 @@ {

"author": "heartyoh",
"version": "0.2.35",
"version": "0.2.36",
"main": "dist/src/index.js",

@@ -36,2 +36,3 @@ "module": "dist/src/index.js",

"@material/mwc-icon": "^0.25.3",
"@operato/styles": "^0.2.36",
"lit": "^2.0.2"

@@ -71,3 +72,3 @@ },

},
"gitHead": "6099777251e8f46c5adc98dc9fc2cfbc8194cf12"
"gitHead": "fa4b02d776ebca4674d2c5e02fafa7042a5d5448"
}
import { PropertyValues, css, html } from 'lit'
import { customElement, property } from 'lit/decorators.js'
import { customElement, property, state } from 'lit/decorators.js'
import { Popup } from './ox-popup'
import { OxPopup } from './ox-popup'
import { render } from 'lit-html'
function focusClosest(element: HTMLElement) {
/* Find the closest focusable element. */
function guaranteeFocus(element: HTMLElement) {
// 1. 옵션 엘리먼트의 하위 첫번째 focusible 엘리먼트에 focus 기회를 준다.
const focusible = element.querySelector('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])')
if (focusible) {
;(focusible as HTMLElement).focus()
return
}
// 2. 자신을 포함해서 가장 가까운 부모에게 focus 기회를 준다.
const closest = element.closest(

@@ -14,10 +22,8 @@ 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'

closest?.focus()
return closest
}
@customElement('ox-popup-list')
export class PopupList extends Popup {
export class OxPopupList extends OxPopup {
static styles = [
...Popup.styles,
...OxPopup.styles,
css`

@@ -45,2 +51,6 @@ :host {

::slotted([option]) {
white-space: nowrap;
}
::slotted(*) {

@@ -64,2 +74,7 @@ margin: 1px 0;

::slotted([option][selected]) {
background-color: red;
cursor: pointer;
}
::slotted([separator]) {

@@ -77,9 +92,19 @@ height: 1px;

@property({ type: Number }) activeIndex: number = 0
@property({ type: Boolean }) multiple: boolean = false
@property({ type: String, attribute: 'attr-selected' }) attrSelected?: string
@state() activeIndex?: number
render() {
return html` <slot> </slot> `
return html`
<slot
@change=${(e: Event) => {
e.stopPropagation()
}}
>
</slot>
`
}
protected _onkeydown: (e: KeyboardEvent) => void = function (this: PopupList, e: KeyboardEvent) {
protected _onkeydown: (e: KeyboardEvent) => void = function (this: OxPopupList, e: KeyboardEvent) {
e.stopPropagation()

@@ -97,3 +122,3 @@

case 'ArrowUp':
this.activeIndex--
this.activeIndex!--
break

@@ -105,11 +130,10 @@

case 'ArrowDown':
this.activeIndex++
this.activeIndex!++
break
case 'Enter':
e.stopPropagation()
var option = (e.target as HTMLElement)?.closest('[option]')
if (option) {
this.select(option)
}
case ' ':
case 'Spacebar': // for old firefox
this.setActive(this.activeIndex!, true)
this.select()
break

@@ -119,22 +143,13 @@ }

protected _onfocusout: (e: FocusEvent) => void = function (this: PopupList, e: FocusEvent) {
const target = e.target as HTMLElement
protected _onfocusout: (e: FocusEvent) => void = function (this: OxPopupList, e: FocusEvent) {
const to = e.relatedTarget as HTMLElement
const from = target.closest('ox-popup-list')
if (!to && from !== this) {
e.stopPropagation()
/* "하위의 ox-popup-list 엘리먼트가 포커스를 잃었지만, 그 포커스를 받은 엘리먼트가 없다."는 의미는 그 서브메뉴가 클로즈된 것을 의미한다. */
this.setActive(this.activeIndex)
} else {
if (!this.contains(to)) {
/* 분명히 내 범위가 아닌 엘리먼트로 포커스가 옮겨졌다면, ox-popup-list는 닫혀야 한다. */
// @ts-ignore for debug
!window.POPUP_DEBUG && this.close()
}
if (!this.contains(to)) {
/* 분명히 내 범위가 아닌 엘리먼트로 포커스가 옮겨졌다면, ox-popup-list는 닫혀야 한다. */
// @ts-ignore for debug
!window.POPUP_DEBUG && this.close()
}
}.bind(this)
protected _onclick: (e: MouseEvent) => void = function (this: PopupList, e: MouseEvent) {
protected _onclick: (e: MouseEvent) => void = function (this: OxPopupList, e: MouseEvent) {
e.stopPropagation()

@@ -144,4 +159,4 @@

if (option) {
this.setActive(option)
this.select(option)
this.setActive(option, true)
this.select()
}

@@ -152,10 +167,25 @@ }.bind(this)

if (changes.has('activeIndex')) {
this.setActive(this.activeIndex)
this.activeIndex !== undefined && this.setActive(this.activeIndex)
}
}
select(option: Element) {
option.dispatchEvent(new CustomEvent('selected', { bubbles: true, composed: true, detail: this }))
async select() {
await this.updateComplete
if (!option.hasAttribute('alive-on-select') && !this.hasAttribute('alive-on-select')) {
const options = Array.from(this.querySelectorAll(':scope > [option]'))
const selected = options
.filter(option => option.hasAttribute('value') && option.hasAttribute(this.attrSelected || 'selected'))
.map(option => option.getAttribute('value'))
this.dispatchEvent(
new CustomEvent('select', {
bubbles: true,
composed: true,
detail: this.multiple ? selected : selected[0]
})
)
const option = options[this.activeIndex!]
if (!option.hasAttribute('alive-on-select') && !this.hasAttribute('multiple')) {
this.close()

@@ -165,15 +195,24 @@ }

setActive(active: number | Element | null) {
const options = Array.from(this.querySelectorAll(':scope > [option]'))
setActive(active: number | Element | null, withSelect?: boolean) {
const options = Array.from(this.querySelectorAll('[option]'))
options.map(async (option, index) => {
if (active instanceof Element) {
const index = options.findIndex(option => option === active)
this.setActive(index === -1 ? 0 : index, withSelect)
return
}
options.forEach(async (option, index) => {
if (typeof active === 'number' && index === (active + options.length) % options.length) {
option.setAttribute('active', '')
focusClosest(option as HTMLElement)
if (withSelect && !this.attrSelected) {
this.multiple ? option.toggleAttribute('selected') : option.setAttribute('selected', '')
}
guaranteeFocus(option as HTMLElement)
this.activeIndex = index
} else if (active === option) {
this.activeIndex = index
} else {
option.removeAttribute('active')
!this.attrSelected && !this.multiple && withSelect && option.removeAttribute('selected')
}

@@ -183,4 +222,27 @@ })

override open(params: { left?: number; top?: number; right?: number; bottom?: number; silent?: boolean }) {
super.open(params)
if (this.activeIndex === undefined) {
this.activeIndex = 0
} else {
this.setActive(this.activeIndex)
}
}
override close() {
if (this.hasAttribute('active')) {
this.dispatchEvent(
new CustomEvent('close', {
bubbles: true,
composed: true
})
)
}
super.close()
}
/**
* Open Popup
* Open OxPopup
*

@@ -193,18 +255,22 @@ * @param {PopupOpenOptions}

left,
right,
bottom,
parent
}: {
template: unknown
top: number
left: number
top?: number
left?: number
right?: number
bottom?: number
parent?: Element | null
}) {
const owner = parent || document.body
const target = document.createElement('ox-popup-list') as PopupList
const target = document.createElement('ox-popup-list') as OxPopupList
render(template, target)
target.style.left = `${left}px`
target.style.top = `${top}px`
if (left !== undefined) target.style.left = `${left}px`
if (top !== undefined) target.style.top = `${top}px`
if (right !== undefined) target.style.right = `${right}px`
if (bottom !== undefined) target.style.bottom = `${bottom}px`
target.setAttribute('active', '')
target._parent = owner

@@ -211,0 +277,0 @@

import { PropertyValues, css, html } from 'lit'
import { customElement, property } from 'lit/decorators.js'
import { Popup } from './ox-popup'
import { OxPopup } from './ox-popup'
import { render } from 'lit-html'

@@ -19,5 +19,5 @@

@customElement('ox-popup-menu')
export class PopupMenu extends Popup {
export class OxPopupMenu extends OxPopup {
static styles = [
...Popup.styles,
...OxPopup.styles,
css`

@@ -83,3 +83,3 @@ :host {

protected _onkeydown: (e: KeyboardEvent) => void = function (this: PopupMenu, e: KeyboardEvent) {
protected _onkeydown: (e: KeyboardEvent) => void = function (this: OxPopupMenu, e: KeyboardEvent) {
e.stopPropagation()

@@ -117,3 +117,3 @@

protected _onfocusout: (e: FocusEvent) => void = function (this: PopupMenu, e: FocusEvent) {
protected _onfocusout: (e: FocusEvent) => void = function (this: OxPopupMenu, e: FocusEvent) {
const target = e.target as HTMLElement

@@ -137,3 +137,3 @@ const to = e.relatedTarget as HTMLElement

protected _onclick: (e: MouseEvent) => void = function (this: PopupMenu, e: MouseEvent) {
protected _onclick: (e: MouseEvent) => void = function (this: OxPopupMenu, e: MouseEvent) {
e.stopPropagation()

@@ -155,3 +155,3 @@

select(menu: Element) {
menu.dispatchEvent(new CustomEvent('selected'))
menu.dispatchEvent(new CustomEvent('select'))
if (!menu.hasAttribute('alive-on-select')) {

@@ -203,3 +203,3 @@ this.dispatchEvent(new CustomEvent('ox-close', { bubbles: true, composed: true, detail: this }))

const owner = parent || document.body
const target = document.createElement('ox-popup-menu') as PopupMenu
const target = document.createElement('ox-popup-menu') as OxPopupMenu
render(template, target)

@@ -206,0 +206,0 @@

import { LitElement, PropertyValues, css, html } from 'lit'
import { customElement, property, state } from 'lit/decorators.js'
import { PopupMenu } from './ox-popup-menu'
import { OxPopupMenu } from './ox-popup-menu'
@customElement('ox-popup-menuitem')
export class PopupMenuItem extends LitElement {
export class OxPopupMenuItem extends LitElement {
static styles = [

@@ -55,3 +55,3 @@ css`

@state() _submenu?: PopupMenu
@state() _submenu?: OxPopupMenu

@@ -77,3 +77,3 @@ render() {

protected _onclick: (e: MouseEvent) => void = function (this: PopupMenuItem, e: MouseEvent) {
protected _onclick: (e: MouseEvent) => void = function (this: OxPopupMenuItem, e: MouseEvent) {
if (!this._submenu) {

@@ -85,3 +85,3 @@ return

const parent = this.closest('ox-popup-menu') as PopupMenu
const parent = this.closest('ox-popup-menu') as OxPopupMenu
if (parent) {

@@ -91,3 +91,3 @@ parent.setActive(this)

this.dispatchEvent(new CustomEvent('selected'))
this.dispatchEvent(new CustomEvent('select'))

@@ -99,3 +99,3 @@ requestAnimationFrame(() => {

protected _onkeydown: (e: KeyboardEvent) => void = function (this: PopupMenuItem, e: KeyboardEvent) {
protected _onkeydown: (e: KeyboardEvent) => void = function (this: OxPopupMenuItem, e: KeyboardEvent) {
switch (e.key) {

@@ -123,4 +123,4 @@ case 'Right':

protected _onslotchange: (e: Event) => void = function (this: PopupMenuItem, e: Event) {
this._submenu = this.querySelector('ox-popup-menu') as PopupMenu
protected _onslotchange: (e: Event) => void = function (this: OxPopupMenuItem, e: Event) {
this._submenu = this.querySelector('ox-popup-menu') as OxPopupMenu
}.bind(this)

@@ -127,0 +127,0 @@

import { LitElement, css, html } from 'lit'
import { customElement, state } from 'lit/decorators.js'
import { ScrollbarStyles } from '@operato/styles'
import { render } from 'lit-html'
@customElement('ox-popup')
export class Popup extends LitElement {
export class OxPopup extends LitElement {
static styles = [
ScrollbarStyles,
css`

@@ -15,2 +17,4 @@ :host {

z-index: 100;
box-sizing: border-box;
min-width: fit-content;
}

@@ -34,3 +38,3 @@

protected _onfocusout: (e: FocusEvent) => void = function (this: Popup, e: FocusEvent) {
protected _onfocusout: (e: FocusEvent) => void = function (this: OxPopup, e: FocusEvent) {
const to = e.relatedTarget as HTMLElement

@@ -45,3 +49,3 @@

protected _onkeydown: (e: KeyboardEvent) => void = function (this: Popup, e: KeyboardEvent) {
protected _onkeydown: (e: KeyboardEvent) => void = function (this: OxPopup, e: KeyboardEvent) {
e.stopPropagation()

@@ -57,15 +61,15 @@

protected _onkeyup: (e: KeyboardEvent) => void = function (this: Popup, e: KeyboardEvent) {
protected _onkeyup: (e: KeyboardEvent) => void = function (this: OxPopup, e: KeyboardEvent) {
e.stopPropagation()
}.bind(this)
protected _onclick: (e: MouseEvent) => void = function (this: Popup, e: MouseEvent) {
protected _onclick: (e: MouseEvent) => void = function (this: OxPopup, e: MouseEvent) {
e.stopPropagation()
}.bind(this)
protected _onclose: (e: Event) => void = function (this: Popup, e: Event) {
protected _onclose: (e: Event) => void = function (this: OxPopup, e: Event) {
this.close()
}.bind(this)
protected _oncollapse: (e: Event) => void = function (this: Popup, e: Event) {
protected _oncollapse: (e: Event) => void = function (this: OxPopup, e: Event) {
e.stopPropagation()

@@ -75,3 +79,3 @@ this.close()

protected _onwindowblur: (e: Event) => void = function (this: Popup, e: Event) {
protected _onwindowblur: (e: Event) => void = function (this: OxPopup, e: Event) {
// @ts-ignore for debug

@@ -91,5 +95,2 @@ !window.POPUP_DEBUG && this.close()

/* When the window is out of focus, all pop-ups should disappear. */
window.addEventListener('blur', this._onwindowblur)
this.setAttribute('tabindex', '0') // make this element focusable

@@ -118,25 +119,41 @@ this.guaranteeFocus()

left,
right,
bottom,
parent
}: {
template: unknown
top: number
left: number
top?: number
left?: number
right?: number
bottom?: number
parent?: Element | null
}) {
const owner = parent || document.body
const target = document.createElement('ox-popup') as Popup
const target = document.createElement('ox-popup') as OxPopup
render(template, target)
target.style.left = `${left}px`
target.style.top = `${top}px`
target.setAttribute('active', '')
target._parent = owner
owner.appendChild(target)
target.open({ top, left, right, bottom })
}
open({ left = 0, top = 0, silent = false }: { left?: number; top?: number; silent?: boolean }) {
this.style.left = `${left}px`
this.style.top = `${top}px`
open({
left,
top,
right,
bottom,
silent = false
}: {
left?: number
top?: number
right?: number
bottom?: number
silent?: boolean
}) {
if (left !== undefined) this.style.left = `${left}px`
if (top !== undefined) this.style.top = `${top}px`
if (right !== undefined) this.style.right = `${right}px`
if (bottom !== undefined) this.style.bottom = `${bottom}px`

@@ -146,2 +163,5 @@ this.setAttribute('active', '')

!silent && this.guaranteeFocus()
/* When the window is out of focus, all pop-ups should disappear. */
window.addEventListener('blur', this._onwindowblur)
}

@@ -164,4 +184,6 @@

window.removeEventListener('blur', this._onwindowblur)
if (this._parent) {
/* this case is when the popup is opened by Popup.open(...) */
/* this case is when the popup is opened by OxPopup.open(...) */
this.removeEventListener('focusout', this._onfocusout)

@@ -174,4 +196,2 @@ this.removeEventListener('keydown', this._onkeydown)

window.removeEventListener('blur', this._onwindowblur)
this._parent.removeChild(this)

@@ -178,0 +198,0 @@ delete this._parent

import '../src/ox-popup-menu'
import { html } from 'lit'
import { expect, fixture } from '@open-wc/testing'
import { PopupMenu } from '../src/ox-popup-menu'
import { OxPopupMenu } from '../src/ox-popup-menu'
import { html } from 'lit'
describe('PopupMenu', () => {
describe('OxPopupMenu', () => {
it('has a default title "Hey there" and counter 5', async () => {
const el = await fixture<PopupMenu>(html`<ox-popup-menu></ox-popup-menu>`)
const el = await fixture<OxPopupMenu>(html`<ox-popup-menu></ox-popup-menu>`)

@@ -18,3 +17,3 @@ expect(el.title).to.equal('Hey there')

it('increases the counter on button click', async () => {
const el = await fixture<PopupMenu>(html`<ox-popup-menu></ox-popup-menu>`)
const el = await fixture<OxPopupMenu>(html`<ox-popup-menu></ox-popup-menu>`)
el.shadowRoot!.querySelector('button')!.click()

@@ -26,3 +25,3 @@

it('can override the title via attribute', async () => {
const el = await fixture<PopupMenu>(html`<ox-popup-menu title="attribute title"></ox-popup-menu>`)
const el = await fixture<OxPopupMenu>(html`<ox-popup-menu title="attribute title"></ox-popup-menu>`)

@@ -33,3 +32,3 @@ expect(el.title).to.equal('attribute title')

it('passes the a11y audit', async () => {
const el = await fixture<PopupMenu>(html`<ox-popup-menu></ox-popup-menu>`)
const el = await fixture<OxPopupMenu>(html`<ox-popup-menu></ox-popup-menu>`)

@@ -36,0 +35,0 @@ await expect(el).shadowDom.to.be.accessible()

import '../src/ox-popup'
import { html } from 'lit'
import { expect, fixture } from '@open-wc/testing'
import { Popup } from '../src/ox-popup'
import { OxPopup } from '../src/ox-popup'
import { html } from 'lit'
describe('Popup', () => {
it('has a default title "Hey there" and counter 5', async () => {
const el = await fixture<Popup>(html`<ox-popup></ox-popup>`)
const el = await fixture<OxPopup>(html`<ox-popup></ox-popup>`)

@@ -18,3 +17,3 @@ expect(el.title).to.equal('Hey there')

it('increases the counter on button click', async () => {
const el = await fixture<Popup>(html`<ox-popup></ox-popup>`)
const el = await fixture<OxPopup>(html`<ox-popup></ox-popup>`)
el.shadowRoot!.querySelector('button')!.click()

@@ -26,3 +25,3 @@

it('can override the title via attribute', async () => {
const el = await fixture<Popup>(html`<ox-popup title="attribute title"></ox-popup>`)
const el = await fixture<OxPopup>(html`<ox-popup title="attribute title"></ox-popup>`)

@@ -33,3 +32,3 @@ expect(el.title).to.equal('attribute title')

it('passes the a11y audit', async () => {
const el = await fixture<Popup>(html`<ox-popup></ox-popup>`)
const el = await fixture<OxPopup>(html`<ox-popup></ox-popup>`)

@@ -36,0 +35,0 @@ await expect(el).shadowDom.to.be.accessible()

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc