diff --git a/apps/demo/src/app/app.component.html b/apps/demo/src/app/app.component.html index ccf44aa5..9764fe9c 100644 --- a/apps/demo/src/app/app.component.html +++ b/apps/demo/src/app/app.component.html @@ -9,11 +9,6 @@

Getting up and running...

-
Generic React component wrapper
- -
test
-
-
diff --git a/apps/demo/src/app/app.component.ts b/apps/demo/src/app/app.component.ts index c3123193..a9d86a57 100644 --- a/apps/demo/src/app/app.component.ts +++ b/apps/demo/src/app/app.component.ts @@ -178,12 +178,6 @@ export class AppComponent { this.onDecrement = this.onDecrement.bind(this); } - count = 3; - - reactCustomOnIncrement(newCount: number) { - this.count = newCount; - } - customItemCount = 1; // FIXME: Allow declarative syntax too diff --git a/apps/demo/src/app/app.module.ts b/apps/demo/src/app/app.module.ts index 75ff7b14..3bae67a2 100644 --- a/apps/demo/src/app/app.module.ts +++ b/apps/demo/src/app/app.module.ts @@ -1,4 +1,4 @@ -import { AngularReactBrowserModule, wrapComponent } from '@angular-react/core'; +import { AngularReactBrowserModule } from '@angular-react/core'; import { FabBreadcrumbModule, FabButtonModule, @@ -35,18 +35,11 @@ import { FabSpinButtonModule, FabTextFieldModule, } from '@angular-react/fabric'; -import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core'; +import { NgModule } from '@angular/core'; import { NxModule } from '@nrwl/nx'; import { initializeIcons } from 'office-ui-fabric-react/lib/Icons'; import { AppComponent } from './app.component'; import { CounterComponent } from './counter/counter.component'; -import { CounterProps, Counter } from './counter/react-counter'; - -const MyCounterComponent = wrapComponent({ - ReactComponent: Counter, - selector: 'my-counter', - // propNames: ['count', 'onIncrement'], // needed if propTypes are not defined on `ReactComponent` -}); @NgModule({ imports: [ @@ -87,9 +80,8 @@ const MyCounterComponent = wrapComponent({ FabSpinButtonModule, FabTextFieldModule, ], - declarations: [AppComponent, CounterComponent, MyCounterComponent], + declarations: [AppComponent, CounterComponent], bootstrap: [AppComponent], - schemas: [NO_ERRORS_SCHEMA], }) export class AppModule { constructor() { diff --git a/apps/demo/src/app/counter/react-counter.tsx b/apps/demo/src/app/counter/react-counter.tsx deleted file mode 100644 index a2c0898a..00000000 --- a/apps/demo/src/app/counter/react-counter.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import * as React from 'react'; -import * as PropTypes from 'prop-types'; - -export interface CounterProps { - count?: number; - onIncrement?: (count: number) => void; -} - -export const Counter: React.FC = ({ count = 0, onIncrement, children, ...rest } = {}) => { - return ( - - ); -}; - -Counter.propTypes = { - count: PropTypes.number, - onIncrement: PropTypes.func, -}; diff --git a/apps/demo/tsconfig.app.json b/apps/demo/tsconfig.app.json index fade5b38..46debef0 100644 --- a/apps/demo/tsconfig.app.json +++ b/apps/demo/tsconfig.app.json @@ -2,8 +2,7 @@ "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "../../dist/out-tsc/apps/demo", - "module": "es2015", - "jsx": "react" + "module": "es2015" }, "include": ["**/*.ts"], "exclude": ["**/*.spec.ts", "src/test.ts"] diff --git a/libs/core/src/lib/components/generic-wrap-component.ts b/libs/core/src/lib/components/generic-wrap-component.ts deleted file mode 100644 index 912cccf0..00000000 --- a/libs/core/src/lib/components/generic-wrap-component.ts +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -import * as React from 'react'; -import { - Component, - ElementRef, - ViewChild, - ChangeDetectionStrategy, - Input, - ChangeDetectorRef, - Renderer2, - NgZone, - Output, - EventEmitter, - Type, -} from '@angular/core'; - -declare const __decorate: typeof import('tslib').__decorate; - -import { ReactWrapperComponent } from './wrapper-component'; -import { registerElement } from '../renderer/registry'; - -export interface WrapComponentOptions { - /** - * The type of the component to wrap. - */ - ReactComponent: React.ComponentType; - - /** - * The selector to use. - */ - selector: string; - - /** - * The prop names to pass to the `reactComponent`, if any. - * Note that any prop starting with `on` will be converted to an `Output`, and other to `Input`s. - * - * @note If `reactComponent` has `propTypes`, this can be omitted. - */ - propNames?: string[]; - - /** - * @see `WrapperComponentOptions#setHostDisplay`. - */ - setHostDisplay?: boolean; - - /** - * An _optional_ callback for specified wether a prop should be considered an `Output`. - * @default propName => propName.startsWith('on') - */ - isOutputProp?: (propName: string) => boolean; -} - -/** - * Gets the display name of a component. - * @param WrappedComponent The type of the wrapper component - */ -function getDisplayName(WrappedComponent: React.ComponentType): string { - return WrappedComponent.displayName || WrappedComponent.name || 'Component'; -} - -/** - * Checks if the propName is an output one. - * Currently uses a simple check - anything that starts with `on` is considered an output prop. - */ -function defaultIsOutputProp(propName: string): boolean { - return propName.startsWith('on'); -} - -function getPropNames(ReactComponent: React.ComponentType) { - if (!ReactComponent.propTypes) { - return null; - } - - return Object.keys(ReactComponent.propTypes); -} - -/** - * Wrap a React component with an Angular one. - * - * @template TProps The type of props of the underlying React element. - * @param options Options for wrapping the component. - * @returns A class of a wrapper Angular component. - */ -export function wrapComponent( - options: Readonly> -): Type> { - const Tag = getDisplayName(options.ReactComponent); - registerElement(Tag, () => options.ReactComponent); - - const propNames = options.propNames || getPropNames(options.ReactComponent); - const isOutputProp = options.isOutputProp || defaultIsOutputProp; - - const inputProps = propNames.filter(propName => !isOutputProp(propName)); - const outputProps = propNames.filter(isOutputProp); - - const inputPropsBindings = inputProps.map(propName => `[${propName}]="${propName}"`); - const outputPropsBindings = outputProps.map(propName => `(${propName})="${propName}.emit($event)"`); - const propsBindings = [...inputPropsBindings, ...outputPropsBindings].join('\n'); - - @Component({ - changeDetection: ChangeDetectionStrategy.OnPush, - styles: ['react-renderer'], - selector: options.selector, - template: ` - <${Tag} - #reactNode - ${propsBindings} - > - - - `, - }) - class WrapperComponent extends ReactWrapperComponent { - @ViewChild('reactNode') protected reactNodeRef: ElementRef; - - constructor(elementRef: ElementRef, changeDetectorRef: ChangeDetectorRef, renderer: Renderer2, ngZone: NgZone) { - super(elementRef, changeDetectorRef, renderer, { ngZone, setHostDisplay: options.setHostDisplay }); - - outputProps.forEach(propName => { - this[propName] = new EventEmitter(); - }); - } - } - - inputProps.forEach(propName => __decorate([Input()], WrapperComponent.prototype, propName)); - outputProps.forEach(propName => __decorate([Output()], WrapperComponent.prototype, propName)); - - return WrapperComponent; -} diff --git a/libs/core/src/lib/components/wrapper-component.ts b/libs/core/src/lib/components/wrapper-component.ts index 283371f3..bc97cf1c 100644 --- a/libs/core/src/lib/components/wrapper-component.ts +++ b/libs/core/src/lib/components/wrapper-component.ts @@ -12,7 +12,6 @@ import { Renderer2, SimpleChanges, AfterContentInit, - ɵBaseDef, } from '@angular/core'; import classnames from 'classnames'; import toStyle from 'css-to-style'; @@ -22,10 +21,9 @@ import { Many } from '../declarations/many'; import { ReactContentProps } from '../renderer/react-content'; import { isReactNode } from '../renderer/react-node'; import { isReactRendererData } from '../renderer/renderer'; -import { fromPairs } from '../utils/object/from-pairs'; +import { toObject } from '../utils/object/to-object'; import { afterRenderFinished } from '../utils/render/render-delay'; import { InputRendererOptions, JsxRenderFunc, createInputJsxRenderer, createRenderPropHandler } from './render-props'; -import { omit } from '../utils/object/omit'; // Forbidden attributes are still ignored, since they may be set from the wrapper components themselves (forbidden is only applied for users of the wrapper components) const ignoredAttributeMatchers = [/^_?ng-?.*/, /^style$/, /^class$/]; @@ -233,23 +231,17 @@ export abstract class ReactWrapperComponent implements AfterC ); const eventListeners = this.elementRef.nativeElement.getEventListeners(); - // Event listeners already being handled natively by the derived component - const handledEventListeners = Object.keys( - ((this.constructor as any).ngBaseDef as ɵBaseDef).outputs - ) as (keyof typeof eventListeners)[]; - const unhandledEventListeners = omit(eventListeners, ...handledEventListeners); - const eventHandlersProps = - unhandledEventListeners && Object.keys(unhandledEventListeners).length - ? fromPairs( - Object.values(unhandledEventListeners).map<[string, React.EventHandler]>( - ([eventListener]) => [ - eventListener.type, - (ev: React.SyntheticEvent) => eventListener.listener(ev && ev.nativeEvent), - ] - ) + eventListeners && Object.keys(eventListeners).length + ? toObject( + Object.values(eventListeners).map<[string, React.EventHandler]>(([eventListener]) => [ + eventListener.type, + (ev: React.SyntheticEvent) => eventListener.listener(ev && ev.nativeEvent), + ]) ) : {}; + { + } this.reactNodeRef.nativeElement.setProperties({ ...props, ...eventHandlersProps }); } diff --git a/libs/core/src/lib/declarations/known-keys.ts b/libs/core/src/lib/declarations/known-keys.ts index b495321a..1b999789 100644 --- a/libs/core/src/lib/declarations/known-keys.ts +++ b/libs/core/src/lib/declarations/known-keys.ts @@ -1,6 +1,3 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - // prettier-ignore /** * Get the known keys (i.e. no index signature) of T. diff --git a/libs/core/src/lib/declarations/many.ts b/libs/core/src/lib/declarations/many.ts index 00e68e21..bb631eab 100644 --- a/libs/core/src/lib/declarations/many.ts +++ b/libs/core/src/lib/declarations/many.ts @@ -1,4 +1 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - export type Many = T | T[]; diff --git a/libs/core/src/lib/utils/object/from-pairs.ts b/libs/core/src/lib/utils/object/to-object.ts similarity index 70% rename from libs/core/src/lib/utils/object/from-pairs.ts rename to libs/core/src/lib/utils/object/to-object.ts index 99dc6fbe..ed1472eb 100644 --- a/libs/core/src/lib/utils/object/from-pairs.ts +++ b/libs/core/src/lib/utils/object/to-object.ts @@ -1,7 +1,7 @@ /** * Transforms an array of [key, value] tuples to an object */ -export function fromPairs(pairs: T): object { +export function toObject(pairs: T): object { return pairs.reduce( (acc, [key, value]) => Object.assign(acc, { diff --git a/libs/core/src/public-api.ts b/libs/core/src/public-api.ts index f23bc2cd..63b74187 100644 --- a/libs/core/src/public-api.ts +++ b/libs/core/src/public-api.ts @@ -3,15 +3,12 @@ export { AngularReactBrowserModule } from './lib/angular-react-browser.module'; export * from './lib/components/wrapper-component'; -export * from './lib/components/generic-wrap-component'; export * from './lib/declarations/public-api'; export * from './lib/renderer/components/Disguise'; export { getPassProps, passProp, PassProp } from './lib/renderer/pass-prop-decorator'; export { createReactContentElement, ReactContent, ReactContentProps } from './lib/renderer/react-content'; export * from './lib/renderer/react-template'; -export { registerElement, ComponentResolver } from './lib/renderer/registry'; - -export * from './lib/utils/object/omit'; +export { registerElement } from './lib/renderer/registry'; export { JsxRenderFunc, RenderComponentOptions, diff --git a/libs/fabric/src/lib/components/button/base-button.component.ts b/libs/fabric/src/lib/components/button/base-button.component.ts index 31d4af96..e43cd76d 100644 --- a/libs/fabric/src/lib/components/button/base-button.component.ts +++ b/libs/fabric/src/lib/components/button/base-button.component.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import { InputRendererOptions, JsxRenderFunc, ReactWrapperComponent, omit } from '@angular-react/core'; +import { InputRendererOptions, JsxRenderFunc, ReactWrapperComponent } from '@angular-react/core'; import { ChangeDetectorRef, ElementRef, @@ -23,6 +23,7 @@ import { IContextualMenuItem } from 'office-ui-fabric-react'; import { Subscription } from 'rxjs'; import { CommandBarItemChangedPayload } from '../command-bar/directives/command-bar-item.directives'; import { mergeItemChanges } from '../core/declarative/item-changed'; +import { omit } from '../../utils/omit'; import { getDataAttributes } from '../../utils/get-data-attributes'; export abstract class FabBaseButtonComponent extends ReactWrapperComponent diff --git a/libs/fabric/src/lib/components/command-bar/command-bar.component.ts b/libs/fabric/src/lib/components/command-bar/command-bar.component.ts index 809b1fd6..3c5358a6 100644 --- a/libs/fabric/src/lib/components/command-bar/command-bar.component.ts +++ b/libs/fabric/src/lib/components/command-bar/command-bar.component.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import { InputRendererOptions, KnownKeys, ReactWrapperComponent, omit } from '@angular-react/core'; +import { InputRendererOptions, KnownKeys, ReactWrapperComponent } from '@angular-react/core'; import { AfterContentInit, ChangeDetectionStrategy, @@ -22,6 +22,7 @@ import { ICommandBarItemProps, ICommandBarProps } from 'office-ui-fabric-react/l import { IContextualMenuItem } from 'office-ui-fabric-react/lib/ContextualMenu'; import { Subscription } from 'rxjs'; import { OnChanges, TypedChanges } from '../../declarations/angular/typed-changes'; +import omit from '../../utils/omit'; import { mergeItemChanges } from '../core/declarative/item-changed'; import { CommandBarItemChangedPayload, CommandBarItemDirective } from './directives/command-bar-item.directives'; import { diff --git a/libs/fabric/src/lib/components/details-list/details-list.component.ts b/libs/fabric/src/lib/components/details-list/details-list.component.ts index b3c9663f..3ad42d6d 100644 --- a/libs/fabric/src/lib/components/details-list/details-list.component.ts +++ b/libs/fabric/src/lib/components/details-list/details-list.component.ts @@ -18,7 +18,7 @@ import { Renderer2, ViewChild, } from '@angular/core'; -import { InputRendererOptions, JsxRenderFunc, ReactWrapperComponent, omit } from '@angular-react/core'; +import { InputRendererOptions, JsxRenderFunc, ReactWrapperComponent } from '@angular-react/core'; import { DetailsListBase, IColumn, @@ -32,6 +32,7 @@ import { IListProps } from 'office-ui-fabric-react/lib/List'; import { Subscription } from 'rxjs'; import { OnChanges, TypedChanges } from '../../declarations/angular/typed-changes'; +import { omit } from '../../utils/omit'; import { mergeItemChanges } from '../core/declarative/item-changed'; import { ChangeableItemsDirective } from '../core/shared/changeable-items.directive'; import { IDetailsListColumnOptions } from './directives/details-list-column.directive'; diff --git a/libs/fabric/src/lib/components/hover-card/hover-card.component.ts b/libs/fabric/src/lib/components/hover-card/hover-card.component.ts index f5aff0fa..04add79f 100644 --- a/libs/fabric/src/lib/components/hover-card/hover-card.component.ts +++ b/libs/fabric/src/lib/components/hover-card/hover-card.component.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import { InputRendererOptions, Omit, ReactWrapperComponent, omit } from '@angular-react/core'; +import { InputRendererOptions, Omit, ReactWrapperComponent } from '@angular-react/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, @@ -15,6 +15,7 @@ import { ViewChild, } from '@angular/core'; import { IExpandingCardProps, IHoverCardProps, IPlainCardProps } from 'office-ui-fabric-react/lib/HoverCard'; +import { omit } from '../../utils/omit'; @Component({ selector: 'fab-hover-card', diff --git a/libs/fabric/src/lib/components/pickers/base-picker/base-picker.component.ts b/libs/fabric/src/lib/components/pickers/base-picker/base-picker.component.ts index 5bc7a5cb..e923e469 100644 --- a/libs/fabric/src/lib/components/pickers/base-picker/base-picker.component.ts +++ b/libs/fabric/src/lib/components/pickers/base-picker/base-picker.component.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import { InputRendererOptions, JsxRenderFunc, Omit, ReactWrapperComponent, omit } from '@angular-react/core'; +import { InputRendererOptions, JsxRenderFunc, Omit, ReactWrapperComponent } from '@angular-react/core'; import { ChangeDetectorRef, ElementRef, EventEmitter, Input, NgZone, OnInit, Output, Renderer2 } from '@angular/core'; import { IPersonaProps } from 'office-ui-fabric-react/lib/Persona'; import { @@ -10,6 +10,7 @@ import { IBasePickerSuggestionsProps, IPickerItemProps, } from 'office-ui-fabric-react/lib/Pickers'; +import omit from '../../../utils/omit'; export abstract class FabBasePickerComponent> extends ReactWrapperComponent @@ -18,7 +19,7 @@ export abstract class FabBasePickerComponent['resolveDelay']; @Input() defaultSelectedItems?: IBasePickerProps['defaultSelectedItems']; @Input() getTextFromItem?: IBasePickerProps['getTextFromItem']; - @Input() className?: IBasePickerProps['className']; + @Input() className?: IBasePickerProps['className']; @Input() pickerCalloutProps?: IBasePickerProps['pickerCalloutProps']; @Input() searchingText?: IBasePickerProps['searchingText']; @Input() disabled?: IBasePickerProps['disabled']; diff --git a/libs/fabric/src/lib/components/search-box/search-box.component.ts b/libs/fabric/src/lib/components/search-box/search-box.component.ts index 12791073..fa1c1a87 100644 --- a/libs/fabric/src/lib/components/search-box/search-box.component.ts +++ b/libs/fabric/src/lib/components/search-box/search-box.component.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import { InputRendererOptions, Omit, ReactWrapperComponent, omit } from '@angular-react/core'; +import { InputRendererOptions, Omit, ReactWrapperComponent } from '@angular-react/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, @@ -16,6 +16,7 @@ import { } from '@angular/core'; import { IButtonProps } from 'office-ui-fabric-react/lib/Button'; import { ISearchBoxProps } from 'office-ui-fabric-react/lib/SearchBox'; +import omit from '../../utils/omit'; @Component({ selector: 'fab-search-box', diff --git a/libs/fabric/src/lib/components/tooltip/tooltip-host.component.ts b/libs/fabric/src/lib/components/tooltip/tooltip-host.component.ts index 92a3094d..99f5d264 100644 --- a/libs/fabric/src/lib/components/tooltip/tooltip-host.component.ts +++ b/libs/fabric/src/lib/components/tooltip/tooltip-host.component.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import { InputRendererOptions, Omit, ReactWrapperComponent, omit } from '@angular-react/core'; +import { InputRendererOptions, Omit, ReactWrapperComponent } from '@angular-react/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, @@ -15,6 +15,7 @@ import { ViewChild, } from '@angular/core'; import { ITooltipHostProps, ITooltipProps } from 'office-ui-fabric-react/lib/Tooltip'; +import { omit } from '../../utils/omit'; @Component({ selector: 'fab-tooltip-host', diff --git a/libs/core/src/lib/utils/object/omit.ts b/libs/fabric/src/lib/utils/omit.ts similarity index 92% rename from libs/core/src/lib/utils/object/omit.ts rename to libs/fabric/src/lib/utils/omit.ts index d7a51812..02c8b004 100644 --- a/libs/core/src/lib/utils/object/omit.ts +++ b/libs/fabric/src/lib/utils/omit.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import { Omit } from '../../declarations/omit'; +import { Omit } from '@angular-react/core'; /** * Omit a a set of properties from an object.