fix(select-rich): keyboard navigation should handle scrolling
This commit is contained in:
parent
3cd6c43e9a
commit
0dad105109
2 changed files with 83 additions and 1 deletions
|
|
@ -19,6 +19,26 @@ function detectInteractionMode() {
|
|||
return 'windows/linux';
|
||||
}
|
||||
|
||||
function isInView(container, element, partial = false) {
|
||||
const cTop = container.scrollTop;
|
||||
const cBottom = cTop + container.clientHeight;
|
||||
const eTop = element.offsetTop;
|
||||
const eBottom = eTop + element.clientHeight;
|
||||
const isTotal = eTop >= cTop && eBottom <= cBottom;
|
||||
let isPartial;
|
||||
|
||||
if (partial === true) {
|
||||
isPartial = (eTop < cTop && eBottom > cTop) || (eBottom > cBottom && eTop < cBottom);
|
||||
} else if (typeof partial === 'number') {
|
||||
if (eTop < cTop && eBottom > cTop) {
|
||||
isPartial = ((eBottom - cTop) * 100) / element.clientHeight > partial;
|
||||
} else if (eBottom > cBottom && eTop < cBottom) {
|
||||
isPartial = ((cBottom - eTop) * 100) / element.clientHeight > partial;
|
||||
}
|
||||
}
|
||||
return isTotal || isPartial;
|
||||
}
|
||||
|
||||
/**
|
||||
* LionSelectRich: wraps the <lion-listbox> element
|
||||
*
|
||||
|
|
@ -129,9 +149,18 @@ export class LionSelectRich extends OverlayMixin(
|
|||
return this.formElements.findIndex(el => el.active === true);
|
||||
}
|
||||
|
||||
get scrollTarget() {
|
||||
return this._overlayContentNode.scrollTarget || this._overlayContentNode;
|
||||
}
|
||||
|
||||
set activeIndex(index) {
|
||||
if (this.formElements[index]) {
|
||||
this.formElements[index].active = true;
|
||||
const el = this.formElements[index];
|
||||
el.active = true;
|
||||
|
||||
if (!isInView(this.scrollTarget, el)) {
|
||||
el.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -591,11 +620,30 @@ export class LionSelectRich extends OverlayMixin(
|
|||
this._invokerNode.focus();
|
||||
};
|
||||
this._overlayCtrl.addEventListener('hide', this.__overlayOnHide);
|
||||
|
||||
this.__preventScrollingWithArrowKeys = this.__preventScrollingWithArrowKeys.bind(this);
|
||||
this.scrollTarget.addEventListener('keydown', this.__preventScrollingWithArrowKeys);
|
||||
}
|
||||
|
||||
__teardownOverlay() {
|
||||
this._overlayCtrl.removeEventListener('show', this.__overlayOnShow);
|
||||
this._overlayCtrl.removeEventListener('hide', this.__overlayOnHide);
|
||||
this.scrollTarget.removeEventListener('keydown', this.__overlayOnHide);
|
||||
}
|
||||
|
||||
__preventScrollingWithArrowKeys(ev) {
|
||||
if (this.disabled) {
|
||||
return;
|
||||
}
|
||||
const { key } = ev;
|
||||
switch (key) {
|
||||
case 'ArrowUp':
|
||||
case 'ArrowDown':
|
||||
case 'Home':
|
||||
case 'End':
|
||||
ev.preventDefault();
|
||||
/* no default */
|
||||
}
|
||||
}
|
||||
|
||||
_isEmpty() {
|
||||
|
|
|
|||
|
|
@ -59,6 +59,40 @@ storiesOf('Forms|Select Rich', module)
|
|||
</div>
|
||||
`,
|
||||
)
|
||||
.add(
|
||||
'Many Options with scrolling',
|
||||
() => html`
|
||||
<style>
|
||||
.demo-listbox {
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
display: block;
|
||||
}
|
||||
${selectRichDemoStyle}
|
||||
</style>
|
||||
<div class="demo-area">
|
||||
<lion-select-rich label="Favorite color" name="color">
|
||||
<lion-options slot="input" class="demo-listbox">
|
||||
<lion-option .modelValue=${{ value: 'red', checked: false }}>
|
||||
<p style="color: red;">I am red</p>
|
||||
</lion-option>
|
||||
<lion-option .modelValue=${{ value: 'hotpink', checked: true }}>
|
||||
<p style="color: hotpink;">I am hotpink</p>
|
||||
</lion-option>
|
||||
<lion-option .modelValue=${{ value: 'teal', checked: false }}>
|
||||
<p style="color: teal;">I am teal</p>
|
||||
</lion-option>
|
||||
<lion-option .modelValue=${{ value: 'green', checked: false }}>
|
||||
<p style="color: green;">I am green</p>
|
||||
</lion-option>
|
||||
<lion-option .modelValue=${{ value: 'blue', checked: false }}>
|
||||
<p style="color: blue;">I am blue</p>
|
||||
</lion-option>
|
||||
</lion-options>
|
||||
</lion-select-rich>
|
||||
</div>
|
||||
`,
|
||||
)
|
||||
.add(
|
||||
'Read-only prefilled',
|
||||
() => html`
|
||||
|
|
|
|||
Loading…
Reference in a new issue