From 5a7763f0f78d7d3049ff729a2c1d779a0d1c3181 Mon Sep 17 00:00:00 2001 From: Ben Grynhaus Date: Fri, 14 Dec 2018 18:36:44 +0200 Subject: [PATCH 1/2] [fabric] add spin button component --- .../lib/components/spin-button/public-api.ts | 5 + .../spin-button/spin-button.component.ts | 106 ++++++++++++++++++ .../spin-button/spin-button.module.ts | 23 ++++ libs/fabric/src/public-api.ts | 1 + 4 files changed, 135 insertions(+) create mode 100644 libs/fabric/src/lib/components/spin-button/public-api.ts create mode 100644 libs/fabric/src/lib/components/spin-button/spin-button.component.ts create mode 100644 libs/fabric/src/lib/components/spin-button/spin-button.module.ts diff --git a/libs/fabric/src/lib/components/spin-button/public-api.ts b/libs/fabric/src/lib/components/spin-button/public-api.ts new file mode 100644 index 00000000..b831c2ae --- /dev/null +++ b/libs/fabric/src/lib/components/spin-button/public-api.ts @@ -0,0 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +export * from './spin-button.component'; +export * from './spin-button.module'; diff --git a/libs/fabric/src/lib/components/spin-button/spin-button.component.ts b/libs/fabric/src/lib/components/spin-button/spin-button.component.ts new file mode 100644 index 00000000..75855887 --- /dev/null +++ b/libs/fabric/src/lib/components/spin-button/spin-button.component.ts @@ -0,0 +1,106 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { ReactWrapperComponent } from '@angular-react/core'; +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + ElementRef, + Input, + Renderer2, + ViewChild, + EventEmitter, + Output, + OnInit, +} from '@angular/core'; +import { ISpinButtonProps } from 'office-ui-fabric-react/lib/SpinButton'; + +@Component({ + selector: 'fab-spin-button', + exportAs: 'fabSpinButton', + template: ` + + + `, + styles: ['react-renderer'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class FabSpinButtonComponent extends ReactWrapperComponent { + @ViewChild('reactNode') protected reactNodeRef: ElementRef; + + @Input() componentRef?: ISpinButtonProps['componentRef']; + @Input() defaultValue?: ISpinButtonProps['defaultValue']; + @Input() value?: ISpinButtonProps['value']; + @Input() min?: ISpinButtonProps['min']; + @Input() max?: ISpinButtonProps['max']; + @Input() step?: ISpinButtonProps['step']; + @Input() ariaLabel?: ISpinButtonProps['ariaLabel']; + @Input() title?: ISpinButtonProps['title']; + @Input() disabled?: ISpinButtonProps['disabled']; + @Input() className?: ISpinButtonProps['className']; + @Input() label: ISpinButtonProps['label']; + @Input() labelPosition?: ISpinButtonProps['labelPosition']; + @Input() iconProps?: ISpinButtonProps['iconProps']; + @Input() incrementButtonIcon?: ISpinButtonProps['incrementButtonIcon']; + @Input() decrementButtonIcon?: ISpinButtonProps['decrementButtonIcon']; + @Input() styles?: ISpinButtonProps['styles']; + @Input() getClassNames?: ISpinButtonProps['getClassNames']; + @Input() upArrowButtonStyles?: ISpinButtonProps['upArrowButtonStyles']; + @Input() downArrowButtonStyles?: ISpinButtonProps['downArrowButtonStyles']; + @Input() theme?: ISpinButtonProps['theme']; + @Input() incrementButtonAriaLabel?: ISpinButtonProps['incrementButtonAriaLabel']; + @Input() decrementButtonAriaLabel?: ISpinButtonProps['decrementButtonAriaLabel']; + @Input() precision?: ISpinButtonProps['precision']; + @Input() ariaPositionInSet?: ISpinButtonProps['ariaPositionInSet']; + @Input() ariaSetSize?: ISpinButtonProps['ariaSetSize']; + @Input() ariaValueNow?: ISpinButtonProps['ariaValueNow']; + @Input() ariaValueText?: ISpinButtonProps['ariaValueText']; + @Input() keytipProps?: ISpinButtonProps['keytipProps']; + + @Input() validate?: ISpinButtonProps['onValidate']; + @Input() increment?: ISpinButtonProps['onIncrement']; + @Input() decrement?: ISpinButtonProps['onDecrement']; + + @Output() readonly onFocus = new EventEmitter(); + @Output() readonly onBlur = new EventEmitter(); + + constructor(elementRef: ElementRef, changeDetectorRef: ChangeDetectorRef, renderer: Renderer2) { + super(elementRef, changeDetectorRef, renderer); + } +} diff --git a/libs/fabric/src/lib/components/spin-button/spin-button.module.ts b/libs/fabric/src/lib/components/spin-button/spin-button.module.ts new file mode 100644 index 00000000..4776ad0d --- /dev/null +++ b/libs/fabric/src/lib/components/spin-button/spin-button.module.ts @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { registerElement } from '@angular-react/core'; +import { CommonModule } from '@angular/common'; +import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core'; +import { SpinButton } from 'office-ui-fabric-react/lib/SpinButton'; +import { FabSpinButtonComponent } from './spin-button.component'; + +const components = [FabSpinButtonComponent]; + +@NgModule({ + imports: [CommonModule], + declarations: components, + exports: components, + schemas: [NO_ERRORS_SCHEMA], +}) +export class FabSpinButtonModule { + constructor() { + // Add any React elements to the registry (used by the renderer). + registerElement('SpinButton', () => SpinButton); + } +} diff --git a/libs/fabric/src/public-api.ts b/libs/fabric/src/public-api.ts index e0784193..dfb6ccb6 100644 --- a/libs/fabric/src/public-api.ts +++ b/libs/fabric/src/public-api.ts @@ -30,6 +30,7 @@ export * from './lib/components/pivot/public-api'; export * from './lib/components/search-box/public-api'; export * from './lib/components/shimmer/public-api'; export * from './lib/components/slider/public-api'; +export * from './lib/components/spin-button/public-api'; export * from './lib/components/spinner/public-api'; export * from './lib/components/toggle/public-api'; export * from './lib/components/tooltip/public-api'; From 090cc94678f483306786ffd3f24e9e90a81cecc6 Mon Sep 17 00:00:00 2001 From: Ben Grynhaus Date: Fri, 14 Dec 2018 18:37:36 +0200 Subject: [PATCH 2/2] [fabric] add example for spin button component --- apps/demo/src/app/app.component.html | 8 +++++ apps/demo/src/app/app.component.ts | 49 ++++++++++++++++++++++++++++ apps/demo/src/app/app.module.ts | 2 ++ 3 files changed, 59 insertions(+) diff --git a/apps/demo/src/app/app.component.html b/apps/demo/src/app/app.component.html index a00b374c..e78caa7e 100644 --- a/apps/demo/src/app/app.component.html +++ b/apps/demo/src/app/app.component.html @@ -12,6 +12,14 @@

Getting up and running...

+ +
Tab 1's content
diff --git a/apps/demo/src/app/app.component.ts b/apps/demo/src/app/app.component.ts index be78a6f4..aa200b68 100644 --- a/apps/demo/src/app/app.component.ts +++ b/apps/demo/src/app/app.component.ts @@ -1,6 +1,8 @@ import { ChangeDetectorRef, Component, TemplateRef, ViewChild, ViewEncapsulation } from '@angular/core'; import { ICalendarStrings, IContextualMenuProps, ISelection, Selection } from 'office-ui-fabric-react'; +const suffix = ' cm'; + @Component({ selector: 'app-root', templateUrl: './app.component.html', @@ -13,6 +15,8 @@ export class AppComponent { dismissMenu: (ev?: any, dismissAll?: boolean) => void; }>; + textFieldValue = 'Hello'; + onClickEventHandler(ev) { console.log('onClick', { ev }); } @@ -92,8 +96,53 @@ export class AppComponent { console.log('Column header clicked', event); } + onIncrement(value: string): string | void { + value = this._removeSuffix(value, suffix); + + if (+value >= 13) { + return value + suffix; + } + + return String(+value + 2) + suffix; + } + + onDecrement(value: string): string | void { + value = this._removeSuffix(value, suffix); + + if (+value <= 3) { + return value + suffix; + } + return String(+value - 2) + suffix; + } + + onValidate(value: string, event: Event): string | void { + value = this._removeSuffix(value, suffix); + if (value.trim().length === 0 || isNaN(+value)) { + return '0' + suffix; + } + + return String(value) + suffix; + } + + private _hasSuffix(value: string, suffix: string): Boolean { + const subString = value.substr(value.length - suffix.length); + return subString === suffix; + } + + private _removeSuffix(value: string, suffix: string): string { + if (!this._hasSuffix(value, suffix)) { + return value; + } + + return value.substr(0, value.length - suffix.length); + } + constructor(private readonly cd: ChangeDetectorRef) { this.selection = new Selection(); + + this.onValidate = this.onValidate.bind(this); + this.onIncrement = this.onIncrement.bind(this); + this.onDecrement = this.onDecrement.bind(this); } customItemCount = 1; diff --git a/apps/demo/src/app/app.module.ts b/apps/demo/src/app/app.module.ts index 0f363758..3523e358 100644 --- a/apps/demo/src/app/app.module.ts +++ b/apps/demo/src/app/app.module.ts @@ -31,6 +31,7 @@ import { FabSpinnerModule, FabToggleModule, FabTooltipModule, + FabSpinButtonModule, } from '@angular-react/fabric'; import { NgModule } from '@angular/core'; import { NxModule } from '@nrwl/nx'; @@ -73,6 +74,7 @@ import { CounterComponent } from './counter/counter.component'; FabDetailsListModule, FabGroupModule, FabMarqueeSelectionModule, + FabSpinButtonModule, ], declarations: [AppComponent, CounterComponent], bootstrap: [AppComponent],