forked from EVOgeek/Vmeda.Online
		
	MOBILE-3947 combobox: Improve combobox
This commit is contained in:
		
							parent
							
								
									0975669042
								
							
						
					
					
						commit
						ab16380626
					
				| @ -71,7 +71,7 @@ | |||||||
|         </ion-col> |         </ion-col> | ||||||
|         <ion-col size="auto" *ngIf="sort.enabled"> |         <ion-col size="auto" *ngIf="sort.enabled"> | ||||||
|             <core-combobox [label]="'core.sortby' | translate" [selection]="sort.selected" (onChange)="sortCourses($event)" |             <core-combobox [label]="'core.sortby' | translate" [selection]="sort.selected" (onChange)="sortCourses($event)" | ||||||
|                 icon="fas-arrow-down-short-wide"> |                 icon="fas-arrow-down-short-wide" class="no-border"> | ||||||
|                 <ion-select-option class="ion-text-wrap" value="fullname"> |                 <ion-select-option class="ion-text-wrap" value="fullname"> | ||||||
|                     {{'addon.block_myoverview.title' | translate}} |                     {{'addon.block_myoverview.title' | translate}} | ||||||
|                 </ion-select-option> |                 </ion-select-option> | ||||||
|  | |||||||
| @ -10,24 +10,19 @@ | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         ion-button, |         ion-button, | ||||||
|         core-combobox ::ng-deep ion-button { |         core-combobox ::ng-deep ion-select { | ||||||
|             --border-width: 0; |  | ||||||
|             --a11y-min-target-size: 40px; |             --a11y-min-target-size: 40px; | ||||||
|             margin: 0; |             margin: 0; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         ion-button { | ||||||
|  |             --border-width: 0; | ||||||
| 
 | 
 | ||||||
|             .select-icon { |  | ||||||
|                 display: none; |  | ||||||
|             } |  | ||||||
|             ion-icon { |             ion-icon { | ||||||
|                 font-size: 20px; |                 font-size: 20px; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         core-combobox ::ng-deep ion-select { |  | ||||||
|             margin: 0; |  | ||||||
|             --a11y-min-target-size: 40px; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         ion-searchbar { |         ion-searchbar { | ||||||
|             padding: 0; |             padding: 0; | ||||||
|             --height: 40px; |             --height: 40px; | ||||||
|  | |||||||
| @ -36,7 +36,7 @@ | |||||||
|         </ion-col> |         </ion-col> | ||||||
|         <ion-col size="auto"> |         <ion-col size="auto"> | ||||||
|             <core-combobox [label]="'core.sortby' | translate" [formControl]="sort" (onChange)="sortChanged($event)" |             <core-combobox [label]="'core.sortby' | translate" [formControl]="sort" (onChange)="sortChanged($event)" | ||||||
|                 icon="fas-arrow-down-short-wide"> |                 icon="fas-arrow-down-short-wide" class="no-border"> | ||||||
|                 <ion-select-option *ngFor="let option of sortOptions" class="ion-text-wrap" [value]="option.value"> |                 <ion-select-option *ngFor="let option of sortOptions" class="ion-text-wrap" [value]="option.value"> | ||||||
|                     {{ option.name | translate }} |                     {{ option.name | translate }} | ||||||
|                 </ion-select-option> |                 </ion-select-option> | ||||||
|  | |||||||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB | 
| @ -5,30 +5,94 @@ | |||||||
|     display: block; |     display: block; | ||||||
|     @include margin-horizontal(var(--ion-safe-area-left), var(--ion-safe-area-right)); |     @include margin-horizontal(var(--ion-safe-area-left), var(--ion-safe-area-right)); | ||||||
| 
 | 
 | ||||||
|  |     &.no-border { | ||||||
|  |         --core-combobox-border-width: 0px; | ||||||
|  | 
 | ||||||
|  |         ion-select.combobox-icon-only { | ||||||
|  |             --padding-start: 8px; | ||||||
|  | 
 | ||||||
|  |             &::part(icon) { | ||||||
|  |                 display: none; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             &::part(label) { | ||||||
|  |                 position: static; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             ion-icon { | ||||||
|  |                 margin: var(--icon-margin); | ||||||
|  |                 font-size: 20px; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|     ion-select, |     ion-select, | ||||||
|     ion-button { |     ion-button { | ||||||
|         --icon-margin: 0 4px; |         --icon-margin: 0 4px; | ||||||
|         --background: var(--core-combobox-background); |  | ||||||
|         --background-hover: black; |  | ||||||
|         --background-activated: black; |  | ||||||
|         --background-focused: black; |  | ||||||
|         --background-hover-opacity: .04; |  | ||||||
| 
 | 
 | ||||||
|  |         --background: var(--core-combobox-background); | ||||||
|  | 
 | ||||||
|  |         --border-color: var(--core-combobox-border-color); | ||||||
|  |         --border-style: solid; | ||||||
|  |         --border-width: var(--core-combobox-border-width); | ||||||
|  |         --border-radius: var(--core-combobox-radius); | ||||||
|  | 
 | ||||||
|  |         --box-shadow: var(--core-combobox-box-shadow); | ||||||
|  | 
 | ||||||
|  |         --padding-start: 16px; | ||||||
|  |         --padding-end: 8px; | ||||||
|  |         --padding-top: 8px; | ||||||
|  |         --padding-bottom: 8px; | ||||||
|  | 
 | ||||||
|  |         background: var(--background); | ||||||
|  |         color: var(--color); | ||||||
|  |         text-overflow: ellipsis; | ||||||
|  |         white-space: nowrap; | ||||||
|  |         min-height: var(--a11y-min-target-size); | ||||||
|  |         overflow: hidden; | ||||||
|  |         box-shadow: var(--box-shadow); | ||||||
|  | 
 | ||||||
|  |         &:focus, | ||||||
|  |         &:focus-within { | ||||||
|  |             @include core-focus-style(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ion-select { | ||||||
|  |         border-color: var(--border-color); | ||||||
|  |         border-style: var(--border-style); | ||||||
|  |         border-width: var(--border-width); | ||||||
|  |         border-radius: var(--core-combobox-radius); | ||||||
|  |         margin: 8px; | ||||||
|  | 
 | ||||||
|  |         &.combobox-icon-only { | ||||||
|  |             &::part(text) { | ||||||
|  |                 display: none; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         &::part(label) { | ||||||
|  |             position: absolute; | ||||||
|  |             margin-inline: 0px; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         &::part(icon) { | ||||||
|  |             margin: var(--icon-margin); | ||||||
|  |             opacity: 1; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ion-button { | ||||||
|         --color: var(--core-combobox-color); |         --color: var(--core-combobox-color); | ||||||
|         --color-activated: var(--core-combobox-color); |         --color-activated: var(--core-combobox-color); | ||||||
|         --color-focused: currentcolor; |         --color-focused: currentcolor; | ||||||
|         --color-hover: currentcolor; |         --color-hover: currentcolor; | ||||||
| 
 | 
 | ||||||
|         --border-color: var(--core-combobox-border-color); |         --background-hover: black; | ||||||
|         --border-style: solid; |         --background-activated: black; | ||||||
|         --border-width: var(--core-combobox-border-width); |         --background-focused: black; | ||||||
|         --border-radius: var(--radius-xs); |         --background-hover-opacity: .04; | ||||||
| 
 |  | ||||||
|         --box-shadow: var(--core-combobox-box-shadow); |  | ||||||
| 
 |  | ||||||
|         --padding-top: 8px; |  | ||||||
|         --padding-end: 8px; |  | ||||||
|         --padding-bottom: 8px; |  | ||||||
| 
 | 
 | ||||||
|         &.md { |         &.md { | ||||||
|             --background-activated-opacity: 0; |             --background-activated-opacity: 0; | ||||||
| @ -39,97 +103,36 @@ | |||||||
|             --background-activated-opacity: .12; |             --background-activated-opacity: .12; | ||||||
|             --background-focused-opacity: .15; |             --background-focused-opacity: .15; | ||||||
|         } |         } | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     ion-button { |  | ||||||
|         --padding-start: 8px; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     ion-select { |  | ||||||
|         --padding-start: 16px; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| ion-select, |  | ||||||
| ion-button { |  | ||||||
|     background: var(--background); |  | ||||||
|     color: var(--color); |  | ||||||
|     text-overflow: ellipsis; |  | ||||||
|     white-space: nowrap; |  | ||||||
|     min-height: var(--a11y-min-target-size); |  | ||||||
|     overflow: hidden; |  | ||||||
|     box-shadow: var(--box-shadow); |  | ||||||
| 
 |  | ||||||
|     &:focus, |  | ||||||
|     &:focus-within { |  | ||||||
|         @include core-focus-style(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| ion-select { |  | ||||||
|     border-color: var(--border-color); |  | ||||||
|     border-style: var(--border-style); |  | ||||||
|     border-width: var(--border-width); |  | ||||||
|     border-radius: var(--core-combobox-radius); |  | ||||||
|     margin: 8px; |  | ||||||
| 
 |  | ||||||
|     &::part(icon) { |  | ||||||
|         margin: var(--icon-margin); |  | ||||||
|         opacity: 1; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     &::after { |  | ||||||
|         @include button-state(); |  | ||||||
|         transition: var(--transition); |  | ||||||
|         z-index: -1; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     &:hover::after { |  | ||||||
|         color: var(--color-hover); |  | ||||||
|         background: var(--background-hover); |  | ||||||
|         opacity: var(--background-hover-opacity); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     &:focus::after, |  | ||||||
|     &:focus-within::after { |  | ||||||
|         color: var(--color-focused); |  | ||||||
|         background: var(--background-focused); |  | ||||||
|         opacity: var(--background-focused-opacity); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     &[hidden] { |  | ||||||
|         display: none !important; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| ion-button { |  | ||||||
|     border-radius: var(--core-combobox-radius); |  | ||||||
|     margin: 4px 8px; |  | ||||||
| 
 |  | ||||||
|     flex: 1; |  | ||||||
| 
 |  | ||||||
|     &::part(native) { |  | ||||||
|         text-transform: none; |  | ||||||
|         font-weight: 400; |  | ||||||
|         font-size: 16px; |  | ||||||
|         line-height: 20px; |  | ||||||
|         border-radius: var(--core-combobox-radius); |         border-radius: var(--core-combobox-radius); | ||||||
|  |         margin: 4px 8px; | ||||||
|  | 
 | ||||||
|  |         flex: 1; | ||||||
|  | 
 | ||||||
|  |         &::part(native) { | ||||||
|  |             text-transform: none; | ||||||
|  |             font-weight: 400; | ||||||
|  |             font-size: 16px; | ||||||
|  |             line-height: 20px; | ||||||
|  |             border-radius: var(--core-combobox-radius); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .select-text { | ||||||
|  |             @include margin-horizontal(null, auto); | ||||||
|  |             overflow: hidden; | ||||||
|  |             text-overflow: ellipsis; | ||||||
|  |         } | ||||||
|  |         .sr-only { | ||||||
|  |             @include sr-only(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         &.ion-activated { | ||||||
|  |             --color: var(--color-activated); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         ion-icon { | ||||||
|  |             margin: var(--icon-margin); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     .select-text { |  | ||||||
|         @include margin-horizontal(null, auto); |  | ||||||
|         overflow: hidden; |  | ||||||
|         text-overflow: ellipsis; |  | ||||||
|     } |  | ||||||
|     .sr-only { |  | ||||||
|         @include sr-only(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     &.ion-activated { |  | ||||||
|         --color: var(--color-activated); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     ion-icon { |  | ||||||
|         margin: var(--icon-margin); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -12,11 +12,10 @@ | |||||||
| // See the License for the specific language governing permissions and
 | // See the License for the specific language governing permissions and
 | ||||||
| // limitations under the License.
 | // limitations under the License.
 | ||||||
| 
 | 
 | ||||||
| import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core'; | import { Component, EventEmitter, Input, Output } from '@angular/core'; | ||||||
| import { Translate } from '@singletons'; | import { Translate } from '@singletons'; | ||||||
| import { ModalOptions } from '@ionic/core'; | import { ModalOptions } from '@ionic/core'; | ||||||
| import { CoreDomUtils } from '@services/utils/dom'; | import { CoreDomUtils } from '@services/utils/dom'; | ||||||
| import { IonSelect } from '@ionic/angular'; |  | ||||||
| import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; | import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @ -51,8 +50,6 @@ import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; | |||||||
| }) | }) | ||||||
| export class CoreComboboxComponent implements ControlValueAccessor { | export class CoreComboboxComponent implements ControlValueAccessor { | ||||||
| 
 | 
 | ||||||
|     @ViewChild(IonSelect) select?: IonSelect; |  | ||||||
| 
 |  | ||||||
|     @Input() interface: 'popover' | 'modal' = 'popover'; |     @Input() interface: 'popover' | 'modal' = 'popover'; | ||||||
|     @Input() label = Translate.instant('core.show'); // Aria label.
 |     @Input() label = Translate.instant('core.show'); // Aria label.
 | ||||||
|     @Input() disabled = false; |     @Input() disabled = false; | ||||||
| @ -112,30 +109,25 @@ export class CoreComboboxComponent implements ControlValueAccessor { | |||||||
|     /** |     /** | ||||||
|      * Shows combobox modal. |      * Shows combobox modal. | ||||||
|      * |      * | ||||||
|      * @param event Event. |  | ||||||
|      * @returns Promise resolved when done. |      * @returns Promise resolved when done. | ||||||
|      */ |      */ | ||||||
|     async openSelect(event?: UIEvent): Promise<void> { |     async openModal(): Promise<void> { | ||||||
|         this.touch(); |         this.touch(); | ||||||
| 
 | 
 | ||||||
|         if (this.interface === 'modal') { |         if (this.expanded || !this.modalOptions) { | ||||||
|             if (this.expanded || !this.modalOptions) { |             return; | ||||||
|                 return; |         } | ||||||
|             } |         this.expanded = true; | ||||||
|             this.expanded = true; |  | ||||||
| 
 | 
 | ||||||
|             if (this.listboxId) { |         if (this.listboxId) { | ||||||
|                 this.modalOptions.id = this.listboxId; |             this.modalOptions.id = this.listboxId; | ||||||
|             } |         } | ||||||
| 
 | 
 | ||||||
|             const data = await CoreDomUtils.openModal(this.modalOptions); |         const data = await CoreDomUtils.openModal(this.modalOptions); | ||||||
|             this.expanded = false; |         this.expanded = false; | ||||||
| 
 | 
 | ||||||
|             if (data) { |         if (data) { | ||||||
|                 this.onValueChanged(data); |             this.onValueChanged(data); | ||||||
|             } |  | ||||||
|         } else if (this.select) { |  | ||||||
|             this.select.open(event); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,18 +1,17 @@ | |||||||
| <ion-button (click)="openSelect($event)" *ngIf="interface !== 'modal' && icon" [disabled]="disabled"> |  | ||||||
|     <ion-icon [name]="icon" [attr.aria-label]="label" slot="start" /> |  | ||||||
|     <div class="select-icon" role="presentation" aria-hidden="true"> |  | ||||||
|         <div class="select-icon-inner"></div> |  | ||||||
|     </div> |  | ||||||
| </ion-button> |  | ||||||
| <ion-select *ngIf="interface !== 'modal'" class="ion-text-start" [(ngModel)]="selection" (ngModelChange)="onValueChanged(selection)" | <ion-select *ngIf="interface !== 'modal'" class="ion-text-start" [(ngModel)]="selection" (ngModelChange)="onValueChanged(selection)" | ||||||
|     [interface]="interface" [attr.aria-label]="label" [disabled]="disabled" [hidden]="!!icon"> |     [interface]="interface" [disabled]="disabled" [class.combobox-icon-only]="icon" [interfaceOptions]="{alignment: 'start', arrow: false}"> | ||||||
|  |     <div slot="label"> | ||||||
|  |         <span class="sr-only" *ngIf="label">{{ label }}</span> | ||||||
|  |         <ion-icon *ngIf="icon" [name]="icon" aria-hidden="true" /> | ||||||
|  |     </div> | ||||||
|  | 
 | ||||||
|     <ng-content></ng-content> |     <ng-content></ng-content> | ||||||
| </ion-select> | </ion-select> | ||||||
| 
 | 
 | ||||||
| <ion-button *ngIf="interface === 'modal'" aria-haspopup="listbox" [attr.aria-controls]="listboxId" [attr.aria-owns]="listboxId" | <ion-button *ngIf="interface === 'modal'" aria-haspopup="listbox" [attr.aria-controls]="listboxId" [attr.aria-owns]="listboxId" | ||||||
|     [attr.aria-expanded]="expanded" (click)="openSelect()" [disabled]="disabled" expand="block" role="combobox"> |     [attr.aria-expanded]="expanded" (click)="openModal()" [disabled]="disabled" expand="block" role="combobox"> | ||||||
|     <ion-icon *ngIf="icon" [name]="icon" slot="start" aria-hidden="true" /> |     <ion-icon *ngIf="icon" [name]="icon" slot="start" aria-hidden="true" /> | ||||||
|     <span class="sr-only" *ngIf="label">{{ label }}:</span> |     <span class="sr-only" *ngIf="label">{{ label }},</span> | ||||||
|     <div class="select-text"> |     <div class="select-text"> | ||||||
|         <slot name="text">{{selection}}</slot> |         <slot name="text">{{selection}}</slot> | ||||||
|     </div> |     </div> | ||||||
|  | |||||||
| @ -1027,7 +1027,6 @@ input[type=radio], | |||||||
|     --border-width: 2px; |     --border-width: 2px; | ||||||
|     --outer-border-width: 2px; |     --outer-border-width: 2px; | ||||||
|     --border-style: solid; |     --border-style: solid; | ||||||
|     --inner-border-radius: 50%; |  | ||||||
|     --size: 20px; |     --size: 20px; | ||||||
| 
 | 
 | ||||||
|     &:not(.ion-color) { |     &:not(.ion-color) { | ||||||
| @ -1045,10 +1044,10 @@ input[type=radio], | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .ios ion-radio { | .ios ion-radio { | ||||||
|     width: var(--size); |  | ||||||
|     height: var(--size); |  | ||||||
| 
 |  | ||||||
|     &::part(container) { |     &::part(container) { | ||||||
|  |         width: var(--size); | ||||||
|  |         height: var(--size); | ||||||
|  | 
 | ||||||
|         margin: 0px; |         margin: 0px; | ||||||
|         border-radius: var(--border-radius); |         border-radius: var(--border-radius); | ||||||
|         border-width: var(--outer-border-width); |         border-width: var(--outer-border-width); | ||||||
| @ -1155,6 +1154,13 @@ ion-select { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ion-select-popover { | ion-select-popover { | ||||||
|  |     ion-list ion-radio-group ion-item.select-interface-option ion-radio.hydrated::part(container) { | ||||||
|  |         opacity: 1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ion-item { | ||||||
|  |         font-size: 14px; | ||||||
|  |     } | ||||||
|     ion-item.core-select-option-border-bottom { |     ion-item.core-select-option-border-bottom { | ||||||
|         border-bottom: 1px solid var(--stroke); |         border-bottom: 1px solid var(--stroke); | ||||||
|     } |     } | ||||||
| @ -1645,6 +1651,7 @@ ion-item.item { | |||||||
| // Change default outline. | // Change default outline. | ||||||
| :focus-visible { | :focus-visible { | ||||||
|     @include core-focus-style(); |     @include core-focus-style(); | ||||||
|  |     border-radius: inherit; | ||||||
|     outline: none; |     outline: none; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user