diff --git a/item/demo/stories.ts b/item/demo/stories.ts index 3cea195fc5..523ee97316 100644 --- a/item/demo/stories.ts +++ b/item/demo/stories.ts @@ -144,7 +144,7 @@ function getKnobContent(knobs: StoryKnobs, threeLines = false) { html`star` : nothing; - return html`${overline}${trailingText}${leadingIcon}${trailingIcon}`; + return [overline, trailingText, leadingIcon, trailingIcon]; } /** Item stories. */ diff --git a/list/demo/demo.ts b/list/demo/demo.ts index 2390abe46a..c2d85efff9 100644 --- a/list/demo/demo.ts +++ b/list/demo/demo.ts @@ -7,63 +7,18 @@ import './index.js'; import './material-collection.js'; -import {KnobTypesToKnobs, MaterialCollection, materialInitsToStoryInits, setUpDemo, title} from './material-collection.js'; +import {KnobTypesToKnobs, MaterialCollection, materialInitsToStoryInits, setUpDemo} from './material-collection.js'; import {boolInput, Knob, textInput} from './index.js'; import {stories, StoryKnobs} from './stories.js'; -/** - * User avatar as a dataurl. - */ -export const AVATAR_URL = - 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAAAAADH8yjkAAABsklEQVR4Ae3WBaLjMAxF0dn/np4hVEY3cQqOupNh/i4oVT76buAUEkmfzgOXgAS8QiABCUhAAg71dlsfhgJOc4vv2flpAICWGr/TS5IGQoV/qoIs0OX4r7wTBcZ40lgSqBGplgMoQ6SMxACPaF4MmCPaXAwoEa0UAyyiWTFAIZoSAwyiGTGgQLRCDJgh2kwMaBCtEQPIIpIluVnkEMkJDjuq8KSKJMd1eDLusiC70U45/ik/Se/kbqbwOzXrBrgqDtOfhJoeBrqLyLvl0nlKp2MCXi1Ap1Prndv59iQOdPVqkqu/J9FoWQcp4LguES1f7B8HaJPhStk6PASElcGN9CL0B9YKd6TWPYFjgTsrjn2ARuPudMMHdgqM1I4LtAqsVMsDyIKZJRawBLslC7BgZzlAQI8CA+gM2JmOAZy9AjPleY/pAswWZx5AFVhVxATOVIJRSfxZRAXurqA+07Qb4c5GXb99QAvc1YJ6bzSncTPtHtnJYYwbjcODV0WT40p5I3C21AUQr6iFDi8/M5HZM/OSp2O7HP+FmPGyHeD4Db5x261rfEjnewISkIAEJODDAV8A/z6x+ahJu3sAAAAASUVORK5CYII='; - -/** - * Example image as a dataurl. - */ -export const IMAGE_URL = - 'data:image/png;base64,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'; - -/** - * One frame of the color blue in webm as a dataurl. - * - * Generated with - * ffmpeg -f lavfi -i color=blue:s=1280x720 -vframes 1 ~/out.webm - * cat ~/out.webm | base64 | tr -d '\n' - */ -export const VIDEO_URL = - 'data:video/webm;base64,GkXfo59ChoEBQveBAULygQRC84EIQoKEd2VibUKHgQJChYECGFOAZwEAAAAAAAJrEU2bdLpNu4tTq4QVSalmU6yBoU27i1OrhBZUrmtTrIHYTbuMU6uEElTDZ1OsggEgTbuMU6uEHFO7a1OsggJV7AEAAAAAAABZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVSalmsirXsYMPQkBNgI1MYXZmNTkuMjcuMTAwV0GNTGF2ZjU5LjI3LjEwMESJiEBEAAAAAAAAFlSua8OuAQAAAAAAADrXgQFzxYjFaDr5zFhASZyBACK1nIN1bmSIgQCGhVZfVlA5g4EBI+ODhAJiWgDgi7CCBQC6ggLQmoECElTDZ0CBc3OgY8CAZ8iaRaOHRU5DT0RFUkSHjUxhdmY1OS4yNy4xMDBzc9tjwItjxYjFaDr5zFhASWfIpUWjh0VOQ09ERVJEh5hMYXZjNTkuMzcuMTAwIGxpYnZweC12cDlnyKJFo4hEVVJBVElPTkSHlDAwOjAwOjAwLjA0MDAwMDAwMAAAH0O2dUCo54EAo0CigQAAgIJJg0IAT/As9gA4JBwYShgAQGIMw/o6+kdo6+kAuaP9KgAAAAAcZw5Vl/m2cRY6ymCqlMFVJYKqSwVSleqUBBBCAAAAABxnDlWX+bZxFjrKYKqUwVUlgqpLBVKV6pQEEEIAAAAAHGcOVZf5tnEWOspgqpTBVSWCqksFUpXqlAQQQgBnDlWX+bZxFjrKYKqUwVUlgqpLBVKV6pQEEEIAHFO7a5G7j7OBALeK94EB8YIBp/CBAw=='; - const collection = new MaterialCollection>('List', [ - new Knob('md-list-item', {ui: title()}), new Knob('disabled', {ui: boolInput(), defaultValue: false}), - new Knob('interactive', {ui: boolInput(), defaultValue: false}), - new Knob( - 'multiLineSupportingText', {ui: boolInput(), defaultValue: false}), - new Knob('headline', {ui: textInput(), defaultValue: 'Headline'}), - new Knob('supportingText', {ui: textInput(), defaultValue: ''}), - new Knob('trailingSupportingText', {ui: textInput(), defaultValue: ''}), - new Knob('href', {ui: textInput(), defaultValue: 'https://google.com'}), - new Knob('target', {ui: textInput(), defaultValue: '_blank'}), - new Knob('link end icon', {ui: textInput(), defaultValue: 'open_in_new'}), - - new Knob('slot[name=start|end-icon]', {ui: title()}), - new Knob('start icon', {ui: textInput(), defaultValue: 'account_circle'}), - new Knob('end icon', {ui: textInput(), defaultValue: 'check_circle'}), - - new Knob('slot[name=start-avatar]', {ui: title()}), - new Knob('avatar img', {ui: textInput(), defaultValue: AVATAR_URL}), - new Knob('avatar label', {ui: textInput(), defaultValue: 'EM'}), - - new Knob('slot[name=start-image]', {ui: title()}), - new Knob('image', {ui: textInput(), defaultValue: IMAGE_URL}), - - new Knob('slot[name=start-video]', {ui: title()}), - new Knob( - 'slot[name=start-video-large]', - {ui: boolInput(), defaultValue: false}), - new Knob('video src', {ui: textInput(), defaultValue: VIDEO_URL}), + new Knob('overline', {ui: textInput()}), + new Knob('trailingSupportingText', {ui: textInput()}), + new Knob('leadingIcon', {ui: boolInput()}), + new Knob('trailingIcon', {ui: boolInput()}), ]); collection.addStories(...materialInitsToStoryInits(stories)); diff --git a/list/demo/stories.ts b/list/demo/stories.ts index 275f98cfbd..d9d91a79ef 100644 --- a/list/demo/stories.ts +++ b/list/demo/stories.ts @@ -10,159 +10,113 @@ import '@material/web/list/list.js'; import '@material/web/icon/icon.js'; import {MaterialStoryInit} from './material-collection.js'; -import {css, html} from 'lit'; +import {css, html, nothing} from 'lit'; +import {classMap} from 'lit/directives/class-map.js'; /** Knob types for list stories. */ export interface StoryKnobs { - 'md-list-item': void; disabled: boolean; - interactive: boolean; - multiLineSupportingText: boolean; - headline: string; - supportingText: string; + overline: string; trailingSupportingText: string; - href: string; - target: string; - 'link end icon': string; - - 'slot[name=start|end-icon]': void; - 'start icon': string; - 'end icon': string; - - 'slot[name=start-avatar]': void; - 'avatar img': string; - 'avatar label': string; - - 'slot[name=start-image]': void; - image: string; - - 'slot[name=start-video]': void; - 'slot[name=start-video-large]': boolean; - 'video src': string; + leadingIcon: boolean; + trailingIcon: boolean; } +const styles = css` + md-list { + border-radius: 8px; + outline: 1px solid var(--md-sys-color-outline); + max-width: 360px; + overflow: hidden; + width: 100%; + } +`; + const standard: MaterialStoryInit = { - name: '', - styles: css` - .list-demo { - border-radius: 8px; - border: 1px solid var(--md-sys-color-outline); - max-width: 360px; - overflow: hidden; - width: 100%; - } - - .list { - max-width: 200px; - }`, + name: 'List', + styles, render(knobs) { - const { - disabled, - interactive, - multiLineSupportingText, - headline, - supportingText, - trailingSupportingText, - href, - target, - image, - } = knobs; return html` -
- - - - - - - ${knobs['start icon']} - - - ${knobs['end icon']} - - - - - ${knobs['link end icon']} - - - - - - - - - - - ${knobs['avatar label']} - - - - - - - - - - - -
+ + + Single line item + ${getKnobContent(knobs)} + + + + Two line item +
Supporting text
+ ${getKnobContent(knobs)} +
+ + + Three line item +
+
Second line text
+
Third line text
+
+ ${getKnobContent(knobs, /* threeLines */ true)} +
+
`; }, }; +const interactive: MaterialStoryInit = { + name: 'Interactive list', + styles, + render(knobs) { + const knobsNoTrailing = {...knobs, trailingIcon: false}; + return html` + + + Link item + link + ${getKnobContent(knobsNoTrailing)} + + + + Button item + ${getKnobContent(knobs)} + + + + Non-interactive item + ${getKnobContent(knobs)} + + + `; + }, +}; + +function getKnobContent(knobs: StoryKnobs, threeLines = false) { + const overline = knobs.overline ? + html`
${knobs.overline}
` : + nothing; + + const classes = { + 'align-start': threeLines, + }; + + const trailingText = knobs.trailingSupportingText ? + html`
${ + knobs.trailingSupportingText}
` : + nothing; + + const leadingIcon = knobs.leadingIcon ? + html`event` : + nothing; + + const trailingIcon = knobs.trailingIcon ? + html`star` : + nothing; + + return [overline, trailingText, leadingIcon, trailingIcon]; +} + /** List stories. */ -export const stories = [standard]; +export const stories = [standard, interactive]; diff --git a/list/harness.ts b/list/harness.ts index 84430a4c9a..8bc500bd7c 100644 --- a/list/harness.ts +++ b/list/harness.ts @@ -35,7 +35,7 @@ export class ListHarness extends Harness { */ protected override async getInteractiveElement() { await this.element.updateComplete; - return this.element.renderRoot.querySelector('.list') as HTMLElement; + return this.element as List; } /** @return List item harnesses. */ @@ -60,8 +60,7 @@ export class ListHarness extends Harness { * @param key The key to dispatch on the list. */ override async keypress(key: string, init = {} as KeyboardEventInit) { - const nativeList = this.element.renderRoot.querySelector('ul')!; init = {code: key, ...init}; - this.simulateKeypress(nativeList, key, init); + await super.keypress(key, init); } } diff --git a/list/internal/_list.scss b/list/internal/_list.scss index cf931ae6f7..df92e2fdbf 100644 --- a/list/internal/_list.scss +++ b/list/internal/_list.scss @@ -6,7 +6,6 @@ // go/keep-sorted start @use 'sass:list'; @use 'sass:map'; -@use 'sass:string'; // go/keep-sorted end // go/keep-sorted start @use '../../tokens'; @@ -29,23 +28,15 @@ @mixin styles() { $tokens: tokens.md-comp-list-values(); + @each $token, $value in $tokens { + $tokens: map.set($tokens, $token, var(--md-list-#{$token}, #{$value})); + } :host { - @each $token, $value in $tokens { - --_#{$token}: var(--md-list-#{$token}, #{$value}); - } - + background: map.get($tokens, 'container-color'); color: unset; display: flex; - } - - .list { - background-color: var(--_container-color); - border-radius: inherit; - display: block; - list-style-type: none; - margin: 0; - min-width: inherit; + flex-direction: column; outline: none; padding: 8px 0; // Add position so the elevation overlay (which is absolutely positioned) diff --git a/list/internal/list.ts b/list/internal/list.ts index 745eb1cdb9..29215ab242 100644 --- a/list/internal/list.ts +++ b/list/internal/list.ts @@ -92,30 +92,13 @@ export class List extends LitElement { } protected override render() { - return this.renderList(); - } - - /** - * Renders the main list element. - */ - private renderList() { - return html` - - `; - } - - /** - * The content to be slotted into the list. - */ - private renderContent() { return html` - `; + + `; } /** diff --git a/list/internal/listitem/_list-item.scss b/list/internal/listitem/_list-item.scss index 39448fca2c..3a5eaf3066 100644 --- a/list/internal/listitem/_list-item.scss +++ b/list/internal/listitem/_list-item.scss @@ -6,7 +6,6 @@ // go/keep-sorted start @use 'sass:list'; @use 'sass:map'; -@use 'sass:string'; // go/keep-sorted end // go/keep-sorted start @use '../../../focus/focus-ring'; @@ -31,35 +30,32 @@ @mixin styles() { $tokens: tokens.md-comp-list-item-values(); - - :host { - @each $token, $value in $tokens { - --_#{$token}: var(--md-list-item-#{$token}, #{$value}); - } + @each $token, $value in $tokens { + $tokens: map.set($tokens, $token, var(--md-list-item-#{$token}, #{$value})); } - @include _list-item; - @include _image; - @include _icon; - @include _avatar; - @include _video; -} - -@mixin _list-item() { :host { - color: unset; + border-radius: map.get($tokens, 'container-shape'); + display: flex; @include ripple.theme( ( - hover-color: var(--_hover-state-layer-color), - hover-opacity: var(--_hover-state-layer-opacity), - pressed-color: var(--_pressed-state-layer-color), - pressed-opacity: var(--_pressed-state-layer-opacity), + hover-color: map.get($tokens, 'hover-state-layer-color'), + hover-opacity: map.get($tokens, 'hover-state-layer-opacity'), + pressed-color: map.get($tokens, 'pressed-state-layer-color'), + pressed-opacity: map.get($tokens, 'pressed-state-layer-opacity'), ) ); } + :host([disabled]) { + opacity: map.get($tokens, 'disabled-opacity'); + pointer-events: none; + } + md-focus-ring { + z-index: 1; + @include focus-ring.theme( ( 'shape': 8px, @@ -67,329 +63,84 @@ ); } + a, + button, + li { + // Resets. These can be removed once we're no longer use these tags + background: none; + border: none; + padding: 0; + margin: 0; + text-align: unset; + text-decoration: none; + } + .list-item { - align-items: center; - box-sizing: border-box; + border-radius: inherit; display: flex; + flex: 1; outline: none; - position: relative; - width: 100%; - text-decoration: none; - background-color: var(--_container-color); - border-radius: var(--_container-shape); // hide android tap color since we have ripple -webkit-tap-highlight-color: transparent; &:not(.disabled).interactive { cursor: pointer; } - - &.disabled { - pointer-events: none; - } } - .content-wrapper { - display: flex; - width: 100%; - box-sizing: border-box; - border-radius: inherit; - padding-inline-end: var(--_trailing-space); + [slot='container'] { + pointer-events: none; } md-ripple { border-radius: inherit; } - .with-one-line { - min-height: var(--_one-line-container-height); - } - - .with-two-line { - min-height: var(--_two-line-container-height); - } - - .with-three-line { - min-height: var(--_three-line-container-height); - } - - .start { - display: inline-flex; - flex-direction: column; - justify-content: center; - align-items: center; - flex: 0 0 auto; - z-index: 1; - - .with-three-line & { - justify-content: start; - } - } - - slot[name='start-icon']::slotted(*), - slot[name='start-image']::slotted(*), - slot[name='start-avatar']::slotted(*) { - margin-inline-start: var(--_leading-element-leading-space); - } - - .body { - display: inline-flex; - justify-content: center; - flex-direction: column; - min-width: 0; - box-sizing: border-box; - flex: 1 0 0; - padding-inline-start: var(--_leading-space); - z-index: 1; - } - - .end { - display: inline-flex; - flex-direction: column; - justify-content: center; - flex: 0 0 auto; - z-index: 1; - - .with-three-line & { - justify-content: start; - } - } - - slot[name='end']::slotted(*), - slot[name='end-icon']::slotted(*), - .trailing-supporting-text { - margin-inline-start: var( - --_trailing-element-headline-trailing-element-space - ); - } - - .label-text { - text-overflow: ellipsis; - overflow-x: hidden; - white-space: nowrap; - color: var(--_label-text-color); - font-family: var(--_label-text-font); - font-size: var(--_label-text-size); - line-height: var(--_label-text-line-height); - font-weight: var(--_label-text-weight); - - :hover & { - color: var(--_hover-label-text-color); - } - - :focus & { - color: var(--_focus-label-text-color); - } - - :active & { - color: var(--_pressed-label-text-color); - } - - .disabled & { - color: var(--_disabled-label-text-color); - opacity: var(--_disabled-label-text-opacity); - } - } - - .supporting-text { - text-overflow: ellipsis; - white-space: normal; - overflow: hidden; - width: 100%; - color: var(--_supporting-text-color); - font-family: var(--_supporting-text-font); - font-size: var(--_supporting-text-size); - line-height: var(--_supporting-text-line-height); - font-weight: var(--_supporting-text-weight); - - // Box is supposed to be deprecated, but line-clamp is not. It's still on - // standards track and can only be applied with display: -webkit-box and - // -webkit-box-orient: vertical. Must change once un-prefixed line-clamp - // ships - -webkit-box-orient: vertical; - -webkit-line-clamp: 1; - display: -webkit-box; - - .disabled & { - color: var(--_disabled-label-text-color); - opacity: var(--_disabled-label-text-opacity); - } + md-item { + border-radius: inherit; + flex: 1; + height: 100%; + color: map.get($tokens, 'label-text-color'); + font-family: map.get($tokens, 'label-text-font'); + font-size: map.get($tokens, 'label-text-size'); + line-height: map.get($tokens, 'label-text-line-height'); + font-weight: map.get($tokens, 'label-text-weight'); + min-height: map.get($tokens, 'one-line-container-height'); + padding-top: map.get($tokens, 'top-space'); + padding-bottom: map.get($tokens, 'bottom-space'); + padding-inline-start: map.get($tokens, 'leading-space'); + padding-inline-end: map.get($tokens, 'trailing-space'); } - .supporting-text--multi-line { - -webkit-line-clamp: 2; + md-item[multiline] { + min-height: map.get($tokens, 'two-line-container-height'); } - .trailing-supporting-text { - font-family: var(--_trailing-supporting-text-font); - font-size: var(--_trailing-supporting-text-size); - line-height: var(--_trailing-supporting-text-line-height); - font-weight: var(--_trailing-supporting-text-weight); - - .list-item:not(.disabled) & { - color: var(--_trailing-supporting-text-color); - } - - .disabled & { - color: var(--_disabled-label-text-color); - opacity: var(--_disabled-label-text-opacity); - } - - .with-three-line & { - // In three line, trailing-supporting-text must align with the mid-line of - // the headline text. - margin-block-start: calc( - ( - var(--_label-text-line-height) - - var(--_trailing-supporting-text-line-height) - ) / 2 - ); - } + [slot='supporting-text'] { + color: map.get($tokens, 'supporting-text-color'); + font-family: map.get($tokens, 'supporting-text-font'); + font-size: map.get($tokens, 'supporting-text-size'); + line-height: map.get($tokens, 'supporting-text-line-height'); + font-weight: map.get($tokens, 'supporting-text-weight'); } - .focus-ring { - z-index: 1; + [slot='trailing-supporting-text'] { + color: map.get($tokens, 'trailing-supporting-text-color'); + font-family: map.get($tokens, 'trailing-supporting-text-font'); + font-size: map.get($tokens, 'trailing-supporting-text-size'); + line-height: map.get($tokens, 'trailing-supporting-text-line-height'); + font-weight: map.get($tokens, 'trailing-supporting-text-weight'); } -} - -@mixin _image() { - slot[name='start-image']::slotted(*) { - display: inline-flex; - height: var(--_leading-image-height); - width: var(--_leading-image-width); - border-radius: var(--_leading-image-shape); - // Min height is two-line height - margin-block: calc( - (var(--_two-line-container-height) - var(--_leading-image-height)) / 2 - ); - .with-three-line & { - margin-block: 0; - } - } -} - -@mixin _icon() { - ::slotted(*) { + :is([slot='start'], [slot='end'])::slotted(*) { fill: currentColor; } - slot[name='start-icon']::slotted(*) { - font-size: var(--_leading-icon-size); - width: var(--_leading-icon-size); - height: var(--_leading-icon-size); - color: var(--_leading-icon-color); - - .with-three-line & { - // In three line, icon must align with the mid-line of headline text - margin-block-start: calc( - (var(--_label-text-line-height) - var(--_leading-icon-size)) / 2 - ); - } - } - - slot[name='end-icon']::slotted(*) { - font-size: var(--_trailing-icon-size); - width: var(--_trailing-icon-size); - height: var(--_trailing-icon-size); - color: var(--_trailing-icon-color); - - .with-three-line & { - // In three line, icon must align with the mid-line of headline text - margin-block-start: calc( - (var(--_label-text-line-height) - var(--_trailing-icon-size)) / 2 - ); - } - } - - :hover { - slot[name='start-icon']::slotted(*) { - color: var(--_hover-leading-icon-icon-color); - } - - slot[name='end-icon']::slotted(*) { - color: var(--_hover-trailing-icon-icon-color); - } - } - - :focus { - slot[name='start-icon']::slotted(*) { - color: var(--_focus-leading-icon-icon-color); - } - - slot[name='end-icon']::slotted(*) { - color: var(--_focus-trailing-icon-icon-color); - } - } - - :active { - slot[name='start-icon']::slotted(*) { - color: var(--_pressed-leading-icon-icon-color); - } - - slot[name='end-icon']::slotted(*) { - color: var(--_pressed-trailing-icon-icon-color); - } + [slot='start'] { + color: map.get($tokens, 'leading-icon-color'); } - .disabled { - slot[name='start-icon']::slotted(*) { - opacity: var(--_disabled-leading-icon-opacity); - color: var(--_disabled-leading-icon-color); - } - - slot[name='end-icon']::slotted(*) { - opacity: var(--_disabled-trailing-icon-opacity); - color: var(--_disabled-trailing-icon-color); - } - } -} - -@mixin _avatar() { - slot[name='start-avatar']::slotted(*) { - display: inline-flex; - justify-content: center; - align-items: center; - background-color: var(--_leading-avatar-color); - height: var(--_leading-avatar-size); - width: var(--_leading-avatar-size); - border-radius: var(--_leading-avatar-shape); - color: var(--_leading-avatar-label-color); - font-family: var(--_leading-avatar-label-font); - font-size: var(--_leading-avatar-label-size); - line-height: var(--_leading-avatar-label-line-height); - font-weight: var(--_leading-avatar-label-weight); - } -} - -@mixin _video() { - slot[name='start-video']::slotted(*), - slot[name='start-video-large']::slotted(*) { - display: inline-flex; - object-fit: cover; - height: var(--_small-leading-video-height); - width: var(--_leading-video-width); - border-radius: var(--_leading-video-shape); - margin-inline-start: var(--_leading-video-leading-space); - // Min height is three-line height - margin-block: calc( - (var(--_three-line-container-height) - var(--_small-leading-video-height)) / - 2 - ); - - // Let it auto-layout so that we don't mess with the icons and supporting - // text that is supposed to be top-aligned in three-line. - .with-three-line & { - margin-block: 0; - } - } - - slot[name='start-video-large']::slotted(*) { - // Min height is three-line height - margin-block: calc( - (var(--_three-line-container-height) - var(--_large-leading-video-height)) / - 2 - ); - height: var(--_large-leading-video-height); + [slot='end'] { + color: map.get($tokens, 'trailing-icon-color'); } } diff --git a/list/internal/listitem/forced-colors-styles.scss b/list/internal/listitem/forced-colors-styles.scss index 7f5a5584d2..e326034976 100644 --- a/list/internal/listitem/forced-colors-styles.scss +++ b/list/internal/listitem/forced-colors-styles.scss @@ -8,16 +8,9 @@ // go/keep-sorted end @media (forced-colors: active) { - :host { - @include list-item.theme( - ( - disabled-label-text-color: GrayText, - disabled-label-text-opacity: 1, - disabled-leading-icon-color: GrayText, - disabled-leading-icon-opacity: 1, - disabled-trailing-icon-color: GrayText, - disabled-trailing-icon-opacity: 1, - ) - ); + :host([disabled]), + :host([disabled]) slot { + color: GrayText; + opacity: 1; } } diff --git a/list/internal/listitem/list-item-only.ts b/list/internal/listitem/list-item-only.ts deleted file mode 100644 index 100d82ee15..0000000000 --- a/list/internal/listitem/list-item-only.ts +++ /dev/null @@ -1,43 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import {nothing} from 'lit'; -import {property} from 'lit/decorators.js'; - -import {createRequestActivationEvent, ListItemEl} from './list-item.js'; - -// tslint:disable-next-line:enforce-comments-on-exported-symbols -export class ListItemOnly extends ListItemEl { - /** - * Enables focusing the list item, and adds hover and click ripples when set - * to true. By default `interactive` is false. - */ - @property({type: Boolean}) interactive = false; - - override getRenderClasses() { - return { - ...super.getRenderClasses(), - 'interactive': this.interactive, - }; - } - - override renderRipple() { - return this.interactive ? super.renderRipple() : nothing; - } - - override renderFocusRing() { - return this.interactive ? super.renderFocusRing() : nothing; - } - - override onFocus() { - if (this.tabIndex !== -1) { - return; - } - - // Handles the case where the user clicks on the element and then tabs. - this.dispatchEvent(createRequestActivationEvent()); - } -} diff --git a/list/internal/listitem/list-item.ts b/list/internal/listitem/list-item.ts index d1bf3b70d7..3f92888778 100644 --- a/list/internal/listitem/list-item.ts +++ b/list/internal/listitem/list-item.ts @@ -6,11 +6,12 @@ import '../../../ripple/ripple.js'; import '../../../focus/md-focus-ring.js'; +import '../../../item/item.js'; -import {html, LitElement, nothing, TemplateResult} from 'lit'; +import {html, LitElement, nothing, PropertyValues, TemplateResult} from 'lit'; import {property, query} from 'lit/decorators.js'; -import {classMap} from 'lit/directives/class-map.js'; -import {html as staticHtml, literal} from 'lit/static-html.js'; +import {ClassInfo, classMap} from 'lit/directives/class-map.js'; +import {html as staticHtml, literal, StaticValue} from 'lit/static-html.js'; import {ARIAMixinStrict} from '../../../internal/aria/aria.js'; import {requestUpdateOnAriaChange} from '../../../internal/aria/delegate.js'; @@ -49,9 +50,9 @@ export type RequestActivationEvent = ReturnType; /** - * Supported roles for a list item. + * Supported behaviors for a list item. */ -export type ListItemRole = 'listitem'|'menuitem'|'option'|'link'|'none'; +export type ListItemType = 'text'|'button'|'link'; interface ListItemSelf { disabled: boolean; @@ -63,7 +64,9 @@ interface ListItemSelf { */ export type ListItem = ListItemSelf&HTMLElement; -// tslint:disable-next-line:enforce-comments-on-exported-symbols +/** + * @fires request-activation + */ export class ListItemEl extends LitElement implements ListItem { static { requestUpdateOnAriaChange(ListItemEl); @@ -75,42 +78,16 @@ export class ListItemEl extends LitElement implements ListItem { delegatesFocus: true }; - /** - * The primary, headline text of the list item. - */ - @property() headline = ''; - - /** - * The one-line supporting text below the headline. Set - * `multiLineSupportingText` to `true` to support multiple lines in the - * supporting text. - */ - @property({attribute: 'supporting-text'}) supportingText = ''; - - /** - * Modifies `supportingText` to support multiple lines. - */ - @property({type: Boolean, attribute: 'multi-line-supporting-text'}) - multiLineSupportingText = false; - - /** - * The supporting text placed at the end of the item. Overridden by elements - * slotted into the `end` slot. - */ - @property({attribute: 'trailing-supporting-text'}) - trailingSupportingText = ''; - /** * Disables the item and makes it non-selectable and non-interactive. */ @property({type: Boolean, reflect: true}) disabled = false; /** - * Sets the role of the list item. Set to 'nothing' to clear the role. This - * property will be ignored if `href` is set since the underlying element will - * be a native anchor tag. + * Sets the behavior of the list item, defaults to "text". Change to "link" or + * "button" for interactive items. */ - @property() type: ListItemRole = 'listitem'; + @property() type: ListItemType = 'text'; /** * READONLY. Sets the `md-list-item` attribute on the element. @@ -131,15 +108,25 @@ export class ListItemEl extends LitElement implements ListItem { @query('.list-item') protected readonly listItemRoot!: HTMLElement|null; + protected override willUpdate(changed: PropertyValues) { + if (this.href) { + this.type = 'link'; + } + + super.willUpdate(changed); + } + protected override render() { return this.renderListItem(html` -
- ${this.renderStart()} + +
+ ${this.renderRipple()} + ${this.renderFocusRing()} +
+ + ${this.renderBody()} - ${this.renderEnd()} - ${this.renderRipple()} - ${this.renderFocusRing()} -
+ `); } @@ -149,15 +136,29 @@ export class ListItemEl extends LitElement implements ListItem { * @param content the child content of the list item. */ protected renderListItem(content: unknown) { - const isAnchor = !!this.href; - const tag = isAnchor ? literal`a` : literal`li`; - const role = isAnchor || this.type === 'none' ? nothing : this.type; + const isAnchor = this.type === 'link'; + let tag: StaticValue; + switch (this.type) { + case 'link': + tag = literal`a`; + break; + case 'button': + tag = literal`button`; + break; + default: + case 'text': + tag = literal`li`; + break; + } + + // TODO(b/265339866): announce "button"/"link" inside of a list item. Until + // then all are "listitem" roles for correct announcement. const target = isAnchor && !!this.target ? this.target : nothing; return staticHtml` <${tag} id="item" - tabindex="${this.disabled ? -1 : 0}" - role=${role} + tabindex="${this.disabled && !isAnchor ? -1 : 0}" + role="listitem" aria-selected=${(this as ARIAMixinStrict).ariaSelected || nothing} aria-checked=${(this as ARIAMixinStrict).ariaChecked || nothing} aria-expanded=${(this as ARIAMixinStrict).ariaExpanded || nothing} @@ -166,10 +167,6 @@ export class ListItemEl extends LitElement implements ListItem { href=${this.href || nothing} target=${target} @focus=${this.onFocus} - @click=${this.onClick} - @mouseenter=${this.onMouseenter} - @mouseleave=${this.onMouseleave} - @keydown=${this.onKeydown} >${content} `; } @@ -178,6 +175,10 @@ export class ListItemEl extends LitElement implements ListItem { * Handles rendering of the ripple element. */ protected renderRipple(): TemplateResult|typeof nothing { + if (this.type === 'text') { + return nothing; + } + return html` `; @@ -203,89 +207,33 @@ export class ListItemEl extends LitElement implements ListItem { /** * Classes applied to the list item root. */ - protected getRenderClasses() { - return { - 'with-one-line': this.supportingText === '', - 'with-two-line': - this.supportingText !== '' && !this.multiLineSupportingText, - 'with-three-line': - this.supportingText !== '' && this.multiLineSupportingText, - 'disabled': this.disabled - }; - } - - /** - * The content rendered at the start of the list item. - */ - protected renderStart() { - return html` -
- - - - - - -
`; + protected getRenderClasses(): ClassInfo { + // TODO(b/265339866): links may not be disabled + return {'disabled': this.disabled}; } /** * Handles rendering the headline and supporting text. */ protected renderBody() { - const supportingText = - this.supportingText !== '' ? this.renderSupportingText() : ''; - - return html`
${this.headline}${supportingText}
`; - } - - /** - * Renders the one-line supporting text. - */ - protected renderSupportingText() { - return html`${this.supportingText}`; - } - - /** - * Gets the classes for the supporting text node - */ - protected getSupportingTextClasses() { - return {'supporting-text--multi-line': this.multiLineSupportingText}; - } - - /** - * The content rendered at the end of the list item. - */ - protected renderEnd() { - const supportingText = this.trailingSupportingText !== '' ? - this.renderTrailingSupportingText() : - ''; return html` -
- ${supportingText} - - -
`; + + + + + + `; } - /** - * Renders the supporting text at the end of the list item. - */ - protected renderTrailingSupportingText() { - return html`${this.trailingSupportingText}`; + protected onFocus() { + if (this.tabIndex !== -1) { + return; + } + // Handles the case where the user clicks on the element and then tabs. + this.dispatchEvent(createRequestActivationEvent()); } - // For easier overriding in menu-item - protected onClick?(event: Event): void; - protected onKeydown?(event: KeyboardEvent): void; - protected onMouseenter?(event: Event): void; - protected onMouseleave?(event: Event): void; - protected onFocus?(event: FocusEvent): void; - override focus() { // TODO(b/300334509): needed for some cases where delegatesFocus doesn't // work programmatically like in FF and select-option diff --git a/list/list-item.ts b/list/list-item.ts index a25dd6e139..1a89872de7 100644 --- a/list/list-item.ts +++ b/list/list-item.ts @@ -7,10 +7,10 @@ import {customElement} from 'lit/decorators.js'; import {styles as forcedColors} from './internal/listitem/forced-colors-styles.css.js'; -import {ListItemOnly as ListItem} from './internal/listitem/list-item-only.js'; +import {ListItemEl as ListItem} from './internal/listitem/list-item.js'; import {styles} from './internal/listitem/list-item-styles.css.js'; -export {ListItemRole} from './internal/listitem/list-item.js'; +export {ListItemType} from './internal/listitem/list-item.js'; declare global { interface HTMLElementTagNameMap { diff --git a/list/list_test.ts b/list/list_test.ts index 032e83c493..89ee10863e 100644 --- a/list/list_test.ts +++ b/list/list_test.ts @@ -1008,85 +1008,6 @@ describe('', () => { expect(internalRoot.tabIndex).toBe(-1); }); - it('supportingText is rendered only when set', async () => { - const root = env.render(html``); - - const listItem = root.querySelector('md-list-item')!; - - await env.waitForStability(); - - let supporingTextEl = listItem.renderRoot.querySelector('.supporting-text'); - - expect(supporingTextEl).toBeNull(); - - listItem.supportingText = 'Yolo'; - - await env.waitForStability(); - - supporingTextEl = listItem.renderRoot.querySelector('.supporting-text'); - expect(supporingTextEl).toBeTruthy(); - }); - - it('trailingSupportingText is rendered only when set', async () => { - const root = env.render(html``); - - const listItem = root.querySelector('md-list-item')!; - - await env.waitForStability(); - - let supporingTextEl = - listItem.renderRoot.querySelector('.trailing-supporting-text'); - - expect(supporingTextEl).toBeNull(); - - listItem.trailingSupportingText = 'Yolo'; - - await env.waitForStability(); - - supporingTextEl = - listItem.renderRoot.querySelector('.trailing-supporting-text'); - expect(supporingTextEl).toBeTruthy(); - }); - - it('only one "with-*-line" class is set at a time', async () => { - const root = env.render(html``); - - const listItem = root.querySelector('md-list-item')!; - - await env.waitForStability(); - - const rootEl = listItem.renderRoot.querySelector('#item') as HTMLElement; - - expect(rootEl.classList.contains('with-one-line')).toBeTrue(); - expect(rootEl.classList.contains('with-two-line')).toBeFalse(); - expect(rootEl.classList.contains('with-three-line')).toBeFalse(); - - listItem.multiLineSupportingText = true; - - await env.waitForStability(); - - expect(rootEl.classList.contains('with-one-line')).toBeTrue(); - expect(rootEl.classList.contains('with-two-line')).toBeFalse(); - expect(rootEl.classList.contains('with-three-line')).toBeFalse(); - - listItem.multiLineSupportingText = false; - listItem.supportingText = 'YOLO'; - - await env.waitForStability(); - - expect(rootEl.classList.contains('with-one-line')).toBeFalse(); - expect(rootEl.classList.contains('with-two-line')).toBeTrue(); - expect(rootEl.classList.contains('with-three-line')).toBeFalse(); - - listItem.multiLineSupportingText = true; - - await env.waitForStability(); - - expect(rootEl.classList.contains('with-one-line')).toBeFalse(); - expect(rootEl.classList.contains('with-two-line')).toBeFalse(); - expect(rootEl.classList.contains('with-three-line')).toBeTrue(); - }); - it('ripple and focus ring rendered on interactive', async () => { const root = env.render(html``); @@ -1100,7 +1021,7 @@ describe('', () => { expect(rippleEl).toBeNull(); expect(focusRingEl).toBeNull(); - listItem.interactive = true; + listItem.type = 'button'; await env.waitForStability(); @@ -1133,20 +1054,6 @@ describe(' link', () => { expect(internalRoot.tagName).toBe('A'); }); - it('setting type and href does not render a role', async () => { - const root = env.render( - html``); - - const listItem = root.querySelector('md-list-item')!; - - await env.waitForStability(); - - const internalRoot = - listItem.renderRoot.querySelector('#item') as HTMLElement; - - expect(internalRoot.hasAttribute('role')).toBe(false); - }); - it('setting target without href renders nothing', async () => { const root = env.render(html``); diff --git a/tokens/_md-comp-list-item.scss b/tokens/_md-comp-list-item.scss index f0ed796e8b..ef3e2378c4 100644 --- a/tokens/_md-comp-list-item.scss +++ b/tokens/_md-comp-list-item.scss @@ -10,8 +10,6 @@ // go/keep-sorted end // go/keep-sorted start @use './md-sys-color'; -@use './md-sys-elevation'; -@use './md-sys-shape'; @use './md-sys-state'; @use './md-sys-typescale'; @use './v0_192/md-comp-list'; @@ -20,62 +18,29 @@ $supported-tokens: ( // go/keep-sorted start - 'container-color', - 'container-shape', - 'disabled-label-text-color', - 'disabled-label-text-opacity', - 'disabled-leading-icon-color', - 'disabled-leading-icon-opacity', - 'disabled-trailing-icon-color', - 'disabled-trailing-icon-opacity', - 'focus-label-text-color', - 'focus-leading-icon-icon-color', - 'focus-trailing-icon-icon-color', - 'hover-label-text-color', - 'hover-leading-icon-icon-color', + 'bottom-space', + 'disabled-opacity', + 'focus-state-layer-color', + 'focus-state-layer-opacity', 'hover-state-layer-color', 'hover-state-layer-opacity', - 'hover-trailing-icon-icon-color', 'label-text-color', 'label-text-font', 'label-text-line-height', 'label-text-size', 'label-text-weight', - 'large-leading-video-height', - 'leading-avatar-color', - 'leading-avatar-label-color', - 'leading-avatar-label-font', - 'leading-avatar-label-line-height', - 'leading-avatar-label-size', - 'leading-avatar-label-weight', - 'leading-avatar-shape', - 'leading-avatar-size', - 'leading-element-leading-space', 'leading-icon-color', - 'leading-icon-size', - 'leading-image-height', - 'leading-image-shape', - 'leading-image-width', 'leading-space', - 'leading-video-leading-space', - 'leading-video-shape', - 'leading-video-width', 'one-line-container-height', - 'pressed-label-text-color', - 'pressed-leading-icon-icon-color', 'pressed-state-layer-color', 'pressed-state-layer-opacity', - 'pressed-trailing-icon-icon-color', - 'small-leading-video-height', 'supporting-text-color', 'supporting-text-font', 'supporting-text-line-height', 'supporting-text-size', 'supporting-text-weight', - 'three-line-container-height', - 'trailing-element-headline-trailing-element-space', + 'top-space', 'trailing-icon-color', - 'trailing-icon-size', 'trailing-space', 'trailing-supporting-text-color', 'trailing-supporting-text-font', @@ -88,9 +53,17 @@ $supported-tokens: ( $unsupported-tokens: ( // go/keep-sorted start + 'container-color', 'container-elevation', + 'container-shape', + 'disabled-label-text-color', + 'disabled-label-text-opacity', + 'disabled-leading-icon-color', + 'disabled-leading-icon-opacity', 'disabled-state-layer-color', 'disabled-state-layer-opacity', + 'disabled-trailing-icon-color', + 'disabled-trailing-icon-opacity', 'divider-leading-space', 'divider-trailing-space', 'dragged-container-elevation', @@ -99,12 +72,31 @@ $unsupported-tokens: ( 'dragged-state-layer-color', 'dragged-state-layer-opacity', 'dragged-trailing-icon-icon-color', - 'focus-state-layer-color', - 'focus-state-layer-opacity', + 'focus-label-text-color', + 'focus-leading-icon-icon-color', + 'focus-trailing-icon-icon-color', + 'hover-label-text-color', + 'hover-leading-icon-icon-color', + 'hover-trailing-icon-icon-color', 'label-text-tracking', 'label-text-type', + 'large-leading-video-height', + 'leading-avatar-color', + 'leading-avatar-label-color', + 'leading-avatar-label-font', + 'leading-avatar-label-line-height', + 'leading-avatar-label-size', 'leading-avatar-label-tracking', 'leading-avatar-label-type', + 'leading-avatar-label-weight', + 'leading-avatar-shape', + 'leading-avatar-size', + 'leading-icon-size', + 'leading-image-height', + 'leading-image-shape', + 'leading-image-width', + 'leading-video-shape', + 'leading-video-width', 'overline-color', 'overline-font', 'overline-line-height', @@ -112,9 +104,15 @@ $unsupported-tokens: ( 'overline-tracking', 'overline-type', 'overline-weight', + 'pressed-label-text-color', + 'pressed-leading-icon-icon-color', + 'pressed-trailing-icon-icon-color', 'selected-trailing-icon-color', + 'small-leading-video-height', 'supporting-text-tracking', 'supporting-text-type', + 'three-line-container-height', + 'trailing-icon-size', 'trailing-supporting-text-tracking', 'trailing-supporting-text-type', 'unselected-trailing-icon-color', @@ -123,8 +121,6 @@ $unsupported-tokens: ( $_default: ( 'md-sys-color': md-sys-color.values-light(), - 'md-sys-elevation': md-sys-elevation.values(), - 'md-sys-shape': md-sys-shape.values(), 'md-sys-state': md-sys-state.values(), 'md-sys-typescale': md-sys-typescale.values(), ); @@ -136,7 +132,12 @@ $_default: ( $original-tokens, $supported-tokens: $supported-tokens, $unsupported-tokens: $unsupported-tokens, - $new-tokens: _get-new-tokens($deps, $exclude-hardcoded-values), + $new-tokens: ( + 'top-space': if($exclude-hardcoded-values, null, 12px), + 'bottom-space': if($exclude-hardcoded-values, null, 12px), + 'disabled-opacity': + map.get($original-tokens, 'list-item-disabled-label-text-opacity'), + ), $renamed-tokens: _get-renamed-tokens($original-tokens) ); @@ -157,20 +158,3 @@ $_default: ( @return $renamed-tokens; } - -@function _get-new-tokens($deps, $exclude-hardcoded-values) { - // Values pulled from b/198759625 spreadsheet - @return ( - // go/keep-sorted start - 'leading-element-leading-space': if($exclude-hardcoded-values, null, 16px), - 'leading-video-leading-space': if($exclude-hardcoded-values, null, 0px), - // Commented out until the comments in the spreadsheet linked above are - // resolved regarding vertical alignment. - // 'leading-item-top-space': if($exclude-hardcoded-values, null, 8px), - // 'leading-video-top-space': if($exclude-hardcoded-values, null, 0px), - // 'leading-item-bottom-space': if($exclude-hardcoded-values, null, 8px), - // 'leading-video-bottom-space': if($exclude-hardcoded-values, null, 0px), - 'trailing-element-headline-trailing-element-space': 16px, - // go/keep-sorted end - ); -} diff --git a/tokens/_md-comp-list.scss b/tokens/_md-comp-list.scss index d32e149d72..85c14842c4 100644 --- a/tokens/_md-comp-list.scss +++ b/tokens/_md-comp-list.scss @@ -8,10 +8,6 @@ // go/keep-sorted end // go/keep-sorted start @use './md-sys-color'; -@use './md-sys-elevation'; -@use './md-sys-shape'; -@use './md-sys-state'; -@use './md-sys-typescale'; @use './v0_192/md-comp-list'; @use './values'; // go/keep-sorted end @@ -22,117 +18,15 @@ $supported-tokens: ( // go/keep-sorted end ); -$unsupported-tokens: ( - // go/keep-sorted start - 'divider-leading-space', - 'divider-trailing-space', - 'list-item-container-elevation', - 'list-item-container-shape', - 'list-item-disabled-label-text-color', - 'list-item-disabled-label-text-opacity', - 'list-item-disabled-leading-icon-color', - 'list-item-disabled-leading-icon-opacity', - 'list-item-disabled-state-layer-color', - 'list-item-disabled-state-layer-opacity', - 'list-item-disabled-trailing-icon-color', - 'list-item-disabled-trailing-icon-opacity', - 'list-item-dragged-container-elevation', - 'list-item-dragged-label-text-color', - 'list-item-dragged-leading-icon-icon-color', - 'list-item-dragged-state-layer-color', - 'list-item-dragged-state-layer-opacity', - 'list-item-dragged-trailing-icon-icon-color', - 'list-item-focus-label-text-color', - 'list-item-focus-leading-icon-icon-color', - 'list-item-focus-state-layer-color', - 'list-item-focus-state-layer-opacity', - 'list-item-focus-trailing-icon-icon-color', - 'list-item-hover-label-text-color', - 'list-item-hover-leading-icon-icon-color', - 'list-item-hover-state-layer-color', - 'list-item-hover-state-layer-opacity', - 'list-item-hover-trailing-icon-icon-color', - 'list-item-label-text-color', - 'list-item-label-text-font', - 'list-item-label-text-line-height', - 'list-item-label-text-size', - 'list-item-label-text-tracking', - 'list-item-label-text-type', - 'list-item-label-text-weight', - 'list-item-large-leading-video-height', - 'list-item-leading-avatar-color', - 'list-item-leading-avatar-label-color', - 'list-item-leading-avatar-label-font', - 'list-item-leading-avatar-label-line-height', - 'list-item-leading-avatar-label-size', - 'list-item-leading-avatar-label-tracking', - 'list-item-leading-avatar-label-type', - 'list-item-leading-avatar-label-weight', - 'list-item-leading-avatar-shape', - 'list-item-leading-avatar-size', - 'list-item-leading-icon-color', - 'list-item-leading-icon-size', - 'list-item-leading-image-height', - 'list-item-leading-image-shape', - 'list-item-leading-image-width', - 'list-item-leading-space', - 'list-item-leading-video-shape', - 'list-item-leading-video-width', - 'list-item-one-line-container-height', - 'list-item-overline-color', - 'list-item-overline-font', - 'list-item-overline-line-height', - 'list-item-overline-size', - 'list-item-overline-tracking', - 'list-item-overline-type', - 'list-item-overline-weight', - 'list-item-pressed-label-text-color', - 'list-item-pressed-leading-icon-icon-color', - 'list-item-pressed-state-layer-color', - 'list-item-pressed-state-layer-opacity', - 'list-item-pressed-trailing-icon-icon-color', - 'list-item-selected-trailing-icon-color', - 'list-item-small-leading-video-height', - 'list-item-supporting-text-color', - 'list-item-supporting-text-font', - 'list-item-supporting-text-line-height', - 'list-item-supporting-text-size', - 'list-item-supporting-text-tracking', - 'list-item-supporting-text-type', - 'list-item-supporting-text-weight', - 'list-item-three-line-container-height', - 'list-item-trailing-icon-color', - 'list-item-trailing-icon-size', - 'list-item-trailing-space', - 'list-item-trailing-supporting-text-color', - 'list-item-trailing-supporting-text-font', - 'list-item-trailing-supporting-text-line-height', - 'list-item-trailing-supporting-text-size', - 'list-item-trailing-supporting-text-tracking', - 'list-item-trailing-supporting-text-type', - 'list-item-trailing-supporting-text-weight', - 'list-item-two-line-container-height', - 'list-item-unselected-trailing-icon-color', - // go/keep-sorted end -); - $_default: ( 'md-sys-color': md-sys-color.values-light(), - 'md-sys-elevation': md-sys-elevation.values(), - 'md-sys-shape': md-sys-shape.values(), - 'md-sys-state': md-sys-state.values(), - 'md-sys-typescale': md-sys-typescale.values(), ); @function values($deps: $_default, $exclude-hardcoded-values: false) { - $tokens: values.validate( - md-comp-list.values($deps, $exclude-hardcoded-values), - $supported-tokens: $supported-tokens, - $unsupported-tokens: $unsupported-tokens, - $renamed-tokens: ( - 'list-item-container-color': 'container-color', - ) + $list-tokens: md-comp-list.values($deps, $exclude-hardcoded-values); + $tokens: ( + 'container-color': map.get($list-tokens, 'list-item-container-color'), ); - @return $tokens; + @return values.validate($tokens, $supported-tokens: $supported-tokens); }