-
Notifications
You must be signed in to change notification settings - Fork 467
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(cdk): refactor autofill directive
- Loading branch information
Showing
16 changed files
with
289 additions
and
94 deletions.
There are no files selected for viewing
46 changes: 46 additions & 0 deletions
46
projects/cdk/components/autofilled/autofilled.component.less
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
@keyframes tuiAutofillStart { | ||
from { | ||
} | ||
} | ||
|
||
@keyframes tuiAutofillCancel { | ||
from { | ||
} | ||
} | ||
|
||
.tui-autofill { | ||
&, | ||
input { | ||
// @note: need for listen (transitionstart) event | ||
// don't use more than one listener property | ||
transition: box-shadow 0.01s; | ||
|
||
&:-webkit-autofill, | ||
&:-webkit-autofill:hover, | ||
&:-webkit-autofill:focus { | ||
animation-duration: 0.01s; | ||
animation-name: tuiAutofillStart; | ||
|
||
border-radius: inherit; | ||
border-color: var(--tui-autofill); // @note: fix problem with border colors in safari, firefox | ||
|
||
-webkit-text-fill-color: inherit !important; | ||
color: inherit !important; | ||
background-color: var(--tui-autofill) !important; | ||
|
||
-webkit-box-shadow: 0 0 0 62.5rem var(--tui-autofill) inset !important; // to overlay native background | ||
} | ||
|
||
&:not(:-webkit-autofill) { | ||
animation-duration: 0.01s; | ||
animation-name: tuiAutofillCancel; | ||
} | ||
|
||
//noinspection CssInvalidPseudoSelector | ||
&::-webkit-credit-card-auto-fill-button { | ||
pointer-events: none; | ||
background-color: transparent !important; | ||
-webkit-mask-image: none !important; | ||
} | ||
} | ||
} |
63 changes: 63 additions & 0 deletions
63
projects/cdk/components/autofilled/autofilled.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { | ||
ChangeDetectionStrategy, | ||
Component, | ||
ElementRef, | ||
EventEmitter, | ||
HostBinding, | ||
Inject, | ||
Output, | ||
ViewEncapsulation, | ||
} from '@angular/core'; | ||
import {TuiDestroyService} from '@taiga-ui/cdk/services'; | ||
import {fromEvent} from 'rxjs'; | ||
import {filter, takeUntil} from 'rxjs/operators'; | ||
|
||
@Component({ | ||
selector: '[tuiAutofilledChange]', | ||
template: '<ng-content></ng-content>', | ||
styleUrls: ['./autofilled.component.less'], | ||
changeDetection: ChangeDetectionStrategy.OnPush, | ||
encapsulation: ViewEncapsulation.None, | ||
host: {class: 'tui-autofill'}, | ||
providers: [TuiDestroyService], | ||
}) | ||
export class TuiAutofilledComponent { | ||
@HostBinding('class._autofilled') | ||
autofilled = false; | ||
|
||
@Output() | ||
readonly tuiAutofilledChange = new EventEmitter<boolean>(); | ||
|
||
constructor( | ||
@Inject(ElementRef) private readonly elementRef: ElementRef<Element>, | ||
@Inject(TuiDestroyService) private readonly destroy$: TuiDestroyService, | ||
) {} | ||
|
||
get element(): Element { | ||
return this.elementRef.nativeElement; | ||
} | ||
|
||
get inputElement(): HTMLInputElement | null { | ||
return this.element?.tagName === 'INPUT' | ||
? (this.element as HTMLInputElement) | ||
: this.element.getElementsByTagName('input')?.[0] || null; | ||
} | ||
|
||
ngOnInit(): void { | ||
const input = this.inputElement; | ||
|
||
if (input) { | ||
fromEvent<TransitionEvent>(input, 'transitionstart') | ||
.pipe( | ||
filter(event => event.propertyName.includes('box-shadow')), | ||
takeUntil(this.destroy$), | ||
) | ||
.subscribe(() => this.changeAutofill()); | ||
} | ||
} | ||
|
||
private changeAutofill(): void { | ||
this.autofilled = !this.autofilled; | ||
this.tuiAutofilledChange.emit(this.autofilled); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import {NgModule} from '@angular/core'; | ||
|
||
import {TuiAutofilledComponent} from './autofilled.component'; | ||
|
||
@NgModule({ | ||
declarations: [TuiAutofilledComponent], | ||
exports: [TuiAutofilledComponent], | ||
}) | ||
export class TuiAutofilledModule {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './autofilled.component'; | ||
export * from './autofilled.module'; |
File renamed without changes.
165 changes: 165 additions & 0 deletions
165
projects/cdk/components/autofilled/test/autofilled.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
import {Component} from '@angular/core'; | ||
import {ComponentFixture, TestBed} from '@angular/core/testing'; | ||
import {configureTestSuite, NativeInputPO} from '@taiga-ui/testing'; | ||
import {FormsModule} from '@angular/forms'; | ||
import {TuiPrimitiveTextfieldModule} from '@taiga-ui/core'; | ||
import {TuiAutofilledModule} from '@taiga-ui/cdk'; | ||
|
||
describe('TuiAutofillModule', () => { | ||
describe('TuiPrimitiveTextfield', () => { | ||
@Component({ | ||
template: ` | ||
<tui-primitive-textfield | ||
[(value)]="value" | ||
(autofilledChange)="autofilled = $event" | ||
></tui-primitive-textfield> | ||
`, | ||
}) | ||
class TestComponent { | ||
value = ''; | ||
autofilled = false; | ||
} | ||
|
||
let fixture: ComponentFixture<TestComponent>; | ||
let testComponent: TestComponent; | ||
let inputPO: NativeInputPO; | ||
|
||
configureTestSuite(() => { | ||
TestBed.configureTestingModule({ | ||
imports: [FormsModule, TuiPrimitiveTextfieldModule], | ||
declarations: [TestComponent], | ||
}); | ||
}); | ||
|
||
beforeEach(() => { | ||
fixture = TestBed.createComponent(TestComponent); | ||
testComponent = fixture.componentInstance; | ||
fixture.detectChanges(); | ||
inputPO = new NativeInputPO(fixture, `tui-primitive-textfield__native-input`); | ||
}); | ||
|
||
it('correctly works if `tuiAutofilledChange` is set to `tui-wrapper`', () => { | ||
expect(testComponent.autofilled).toBeFalse(); | ||
expect(testComponent.value).toBe(''); | ||
|
||
expect(getWrapperClassList()).toEqual([ | ||
'tui-autofill', | ||
'_no-hover', | ||
'_no-active', | ||
]); | ||
|
||
autoFillEvent(inputPO.nativeElement, '1111 2222 3333 4444'); | ||
fixture.detectChanges(); | ||
|
||
expect(getWrapperClassList()).toEqual([ | ||
'tui-autofill', | ||
'_no-hover', | ||
'_no-active', | ||
'_autofilled', | ||
]); | ||
|
||
expect(testComponent.autofilled).toBeTrue(); | ||
expect(testComponent.value).toBe('1111 2222 3333 4444'); | ||
|
||
autoFillEvent(inputPO.nativeElement); | ||
fixture.detectChanges(); | ||
|
||
expect(getWrapperClassList()).toEqual([ | ||
'tui-autofill', | ||
'_no-hover', | ||
'_no-active', | ||
]); | ||
|
||
expect(testComponent.autofilled).toBeFalse(); | ||
expect(testComponent.value).toBe(''); | ||
}); | ||
|
||
function getWrapperClassList(): string[] { | ||
return Array.from( | ||
fixture.nativeElement.querySelector('tui-wrapper')?.classList || [], | ||
); | ||
} | ||
}); | ||
|
||
describe('native input', () => { | ||
@Component({ | ||
template: ` | ||
<input | ||
id="cardNumber" | ||
type="text" | ||
[(ngModel)]="value" | ||
(tuiAutofilledChange)="autofilled = $event" | ||
/> | ||
`, | ||
}) | ||
class TestComponent { | ||
value = ''; | ||
autofilled = false; | ||
} | ||
|
||
let fixture: ComponentFixture<TestComponent>; | ||
let testComponent: TestComponent; | ||
|
||
configureTestSuite(() => { | ||
TestBed.configureTestingModule({ | ||
imports: [FormsModule, TuiAutofilledModule], | ||
declarations: [TestComponent], | ||
}); | ||
}); | ||
|
||
beforeEach(() => { | ||
fixture = TestBed.createComponent(TestComponent); | ||
testComponent = fixture.componentInstance; | ||
fixture.detectChanges(); | ||
}); | ||
|
||
it('correctly works if `tuiAutofilledChange` is set to `input`', () => { | ||
expect(testComponent.autofilled).toBeFalse(); | ||
expect(testComponent.value).toBe(''); | ||
expect(getInputClassList()).toEqual(['tui-autofill']); | ||
|
||
autoFillEvent(getInput(), '1111 2222 3333 4444'); | ||
fixture.detectChanges(); | ||
|
||
expect(getInputClassList()).toEqual(['tui-autofill', '_autofilled']); | ||
|
||
expect(testComponent.autofilled).toBeTrue(); | ||
expect(testComponent.value).toBe('1111 2222 3333 4444'); | ||
|
||
autoFillEvent(getInput()); | ||
fixture.detectChanges(); | ||
|
||
expect(testComponent.autofilled).toBeFalse(); | ||
expect(testComponent.value).toBe(''); | ||
expect(getInputClassList()).toEqual(['tui-autofill']); | ||
}); | ||
|
||
function getInput(): HTMLInputElement { | ||
return fixture.nativeElement?.querySelector('#cardNumber'); | ||
} | ||
|
||
function getInputClassList(): string[] { | ||
return Array.from(getInput()?.classList || []).filter( | ||
className => !className.includes('ng-'), | ||
); | ||
} | ||
}); | ||
}); | ||
|
||
function triggerTransitionStart(element: Element, propertyName: string): void { | ||
const event = new TransitionEvent('transitionstart', {propertyName}); | ||
|
||
element.dispatchEvent(event); | ||
} | ||
|
||
function triggerInputChange(element: HTMLInputElement, data: string): void { | ||
const event = new InputEvent('input', {data}); | ||
|
||
element.value = data; | ||
element.dispatchEvent(event); | ||
} | ||
|
||
function autoFillEvent(input: HTMLInputElement, data?: string): void { | ||
triggerTransitionStart(input, '-webkit-box-shadow'); | ||
triggerInputChange(input, data || ''); | ||
} |
53 changes: 0 additions & 53 deletions
53
projects/cdk/directives/autofilled/autofilled.directive.ts
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,6 +43,8 @@ | |
} | ||
|
||
.t-input { | ||
text-overflow: ellipsis; | ||
|
||
&:not(:first-child) { | ||
display: none; | ||
} | ||
|
Oops, something went wrong.