Skip to content

Commit

Permalink
chore(list-item): improve anchor handling and semantics
Browse files Browse the repository at this point in the history
  • Loading branch information
DRiFTy17 committed Nov 8, 2023
1 parent 450c61a commit b1d2fb8
Show file tree
Hide file tree
Showing 7 changed files with 226 additions and 70 deletions.
72 changes: 24 additions & 48 deletions src/dev/pages/list/list.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@
<span slot="secondary-text">22 Dec 2017</span>
<forge-icon slot="trailing" name="info"></forge-icon>
</forge-list-item>
<forge-divider></forge-divider>
<forge-divider aria-hidden="true"></forge-divider>
<forge-list-item>
<forge-icon external name="folder" slot="avatar"></forge-icon>
<span slot="primary-text">Potatoes</span>
Expand Down Expand Up @@ -329,7 +329,7 @@
<forge-list-item>List Item Three</forge-list-item>
</forge-list>
</forge-expansion-panel>
<forge-divider></forge-divider>
<forge-divider aria-hidden="true"></forge-divider>
<forge-expansion-panel>
<forge-list-item slot="header">
<forge-icon slot="leading" name="face"></forge-icon>
Expand All @@ -342,7 +342,7 @@
<forge-list-item>List Item Three</forge-list-item>
</forge-list>
</forge-expansion-panel>
<forge-divider></forge-divider>
<forge-divider aria-hidden="true"></forge-divider>
<forge-list-item>List Item Three</forge-list-item>
</forge-list>
</div>
Expand All @@ -354,21 +354,15 @@
<div class="list-demo">
<forge-list>
<forge-list-item>
<forge-checkbox slot="leading">
<input type="checkbox" checked aria-label="Select list item one" />
</forge-checkbox>
<forge-checkbox slot="leading" checked aria-label="Select list item one"></forge-checkbox>
List Item
</forge-list-item>
<forge-list-item>
<forge-checkbox slot="leading">
<input type="checkbox" aria-label="Select list item two" />
</forge-checkbox>
<forge-checkbox slot="leading" aria-label="Select list item two"></forge-checkbox>
List Item
</forge-list-item>
<forge-list-item>
<forge-checkbox slot="leading">
<input type="checkbox" aria-label="Select list item three" />
</forge-checkbox>
<forge-checkbox slot="leading" aria-label="Select list item three"></forge-checkbox>
List Item
</forge-list-item>
</forge-list>
Expand All @@ -382,21 +376,15 @@
<forge-list>
<forge-list-item>
List Item
<forge-checkbox slot="trailing">
<input type="checkbox" checked aria-label="Select list item one" />
</forge-checkbox>
<forge-checkbox slot="trailing" checked aria-label="Select list item one"></forge-checkbox>
</forge-list-item>
<forge-list-item>
List Item
<forge-checkbox slot="trailing">
<input type="checkbox" aria-label="Select list item two" />
</forge-checkbox>
<forge-checkbox slot="trailing" aria-label="Select list item two"></forge-checkbox>
</forge-list-item>
<forge-list-item>
List Item
<forge-checkbox slot="trailing">
<input type="checkbox" aria-label="Select list item three" />
</forge-checkbox>
<forge-checkbox slot="trailing" aria-label="Select list item three"></forge-checkbox>
</forge-list-item>
</forge-list>
</div>
Expand All @@ -405,8 +393,8 @@
<!-- List with Leading Radio Buttons -->
<div>
<h3 class="forge-typography--heading2">List with Leading Radio Buttons</h3>
<div class="list-demo">
<forge-list role="radiogroup" aria-label="Choose radio option">
<div class="list-demo" role="radiogroup">
<forge-list aria-label="Choose radio option">
<forge-list-item>
<forge-radio slot="leading">
<input type="radio" name="list-radio" aria-label="Select list item one" />
Expand All @@ -432,8 +420,8 @@
<!-- List with Trailing Radio Buttons -->
<div>
<h3 class="forge-typography--heading2">List with Trailing Radio Buttons</h3>
<div class="list-demo">
<forge-list role="radiogroup" aria-label="Choose radio option">
<div class="list-demo" role="radiogroup">
<forge-list aria-label="Choose radio option">
<forge-list-item>
List Item
<forge-radio slot="trailing">
Expand Down Expand Up @@ -464,15 +452,15 @@
<forge-list>
<forge-list-item>
List Item
<forge-switch slot="trailing"></forge-switch>
<forge-switch slot="trailing" aria-label="Toggle list item"></forge-switch>
</forge-list-item>
<forge-list-item>
List Item
<forge-switch slot="trailing"></forge-switch>
<forge-switch slot="trailing" aria-label="Toggle list item"></forge-switch>
</forge-list-item>
<forge-list-item>
List Item
<forge-switch slot="trailing"></forge-switch>
<forge-switch slot="trailing" aria-label="Toggle list item"></forge-switch>
</forge-list-item>
</forge-list>
</div>
Expand All @@ -484,30 +472,18 @@
<div class="list-demo">
<forge-list>
<forge-list-item>
<forge-checkbox slot="leading">
<input type="checkbox" checked aria-label="Select list item one" />
</forge-checkbox>
<forge-checkbox slot="trailing">
<input type="checkbox" forge-ignore aria-label="Select list item one" />
</forge-checkbox>
<forge-checkbox slot="leading" checked aria-label="Select list item"></forge-checkbox>
<forge-checkbox slot="trailing" forge-ignore aria-label="Select list item"></forge-checkbox>
List Item
</forge-list-item>
<forge-list-item>
<forge-checkbox slot="leading">
<input type="checkbox" aria-label="Select list item one" />
</forge-checkbox>
<forge-checkbox slot="trailing">
<input type="checkbox" forge-ignore aria-label="Select list item one" />
</forge-checkbox>
<forge-checkbox slot="leading" aria-label="Select list item"></forge-checkbox>
<forge-checkbox slot="trailing" forge-ignore aria-label="Select list item"></forge-checkbox>
List Item
</forge-list-item>
<forge-list-item>
<forge-checkbox slot="leading">
<input type="checkbox" aria-label="Select list item one" />
</forge-checkbox>
<forge-checkbox slot="trailing">
<input type="checkbox" forge-ignore aria-label="Select list item one" />
</forge-checkbox>
<forge-checkbox slot="leading" aria-label="Select list item"></forge-checkbox>
<forge-checkbox slot="trailing" forge-ignore aria-label="Select list item"></forge-checkbox>
List Item
</forge-list-item>
</forge-list>
Expand All @@ -522,9 +498,9 @@
<aside>
<forge-list navlist>
<forge-list-item>List Item One</forge-list-item>
<forge-divider></forge-divider>
<forge-divider aria-hidden="true"></forge-divider>
<forge-list-item selected>List Item Two</forge-list-item>
<forge-divider></forge-divider>
<forge-divider aria-hidden="true"></forge-divider>
<forge-list-item>List Item Three</forge-list-item>
</forge-list>
</aside>
Expand Down
53 changes: 46 additions & 7 deletions src/lib/list/list-item/list-item-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ import { ISwitchComponent } from '../../switch';

export interface IListItemAdapter extends IBaseAdapter<IListItemComponent> {
initialize(): void;
setHref(href: string, target: string): void;
setHrefTarget(target: string): void;
setHref(href: string): void;
setAnchorTarget(target: string): void;
setAnchorDownload(download: string): void;
setAnchorRel(rel: string): void;
setNonInteractive(value: boolean): void;
setDisabled(value: boolean): void;
setActive(value: boolean): void;
Expand All @@ -21,6 +23,8 @@ export interface IListItemAdapter extends IBaseAdapter<IListItemComponent> {
isFocused(): boolean;
setFocus(): void;
animateStateLayer(): void;
clickAnchor(): void;
clickHost(): void;
}

export class ListItemAdapter extends BaseAdapter<IListItemComponent> implements IListItemAdapter {
Expand Down Expand Up @@ -49,10 +53,10 @@ export class ListItemAdapter extends BaseAdapter<IListItemComponent> implements
}
}

public setHref(href: string, target: string): void {
public setHref(href: string): void {
if (href) {
if (this._rootElement.tagName !== 'A') {
const anchor = this._createAnchorRootElement(target);
const anchor = this._createAnchorRootElement();
this._rootElement = replaceElement(this._rootElement, anchor);
}
(this._rootElement as HTMLAnchorElement).href = href;
Expand All @@ -62,12 +66,24 @@ export class ListItemAdapter extends BaseAdapter<IListItemComponent> implements
}
}

public setHrefTarget(target: string): void {
public setAnchorTarget(target: string): void {
if (this._rootElement.tagName === 'A') {
(this._rootElement as HTMLAnchorElement).target = target;
}
}

public setAnchorDownload(download: string): void {
if (this._rootElement.tagName === 'A') {
(this._rootElement as HTMLAnchorElement).download = download;
}
}

public setAnchorRel(rel: string): void {
if (this._rootElement.tagName === 'A') {
(this._rootElement as HTMLAnchorElement).rel = rel;
}
}

public setNonInteractive(value: boolean): void {
this._rootElement.tabIndex = value ? -1 : 0;

Expand Down Expand Up @@ -161,11 +177,34 @@ export class ListItemAdapter extends BaseAdapter<IListItemComponent> implements
this._stateLayerElement.playAnimation();
}

private _createAnchorRootElement(target: string): HTMLAnchorElement {
public clickAnchor(): void {
if (this._rootElement.tagName === 'A') {
(this._rootElement as HTMLAnchorElement).click();
}
}

public clickHost(): void {
// Calling click() on the prototype ensures we don't end up in an infinite
// recursion since the host overrides the HTMLElement.click() method
HTMLElement.prototype.click.call(this._component);
}

private _createAnchorRootElement(): HTMLAnchorElement {
const a = document.createElement('a');
a.classList.add(LIST_ITEM_CONSTANTS.classes.ROOT);
a.setAttribute('part', 'root');
a.target = target;
if (this._component.href) {
a.href = this._component.href;
}
if (this._component.target) {
a.target = this._component.target;
}
if (this._component.download) {
a.download = this._component.download;
}
if (this._component.rel) {
a.rel = this._component.rel;
}
return a;
}

Expand Down
4 changes: 3 additions & 1 deletion src/lib/list/list-item/list-item-constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ const elementName = `${COMPONENT_NAME_PREFIX}list-item`;
const observedAttributes = {
HREF: 'href',
TARGET: 'target',
DOWNLOAD: 'download',
REL: 'rel',
STATIC: 'static',
NON_INTERACTIVE: 'non-interactive',
DISABLED: 'disabled',
Expand All @@ -30,7 +32,7 @@ const classes = {

const selectors = {
ROOT: `.${classes.ROOT}`,
CHECKBOX_RADIO_SELECTOR: 'input[type=checkbox]:not(:disabled):not([forge-ignore]),input[type=radio]:not(:disabled):not([forge-ignore])',
CHECKBOX_RADIO_SELECTOR: ':is(input[type=checkbox], input[type=radio], forge-checkbox):not(:disabled):not([forge-ignore])',
SWITCH_SELECTOR: 'forge-switch:not([disabled]):not([forge-ignore])',
IGNORE: '[forge-ignore],[data-forge-ignore]'
};
Expand Down
42 changes: 38 additions & 4 deletions src/lib/list/list-item/list-item-foundation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { IListItemSelectEventData, LIST_ITEM_CONSTANTS } from './list-item-const
export interface IListItemFoundation extends ICustomElementFoundation {
href: string;
target: string;
download: string;
rel: string;
static: boolean;
nonInteractive: boolean;
disabled: boolean;
Expand All @@ -23,7 +25,9 @@ export interface IListItemFoundation extends ICustomElementFoundation {

export class ListItemFoundation implements IListItemFoundation {
private _href: string;
private _target = '_blank';
private _target = '';
private _download = '';
private _rel = '';
private _nonInteractive = false;
private _disabled = false;
private _selected = false;
Expand Down Expand Up @@ -69,6 +73,14 @@ export class ListItemFoundation implements IListItemFoundation {
this._adapter.setFocus();
}

public click(): void {
if (this._href) {
this._adapter.clickAnchor();
} else {
this._adapter.clickHost();
}
}

private _onPointerDown(evt: MouseEvent): void {
if (this._adapter.isFocused()) {
evt.preventDefault();
Expand All @@ -77,7 +89,7 @@ export class ListItemFoundation implements IListItemFoundation {

private _onKeydown(evt: KeyboardEvent): void {
if (evt.key === 'Enter' || evt.key === ' ') {
if (evt.key === ' ') {
if (!this._href && evt.key === ' ') {
evt.preventDefault();
}
this._adapter.animateStateLayer();
Expand Down Expand Up @@ -117,7 +129,7 @@ export class ListItemFoundation implements IListItemFoundation {
public set href(value: string) {
if (this._href !== value) {
this._href = value;
this._adapter.setHref(this._href, this._target);
this._adapter.setHref(this._href);
this._adapter.toggleHostAttribute(LIST_ITEM_CONSTANTS.attributes.HREF, !!this._href, this._href);
}
}
Expand All @@ -129,12 +141,34 @@ export class ListItemFoundation implements IListItemFoundation {
if (this._target !== value) {
this._target = value;
if (this._href) {
this._adapter.setHrefTarget(this._target);
this._adapter.setAnchorTarget(this._target);
}
this._adapter.toggleHostAttribute(LIST_ITEM_CONSTANTS.attributes.TARGET, !!this._target, this._target);
}
}

public get download(): string {
return this._download;
}
public set download(value: string) {
if (this._download !== value) {
this._download = value;
this._adapter.setAnchorDownload(this._download);
this._adapter.toggleHostAttribute(LIST_ITEM_CONSTANTS.attributes.DOWNLOAD, !!this._download, this._download);
}
}

public get rel(): string {
return this._rel;
}
public set rel(value: string) {
if (this._rel !== value) {
this._rel = value;
this._adapter.setAnchorRel(this._rel);
this._adapter.toggleHostAttribute(LIST_ITEM_CONSTANTS.attributes.REL, !!this._rel, this._rel);
}
}

public get static(): boolean {
return this.nonInteractive;
}
Expand Down
4 changes: 2 additions & 2 deletions src/lib/list/list-item/list-item.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<slot name="tertiary-title"></slot>
</div>
<slot name="trailing"></slot>
<forge-state-layer exportparts="surface:state-layer__surface"></forge-state-layer>
<forge-focus-indicator exportparts="indicator:focus-indicator__indicator" inward></forge-focus-indicator>
<forge-state-layer exportparts="surface:state-layer"></forge-state-layer>
<forge-focus-indicator exportparts="indicator:focus-indicator" inward></forge-focus-indicator>
</div>
</template>
Loading

0 comments on commit b1d2fb8

Please sign in to comment.