Skip to content

Commit d18320e

Browse files
authored
[Fabric] Add TextField and MaskedTextField components (#58)
1 parent 7528f0e commit d18320e

File tree

10 files changed

+259
-0
lines changed

10 files changed

+259
-0
lines changed

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"messagebar",
1717
"nrwl",
1818
"renderprop",
19+
"resizable",
1920
"scrollable",
2021
"stylenames",
2122
"submenu",

apps/demo/src/app/app.component.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ <h2>Getting up and running...</h2>
1212
<fab-icon iconName="Add" (onClick)="onClickEventHandler($event)" (onMouseOver)="onMouseOverEventHandler($event)">
1313
</fab-icon>
1414

15+
<fab-text-field [(value)]="textFieldValue"></fab-text-field>
16+
17+
<span>{{ textFieldValue }}</span>
18+
1519
<div>
1620
<fab-pivot>
1721
<fab-pivot-item headerText="Tab 1"> <div>Tab 1's content</div> </fab-pivot-item>

apps/demo/src/app/app.component.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ export class AppComponent {
2121
console.log('onMouseOver', { ev });
2222
}
2323

24+
textFieldValue = 'Hello';
25+
2426
marqueeEnabled: boolean;
2527
runDisabled: boolean;
2628
selection: ISelection;

apps/demo/src/app/app.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
FabSpinnerModule,
3232
FabToggleModule,
3333
FabTooltipModule,
34+
FabTextFieldModule,
3435
} from '@angular-react/fabric';
3536
import { NgModule } from '@angular/core';
3637
import { NxModule } from '@nrwl/nx';
@@ -73,6 +74,7 @@ import { CounterComponent } from './counter/counter.component';
7374
FabDetailsListModule,
7475
FabGroupModule,
7576
FabMarqueeSelectionModule,
77+
FabTextFieldModule,
7678
],
7779
declarations: [AppComponent, CounterComponent],
7880
bootstrap: [AppComponent],
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
import { ReactWrapperComponent, InputRendererOptions, JsxRenderFunc } from '@angular-react/core';
5+
import {
6+
ChangeDetectorRef,
7+
EventEmitter,
8+
ElementRef,
9+
Input,
10+
Renderer2,
11+
ViewChild,
12+
OnInit,
13+
Output,
14+
} from '@angular/core';
15+
import { ITextFieldProps } from 'office-ui-fabric-react/lib/TextField';
16+
17+
export class FabBaseTextFieldComponent extends ReactWrapperComponent<ITextFieldProps> implements OnInit {
18+
@ViewChild('reactNode') protected reactNodeRef: ElementRef;
19+
20+
@Input() componentRef?: ITextFieldProps['componentRef'];
21+
@Input() multiline?: ITextFieldProps['multiline'];
22+
@Input() resizable?: ITextFieldProps['resizable'];
23+
@Input() autoAdjustHeight?: ITextFieldProps['autoAdjustHeight'];
24+
@Input() underlined?: ITextFieldProps['underlined'];
25+
@Input() borderless?: ITextFieldProps['borderless'];
26+
@Input() label?: ITextFieldProps['label'];
27+
@Input() description?: ITextFieldProps['description'];
28+
@Input() prefix?: ITextFieldProps['prefix'];
29+
@Input() suffix?: ITextFieldProps['suffix'];
30+
@Input() iconProps?: ITextFieldProps['iconProps'];
31+
@Input() defaultValue?: ITextFieldProps['defaultValue'];
32+
@Input() value?: ITextFieldProps['value'];
33+
@Input() disabled?: ITextFieldProps['disabled'];
34+
@Input() readOnly?: ITextFieldProps['readOnly'];
35+
@Input() errorMessage?: ITextFieldProps['errorMessage'];
36+
@Input() deferredValidationTime?: ITextFieldProps['deferredValidationTime'];
37+
@Input() className?: ITextFieldProps['className'];
38+
@Input() inputClassName?: ITextFieldProps['inputClassName'];
39+
@Input() ariaLabel?: ITextFieldProps['ariaLabel'];
40+
@Input() validateOnFocusIn?: ITextFieldProps['validateOnFocusIn'];
41+
@Input() validateOnFocusOut?: ITextFieldProps['validateOnFocusOut'];
42+
@Input() validateOnLoad?: ITextFieldProps['validateOnLoad'];
43+
@Input() theme?: ITextFieldProps['theme'];
44+
@Input() styles?: ITextFieldProps['styles'];
45+
@Input() autoComplete?: ITextFieldProps['autoComplete'];
46+
@Input() mask?: ITextFieldProps['mask'];
47+
@Input() maskChar?: ITextFieldProps['maskChar'];
48+
@Input() maskFormat?: ITextFieldProps['maskFormat'];
49+
@Input() getErrorMessage?: ITextFieldProps['onGetErrorMessage'];
50+
51+
@Input() renderLabel?: InputRendererOptions<ITextFieldProps>;
52+
@Input() renderDescription?: InputRendererOptions<ITextFieldProps>;
53+
@Input() renderPrefix?: InputRendererOptions<ITextFieldProps>;
54+
@Input() renderSuffix?: InputRendererOptions<ITextFieldProps>;
55+
56+
@Output() readonly onChange = new EventEmitter<{ event: Event; newValue?: string }>();
57+
@Output() readonly onBeforeChange = new EventEmitter<{ newValue: any }>();
58+
@Output() readonly onNotifyValidationResult = new EventEmitter<{ errorMessage: string; value: string | undefined }>();
59+
60+
/* Non-React props, more native support for Angular */
61+
// support for two-way data binding for `@Input() checked`.
62+
@Output() readonly valueChange = new EventEmitter<string>();
63+
64+
onRenderLabel: (props?: ITextFieldProps, defaultRender?: JsxRenderFunc<ITextFieldProps>) => JSX.Element;
65+
onRenderDescription: (props?: ITextFieldProps, defaultRender?: JsxRenderFunc<ITextFieldProps>) => JSX.Element;
66+
onRenderPrefix: (props?: ITextFieldProps, defaultRender?: JsxRenderFunc<ITextFieldProps>) => JSX.Element;
67+
onRenderSuffix: (props?: ITextFieldProps, defaultRender?: JsxRenderFunc<ITextFieldProps>) => JSX.Element;
68+
69+
constructor(elementRef: ElementRef, changeDetectorRef: ChangeDetectorRef, renderer: Renderer2) {
70+
super(elementRef, changeDetectorRef, renderer);
71+
72+
this.onChangeHandler = this.onChangeHandler.bind(this);
73+
this.onBeforeChangeHandler = this.onBeforeChangeHandler.bind(this);
74+
this.onNotifyValidationResultHandler = this.onNotifyValidationResultHandler.bind(this);
75+
}
76+
77+
ngOnInit() {
78+
this.onRenderLabel = this.createRenderPropHandler(this.renderLabel);
79+
this.onRenderDescription = this.createRenderPropHandler(this.renderDescription);
80+
this.onRenderPrefix = this.createRenderPropHandler(this.renderPrefix);
81+
this.onRenderSuffix = this.createRenderPropHandler(this.renderSuffix);
82+
}
83+
84+
onChangeHandler(event: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>, newValue?: string) {
85+
this.onChange.emit({ event: event.nativeEvent, newValue });
86+
87+
this.valueChange.emit(newValue);
88+
}
89+
90+
onBeforeChangeHandler(newValue: any) {
91+
this.onBeforeChange.emit({ newValue });
92+
}
93+
94+
onNotifyValidationResultHandler(errorMessage: string, value: string | undefined) {
95+
this.onNotifyValidationResult.emit({ errorMessage, value });
96+
}
97+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, Renderer2, ViewChild } from '@angular/core';
5+
import { FabBaseTextFieldComponent } from './base-text-field.component';
6+
7+
@Component({
8+
selector: 'fab-masked-text-field',
9+
exportAs: 'fabMaskedTextField',
10+
template: `
11+
<MaskedTextField
12+
#reactNode
13+
[componentRef]="componentRef"
14+
[multiline]="multiline"
15+
[resizable]="resizable"
16+
[autoAdjustHeight]="autoAdjustHeight"
17+
[underlined]="underlined"
18+
[borderless]="borderless"
19+
[label]="label"
20+
[description]="description"
21+
[prefix]="prefix"
22+
[suffix]="suffix"
23+
[iconProps]="iconProps"
24+
[defaultValue]="defaultValue"
25+
[value]="value"
26+
[disabled]="disabled"
27+
[readOnly]="readOnly"
28+
[errorMessage]="errorMessage"
29+
[deferredValidationTime]="deferredValidationTime"
30+
[className]="className"
31+
[inputClassName]="inputClassName"
32+
[ariaLabel]="ariaLabel"
33+
[validateOnFocusIn]="validateOnFocusIn"
34+
[validateOnFocusOut]="validateOnFocusOut"
35+
[validateOnLoad]="validateOnLoad"
36+
[theme]="theme"
37+
[styles]="styles"
38+
[autoComplete]="autoComplete"
39+
[mask]="mask"
40+
[maskChar]="maskChar"
41+
[maskFormat]="maskFormat"
42+
[GetErrorMessage]="getErrorMessage"
43+
[RenderLabel]="renderLabel"
44+
[RenderDescription]="renderDescription"
45+
[RenderPrefix]="renderPrefix"
46+
[RenderSuffix]="renderSuffix"
47+
[Change]="onChangeHandler"
48+
[BeforeChange]="onBeforeChangeHandler"
49+
[NotifyValidationResult]="onNotifyValidationResultHandler"
50+
>
51+
</MaskedTextField>
52+
`,
53+
styles: ['react-renderer'],
54+
changeDetection: ChangeDetectionStrategy.OnPush,
55+
})
56+
export class FabMaskedTextFieldComponent extends FabBaseTextFieldComponent {
57+
@ViewChild('reactNode') protected reactNodeRef: ElementRef;
58+
59+
constructor(elementRef: ElementRef, changeDetectorRef: ChangeDetectorRef, renderer: Renderer2) {
60+
super(elementRef, changeDetectorRef, renderer);
61+
}
62+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * from './text-field.module';
2+
export * from './masked-text-field.component';
3+
export * from './text-field.component';
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, Renderer2, ViewChild } from '@angular/core';
5+
import { FabBaseTextFieldComponent } from './base-text-field.component';
6+
7+
@Component({
8+
selector: 'fab-text-field',
9+
exportAs: 'fabTextField',
10+
template: `
11+
<TextField
12+
#reactNode
13+
[componentRef]="componentRef"
14+
[multiline]="multiline"
15+
[resizable]="resizable"
16+
[autoAdjustHeight]="autoAdjustHeight"
17+
[underlined]="underlined"
18+
[borderless]="borderless"
19+
[label]="label"
20+
[description]="description"
21+
[prefix]="prefix"
22+
[suffix]="suffix"
23+
[iconProps]="iconProps"
24+
[defaultValue]="defaultValue"
25+
[value]="value"
26+
[disabled]="disabled"
27+
[readOnly]="readOnly"
28+
[errorMessage]="errorMessage"
29+
[deferredValidationTime]="deferredValidationTime"
30+
[className]="className"
31+
[inputClassName]="inputClassName"
32+
[ariaLabel]="ariaLabel"
33+
[validateOnFocusIn]="validateOnFocusIn"
34+
[validateOnFocusOut]="validateOnFocusOut"
35+
[validateOnLoad]="validateOnLoad"
36+
[theme]="theme"
37+
[styles]="styles"
38+
[autoComplete]="autoComplete"
39+
[mask]="mask"
40+
[maskChar]="maskChar"
41+
[maskFormat]="maskFormat"
42+
[GetErrorMessage]="getErrorMessage"
43+
[RenderLabel]="renderLabel"
44+
[RenderDescription]="renderDescription"
45+
[RenderPrefix]="renderPrefix"
46+
[RenderSuffix]="renderSuffix"
47+
[Change]="onChangeHandler"
48+
[BeforeChange]="onBeforeChangeHandler"
49+
[NotifyValidationResult]="onNotifyValidationResultHandler"
50+
>
51+
</TextField>
52+
`,
53+
styles: ['react-renderer'],
54+
changeDetection: ChangeDetectionStrategy.OnPush,
55+
})
56+
export class FabTextFieldComponent extends FabBaseTextFieldComponent {
57+
@ViewChild('reactNode') protected reactNodeRef: ElementRef;
58+
59+
constructor(elementRef: ElementRef, changeDetectorRef: ChangeDetectorRef, renderer: Renderer2) {
60+
super(elementRef, changeDetectorRef, renderer);
61+
}
62+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
import { registerElement } from '@angular-react/core';
5+
import { CommonModule } from '@angular/common';
6+
import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core';
7+
import { TextField, MaskedTextField } from 'office-ui-fabric-react/lib/TextField';
8+
import { FabTextFieldComponent } from './text-field.component';
9+
import { FabMaskedTextFieldComponent } from './masked-text-field.component';
10+
11+
const components = [FabTextFieldComponent, FabMaskedTextFieldComponent];
12+
13+
@NgModule({
14+
imports: [CommonModule],
15+
declarations: components,
16+
exports: components,
17+
schemas: [NO_ERRORS_SCHEMA],
18+
})
19+
export class FabTextFieldModule {
20+
constructor() {
21+
// Add any React elements to the registry (used by the renderer).
22+
registerElement('TextField', () => TextField);
23+
registerElement('MaskedTextField', () => MaskedTextField);
24+
}
25+
}

libs/fabric/src/public-api.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export * from './lib/components/search-box/public-api';
3131
export * from './lib/components/shimmer/public-api';
3232
export * from './lib/components/slider/public-api';
3333
export * from './lib/components/spinner/public-api';
34+
export * from './lib/components/text-field/public-api';
3435
export * from './lib/components/toggle/public-api';
3536
export * from './lib/components/tooltip/public-api';
3637

0 commit comments

Comments
 (0)