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

@vaadin/vaadin-list-mixin

Package Overview
Dependencies
Maintainers
18
Versions
256
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@vaadin/vaadin-list-mixin - npm Package Compare versions

Comparing version 2.5.1 to 20.0.0-alpha1

38

package.json
{
"name": "@vaadin/vaadin-list-mixin",
"version": "20.0.0-alpha1",
"description": "vaadin-list-mixin",
"main": "vaadin-list-mixin.js",
"module": "vaadin-list-mixin.js",
"repository": "vaadin/vaadin-list-mixin",
"keywords": [

@@ -10,7 +15,2 @@ "Vaadin",

],
"repository": "vaadin/vaadin-list-mixin",
"homepage": "https://vaadin.com/elements",
"name": "@vaadin/vaadin-list-mixin",
"version": "2.5.1",
"main": "vaadin-list-mixin.js",
"author": "Vaadin Ltd",

@@ -21,2 +21,3 @@ "license": "Apache-2.0",

},
"homepage": "https://vaadin.com/elements",
"files": [

@@ -26,25 +27,16 @@ "*.d.ts",

],
"resolutions": {
"es-abstract": "1.17.6",
"@types/doctrine": "0.0.3",
"inherits": "2.0.3",
"samsam": "1.1.3",
"supports-color": "3.1.2",
"type-detect": "1.0.0"
},
"dependencies": {
"@polymer/polymer": "^3.0.0",
"@vaadin/vaadin-element-mixin": "^2.4.1"
"@vaadin/vaadin-element-mixin": "^20.0.0-alpha1"
},
"scripts": {
"generate-typings": "gen-typescript-declarations --outDir . --verify"
},
"devDependencies": {
"@esm-bundle/chai": "^4.1.5",
"@open-wc/testing-helpers": "^1.8.12",
"@polymer/iron-test-helpers": "^3.0.0",
"wct-browser-legacy": "^1.0.1",
"@webcomponents/webcomponentsjs": "^2.0.0",
"@vaadin/vaadin-context-menu": "^4.3.13",
"@vaadin/vaadin-select": "^2.1.6",
"@vaadin/vaadin-tabs": "^3.0.5"
}
"sinon": "^9.2.4"
},
"publishConfig": {
"access": "public"
},
"gitHead": "93c8e0ec03a178c6d74261261f985bd07f7cc79c"
}

@@ -1,9 +0,8 @@

![Bower version](https://img.shields.io/bower/v/vaadin-list-mixin.svg)
[![Published on webcomponents.org](https://img.shields.io/badge/webcomponents.org-published-blue.svg)](https://www.webcomponents.org/element/vaadin/vaadin-list-mixin)
[![Build Status](https://travis-ci.org/vaadin/vaadin-list-mixin.svg?branch=master)](https://travis-ci.org/vaadin/vaadin-list-mixin)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/vaadin/web-components?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
# vaadin-list-mixin
# vaadin-list-mixin
`vaadin-list-mixin` is a mixin for `nav` elements, facilitating navigation and selection of childNodes.
[![npm version](https://badgen.net/npm/v/@vaadin/vaadin-list-mixin)](https://www.npmjs.com/package/@vaadin/vaadin-list-mixin)
[![Discord](https://img.shields.io/discord/732335336448852018?label=discord)](https://discord.gg/PHmkCKC)
## Running tests in browser

@@ -13,23 +12,17 @@

1. Make sure you have [npm](https://www.npmjs.com/) and [Bower](https://bower.io) installed.
1. Make sure you have [npm](https://www.npmjs.com/).
1. When in the `vaadin-list-mixin` directory, run `npm install` and then `bower install` to install dependencies.
1. When in the `vaadin-list-mixin` directory, run `npm install` to install dependencies.
1. Make sure you have [polymer-cli](https://www.npmjs.com/package/polymer-cli) installed globally: `npm i -g polymer-cli`.
1. Run `npm test` to start the tests in Chrome.
1. Run `npm start`.
1. Navigate to http://127.0.0.1:3000/components/vaadin-list-mixin/test/index.html
## Debugging tests in browser
1. Run `npm run debug`, then choose manual mode (M) and open the link in browser.
## Running tests from the command line
1. Install [web-component-tester](https://www.npmjs.com/package/web-component-tester): `npm install -g web-component-tester`
1. When in the `vaadin-list-mixin` directory, run `wct` or `npm test`
## Following the coding style
We are using [ESLint](http://eslint.org/) for linting JavaScript code. You can check if your code is following our standards by running `npm run lint`, which will automatically lint all `.js` files as well as JavaScript snippets inside `.html` files.
We are using [ESLint](http://eslint.org/) for linting JavaScript code. You can check if your code is following our standards by running `npm run lint`, which will automatically lint all `.js` files.

@@ -36,0 +29,0 @@

@@ -1,26 +0,3 @@

/**
* DO NOT EDIT
*
* This file was automatically generated by
* https://github.com/Polymer/tools/tree/master/packages/gen-typescript-declarations
*
* To modify these typings, edit the source file(s):
* vaadin-list-mixin.js
*/
import { ListOrientation } from './interfaces';
// tslint:disable:variable-name Describing an API that's defined elsewhere.
// tslint:disable:no-any describes the API as best we are able today
import {FlattenedNodesObserver} from '@polymer/polymer/lib/utils/flattened-nodes-observer.js';
import {DirHelper} from '@vaadin/vaadin-element-mixin/vaadin-dir-helper.js';
import {Debouncer} from '@polymer/polymer/lib/utils/debounce.js';
import {timeOut} from '@polymer/polymer/lib/utils/async.js';
export {ListMixin};
/**

@@ -32,11 +9,12 @@ * A mixin for `nav` elements, facilitating navigation and selection of childNodes.

interface ListMixinConstructor {
new(...args: any[]): ListMixin;
new (...args: any[]): ListMixin;
}
export {ListMixinConstructor};
interface ListMixin {
readonly focused: Element | null;
interface ListMixin {
readonly focused: Element|null;
readonly _isRTL: boolean;
readonly _scrollerElement: HTMLElement;
readonly _vertical: boolean;

@@ -53,3 +31,3 @@

*/
selected: number|null|undefined;
selected: number | null | undefined;

@@ -74,12 +52,22 @@ /**

*/
readonly items: Element[]|undefined;
readonly items: Element[] | undefined;
ready(): void;
_filterItems(array: Element[]): Element[];
_onClick(event: MouseEvent): void;
_searchKey(currentIdx: number, key: string): number;
_onKeydown(event: KeyboardEvent): void;
_getAvailableIndex(idx: number, increment: number, condition: (p0: Element) => boolean): number;
_isItemHidden(item: Element): boolean;
_setFocusable(idx: number): void;
_focus(idx: number): void;
focus(): void;

@@ -91,5 +79,6 @@

_scrollToItem(idx: number): void;
_scroll(pixels: number): void;
}
import {ListOrientation} from './interfaces';
export { ListMixin, ListMixinConstructor };
/**
@license
Copyright (c) 2017 Vaadin Ltd.
This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
*/
* @license
* Copyright (c) 2021 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
*/
import { FlattenedNodesObserver } from '@polymer/polymer/lib/utils/flattened-nodes-observer.js';
import { DirHelper } from '@vaadin/vaadin-element-mixin/vaadin-dir-helper.js';

@@ -17,346 +16,357 @@ import { Debouncer } from '@polymer/polymer/lib/utils/debounce.js';

*/
export const ListMixin = superClass => class VaadinListMixin extends superClass {
static get properties() {
return {
/**
* Used for mixin detection because `instanceof` does not work with mixins.
* @type {boolean}
*/
_hasVaadinListMixin: {
value: true
},
export const ListMixin = (superClass) =>
class VaadinListMixin extends superClass {
static get properties() {
return {
/**
* Used for mixin detection because `instanceof` does not work with mixins.
* @type {boolean}
*/
_hasVaadinListMixin: {
value: true
},
/**
* The index of the item selected in the items array.
* Note: Not updated when used in `multiple` selection mode.
*/
selected: {
type: Number,
reflectToAttribute: true,
notify: true
},
/**
* The index of the item selected in the items array.
* Note: Not updated when used in `multiple` selection mode.
*/
selected: {
type: Number,
reflectToAttribute: true,
notify: true
},
/**
* Define how items are disposed in the dom.
* Possible values are: `horizontal|vertical`.
* It also changes navigation keys from left/right to up/down.
* @type {!ListOrientation}
*/
orientation: {
type: String,
reflectToAttribute: true,
value: ''
},
/**
* Define how items are disposed in the dom.
* Possible values are: `horizontal|vertical`.
* It also changes navigation keys from left/right to up/down.
* @type {!ListOrientation}
*/
orientation: {
type: String,
reflectToAttribute: true,
value: ''
},
/**
* The list of items from which a selection can be made.
* It is populated from the elements passed to the light DOM,
* and updated dynamically when adding or removing items.
*
* The item elements must implement `Vaadin.ItemMixin`.
*
* Note: unlike `<vaadin-combo-box>`, this property is read-only,
* so if you want to provide items by iterating array of data,
* you have to use `dom-repeat` and place it to the light DOM.
* @type {!Array<!Element> | undefined}
*/
items: {
type: Array,
readOnly: true,
notify: true
},
/**
* The list of items from which a selection can be made.
* It is populated from the elements passed to the light DOM,
* and updated dynamically when adding or removing items.
*
* The item elements must implement `Vaadin.ItemMixin`.
*
* Note: unlike `<vaadin-combo-box>`, this property is read-only,
* so if you want to provide items by iterating array of data,
* you have to use `dom-repeat` and place it to the light DOM.
* @type {!Array<!Element> | undefined}
*/
items: {
type: Array,
readOnly: true,
notify: true
},
/**
* The search buffer for the keyboard selection feature.
* @private
*/
_searchBuf: {
type: String,
value: ''
}
};
}
/**
* The search buffer for the keyboard selection feature.
* @private
*/
_searchBuf: {
type: String,
value: ''
}
};
}
static get observers() {
return ['_enhanceItems(items, orientation, selected, disabled)'];
}
static get observers() {
return ['_enhanceItems(items, orientation, selected, disabled)'];
}
/** @protected */
ready() {
super.ready();
this.addEventListener('keydown', e => this._onKeydown(e));
this.addEventListener('click', e => this._onClick(e));
/** @protected */
ready() {
super.ready();
this.addEventListener('keydown', (e) => this._onKeydown(e));
this.addEventListener('click', (e) => this._onClick(e));
this._observer = new FlattenedNodesObserver(this, info => {
this._setItems(this._filterItems(Array.from(this.children)));
});
}
this._observer = new FlattenedNodesObserver(this, () => {
this._setItems(this._filterItems(Array.from(this.children)));
});
}
/** @private */
_enhanceItems(items, orientation, selected, disabled) {
if (!disabled) {
if (items) {
this.setAttribute('aria-orientation', orientation || 'vertical');
this.items.forEach(item => {
orientation ? item.setAttribute('orientation', orientation) : item.removeAttribute('orientation');
item.updateStyles();
});
/** @private */
_enhanceItems(items, orientation, selected, disabled) {
if (!disabled) {
if (items) {
this.setAttribute('aria-orientation', orientation || 'vertical');
this.items.forEach((item) => {
orientation ? item.setAttribute('orientation', orientation) : item.removeAttribute('orientation');
});
this._setFocusable(selected);
this._setFocusable(selected);
const itemToSelect = items[selected];
items.forEach(item => item.selected = item === itemToSelect);
if (itemToSelect && !itemToSelect.disabled) {
this._scrollToItem(selected);
const itemToSelect = items[selected];
items.forEach((item) => (item.selected = item === itemToSelect));
if (itemToSelect && !itemToSelect.disabled) {
this._scrollToItem(selected);
}
}
}
}
}
/**
* @return {Element}
*/
get focused() {
return this.getRootNode().activeElement;
}
/**
* @param {!Array<!Element>} array
* @return {!Array<!Element>}
* @protected
*/
_filterItems(array) {
return array.filter(e => e._hasVaadinItemMixin);
}
/**
* @param {!MouseEvent} event
* @protected
*/
_onClick(event) {
if (event.metaKey || event.shiftKey || event.ctrlKey || event.defaultPrevented) {
return;
/**
* @return {Element}
*/
get focused() {
return this.getRootNode().activeElement;
}
const item = this._filterItems(event.composedPath())[0];
let idx;
if (item && !item.disabled && ((idx = this.items.indexOf(item)) >= 0)) {
this.selected = idx;
/**
* @param {!Array<!Element>} array
* @return {!Array<!Element>}
* @protected
*/
_filterItems(array) {
return array.filter((e) => e._hasVaadinItemMixin);
}
}
/**
* @param {number} currentIdx
* @param {string} key
* @return {number}
* @protected
*/
_searchKey(currentIdx, key) {
this._searchReset = Debouncer.debounce(
this._searchReset,
timeOut.after(500),
() => this._searchBuf = ''
);
this._searchBuf += key.toLowerCase();
const increment = 1;
const condition = item => !(item.disabled || this._isItemHidden(item)) &&
item.textContent.replace(/[^a-zA-Z0-9]/g, '').toLowerCase().indexOf(this._searchBuf) === 0;
/**
* @param {!MouseEvent} event
* @protected
*/
_onClick(event) {
if (event.metaKey || event.shiftKey || event.ctrlKey || event.defaultPrevented) {
return;
}
if (!this.items.some(item => item.textContent.replace(/[^a-zA-Z0-9]/g, '').toLowerCase().indexOf(this._searchBuf) === 0)) {
this._searchBuf = key.toLowerCase();
const item = this._filterItems(event.composedPath())[0];
let idx;
if (item && !item.disabled && (idx = this.items.indexOf(item)) >= 0) {
this.selected = idx;
}
}
const idx = this._searchBuf.length === 1 ? currentIdx + 1 : currentIdx;
return this._getAvailableIndex(idx, increment, condition);
}
/**
* @param {number} currentIdx
* @param {string} key
* @return {number}
* @protected
*/
_searchKey(currentIdx, key) {
this._searchReset = Debouncer.debounce(this._searchReset, timeOut.after(500), () => (this._searchBuf = ''));
this._searchBuf += key.toLowerCase();
const increment = 1;
const condition = (item) =>
!(item.disabled || this._isItemHidden(item)) &&
item.textContent
.replace(/[^a-zA-Z0-9]/g, '')
.toLowerCase()
.indexOf(this._searchBuf) === 0;
/**
* @return {boolean}
* @protected
*/
get _isRTL() {
return !this._vertical && this.getAttribute('dir') === 'rtl';
}
if (
!this.items.some(
(item) =>
item.textContent
.replace(/[^a-zA-Z0-9]/g, '')
.toLowerCase()
.indexOf(this._searchBuf) === 0
)
) {
this._searchBuf = key.toLowerCase();
}
/**
* @param {!KeyboardEvent} event
* @protected
*/
_onKeydown(event) {
if (event.metaKey || event.ctrlKey) {
return;
const idx = this._searchBuf.length === 1 ? currentIdx + 1 : currentIdx;
return this._getAvailableIndex(idx, increment, condition);
}
// IE names for arrows do not include the Arrow prefix
const key = event.key.replace(/^Arrow/, '');
/**
* @return {boolean}
* @protected
*/
get _isRTL() {
return !this._vertical && this.getAttribute('dir') === 'rtl';
}
const currentIdx = this.items.indexOf(this.focused);
/**
* @param {!KeyboardEvent} event
* @protected
*/
_onKeydown(event) {
if (event.metaKey || event.ctrlKey) {
return;
}
if (/[a-zA-Z0-9]/.test(key) && key.length === 1) {
const idx = this._searchKey(currentIdx, key);
const key = event.key;
const currentIdx = this.items.indexOf(this.focused);
if (/[a-zA-Z0-9]/.test(key) && key.length === 1) {
const idx = this._searchKey(currentIdx, key);
if (idx >= 0) {
this._focus(idx);
}
return;
}
const condition = (item) => !(item.disabled || this._isItemHidden(item));
let idx, increment;
const dirIncrement = this._isRTL ? -1 : 1;
if ((this._vertical && key === 'ArrowUp') || (!this._vertical && key === 'ArrowLeft')) {
increment = -dirIncrement;
idx = currentIdx - dirIncrement;
} else if ((this._vertical && key === 'ArrowDown') || (!this._vertical && key === 'ArrowRight')) {
increment = dirIncrement;
idx = currentIdx + dirIncrement;
} else if (key === 'Home') {
increment = 1;
idx = 0;
} else if (key === 'End') {
increment = -1;
idx = this.items.length - 1;
}
idx = this._getAvailableIndex(idx, increment, condition);
if (idx >= 0) {
this._focus(idx);
event.preventDefault();
}
return;
}
const condition = item => !(item.disabled || this._isItemHidden(item));
let idx, increment;
/**
* @param {number} idx
* @param {number} increment
* @param {function(!Element):boolean} condition
* @return {number}
* @protected
*/
_getAvailableIndex(idx, increment, condition) {
const totalItems = this.items.length;
for (let i = 0; typeof idx == 'number' && i < totalItems; i++, idx += increment || 1) {
if (idx < 0) {
idx = totalItems - 1;
} else if (idx >= totalItems) {
idx = 0;
}
const dirIncrement = this._isRTL ? -1 : 1;
const item = this.items[idx];
if (this._vertical && key === 'Up' || !this._vertical && key === 'Left') {
increment = -dirIncrement;
idx = currentIdx - dirIncrement;
} else if (this._vertical && key === 'Down' || !this._vertical && key === 'Right') {
increment = dirIncrement;
idx = currentIdx + dirIncrement;
} else if (key === 'Home') {
increment = 1;
idx = 0;
} else if (key === 'End') {
increment = -1;
idx = this.items.length - 1;
if (condition(item)) {
return idx;
}
}
return -1;
}
idx = this._getAvailableIndex(idx, increment, condition);
if (idx >= 0) {
this._focus(idx);
event.preventDefault();
/**
* @param {!Element} item
* @return {boolean}
* @protected
*/
_isItemHidden(item) {
return getComputedStyle(item).display === 'none';
}
}
/**
* @param {number} idx
* @param {number} increment
* @param {function(!Element):boolean} condition
* @return {number}
* @protected
*/
_getAvailableIndex(idx, increment, condition) {
const totalItems = this.items.length;
for (let i = 0; typeof idx == 'number' && i < totalItems; i++, idx += (increment || 1)) {
if (idx < 0) {
idx = totalItems - 1;
} else if (idx >= totalItems) {
idx = 0;
}
/**
* @param {number} idx
* @protected
*/
_setFocusable(idx) {
idx = this._getAvailableIndex(idx, 1, (item) => !item.disabled);
const item = this.items[idx] || this.items[0];
this.items.forEach((e) => (e.tabIndex = e === item ? 0 : -1));
}
/**
* @param {number} idx
* @protected
*/
_focus(idx) {
const item = this.items[idx];
this.items.forEach((e) => (e.focused = e === item));
this._setFocusable(idx);
this._scrollToItem(idx);
item.focus();
}
if (condition(item)) {
return idx;
}
focus() {
// In initialisation (e.g vaadin-select) observer might not been run yet.
this._observer && this._observer.flush();
const firstItem = this.querySelector('[tabindex="0"]') || (this.items ? this.items[0] : null);
firstItem && firstItem.focus();
}
return -1;
}
/**
* @param {!Element} item
* @return {boolean}
* @protected
*/
_isItemHidden(item) {
return getComputedStyle(item).display === 'none';
}
/**
* @return {!HTMLElement}
* @protected
*/
get _scrollerElement() {
// Returning scroller element of the component
console.warn(`Please implement the '_scrollerElement' property in <${this.localName}>`);
return this;
}
/**
* @param {number} idx
* @protected
*/
_setFocusable(idx) {
idx = this._getAvailableIndex(idx, 1, item => !item.disabled);
const item = this.items[idx] || this.items[0];
this.items.forEach(e => e.tabIndex = e === item ? 0 : -1);
}
/**
* Scroll the container to have the next item by the edge of the viewport.
* @param {number} idx
* @protected
*/
_scrollToItem(idx) {
const item = this.items[idx];
if (!item) {
return;
}
/**
* @param {number} idx
* @protected
*/
_focus(idx) {
const item = this.items[idx];
this.items.forEach(e => e.focused = e === item);
this._setFocusable(idx);
this._scrollToItem(idx);
item.focus();
}
const props = this._vertical ? ['top', 'bottom'] : this._isRTL ? ['right', 'left'] : ['left', 'right'];
focus() {
// In initialisation (e.g vaadin-select) observer might not been run yet.
this._observer && this._observer.flush();
const firstItem = this.querySelector('[tabindex="0"]') || (this.items ? this.items[0] : null);
firstItem && firstItem.focus();
}
const scrollerRect = this._scrollerElement.getBoundingClientRect();
const nextItemRect = (this.items[idx + 1] || item).getBoundingClientRect();
const prevItemRect = (this.items[idx - 1] || item).getBoundingClientRect();
/**
* @return {!HTMLElement}
* @protected
*/
get _scrollerElement() {
// Returning scroller element of the component
}
let scrollDistance = 0;
if (
(!this._isRTL && nextItemRect[props[1]] >= scrollerRect[props[1]]) ||
(this._isRTL && nextItemRect[props[1]] <= scrollerRect[props[1]])
) {
scrollDistance = nextItemRect[props[1]] - scrollerRect[props[1]];
} else if (
(!this._isRTL && prevItemRect[props[0]] <= scrollerRect[props[0]]) ||
(this._isRTL && prevItemRect[props[0]] >= scrollerRect[props[0]])
) {
scrollDistance = prevItemRect[props[0]] - scrollerRect[props[0]];
}
/**
* Scroll the container to have the next item by the edge of the viewport.
* @param {number} idx
* @protected
*/
_scrollToItem(idx) {
const item = this.items[idx];
if (!item) {
return;
this._scroll(scrollDistance);
}
const props = this._vertical ? ['top', 'bottom'] :
this._isRTL ? ['right', 'left'] : ['left', 'right'];
const scrollerRect = this._scrollerElement.getBoundingClientRect();
const nextItemRect = (this.items[idx + 1] || item).getBoundingClientRect();
const prevItemRect = (this.items[idx - 1] || item).getBoundingClientRect();
let scrollDistance = 0;
if (!this._isRTL && nextItemRect[props[1]] >= scrollerRect[props[1]] ||
this._isRTL && nextItemRect[props[1]] <= scrollerRect[props[1]]) {
scrollDistance = nextItemRect[props[1]] - scrollerRect[props[1]];
} else if (!this._isRTL && prevItemRect[props[0]] <= scrollerRect[props[0]] ||
this._isRTL && prevItemRect[props[0]] >= scrollerRect[props[0]]) {
scrollDistance = prevItemRect[props[0]] - scrollerRect[props[0]];
/**
* @return {boolean}
* @protected
*/
get _vertical() {
return this.orientation !== 'horizontal';
}
this._scroll(scrollDistance);
}
/**
* @return {boolean}
* @protected
*/
get _vertical() {
return this.orientation !== 'horizontal';
}
/**
* @param {number} pixels
* @protected
*/
_scroll(pixels) {
if (this._vertical) {
this._scrollerElement['scrollTop'] += pixels;
} else {
const scrollType = DirHelper.detectScrollType();
const scrollLeft = DirHelper.getNormalizedScrollLeft(scrollType,
this.getAttribute('dir') || 'ltr', this._scrollerElement) + pixels;
DirHelper.setNormalizedScrollLeft(scrollType,
this.getAttribute('dir') || 'ltr', this._scrollerElement, scrollLeft);
/**
* @param {number} pixels
* @protected
*/
_scroll(pixels) {
if (this._vertical) {
this._scrollerElement['scrollTop'] += pixels;
} else {
const dir = this.getAttribute('dir') || 'ltr';
const scrollType = DirHelper.detectScrollType();
const scrollLeft = DirHelper.getNormalizedScrollLeft(scrollType, dir, this._scrollerElement) + pixels;
DirHelper.setNormalizedScrollLeft(scrollType, dir, this._scrollerElement, scrollLeft);
}
}
}
/**
* Fired when the selection is changed.
* Not fired when used in `multiple` selection mode.
*
* @event selected-changed
* @param {Object} detail
* @param {Object} detail.value the index of the item selected in the items array.
*/
};
/**
* Fired when the selection is changed.
* Not fired when used in `multiple` selection mode.
*
* @event selected-changed
* @param {Object} detail
* @param {Object} detail.value the index of the item selected in the items array.
*/
};

@@ -1,39 +0,19 @@

/**
* DO NOT EDIT
*
* This file was automatically generated by
* https://github.com/Polymer/tools/tree/master/packages/gen-typescript-declarations
*
* To modify these typings, edit the source file(s):
* vaadin-multi-select-list-mixin.js
*/
import { ListMixin, ListMixinConstructor } from './vaadin-list-mixin.js';
// tslint:disable:variable-name Describing an API that's defined elsewhere.
// tslint:disable:no-any describes the API as best we are able today
import {ListMixin} from './vaadin-list-mixin.js';
export {MultiSelectListMixin};
/**
* A mixin for `nav` elements, facilitating multiple selection of childNodes.
*/
declare function MultiSelectListMixin<T extends new (...args: any[]) => {}>(base: T): T & MultiSelectListMixinConstructor & ListMixinConstructor;
declare function MultiSelectListMixin<T extends new (...args: any[]) => {}>(
base: T
): T & MultiSelectListMixinConstructor & ListMixinConstructor;
import {ListMixinConstructor} from './vaadin-list-mixin.js';
interface MultiSelectListMixinConstructor {
new(...args: any[]): MultiSelectListMixin;
new (...args: any[]): MultiSelectListMixin;
}
export {MultiSelectListMixinConstructor};
interface MultiSelectListMixin extends ListMixin {
/**
* Specifies that multiple options can be selected at once.
*/
multiple: boolean|null|undefined;
multiple: boolean | null | undefined;

@@ -44,5 +24,7 @@ /**

*/
selectedValues: string[]|null|undefined;
ready(): void;
selectedValues: string[] | null | undefined;
_onMultipleClick(event: MouseEvent): void;
}
export { MultiSelectListMixin, MultiSelectListMixinConstructor };
/**
@license
Copyright (c) 2019 Vaadin Ltd.
This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
*/
* @license
* Copyright (c) 2021 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
*/
import { ListMixin } from './vaadin-list-mixin.js';

@@ -14,108 +14,107 @@

*/
export const MultiSelectListMixin = superClass => class VaadinMultiSelectListMixin extends ListMixin(superClass) {
static get properties() {
return {
/**
* Specifies that multiple options can be selected at once.
*/
multiple: {
type: Boolean,
value: false,
reflectToAttribute: true,
observer: '_multipleChanged'
},
export const MultiSelectListMixin = (superClass) =>
class VaadinMultiSelectListMixin extends ListMixin(superClass) {
static get properties() {
return {
/**
* Specifies that multiple options can be selected at once.
*/
multiple: {
type: Boolean,
value: false,
reflectToAttribute: true,
observer: '_multipleChanged'
},
/**
* Array of indexes of the items selected in the items array
* Note: Not updated when used in single selection mode.
* @type {string[] | null | undefined}
*/
selectedValues: {
type: Array,
notify: true,
value: function() {
return [];
/**
* Array of indexes of the items selected in the items array
* Note: Not updated when used in single selection mode.
* @type {string[] | null | undefined}
*/
selectedValues: {
type: Array,
notify: true,
value: function () {
return [];
}
}
}
};
}
};
}
static get observers() {
return [
`_enhanceMultipleItems(items, multiple, selected, selectedValues, selectedValues.*)`
];
}
static get observers() {
return [`_enhanceMultipleItems(items, multiple, selected, selectedValues, selectedValues.*)`];
}
/** @protected */
ready() {
// Should be attached before click listener in list-mixin
this.addEventListener('click', e => this._onMultipleClick(e));
/** @protected */
ready() {
// Should be attached before click listener in list-mixin
this.addEventListener('click', (e) => this._onMultipleClick(e));
super.ready();
}
/** @private */
_enhanceMultipleItems(items, multiple, selected, selectedValues) {
if (!items || !multiple) {
return;
super.ready();
}
if (selectedValues) {
const selectedItems = selectedValues.map(selectedId => items[selectedId]);
items.forEach(item => item.selected = selectedItems.indexOf(item) !== -1);
}
/** @private */
_enhanceMultipleItems(items, multiple, selected, selectedValues) {
if (!items || !multiple) {
return;
}
this._scrollToLastSelectedItem();
}
if (selectedValues) {
const selectedItems = selectedValues.map((selectedId) => items[selectedId]);
items.forEach((item) => (item.selected = selectedItems.indexOf(item) !== -1));
}
/** @private */
_scrollToLastSelectedItem() {
const lastSelectedItem = this.selectedValues.slice(-1)[0];
if (lastSelectedItem && !lastSelectedItem.disabled) {
this._scrollToItem(lastSelectedItem);
this._scrollToLastSelectedItem();
}
}
/**
* @param {!MouseEvent} event
* @protected
*/
_onMultipleClick(event) {
const item = this._filterItems(event.composedPath())[0];
const idx = item && !item.disabled ? this.items.indexOf(item) : -1;
if (idx < 0 || !this.multiple) {
return;
/** @private */
_scrollToLastSelectedItem() {
const lastSelectedItem = this.selectedValues.slice(-1)[0];
if (lastSelectedItem && !lastSelectedItem.disabled) {
this._scrollToItem(lastSelectedItem);
}
}
event.preventDefault();
if (this.selectedValues.indexOf(idx) !== -1) {
this.selectedValues = this.selectedValues.filter(v => v !== idx);
} else {
this.selectedValues = this.selectedValues.concat(idx);
}
}
/**
* @param {!MouseEvent} event
* @protected
*/
_onMultipleClick(event) {
const item = this._filterItems(event.composedPath())[0];
const idx = item && !item.disabled ? this.items.indexOf(item) : -1;
if (idx < 0 || !this.multiple) {
return;
}
/** @private */
_multipleChanged(value, oldValue) {
// Changing from multiple to single selection, clear selection.
if (!value && oldValue) {
this.selectedValues = [];
this.items.forEach(item => item.selected = false);
event.preventDefault();
if (this.selectedValues.indexOf(idx) !== -1) {
this.selectedValues = this.selectedValues.filter((v) => v !== idx);
} else {
this.selectedValues = this.selectedValues.concat(idx);
}
}
// Changing from single to multiple selection, add selected to selectedValues.
if (value && !oldValue && this.selected !== undefined) {
this.push('selectedValues', this.selected);
this.selected = undefined;
/** @private */
_multipleChanged(value, oldValue) {
// Changing from multiple to single selection, clear selection.
if (!value && oldValue) {
this.selectedValues = [];
this.items.forEach((item) => (item.selected = false));
}
// Changing from single to multiple selection, add selected to selectedValues.
if (value && !oldValue && this.selected !== undefined) {
this.push('selectedValues', this.selected);
this.selected = undefined;
}
}
}
/**
* Fired when the selection is changed.
* Not fired in single selection mode.
*
* @event selected-values-changed
* @param {Object} detail
* @param {Object} detail.value the array of indexes of the items selected in the items array.
*/
};
/**
* Fired when the selection is changed.
* Not fired in single selection mode.
*
* @event selected-values-changed
* @param {Object} detail
* @param {Object} detail.value the array of indexes of the items selected in the items array.
*/
};
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