Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): add listbox support for roving-tabindex-controller #2563

Closed
wants to merge 40 commits into from
Closed
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
cfcf45d
feat(core): added `ariaActivedescendant` to `internals-controller`
Jul 18, 2023
20be42c
feat(listbox): init pf-listbox, pf-listbox-group, and pf-listbox-option
Jul 18, 2023
12f6c52
feat(listbox): init pf-listbox-item
Jul 18, 2023
02e352b
feat(core): added orientation to arrow key handling
Jul 19, 2023
9b8cdaf
fix(core): removed pageUp and pageDown key handlers because default b…
Jul 19, 2023
d6a46cc
feat(core): fixed roving-tabindex-controller's `updateActiveItem` so …
Jul 20, 2023
c647911
feat(elements): added listbox-optiontemporary styles for filtered and…
Jul 20, 2023
b95ba67
feat(elements): added filtering to listbox-option
Jul 20, 2023
dc739c7
feat(elements): added temporary orientation styles to listbox
Jul 20, 2023
1c0cdd6
feat(elements): added more variations to demo
Jul 20, 2023
fc55e07
feat(elements): added roving-tabindex-controller and filtering to lis…
Jul 20, 2023
13cc4f9
feat(elements): added temporary aria-selected styles to listbox-option
Jul 20, 2023
51944a0
feat(elements): added focus and blur event handlers for listbox-option
Jul 20, 2023
d3530bd
feat(elements): added temporary active descendant syling when listbox…
Jul 20, 2023
471a6c9
feat(elements): change and input events, and updated filter and activ…
Jul 20, 2023
c8732e5
feat(elements): fixed listbox filterbyKeyword for multiselect and ext…
Jul 20, 2023
d772a34
feat(listbox): added keyboardmultiselect support
Jul 20, 2023
ec5f937
feat(listbox): added flex temporary style
Jul 20, 2023
43df77d
feat(listbox): added temporary listbox styles
Jul 20, 2023
159a37f
feat(listbox): added multiselect with keyboard events
Jul 20, 2023
fe95a58
feat(listbox): updated temporary styles and demo
Jul 20, 2023
0fcd9cb
feat(listbox): added support for listbox groups
Jul 20, 2023
fd4decf
feat(listbox): removed unused `#hasFocus` variable from listbox
Jul 20, 2023
d8b5d0c
feat(listbox): updated demo styles
Jul 20, 2023
c464616
feat(listbox): fixed multiselect handling, added internals for aria, …
Jul 21, 2023
827ec5c
feat(listbox): updated docs with more examples
Jul 21, 2023
ac10a63
feat(listbox): added support for combobox filtering
Jul 21, 2023
9a965a4
feat(listbox): updated demo for filter modes
Jul 21, 2023
7a63196
fix(listbox): updated demo js
Jul 24, 2023
40c038e
feat(listbox): added case sensitivity
Jul 24, 2023
b99edd1
fix(listbox): typo on option
Jul 24, 2023
f942a2d
feat(core): init listbox-controller
Jul 28, 2023
2220a4b
feat(listbox): updated listbox to use listbox-controller
Jul 28, 2023
f61771c
feat(core): updated listbox-controller api
Jul 28, 2023
764671d
feat(listbox): updated listbox to use listbox-controller
Jul 28, 2023
dae5258
feat(listbox): updated listbox group based on listbox changes
Jul 28, 2023
7768d4b
chore(simple-list): renamed pf-listbox to match upstream patternfly s…
Jul 28, 2023
62d689e
feat(core): fixed selection issue with listbox-controller
Jul 28, 2023
c3b47e7
feat(simple-list): fixed required filterMode for comboboxes and updat…
Jul 28, 2023
c6fe972
feat(simple-list): updated demos
Jul 28, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions core/pfe-core/controllers/internals-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export class InternalsController implements ReactiveController, ARIAMixin {
declare role: ARIAMixin['role'];
declare ariaAtomic: ARIAMixin['ariaAtomic'];
declare ariaAutoComplete: ARIAMixin['ariaAutoComplete'];
declare ariaActivedescendant: string | null;
declare ariaBusy: ARIAMixin['ariaBusy'];
declare ariaChecked: ARIAMixin['ariaChecked'];
declare ariaColCount: ARIAMixin['ariaColCount'];
Expand Down
33 changes: 14 additions & 19 deletions core/pfe-core/controllers/roving-tabindex-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,20 +101,28 @@ export class RovingTabindexController<
this.#focusableItems.includes(x as ItemType))) {
return;
}

const orientation = this.host.getAttribute('aria-orientation');

const item = this.activeItem;
let shouldPreventDefault = false;
const horizontalOnly =
!item ? false
: item.tagName === 'SELECT' ||
item.getAttribute('role') === 'spinbutton';


item.getAttribute('role') === 'spinbutton' || orientation === 'horizontal';
const verticalOnly = orientation === 'vertical';
switch (event.key) {
case 'ArrowLeft':
if (verticalOnly) {
return;
}
this.focusOnItem(this.prevItem);
shouldPreventDefault = true;
break;
case 'ArrowRight':
if (verticalOnly) {
return;
}
this.focusOnItem(this.nextItem);
shouldPreventDefault = true;
break;
Expand All @@ -136,24 +144,10 @@ export class RovingTabindexController<
this.focusOnItem(this.firstItem);
shouldPreventDefault = true;
break;
case 'PageUp':
if (horizontalOnly) {
return;
}
this.focusOnItem(this.firstItem);
shouldPreventDefault = true;
break;
case 'End':
this.focusOnItem(this.lastItem);
shouldPreventDefault = true;
break;
case 'PageDown':
if (horizontalOnly) {
return;
}
this.focusOnItem(this.lastItem);
shouldPreventDefault = true;
break;
default:
break;
}
Expand All @@ -168,8 +162,8 @@ export class RovingTabindexController<
* sets tabindex of item based on whether or not it is active
*/
updateActiveItem(item?: ItemType): void {
if (item) {
if (!!this.#activeItem && item !== this.#activeItem) {
if (item && item !== this.#activeItem) {
if (this.#activeItem) {
this.#activeItem.tabIndex = -1;
}
item.tabIndex = 0;
Expand All @@ -192,6 +186,7 @@ export class RovingTabindexController<
updateItems(items: ItemType[]) {
const sequence = [...items.slice(this.#itemIndex), ...items.slice(0, this.#itemIndex)];
const first = sequence.find(item => this.#focusableItems.includes(item));
this.#items = items ?? [];
this.focusOnItem(first || this.firstItem);
}

Expand Down
3 changes: 3 additions & 0 deletions elements/package.json
nikkimk marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@
"./pf-jump-links/pf-jump-links.js": "./pf-jump-links/pf-jump-links.js",
"./pf-label/BaseLabel.js": "./pf-label/BaseLabel.js",
"./pf-label/pf-label.js": "./pf-label/pf-label.js",
"./pf-listbox/pf-listbox.js": "./pf-listbox/pf-listbox.js",
"./pf-listbox/pf-listbox-group.js": "./pf-listbox/pf-listbox-group.js",
"./pf-listbox/pf-listbox-option.js": "./pf-listbox/pf-listbox-option.js",
"./pf-modal/pf-modal.js": "./pf-modal/pf-modal.js",
"./pf-panel/pf-panel.js": "./pf-panel/pf-panel.js",
"./pf-progress-stepper/pf-progress-step.js": "./pf-progress-stepper/pf-progress-step.js",
Expand Down
11 changes: 11 additions & 0 deletions elements/pf-listbox/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Listbox
Add a description of the component here.

## Usage
Describe how best to use this web component along with best practices.

```html
<pf-listbox>

</pf-listbox>
```
13 changes: 13 additions & 0 deletions elements/pf-listbox/demo/demo.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[data-demo="pf-listbox"] {
padding: 20px;
}

#combo {
display: inline-flex;
align-items: stretch;
flex-direction: column;
}

#listbox {
display: flex;
}
43 changes: 43 additions & 0 deletions elements/pf-listbox/demo/filter-modes.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<link rel="stylesheet" href="demo.css">
<script type="module" src="pf-listbox.js"></script>

<h2>filter-mode="disabled"</h2>
<p>
Any arrow keys work.
Only one option can be selected.
Filter is disabled.</p>
<pf-listbox filter-mode="disabled">
<pf-listbox-option>Blue</pf-listbox-option>
<pf-listbox-option>Green</pf-listbox-option>
<pf-listbox-option>Magenta</pf-listbox-option>
<pf-listbox-option>Orange</pf-listbox-option>
<pf-listbox-option>Purple</pf-listbox-option>
<pf-listbox-option>Pink</pf-listbox-option>
<pf-listbox-option>Red</pf-listbox-option>
<pf-listbox-option>Yellow</pf-listbox-option>
</pf-listbox>

<h2>filter-mode="required": combobox example</h2>
<p>
Any arrow keys work.
Only one option can be selected.
Listbox wont appear until input has text.
</p>
<label id="combo">
Pick a color:
<input id="text"
aria-controls="listbox"
aria-role="combobox"
aria-autocomplete="both"
aria-expanded="false"/>
<pf-listbox id="listbox" filter-mode="required">
<pf-listbox-option>Blue</pf-listbox-option>
<pf-listbox-option>Green</pf-listbox-option>
<pf-listbox-option>Magenta</pf-listbox-option>
<pf-listbox-option>Orange</pf-listbox-option>
<pf-listbox-option>Purple</pf-listbox-option>
<pf-listbox-option>Pink</pf-listbox-option>
<pf-listbox-option>Red</pf-listbox-option>
<pf-listbox-option>Yellow</pf-listbox-option>
</pf-listbox>
</label>
23 changes: 23 additions & 0 deletions elements/pf-listbox/demo/grouped-options.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<link rel="stylesheet" href="demo.css">
<script type="module" src="pf-listbox.js"></script>

<p>
Any arrow keys work.
Only one option can be selected.
Filter by typing a letter.
Headings are not selectable.
</p>
<pf-listbox>
<pf-listbox-group>
<span slot="group-heading">Breakfast</span>
<pf-listbox-option>Eggs</pf-listbox-option>
<pf-listbox-option>Toast</pf-listbox-option>
<pf-listbox-option>Waffles</pf-listbox-option>
</pf-listbox-group>
<pf-listbox-group>
<span slot="group-heading">Lunch</span>
<pf-listbox-option>Salad</pf-listbox-option>
<pf-listbox-option>Sandwich</pf-listbox-option>
<pf-listbox-option>Soup</pf-listbox-option>
</pf-listbox-group>
</pf-listbox>
19 changes: 19 additions & 0 deletions elements/pf-listbox/demo/multiple-selections.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<link rel="stylesheet" href="demo.css">
<script type="module" src="pf-listbox.js"></script>

<p>
Multiple options can be selected. Any arrow keys work.
<kbd>Shift</kbd> will toggling off multiple items.
<kbd>Ctrl+A</kbd> will toggle selection on all items.
Filter by typing a letter.
</p>
<pf-listbox multiple>
<pf-listbox-option>Blue</pf-listbox-option>
<pf-listbox-option>Green</pf-listbox-option>
<pf-listbox-option>Magenta</pf-listbox-option>
<pf-listbox-option>Orange</pf-listbox-option>
<pf-listbox-option>Purple</pf-listbox-option>
<pf-listbox-option>Pink</pf-listbox-option>
<pf-listbox-option>Red</pf-listbox-option>
<pf-listbox-option>Yellow</pf-listbox-option>
</pf-listbox>
28 changes: 28 additions & 0 deletions elements/pf-listbox/demo/orientation.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<link rel="stylesheet" href="demo.css">
<script type="module" src="pf-listbox.js"></script>

<h2>orientation="vertical"</h2>
<p>Only vertical arrow keys work. Filter by typing a letter.</p>
<pf-listbox orientation="vertical">
<pf-listbox-option>Blue</pf-listbox-option>
<pf-listbox-option>Green</pf-listbox-option>
<pf-listbox-option>Magenta</pf-listbox-option>
<pf-listbox-option>Orange</pf-listbox-option>
<pf-listbox-option>Purple</pf-listbox-option>
<pf-listbox-option>Pink</pf-listbox-option>
<pf-listbox-option>Red</pf-listbox-option>
<pf-listbox-option>Yellow</pf-listbox-option>
</pf-listbox>

<h2>orientation="horizontal"</h2>
<p>Only horizontal arrow keys work. Filter by typing a letter.</p>
<pf-listbox orientation="horizontal">
<pf-listbox-option>Blue</pf-listbox-option>
<pf-listbox-option>Green</pf-listbox-option>
<pf-listbox-option>Magenta</pf-listbox-option>
<pf-listbox-option>Orange</pf-listbox-option>
<pf-listbox-option>Purple</pf-listbox-option>
<pf-listbox-option>Pink</pf-listbox-option>
<pf-listbox-option>Red</pf-listbox-option>
<pf-listbox-option>Yellow</pf-listbox-option>
</pf-listbox>
19 changes: 19 additions & 0 deletions elements/pf-listbox/demo/pf-listbox.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<link rel="stylesheet" href="demo.css">
<script type="module" src="pf-listbox.js"></script>

<h2>default</h2>
<p>
Any arrow keys work.
Only one option can be selected.
Filter by typing a letter.
</p>
<pf-listbox>
<pf-listbox-option>Blue</pf-listbox-option>
<pf-listbox-option>Green</pf-listbox-option>
<pf-listbox-option>Magenta</pf-listbox-option>
<pf-listbox-option>Orange</pf-listbox-option>
<pf-listbox-option>Purple</pf-listbox-option>
<pf-listbox-option>Pink</pf-listbox-option>
<pf-listbox-option>Red</pf-listbox-option>
<pf-listbox-option>Yellow</pf-listbox-option>
</pf-listbox>
29 changes: 29 additions & 0 deletions elements/pf-listbox/demo/pf-listbox.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import '@patternfly/elements/pf-listbox/pf-listbox.js';

window.addEventListener('load', () => {
nikkimk marked this conversation as resolved.
Show resolved Hide resolved
/**
* pf-listbox in a combox box
* @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/combobox/examples/combobox-autocomplete-both/|WAI ARIA Examples: Combobox with ARIAutocomplete}
*/
const input = document.querySelector('#text');
const listbox = document.querySelector('#listbox');
if (listbox && input) {
listbox.filter = input.value;
input.addEventListener('input', () => {
if (input.value !== listbox.value) {
listbox.filter = input.value;
}
});
listbox.addEventListener('change', () => {
const val = (listbox.value || '');
if (val.length > 0) {
input.value = val;
input.focus();
input.setSelectionRange(
listbox.filter.length,
val.length
);
}
});
}
});
17 changes: 17 additions & 0 deletions elements/pf-listbox/docs/pf-listbox.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{% renderOverview %}
<pf-listbox></pf-listbox>
{% endrenderOverview %}

{% band header="Usage" %}{% endband %}

{% renderSlots %}{% endrenderSlots %}

{% renderAttributes %}{% endrenderAttributes %}

{% renderMethods %}{% endrenderMethods %}

{% renderEvents %}{% endrenderEvents %}

{% renderCssCustomProperties %}{% endrenderCssCustomProperties %}

{% renderCssParts %}{% endrenderCssParts %}
14 changes: 14 additions & 0 deletions elements/pf-listbox/pf-listbox-group.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
:host {
display: block;
}

slot {
padding: 10px;
}

slot[name="group-heading"] {
background-color: #f0f0f0;
display: block;
font-weight: bold;
padding: 0 10px;
}
45 changes: 45 additions & 0 deletions elements/pf-listbox/pf-listbox-group.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { LitElement, html } from 'lit';
import { customElement } from 'lit/decorators/custom-element.js';
import { InternalsController } from '@patternfly/pfe-core/controllers/internals-controller.js';
import { queryAssignedElements } from 'lit/decorators/query-assigned-elements.js';
import { PfListboxOption } from './pf-listbox-option.js';

import styles from './pf-listbox-group.css';

export type PfListboxGroupOrOption = PfListboxGroup | PfListboxOption;

/**
* Group of options within a listbox
* @slot - Place element content here
*/
@customElement('pf-listbox-group')
export class PfListboxGroup extends LitElement {
static readonly styles = [styles];

#internals = new InternalsController(this, {
role: 'group'
});

@queryAssignedElements() private _options!: PfListboxOption[];

render() {
return html`
<slot name="group-heading" role="presentation"></slot>
<slot @slotchange="${this.#onSlotchange}"></slot>
`;
}

get options() {
return this._options;
}

#onSlotchange() {
this.dispatchEvent(new Event('slotchange', { bubbles: true }));
nikkimk marked this conversation as resolved.
Show resolved Hide resolved
}
}

declare global {
interface HTMLElementTagNameMap {
'pf-listbox-group': PfListboxGroup;
}
}
23 changes: 23 additions & 0 deletions elements/pf-listbox/pf-listbox-option.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
:host {
display: block;
padding: 2px 10px;
}

:host([hidden]),
:host([hidden-by-filter]) {
display: none !important;
}

:host:after,
:host:before {
content: '\2713 ';
opacity: 0;
}

:host([aria-selected="true"]):before {
opacity: 1;
}

:host([active-descendant]) {
background-color: var(--_active-descendant-color, transparent);
}
Loading