Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions ember-headlessui/addon/components/listbox.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
openListbox=this.openListbox
closeListbox=this.closeListbox
handleClickOutside=this.handleClickOutside
selectedValue=@value
scrollIntoView=this.scrollIntoView
)
Button=(component
'listbox/-button'
Expand Down
2 changes: 0 additions & 2 deletions ember-headlessui/addon/components/listbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,6 @@ export default class ListboxComponent extends Component {
if (this.args.value === optionComponent.args.value) {
this.selectedOptionIndex = this.activeOptionIndex =
this.optionElements.length - 1;

this.scrollIntoView(optionElement);
}
}

Expand Down
1 change: 1 addition & 0 deletions ember-headlessui/addon/components/listbox/-option.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
id={{this.guid}}
tabindex='-1'
{{this.registerOption}}
{{this.scroll this.shouldScroll @scrollIntoView}}
{{on 'focus' (fn @setActiveOption this)}}
{{on 'mouseover' (fn @setActiveOption this)}}
{{on 'mouseout' @unsetActiveOption}}
Expand Down
12 changes: 12 additions & 0 deletions ember-headlessui/addon/components/listbox/-option.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,23 @@ import { modifier } from 'ember-modifier';

export default class ListboxOptionComponent extends Component {
@tracked guid = `${guidFor(this)}-headlessui-listbox-option`;
@tracked shouldScroll = false;

constructor() {
super(...arguments);
this.shouldScroll = this.args.selectedValue === this.args.value;
}

registerOption = modifier((element) => {
this.args.registerOptionElement(this, element);
});

scroll = modifier((element, [shouldScroll, scrollFn]) => {
if (shouldScroll) {
scrollFn(element);
}
});

@action
handleClick(e) {
e.stopPropagation();
Expand Down
2 changes: 2 additions & 0 deletions ember-headlessui/addon/components/listbox/-options.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
setActiveOption=@setActiveOption
unsetActiveOption=@unsetActiveOption
setSelectedOption=@setSelectedOption
selectedValue=@selectedValue
scrollIntoView=@scrollIntoView
)
)
}}
Expand Down
38 changes: 38 additions & 0 deletions test-app/tests/integration/components/listbox-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3440,4 +3440,42 @@ module('Integration | Component | <Listbox>', function (hooks) {

assert.strictEqual(callCount, 0, 'onSubmit not called');
});

test('should scroll to selected item only once', async function (assert) {
this.set('items', [1, 2, 3, 4]);
this.set('selected', 1);
this.set('select', (item) => {
this.selected = item;
});

let factory = this.owner.factoryFor('component:listbox');
let callCount = 0;
class ExtendedListbox extends factory.class {
scrollIntoView() {
callCount++;
}
}

this.owner.unregister('component:listbox');
this.owner.register('component:listbox', ExtendedListbox);

await render(hbs`
<Listbox @onChange={{this.select}} @value={{this.selected}} as |listbox|>
<listbox.Button>Trigger</listbox.Button>
<listbox.Options as |options|>
{{#each this.items as |item|}}
<options.Option @value={{item}} as |option|>
{{item}}
</options.Option>
{{/each}}
</listbox.Options>
</Listbox>
`);

await click(getListboxButton());
let options = getListboxOptions();
await click(options[2]);

assert.strictEqual(callCount, 1, 'called exactly once');
});
});