Skip to content

Commit

Permalink
feat(suggest): use CDK Layout to display the dropdown
Browse files Browse the repository at this point in the history
  • Loading branch information
ZoicanDenisUi authored and sergiubologa committed Mar 16, 2023
1 parent a04667d commit 06f5bbf
Show file tree
Hide file tree
Showing 13 changed files with 543 additions and 417 deletions.
28 changes: 14 additions & 14 deletions projects/angular/components/ui-suggest/src/_ui-suggest.theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,25 @@
}
}

#{$componentName} {
.item-list-container {
background-color: map-get($background, "dialog");
.mat-list {
&-item {
&.selected {
background-color: map-get($background, "disabled-button");
}
.ui-suggest-dropdown-item-list-container {
background-color: map-get($background, "dialog");
.mat-list {
&-item {
&.selected {
background-color: map-get($background, "disabled-button");
}

&.selected.active,
&.active,
&:hover,
&.selected:hover {
background-color: map-get($background, "hover");
}
&.selected.active,
&.active,
&:hover,
&.selected:hover {
background-color: map-get($background, "hover");
}
}
}
}

#{$componentName} {
.display {
mat-icon {
color: inherit;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/**
* Dropdown direction type definition.
*
* default: 'down'
*
* @export
*/
export type SuggestDirection = 'up' | 'down';
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,9 @@ export class UiSuggestAssert {
expect(combo).toHaveAttr('aria-expanded', expectedIsOpen.toString());
}

const itemList = this._root.query(By.css('.item-list-container'));
const itemListClasses = itemList.nativeElement.classList;
expect(itemListClasses.contains('item-list-container-state-open')).toBe(expectedIsOpen);
expect(itemListClasses.contains('item-list-container-state-closed')).toBe(!expectedIsOpen);
const dropdownOverlay = document.querySelector('.cdk-overlay-container');
const itemList = dropdownOverlay?.querySelector('.ui-suggest-dropdown-item-list-container');
expect(!!itemList).toBe(expectedIsOpen);
}

private _assertDisableState(expected: 'enabled' | 'disabled'): void {
Expand Down
31 changes: 18 additions & 13 deletions projects/angular/components/ui-suggest/src/ui-suggest.animations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,23 @@ export const UI_SUGGEST_ANIMATIONS: {
readonly transformMenuList: AnimationTriggerMetadata;
} = {
transformMenuList: trigger('displayState', [
state('closed', style({
opacity: 0,
transform: 'scale(0.8)',
})),
transition('closed => open', group([
animate('100ms linear', style({
opacity: 1,
})),
animate('120ms cubic-bezier(0, 0, 0.2, 1)', style({
transform: 'scale(1)',
})),
])),
transition('* => closed', animate('100ms 25ms linear', style({ opacity: 0 }))),
state(
'void',
style({
opacity: 0,
transform: 'scale(0.8)',
}),
),
transition(
'void => open',
group([
animate('100ms linear', style({
opacity: 1,
})),
animate('120ms cubic-bezier(0, 0, 0.2, 1)', style({
transform: 'scale(1)',
})),
]),
),
]),
};
192 changes: 101 additions & 91 deletions projects/angular/components/ui-suggest/src/ui-suggest.component.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<div *ngLet="focus$ | async as focus"
(uiClickOutside)="focused && close(false)"
[style.height]="expandInline ? '100%' : undefined"
#optionsDropdownTrigger="cdkOverlayOrigin"
#suggestContainer
cdkOverlayOrigin
class="ui-suggest-container"
role="application">
<!--
Expand Down Expand Up @@ -138,106 +140,114 @@
</ng-template>
</ng-container>

<ng-container *ngIf="!expandInline; else optionsDropdown">
<ng-template cdkConnectedOverlay
cdkConnectedOverlayBackdropClass="cdk-overlay-transparent-backdrop"
[cdkConnectedOverlayOrigin]="optionsDropdownTrigger"
[cdkConnectedOverlayPositions]="dropdownPosition"
[cdkConnectedOverlayHasBackdrop]="true"
[cdkConnectedOverlayOpen]="isOpen"
(backdropClick)="close(false)">
<ng-container *ngTemplateOutlet="optionsDropdown">
</ng-container>
</ng-template>
</ng-container>

<div class="item-list-container-wrapper"
[class.multi-select]="multiple && !expandInline"
[style.height]="expandInline ? '100%' : undefined">
<div [style.width]="isFormControl ? null : width"
[style.height]="expandInline ? '100%' : undefined"
[class.item-list-container-state-open]="isOpen"
[class.item-list-container-state-closed]="!isOpen"
[class.item-list-container-direction-down]="isDown"
[class.item-list-container-direction-up]="!isDown"
[class.item-list-container-expanded-inline]="expandInline"
[class.searchable]="searchable && !multiple"
[class.mat-elevation-z4]="!expandInline"
[uiAutofocus]="!searchable && !multiple"
[refocus]="isOpen && !multiple"
[@displayState]="isOpen ? 'open' : 'closed'"
(keydown.arrowup)="navigate(-1, $event)"
(keydown.arrowdown)="navigate(1, $event)"
(keyup.enter)="preventDefault($event);"
(keydown.enter)="preventDefault($event);
setSelectedItem();"
(keydown.esc)="preventDefault($event)"
(keyup.esc)="preventDefault($event);
close();"
(keydown.tab)="close(false)"
(keydown.shift.tab)="close()"
tabindex="-1"
class="item-list-container">
<ng-container *ngIf="!isDown">
<ng-container *ngTemplateOutlet="searchableCountInfoTmpl"></ng-container>
</div>

<ng-container *ngTemplateOutlet="resultList">
</ng-container>
<ng-template #optionsDropdown>
<div [class.is-form-control]="isFormControl"
[style.width]="isFormControl ? (this.suggestContainerWidth+1)+'px' : width"
[style.height]="expandInline ? '100%' : undefined"
[class.ui-suggest-dropdown-item-list-container-expanded-inline]="expandInline"
[class.searchable]="searchable && !multiple"
[class.mat-elevation-z4]="!expandInline"
[uiAutofocus]="!searchable && !multiple"
[refocus]="isOpen && !multiple"
[@displayState]="'open'"
(keydown.arrowup)="navigate(-1, $event)"
(keydown.arrowdown)="navigate(1, $event)"
(keyup.enter)="preventDefault($event);"
(keydown.enter)="preventDefault($event);
setSelectedItem();"
(keydown.esc)="preventDefault($event)"
(keyup.esc)="preventDefault($event);
close();"
(keydown.tab)="close(false)"
(keydown.shift.tab)="close()"
tabindex="-1"
class="ui-suggest-dropdown-item-list-container">
<ng-container *ngIf="!isDown">
<ng-container *ngTemplateOutlet="searchableCountInfoTmpl"></ng-container>

<ng-container *ngTemplateOutlet="resultList">
</ng-container>
</ng-container>

<mat-form-field *ngIf="searchable && (!multiple || compact)"
floatLabel="never">
<input #searchInput
[placeholder]="isFormControl ? '' : placeholder"
[formControl]="inputControl"
[uiAutofocus]="isOpen &&
searchable"
[attr.maxlength]="maxLength"
[refocus]="isOpen"
selectionLocation="end"
autocomplete="off"
aria-autocomplete="list"
matInput>
<mat-form-field *ngIf="searchable && (!multiple || compact)"
floatLabel="never">
<input #searchInput
[placeholder]="isFormControl ? '' : placeholder"
[formControl]="inputControl"
[uiAutofocus]="isOpen &&
searchable"
[attr.maxlength]="maxLength"
[refocus]="isOpen"
selectionLocation="end"
autocomplete="off"
aria-autocomplete="list"
matInput>

<mat-icon *ngIf="inDrillDownMode"
[matTooltip]="intl.clearSelectionLabel"
(keydown.space)="removeSelection($event)"
(keydown.enter)="removeSelection($event)"
(click)="removeSelection($event)"
matSuffix
tabindex="0"
role="button"
aria-hidden="false"
class="clear">
<svg width="100%"
height="100%"
viewBox="0 0 20 20"
style="color:currentColor;fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.5;">
<path d="M6.505 13.498l7-7M13.505 13.5l-7-7"
fill="none"
stroke="currentColor"
stroke-width="2.0011213" />
</svg>
</mat-icon>
<mat-icon *ngIf="inDrillDownMode"
[matTooltip]="intl.clearSelectionLabel"
(keydown.space)="removeSelection($event)"
(keydown.enter)="removeSelection($event)"
(click)="removeSelection($event)"
matSuffix
tabindex="0"
role="button"
aria-hidden="false"
class="clear">
<svg width="100%"
height="100%"
viewBox="0 0 20 20"
style="color:currentColor;fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.5;">
<path d="M6.505 13.498l7-7M13.505 13.5l-7-7"
fill="none"
stroke="currentColor"
stroke-width="2.0011213" />
</svg>
</mat-icon>

<mat-icon *ngIf="!drillDown || !searchInput.value"
matSuffix>search</mat-icon>
</mat-form-field>
<mat-icon *ngIf="!drillDown || !searchInput.value"
matSuffix>search</mat-icon>
</mat-form-field>

<ng-container *ngIf="isDown">
<ng-container *ngTemplateOutlet="resultList">
</ng-container>

<ng-container *ngTemplateOutlet="searchableCountInfoTmpl"></ng-container>
<ng-container *ngIf="isDown">
<ng-container *ngTemplateOutlet="resultList">
</ng-container>

<ng-template #searchableCountInfoTmpl>
<mat-list-item *ngIf="items.length &&
(loading$ | async) === false &&
searchableCountInfo?.count === items.length &&
searchable &&
!inputControl.value"
[matTooltip]="searchableCountInfo?.message ?? ''"
[attr.role]="'option'"
matTooltipPosition="right"
class="text-ellipsis item-max-count-info-message">
<mat-divider *ngIf="isDown"></mat-divider>
<mat-icon>info_outline</mat-icon>
<span>{{searchableCountInfo?.message}}</span>
<mat-divider *ngIf="!isDown"></mat-divider>
</mat-list-item>
</ng-template>
</div>
<ng-container *ngTemplateOutlet="searchableCountInfoTmpl"></ng-container>
</ng-container>

<ng-template #searchableCountInfoTmpl>
<mat-list-item *ngIf="items.length &&
(loading$ | async) === false &&
searchableCountInfo?.count === items.length &&
searchable &&
!inputControl.value"
[matTooltip]="searchableCountInfo?.message ?? ''"
[attr.role]="'option'"
matTooltipPosition="right"
class="text-ellipsis item-max-count-info-message">
<mat-divider *ngIf="isDown"></mat-divider>
<mat-icon>info_outline</mat-icon>
<span>{{searchableCountInfo?.message}}</span>
<mat-divider *ngIf="!isDown"></mat-divider>
</mat-list-item>
</ng-template>
</div>
</div>
</ng-template>

<ng-template #resultList>
<mat-list [attr.role]="'listbox'"
Expand Down
Loading

0 comments on commit 06f5bbf

Please sign in to comment.