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

Autocomplete: Add position prop #2846

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,12 @@
margin: 0;
padding: 0;
position: absolute;
width: 100%;
width: auto;

&[data-popper-reference-hidden] {
pointer-events: none;
visibility: hidden;
}

.icon-check {
display: inline-flex;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe('modus-autocomplete', () => {
<modus-text-input aria-autocomplete="list" aria-controls="${listId}" class="input" role="combobox" autocomplete="off" size="medium" type="search" value=""></modus-text-input>
</div>
<div class="error"></div>
<div class="options-container" style="max-height: 300px; z-index: 1; overflow-y: auto;">
<div class="options-container" part="options-container" style="max-height: 300px; z-index: 1; overflow-y: auto; position: absolute; left: 0; top: 0; margin: 0;">
<ul aria-label="options" id="${listId}" role="listbox"></ul>
</div>
<div style="display: none;">
Expand Down Expand Up @@ -57,7 +57,7 @@ describe('modus-autocomplete', () => {
<modus-text-input aria-autocomplete="list" aria-controls="${listId}" class="input" role="combobox" autocomplete="off" size="medium" type="search" value=""></modus-text-input>
</div>
<div class="error"></div>
<div class="options-container" style="max-height: 300px; z-index: 1; overflow-y: auto;">
<div class="options-container" part="options-container" style="max-height: 300px; z-index: 1; overflow-y: auto; position: absolute; left: 0; top: 0; margin: 0;">
<ul aria-label="options" id="${listId}" role="listbox"></ul>
</div>
<div style="display: none;">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
import { IconSearch } from '../../icons/svgs/icon-search';
import { generateElementId } from '../../utils/utils';
import { IconCheck } from '../../icons/generated-icons/IconCheck';
import { createPopper, Instance, Placement } from '@popperjs/core';

export interface ModusAutocompleteOption {
id: string;
Expand Down Expand Up @@ -74,6 +75,9 @@ export class ModusAutocomplete {
/** A promise that returns the filtered options. */
@Prop() filterOptions: (search: string) => Promise<ModusAutocompleteOption[] | string[]>;

/** (optional) The placement of the options */
@Prop() position: Placement = 'bottom-start';

/** An array to hold the selected chips. */
@State() selectedChips: ModusAutocompleteOption[] = [];

Expand All @@ -86,6 +90,8 @@ export class ModusAutocomplete {
/** Whether to show autocomplete's options when focus. */
@Prop() showOptionsOnFocus: boolean;

private popperInstance: Instance;

@Watch('options')
watchOptions() {
this.convertOptions();
Expand Down Expand Up @@ -138,6 +144,42 @@ export class ModusAutocomplete {
@State() ShowItemsOnKeyDown = false;
private listId = generateElementId() + '_list';

componentDidLoad(): void {
this.convertOptions();
if (this.multiple) {
this.initializeSelectedChips();
}
this.initializePopper();
}

disconnectedCallback(): void {
if (this.popperInstance) {
this.popperInstance.destroy();
}
}

initializePopper(): void {
const optionsContainer = this.el.shadowRoot.querySelector(`.options-container`) as HTMLElement;
const referenceElement = this.el.shadowRoot.querySelector(`.chips-container`) as HTMLElement;

this.popperInstance = createPopper(referenceElement, optionsContainer, {
placement: 'bottom-start',
strategy: this.position === 'auto' ? 'fixed' : 'absolute',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add a comment about why we use fixed strategy for auto position

Copy link
Collaborator

@prashanth-offcl prashanth-offcl Sep 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also if I set position to auto, options container width is not restricted to the input width.
image

modifiers: [
{
name: 'offset',
options: {
offset: [0, 2],
},
},
],
});

if (referenceElement && optionsContainer) {
optionsContainer.style.width = `${referenceElement.offsetWidth}px`;
}
}

componentWillLoad(): void {
this.convertOptions();
if (this.multiple) {
Expand Down Expand Up @@ -477,7 +519,7 @@ export class ModusAutocomplete {
const selectedOption = optionList.querySelector('li.selected') as HTMLElement;

if (selectedOption) {
selectedOption.scrollIntoView({ behavior: 'smooth', inline: 'nearest' });
selectedOption.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
};

Expand Down Expand Up @@ -527,6 +569,7 @@ export class ModusAutocomplete {
<div class={'error'}>{this.errorText ? <label class="sub-text error">{this.errorText}</label> : null}</div>
<div
class="options-container"
part="options-container"
style={{ maxHeight: this.dropdownMaxHeight, zIndex: this.dropdownZIndex, overflowY: 'auto' }}>
<ul id={this.listId} aria-label="options" role="listbox">
{this.displayOptions() &&
Expand Down
Loading
Loading