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

feat(kit): Select add ability to use native select on mobile #2964

Merged
merged 4 commits into from
Oct 31, 2022
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
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
(tuiAutofilledChange)="onAutofilled($event)"
>
<ng-content select="input"></ng-content>
<ng-content select="select"></ng-content>
<input
#focusableElement
tuiMaskAccessor
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<form class="b-form">
<tui-select [formControl]="itemControl">
Character
<select
tuiSelect
[items]="items"
></select>
vladimirpotekhin marked this conversation as resolved.
Show resolved Hide resolved
</tui-select>

<tui-select
class="tui-space_top-4"
[formControl]="itemGroupControl"
[tuiTextfieldCleaner]="true"
>
Food
<select
tuiSelect
[items]="groupItems"
[labels]="labels"
nsbarsukov marked this conversation as resolved.
Show resolved Hide resolved
></select>

<input
tuiTextfield
placeholder="Make a choice"
/>
</tui-select>
</form>
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {Component} from '@angular/core';
import {FormControl} from '@angular/forms';
import {changeDetection} from '@demo/emulate/change-detection';
import {encapsulation} from '@demo/emulate/encapsulation';

@Component({
selector: `tui-select-example-11`,
templateUrl: `./index.html`,
changeDetection,
encapsulation,
})
export class TuiSelectExample11 {
itemControl = new FormControl();
itemGroupControl = new FormControl();

items = [
`Luke Skywalker`,
`Leia Organa Solo`,
`Darth Vader`,
`Han Solo`,
`Obi-Wan Kenobi`,
`Yoda`,
];

groupItems = [
[`Caesar`, `Greek`, `Apple and Chicken`],
[`Broccoli Cheddar`, `Chicken and Rice`, `Chicken Noodle`],
];

labels = [`Salad`, `Soup`];
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ export class ExampleTuiSelectComponent extends AbstractExampleTuiControl {
HTML: import(`./examples/10/index.html?raw`),
};

readonly example11: TuiDocExample = {
TypeScript: import(`./examples/11/index.ts?raw`),
HTML: import(`./examples/11/index.html?raw`),
};

readonly items = [new Account(`Ruble`, 500), new Account(`Dollar`, 237)];

readonly valueTemplateVariants = [``, `Template`];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {TuiSelectExample8} from './examples/8';
import {TuiSelectExample9} from './examples/9';
import {ExampleMyAccountComponent} from './examples/9/account/my-account.component';
import {TuiSelectExample10} from './examples/10';
import {TuiSelectExample11} from './examples/11';
import {ExampleTuiSelectComponent} from './select.component';

@NgModule({
Expand Down Expand Up @@ -91,6 +92,7 @@ import {ExampleTuiSelectComponent} from './select.component';
TuiSelectExample8,
TuiSelectExample9,
TuiSelectExample10,
TuiSelectExample11,
],
exports: [ExampleTuiSelectComponent],
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,21 @@
>
<tui-select-example-10></tui-select-example-10>
</tui-doc-example>

<tui-doc-example
id="native-select"
heading="Native select"
[content]="example11"
>
<tui-notification class="tui-space_bottom-4 b-form">
You can enable native select on mobile devices by putting
<code>select</code>
inside with
<code>tuiSelect</code>
directive as shown below
</tui-notification>
<tui-select-example-11></tui-select-example-11>
</tui-doc-example>
</ng-template>

<ng-template pageTab>
Expand Down
3 changes: 3 additions & 0 deletions projects/kit/components/select/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
export * from './native-select/native-select';
export * from './native-select/native-select.component';
export * from './native-select/native-select-group.component';
export * from './select.component';
export * from './select.directive';
export * from './select.module';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {ChangeDetectionStrategy, Component, Input, TemplateRef} from '@angular/core';
import {TuiDataListDirective} from '@taiga-ui/core';

import {AbstractTuiNativeSelect} from './native-select';

@Component({
selector: `select[tuiSelect][labels]`,
templateUrl: `./native-select-group.template.html`,
providers: [
{
provide: TuiDataListDirective,
deps: [TuiNativeSelectGroupComponent],
useExisting: TuiNativeSelectGroupComponent,
},
{
provide: TemplateRef,
deps: [TuiNativeSelectGroupComponent],
useFactory: ({datalist}: TuiNativeSelectGroupComponent) => datalist,
},
{
provide: AbstractTuiNativeSelect,
useExisting: TuiNativeSelectGroupComponent,
},
],
host: {
'[attr.aria-invalid]': `host.invalid`,
'[disabled]': `host.disabled`,
'[tabIndex]': `host.focusable ? 0 : -1`,
'[readOnly]': `host.readOnly`,
'[value]': `host.value`,
'(change)': `host.onValueChange($event.target.value)`,
},
styleUrls: [`./native-select.style.less`],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TuiNativeSelectGroupComponent extends AbstractTuiNativeSelect {
@Input()
items: readonly string[][] | null = [];

@Input()
labels: readonly string[] = [];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<tui-data-list-wrapper
*tuiDataList
[items]="items"
[labels]="labels"
></tui-data-list-wrapper>
<optgroup
*ngFor="let group of items; let index = index"
[label]="labels[index]"
>
<option
*ngFor="let option of group"
[value]="option"
>
{{ option }}
</option>
</optgroup>
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import {ChangeDetectionStrategy, Component, Input, TemplateRef} from '@angular/core';
import {TuiDataListDirective} from '@taiga-ui/core';

import {AbstractTuiNativeSelect} from './native-select';

@Component({
selector: `select[tuiSelect]:not([labels])`,
templateUrl: `./native-select.template.html`,
providers: [
{
provide: TuiDataListDirective,
deps: [TuiNativeSelectComponent],
useExisting: TuiNativeSelectComponent,
},
{
provide: TemplateRef,
deps: [TuiNativeSelectComponent],
useFactory: ({datalist}: TuiNativeSelectComponent) => datalist,
},
{
provide: AbstractTuiNativeSelect,
useExisting: TuiNativeSelectComponent,
},
],
host: {
'[attr.aria-invalid]': `host.invalid`,
'[disabled]': `host.disabled`,
'[tabIndex]': `host.focusable ? 0 : -1`,
'[readOnly]': `host.readOnly`,
'[value]': `host.value`,
'(change)': `host.onValueChange($event.target.value)`,
},
styleUrls: [`./native-select.style.less`],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TuiNativeSelectComponent extends AbstractTuiNativeSelect {
@Input()
items: readonly string[] | null = [];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@import 'taiga-ui-local';

:host {
.fullsize();
opacity: 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<tui-data-list-wrapper
*tuiDataList
[items]="items"
></tui-data-list-wrapper>
<option
*ngFor="let option of items"
[value]="option"
>
{{ option }}
</option>
30 changes: 30 additions & 0 deletions projects/kit/components/select/native-select/native-select.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import {
Directive,
ElementRef,
HostBinding,
Inject,
TemplateRef,
ViewChild,
} from '@angular/core';
import {TuiIdService} from '@taiga-ui/cdk';
import {TUI_TEXTFIELD_HOST, TuiDataListDirective, TuiTextfieldHost} from '@taiga-ui/core';

@Directive()
export abstract class AbstractTuiNativeSelect {
@ViewChild(TuiDataListDirective, {read: TemplateRef, static: true})
readonly datalist: TemplateRef<any> | null = null;

constructor(
@Inject(TUI_TEXTFIELD_HOST) readonly host: TuiTextfieldHost,
@Inject(ElementRef) private readonly elementRef: ElementRef<HTMLInputElement>,
@Inject(TuiIdService)
private readonly idService: TuiIdService,
) {
this.host.process(this.elementRef.nativeElement);
}

@HostBinding(`id`)
get id(): string {
return this.elementRef.nativeElement.id || this.idService.generate();
}
}
15 changes: 14 additions & 1 deletion projects/kit/components/select/select.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import {NgControl} from '@angular/forms';
import {
AbstractTuiNullableControl,
TUI_IS_MOBILE,
TuiActiveZoneDirective,
tuiAsControl,
tuiAsFocusableItemAccessor,
Expand Down Expand Up @@ -41,6 +42,7 @@ import {FIXED_DROPDOWN_CONTROLLER_PROVIDER} from '@taiga-ui/kit/providers';
import {TUI_ITEMS_HANDLERS, TuiItemsHandlers} from '@taiga-ui/kit/tokens';
import {PolymorpheusContent} from '@tinkoff/ng-polymorpheus';

import {AbstractTuiNativeSelect} from './native-select/native-select';
import {TUI_SELECT_OPTIONS, TuiSelectOptions} from './select-options';

@Component({
Expand All @@ -66,6 +68,9 @@ export class TuiSelectComponent<T>
@ViewChild(TuiHostedDropdownComponent)
private readonly hostedDropdown?: TuiHostedDropdownComponent;

@ContentChild(AbstractTuiNativeSelect, {static: true})
private readonly nativeSelect?: AbstractTuiNativeSelect;

@Input()
@tuiDefaultProp()
stringify: TuiItemsHandlers<T>['stringify'] = this.itemsHandlers.stringify;
Expand Down Expand Up @@ -98,6 +103,8 @@ export class TuiSelectComponent<T>
private readonly itemsHandlers: TuiItemsHandlers<T>,
@Inject(TUI_SELECT_OPTIONS)
private readonly options: TuiSelectOptions<T>,
@Inject(TUI_IS_MOBILE)
readonly isMobile: boolean,
) {
super(control, changeDetectorRef);
}
Expand All @@ -119,6 +126,10 @@ export class TuiSelectComponent<T>
);
}

get nativeDropdownMode(): boolean {
return !!this.nativeSelect && this.isMobile;
}

get computedValue(): string {
return this.value === null ? `` : this.stringify(this.value) || ` `;
}
Expand All @@ -127,9 +138,11 @@ export class TuiSelectComponent<T>
return this.valueContent || this.computedValue;
}

onValueChange(value: string): void {
onValueChange(value: T): void {
if (!value) {
this.updateValue(null);
} else {
this.updateValue(value || null);
}
}

Expand Down
21 changes: 19 additions & 2 deletions projects/kit/components/select/select.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@ import {CommonModule} from '@angular/common';
import {NgModule} from '@angular/core';
import {TuiActiveZoneModule} from '@taiga-ui/cdk';
import {
TuiDataListModule,
TuiHostedDropdownModule,
TuiPrimitiveTextfieldModule,
TuiTextfieldComponent,
TuiTextfieldControllerModule,
} from '@taiga-ui/core';
import {TuiArrowModule} from '@taiga-ui/kit/components/arrow';
import {TuiDataListWrapperModule} from '@taiga-ui/kit/components/data-list-wrapper';
import {TuiSelectOptionModule} from '@taiga-ui/kit/components/select-option';
import {PolymorpheusModule} from '@tinkoff/ng-polymorpheus';

import {TuiNativeSelectComponent} from './native-select/native-select.component';
import {TuiNativeSelectGroupComponent} from './native-select/native-select-group.component';
import {TuiSelectComponent} from './select.component';
import {TuiSelectDirective} from './select.directive';

Expand All @@ -24,8 +28,21 @@ import {TuiSelectDirective} from './select.directive';
TuiSelectOptionModule,
TuiArrowModule,
TuiTextfieldControllerModule,
TuiDataListWrapperModule,
TuiDataListModule,
],
declarations: [
TuiSelectComponent,
TuiSelectDirective,
TuiNativeSelectComponent,
TuiNativeSelectGroupComponent,
],
exports: [
TuiSelectComponent,
TuiSelectDirective,
TuiTextfieldComponent,
TuiNativeSelectComponent,
TuiNativeSelectGroupComponent,
],
declarations: [TuiSelectComponent, TuiSelectDirective],
exports: [TuiSelectComponent, TuiSelectDirective, TuiTextfieldComponent],
})
export class TuiSelectModule {}
Loading