Socket
Socket
Sign inDemoInstall

@material/list

Package Overview
Dependencies
Maintainers
13
Versions
1698
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@material/list - npm Package Compare versions

Comparing version 0.37.1 to 0.38.0

dist/mdc.list.js

51

adapter.js

@@ -34,7 +34,7 @@ /**

class MDCListAdapter {
/** @return {Number} */
/** @return {number} */
getListItemCount() {}
/**
* @return {Number} */
* @return {number} */
getFocusedElementIndex() {}

@@ -46,12 +46,49 @@

/**
* @param {number} index
* @param {string} attribute
* @param {string} value
*/
setAttributeForElementIndex(index, attribute, value) {}
/**
* @param {number} index
* @param {string} attribute
*/
removeAttributeForElementIndex(index, attribute) {}
/**
* @param {number} index
* @param {string} className
*/
addClassForElementIndex(index, className) {}
/**
* @param {number} index
* @param {string} className
*/
removeClassForElementIndex(index, className) {}
/**
* Focuses list item at the index specified.
* @param {Number} ndx
* @param {number} index
*/
focusItemAtIndex(ndx) {}
focusItemAtIndex(index) {}
/**
* Checks if the provided element is a focusable sub-element.
* @param {Element} ele
*/
isElementFocusable(ele) {}
/**
* Checks if the provided element is contains the mdc-list-item class.
* @param {Element} ele
*/
isListItem(ele) {}
/**
* Sets the tabindex to the value specified for all button/a element children of
* the list item at the index specified.
* @param {Number} listItemIndex
* @param {Number} tabIndexValue
* @param {number} listItemIndex
* @param {number} tabIndexValue
*/

@@ -61,2 +98,2 @@ setTabIndexForListItemChildren(listItemIndex, tabIndexValue) {}

export {MDCListAdapter};
export default MDCListAdapter;

4

constants.js

@@ -21,2 +21,3 @@ /**

LIST_ITEM_CLASS: 'mdc-list-item',
LIST_ITEM_SELECTED_CLASS: 'mdc-list-item--selected',
};

@@ -28,6 +29,7 @@

ARIA_ORIENTATION_VERTICAL: 'vertical',
ARIA_SELECTED: 'aria-selected',
FOCUSABLE_CHILD_ELEMENTS: 'button:not(:disabled), a',
ITEMS_SELECTOR: '.mdc-list-item',
ENABLED_ITEMS_SELECTOR: '.mdc-list-item:not(.mdc-list-item--disabled)',
};
export {strings, cssClasses};

@@ -19,2 +19,3 @@ /**

import MDCFoundation from '@material/base/foundation';
import MDCListAdapter from './adapter';
import {strings, cssClasses} from './constants';

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

class MDCListFoundation extends MDCFoundation {
/** @return enum {string} */
static get strings() {

@@ -30,2 +32,3 @@ return strings;

/** @return enum {string} */
static get cssClasses() {

@@ -35,8 +38,19 @@ return cssClasses;

/**
* {@see MDCListAdapter} for typing information on parameters and return
* types.
* @return {!MDCListAdapter}
*/
static get defaultAdapter() {
return /** {MDCListAdapter */ ({
return /** @type {!MDCListAdapter} */ ({
getListItemCount: () => {},
getFocusedElementIndex: () => {},
getListItemIndex: () => {},
setAttributeForElementIndex: () => {},
removeAttributeForElementIndex: () => {},
addClassForElementIndex: () => {},
removeClassForElementIndex: () => {},
focusItemAtIndex: () => {},
isElementFocusable: () => {},
isListItem: () => {},
setTabIndexForListItemChildren: () => {},

@@ -52,2 +66,6 @@ });

this.isVertical_ = true;
/** {boolean} */
this.isSingleSelectionList_ = false;
/** {number} */
this.selectedIndex_ = -1;
}

@@ -72,2 +90,44 @@

/**
* Sets the isSingleSelectionList_ private variable.
* @param {boolean} value
*/
setSingleSelection(value) {
this.isSingleSelectionList_ = value;
}
/** @param {number} index */
setSelectedIndex(index) {
if (index === this.selectedIndex_) {
this.adapter_.removeAttributeForElementIndex(this.selectedIndex_, strings.ARIA_SELECTED);
this.adapter_.removeClassForElementIndex(this.selectedIndex_, cssClasses.LIST_ITEM_SELECTED_CLASS);
// Used to reset the first element to tabindex=0 when deselecting a list item.
// If already on the first list item, leave tabindex at 0.
if (this.selectedIndex_ >= 0) {
this.adapter_.setAttributeForElementIndex(this.selectedIndex_, 'tabindex', -1);
this.adapter_.setAttributeForElementIndex(0, 'tabindex', 0);
}
this.selectedIndex_ = -1;
return;
}
if (this.selectedIndex_ >= 0) {
this.adapter_.removeAttributeForElementIndex(this.selectedIndex_, strings.ARIA_SELECTED);
this.adapter_.removeClassForElementIndex(this.selectedIndex_, cssClasses.LIST_ITEM_SELECTED_CLASS);
this.adapter_.setAttributeForElementIndex(this.selectedIndex_, 'tabindex', -1);
}
if (index >= 0 && this.adapter_.getListItemCount() > index) {
this.selectedIndex_ = index;
this.adapter_.setAttributeForElementIndex(this.selectedIndex_, strings.ARIA_SELECTED, true);
this.adapter_.addClassForElementIndex(this.selectedIndex_, cssClasses.LIST_ITEM_SELECTED_CLASS);
this.adapter_.setAttributeForElementIndex(this.selectedIndex_, 'tabindex', 0);
if (this.selectedIndex_ !== 0) {
this.adapter_.setAttributeForElementIndex(0, 'tabindex', -1);
}
}
}
/**
* Focus in handler for the list items.

@@ -80,3 +140,7 @@ * @param evt

this.adapter_.setTabIndexForListItemChildren(this.adapter_.getListItemIndex(listItem), 0);
const listItemIndex = this.adapter_.getListItemIndex(listItem);
if (listItemIndex >= 0) {
this.adapter_.setTabIndexForListItemChildren(listItemIndex, 0);
}
}

@@ -91,4 +155,7 @@

if (!listItem) return;
const listItemIndex = this.adapter_.getListItemIndex(listItem);
this.adapter_.setTabIndexForListItemChildren(this.adapter_.getListItemIndex(listItem), -1);
if (listItemIndex >= 0) {
this.adapter_.setTabIndexForListItemChildren(listItemIndex, -1);
}
}

@@ -107,2 +174,5 @@

const isEnd = evt.key === 'End' || evt.keyCode === 35;
const isEnter = evt.key === 'Enter' || evt.keyCode === 13;
const isSpace = evt.key === 'Space' || evt.keyCode === 32;
let currentIndex = this.adapter_.getFocusedElementIndex();

@@ -132,2 +202,8 @@

this.focusLastElement();
} else if (this.isSingleSelectionList_ && (isEnter || isSpace)) {
this.preventDefaultEvent_(evt);
// Check if the space key was pressed on the list item or a child element.
if (this.adapter_.isListItem(evt.target)) {
this.setSelectedIndex(currentIndex);
}
}

@@ -137,2 +213,13 @@ }

/**
* Click handler for the list.
*/
handleClick() {
const currentIndex = this.adapter_.getFocusedElementIndex();
if (currentIndex === -1) return;
this.setSelectedIndex(currentIndex);
}
/**
* Ensures that preventDefault is only called if the containing element doesn't

@@ -152,3 +239,3 @@ * consume the event, and it will cause an unintended scroll.

* Focuses the next element on the list.
* @param {Number} index
* @param {number} index
*/

@@ -171,3 +258,3 @@ focusNextElement(index) {

* Focuses the previous element on the list.
* @param {Number} index
* @param {number} index
*/

@@ -207,3 +294,3 @@ focusPrevElement(index) {

getListItem_(target) {
while (!target.classList.contains(cssClasses.LIST_ITEM_CLASS)) {
while (!this.adapter_.isListItem(target)) {
if (!target.parentElement) return null;

@@ -216,2 +303,2 @@ target = target.parentElement;

export {MDCListFoundation};
export default MDCListFoundation;

@@ -19,4 +19,5 @@ /**

import MDCComponent from '@material/base/component';
import {MDCListFoundation} from './foundation';
import {strings} from './constants';
import MDCListFoundation from './foundation';
import MDCListAdapter from './adapter';
import {cssClasses, strings} from './constants';

@@ -26,3 +27,3 @@ /**

*/
export class MDCList extends MDCComponent {
class MDCList extends MDCComponent {
/** @param {...?} args */

@@ -34,2 +35,4 @@ constructor(...args) {

/** @private {!Function} */
this.handleClick_;
/** @private {!Function} */
this.focusInEventListener_;

@@ -50,2 +53,3 @@ /** @private {!Function} */

this.root_.removeEventListener('keydown', this.handleKeydown_);
this.root_.removeEventListener('click', this.handleClick_);
this.root_.removeEventListener('focusin', this.focusInEventListener_);

@@ -57,2 +61,3 @@ this.root_.removeEventListener('focusout', this.focusOutEventListener_);

this.handleKeydown_ = this.foundation_.handleKeydown.bind(this.foundation_);
this.handleClick_ = this.foundation_.handleClick.bind(this.foundation_);
this.focusInEventListener_ = this.foundation_.handleFocusIn.bind(this.foundation_);

@@ -88,4 +93,3 @@ this.focusOutEventListener_ = this.foundation_.handleFocusOut.bind(this.foundation_);

get listElements_() {
return [].slice.call(this.root_.querySelectorAll(strings.ITEMS_SELECTOR))
.filter((ele) => ele.parentElement === this.root_);
return [].slice.call(this.root_.querySelectorAll(strings.ENABLED_ITEMS_SELECTOR));
}

@@ -98,16 +102,77 @@

/** @param {boolean} isSingleSelectionList */
set singleSelection(isSingleSelectionList) {
if (isSingleSelectionList) {
this.root_.addEventListener('click', this.handleClick_);
} else {
this.root_.removeEventListener('click', this.handleClick_);
}
this.foundation_.setSingleSelection(isSingleSelectionList);
const selectedElement = this.root_.querySelector('.mdc-list-item--selected');
if (selectedElement) {
this.selectedIndex = this.listElements_.indexOf(selectedElement);
}
}
/** @param {number} index */
set selectedIndex(index) {
this.foundation_.setSelectedIndex(index);
}
/** @return {!MDCListFoundation} */
getDefaultFoundation() {
return new MDCListFoundation(/** @type {!MDCListAdapter} */{
return new MDCListFoundation(/** @type {!MDCListAdapter} */ (Object.assign({
getListItemCount: () => this.listElements_.length,
getFocusedElementIndex: () => this.listElements_.indexOf(document.activeElement),
getListItemIndex: (node) => this.listElements_.indexOf(node),
focusItemAtIndex: (ndx) => this.listElements_[ndx].focus(),
setAttributeForElementIndex: (index, attr, value) => {
const element = this.listElements_[index];
if (element) {
element.setAttribute(attr, value);
}
},
removeAttributeForElementIndex: (index, attr) => {
const element = this.listElements_[index];
if (element) {
element.removeAttribute(attr);
}
},
addClassForElementIndex: (index, className) => {
const element = this.listElements_[index];
if (element) {
element.classList.add(className);
}
},
removeClassForElementIndex: (index, className) => {
const element = this.listElements_[index];
if (element) {
element.classList.remove(className);
}
},
isListItem: (target) => target.classList.contains(cssClasses.LIST_ITEM_CLASS),
focusItemAtIndex: (index) => {
const element = this.listElements_[index];
if (element) {
element.focus();
}
},
isElementFocusable: (ele) => {
if (!ele) return false;
let matches = Element.prototype.matches;
if (!matches) { // IE uses a different name for the same functionality
matches = Element.prototype.msMatchesSelector;
}
return matches.call(ele, strings.FOCUSABLE_CHILD_ELEMENTS);
},
setTabIndexForListItemChildren: (listItemIndex, tabIndexValue) => {
const listItemChildren = [].slice.call(this.listElements_[listItemIndex]
.querySelectorAll(strings.FOCUSABLE_CHILD_ELEMENTS));
const element = this.listElements_[listItemIndex];
const listItemChildren = [].slice.call(element.querySelectorAll(strings.FOCUSABLE_CHILD_ELEMENTS));
listItemChildren.forEach((ele) => ele.setAttribute('tabindex', tabIndexValue));
},
});
})));
}
}
export {MDCList, MDCListFoundation};
{
"name": "@material/list",
"description": "The Material Components for the web list component",
"version": "0.37.1",
"version": "0.38.0",
"license": "Apache-2.0",

@@ -17,7 +17,7 @@ "keywords": [

"@material/base": "^0.35.0",
"@material/ripple": "^0.37.1",
"@material/ripple": "^0.38.0",
"@material/rtl": "^0.36.0",
"@material/theme": "^0.35.0",
"@material/typography": "^0.37.1"
"@material/theme": "^0.38.0",
"@material/typography": "^0.38.0"
}
}

@@ -61,6 +61,4 @@ <!--docs:

<span class="mdc-list-item__text">
First-line text
<span class="mdc-list-item__secondary-text">
Second-line text
</span>
<span class="mdc-list-item__primary-text">First-line text</span>
<span class="mdc-list-item__secondary-text">Second-line text</span>
</span>

@@ -70,6 +68,4 @@ </li>

<span class="mdc-list-item__text">
First-line text
<span class="mdc-list-item__secondary-text">
Second-line text
</span>
<span class="mdc-list-item__primary-text">First-line text</span>
<span class="mdc-list-item__secondary-text">Second-line text</span>
</span>

@@ -79,6 +75,4 @@ </li>

<span class="mdc-list-item__text">
First-line text
<span class="mdc-list-item__secondary-text">
Second-line text
</span>
<span class="mdc-list-item__primary-text">First-line text</span>
<span class="mdc-list-item__secondary-text">Second-line text</span>
</span>

@@ -89,2 +83,4 @@ </li>

> NOTE: Make sure that there are no white-space characters before primary and secondary text.
### List Groups

@@ -142,2 +138,40 @@

### Single Selection List
MDC List can handle selecting/deselecting list elements based on click or keyboard action. When enabled, the `space` and `enter` keys (or `click` event) will trigger an
single list item to become selected or deselected.
```html
<ul id="my-list" class="mdc-list" aria-orientation="vertical">
<li class="mdc-list-item">Single-line item</li>
<li class="mdc-list-item">Single-line item</li>
<li class="mdc-list-item">Single-line item</li>
</ul>
```
```js
var listEle = document.getElementById('my-list');
var list = new mdc.list.MDCList(listEle);
list.singleSelection = true;
```
#### Pre-selected list item
When rendering the list with a pre-selected list item, the list item that needs to be selected should contain
the `mdc-list-item--selected` class and `aria-selected="true"` attribute before creating the list.
```html
<ul id="my-list" class="mdc-list" aria-orientation="vertical">
<li class="mdc-list-item">Single-line item</li>
<li class="mdc-list-item mdc-list-item--selected" aria-selected="true">Single-line item</li>
<li class="mdc-list-item">Single-line item</li>
</ul>
```
```js
var listEle = document.getElementById('my-list');
var list = new mdc.list.MDCList(listEle);
list.singleSelection = true;
```
## Style Customization

@@ -155,3 +189,4 @@

`mdc-list-item` | Mandatory, for the list item element.
`mdc-list-item__text` | Optional, primary text for the row (displayed as middle column of the list item).
`mdc-list-item__text` | Optional, wrapper for two line list item text content (displayed as middle column of the list item).
`mdc-list-item__primary-text` | Optional, primary text for the list item. Should be the child of `mdc-list-item__text`.
`mdc-list-item__secondary-text` | Optional, secondary text for the list item. Displayed below the primary text. Should be the child of `mdc-list-item__text`.

@@ -172,3 +207,3 @@ `mdc-list-item--selected` | Optional, styles the row in an selected* state.

* *Selected* state should be implemented on the `.list-item` when it is likely to change soon. Eg., selecting one or more photos to share in Google Photos.
* *Selected* state should be implemented on the `.mdc-list-item` when it is likely to change soon. Eg., selecting one or more photos to share in Google Photos.
* Multiple items can be selected at the same time when using the *selected* state.

@@ -198,5 +233,6 @@ * *Activated* state is similar to selected state, however should only be implemented once within a specific list.

when the list item is not focused. When the list item receives focus, the child `button` and `a` elements will
receive `tabIndex="0"`. This allows for the user to tab through list items elements and then tab to the
receive `tabIndex="0"`. This allows for the user to tab through list item elements and then tab to the
first element after the list. The `Arrow`, `Home`, and `End` keys should be used for navigating internal list elements.
The MDCList will perform the following actions for each key press
If `singleSelection=true`, the list will allow the user to use the `Space` or `Enter` keys to select or deselect
a list item. The MDCList will perform the following actions for each key press

@@ -211,2 +247,4 @@ Key | Action

`End` | Will cause the last list item in the list to receive focus.
`Space` | Will cause the currently focused list item to become selected/deselected if `singleSelection=true`.
`Enter` | Will cause the currently focused list item to become selected/deselected if `singleSelection=true`.

@@ -217,2 +255,39 @@ ## Usage within Web Frameworks

### Considerations for Advanced Approach
The `MDCListFoundation` expects the HTML to be setup a certain way before being used. This setup is a part of the `layout()` and `singleSelection()` functions within the `index.js`.
#### Setup in `layout()`
The default component requires that every list item receives a `tabindex` value so that it can receive focus
(`li` elements cannot receive focus at all without a `tabindex` value). Any element not already containing a
`tabindex` attribute will receive `tabindex=-1`. The first list item should have `tabindex="0"` so that the
user can find the first element using the `tab` key, but subsequent `tab` keys strokes will cause focus to
skip over the entire list. If the list items contain sub-elements that are focusable (`button` or `a` elements),
these should also receive `tabIndex="-1"`.
```html
<ul id="my-list" class="mdc-list" aria-orientation="vertical">
<li class="mdc-list-item" tabindex="0">Single-line item<button tabindex="-1"></button></li>
<li class="mdc-list-item" tabindex="-1">Single-line item</li>
<li class="mdc-list-item" tabindex="-1">Single-line item</li>
</ul>
```
#### Setup in `singleSelection()`
When implementing a component that will use the single selection variant, the HTML should be modified to include
the `aria-selected` attribute, the `mdc-list-item--selected` class should be added, and the `tabindex` of the selected
element should be `0`. The first list item should have the `tabindex` updated to `-1`. The foundation method
`setSelectedIndex()` should be called with the initially selected element immediately after the foundation is
instantiated.
```html
<ul id="my-list" class="mdc-list" aria-orientation="vertical">
<li class="mdc-list-item" tabindex="-1">Single-line item<button tabindex="-1"></button></li>
<li class="mdc-list-item mdc-list-item--selected" aria-selected="true" tabindex="0">Single-line item</li>
<li class="mdc-list-item" tabindex="-1">Single-line item</li>
</ul>
```
### `MDCListAdapter`

@@ -225,4 +300,8 @@

`getListItemIndex(ele: Element) => Number` | Returns the `index` value of the provided `ele` element.
`focusItemAtIndex(ndx: Number) => void` | Focuses the list item at the `ndx` value specified.
`setTabIndexForListItemChildren(ndx: Number, value: Number) => void` | Sets the `tabindex` attribute to `value` for each child `button` and `a` element in the list item at the `ndx` specified.
`setAttributeForElementIndex(index: Number, attr: String, value: String) => void` | Sets the `attr` attribute to `value` for the list item at `index`.
`addClassForElementIndex(index: Number, className: String) => void` | Adds the `className` class to the list item at `index`.
`removeClassForElementIndex(index: Number, className: String) => void` | Removes the `className` class to the list item at `index`.
`focusItemAtIndex(index: Number) => void` | Focuses the list item at the `index` value specified.
`isElementFocusable(ele: Element) => boolean` | Returns true if `ele` contains a focusable child element.
`setTabIndexForListItemChildren(index: Number, value: Number) => void` | Sets the `tabindex` attribute to `value` for each child `button` and `a` element in the list item at the `index` specified.

@@ -235,5 +314,8 @@ ### `MDCListFoundation`

`setVerticalOrientation(value: Boolean) => void` | Sets the list to an orientation causing the keys used for navigation to change. `true` results in the Up/Down arrow keys being used. `false` results in the Left/Right arrow keys being used.
`setSingleSelection(value: Boolean) => void` | Sets the list to be a selection list. Enables the `enter` and `space` keys for selecting/deselecting a list item.
`setSelectedIndex(index: Number) => void` | Toggles the `selected` state of the list item at index `index`.
`handleFocusIn(evt: Event) => void` | Handles the changing of `tabindex` to `0` for all `button` and `a` elements when a list item receives focus.
`handleFocusOut(evt: Event) => void` | Handles the changing of `tabindex` to `-1` for all `button` and `a` elements when a list item loses focus.
`handleKeydown(evt: Event) => void` | Handles determining if a focus action should occur when a key event is triggered.
`handleClick(evt: Event) => void` | Handles toggling the selected/deselected state for a list item when clicked. This method is only used by the single selection list.
`focusNextElement(index: Number) => void` | Handles focusing the next element using the current `index`.

@@ -240,0 +322,0 @@ `focusPrevElement(index: Number) => void` | Handles focusing the previous element using the current `index`.

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