|
|
|
@ -12,11 +12,11 @@ |
|
|
|
|
import { kebabCase } from 'lodash'; |
|
|
|
|
import React from 'react'; |
|
|
|
|
import ReactDOM from 'react-dom'; |
|
|
|
|
import angular from 'angular'; |
|
|
|
|
import angular, { auto } from 'angular'; |
|
|
|
|
|
|
|
|
|
// get a react component from name (components can be an angular injectable e.g. value, factory or
|
|
|
|
|
// available on window
|
|
|
|
|
function getReactComponent(name, $injector) { |
|
|
|
|
function getReactComponent(name: string, $injector: auto.IInjectorService) { |
|
|
|
|
// if name is a function assume it is component and return it
|
|
|
|
|
if (angular.isFunction(name)) { |
|
|
|
|
return name; |
|
|
|
@ -36,6 +36,7 @@ function getReactComponent(name, $injector) { |
|
|
|
|
if (!reactComponent) { |
|
|
|
|
try { |
|
|
|
|
reactComponent = name.split('.').reduce((current, namePart) => { |
|
|
|
|
// @ts-ignore
|
|
|
|
|
return current[namePart]; |
|
|
|
|
}, window); |
|
|
|
|
} catch (e) {} |
|
|
|
@ -49,7 +50,7 @@ function getReactComponent(name, $injector) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// wraps a function with scope.$apply, if already applied just return
|
|
|
|
|
function applied(fn, scope) { |
|
|
|
|
function applied(fn: any, scope: any) { |
|
|
|
|
if (fn.wrappedInApply) { |
|
|
|
|
return fn; |
|
|
|
|
} |
|
|
|
@ -81,7 +82,7 @@ function applied(fn, scope) { |
|
|
|
|
* @param propsConfig configuration object for all properties |
|
|
|
|
* @returns {Object} props with the functions wrapped in scope.$apply |
|
|
|
|
*/ |
|
|
|
|
function applyFunctions(obj, scope, propsConfig?) { |
|
|
|
|
function applyFunctions(obj: any, scope: any, propsConfig?: any): object { |
|
|
|
|
return Object.keys(obj || {}).reduce((prev, key) => { |
|
|
|
|
const value = obj[key]; |
|
|
|
|
const config = (propsConfig || {})[key] || {}; |
|
|
|
@ -90,6 +91,7 @@ function applyFunctions(obj, scope, propsConfig?) { |
|
|
|
|
* ensures that when function is called from a React component |
|
|
|
|
* the Angular digest cycle is run |
|
|
|
|
*/ |
|
|
|
|
// @ts-ignore
|
|
|
|
|
prev[key] = angular.isFunction(value) && config.wrapApply !== false ? applied(value, scope) : value; |
|
|
|
|
|
|
|
|
|
return prev; |
|
|
|
@ -104,7 +106,7 @@ function applyFunctions(obj, scope, propsConfig?) { |
|
|
|
|
* Uses the watchDepth attribute to determine how to watch props on scope. |
|
|
|
|
* If watchDepth attribute is NOT reference or collection, watchDepth defaults to deep watching by value |
|
|
|
|
*/ |
|
|
|
|
function watchProps(watchDepth, scope, watchExpressions, listener) { |
|
|
|
|
function watchProps(watchDepth: string, scope: any, watchExpressions: any[], listener: any) { |
|
|
|
|
const supportsWatchCollection = angular.isFunction(scope.$watchCollection); |
|
|
|
|
const supportsWatchGroup = angular.isFunction(scope.$watchGroup); |
|
|
|
|
|
|
|
|
@ -138,24 +140,24 @@ function watchProps(watchDepth, scope, watchExpressions, listener) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// render React component, with scope[attrs.props] being passed in as the component props
|
|
|
|
|
function renderComponent(component, props, scope, elem) { |
|
|
|
|
function renderComponent(component: any, props: object, scope: any, elem: Element[]) { |
|
|
|
|
scope.$evalAsync(() => { |
|
|
|
|
ReactDOM.render(React.createElement(component, props), elem[0]); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// get prop name from prop (string or array)
|
|
|
|
|
function getPropName(prop) { |
|
|
|
|
function getPropName(prop: any) { |
|
|
|
|
return Array.isArray(prop) ? prop[0] : prop; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// get prop name from prop (string or array)
|
|
|
|
|
function getPropConfig(prop) { |
|
|
|
|
function getPropConfig(prop: any) { |
|
|
|
|
return Array.isArray(prop) ? prop[1] : {}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// get prop expression from prop (string or array)
|
|
|
|
|
function getPropExpression(prop) { |
|
|
|
|
function getPropExpression(prop: any) { |
|
|
|
|
return Array.isArray(prop) ? prop[0] : prop; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -170,11 +172,12 @@ function findAttribute(attrs: string, propName: string): string { |
|
|
|
|
const index = Object.keys(attrs).find(attr => { |
|
|
|
|
return attr.toLowerCase() === propName.toLowerCase() || attr.toLowerCase() === kebabCase(propName); |
|
|
|
|
}); |
|
|
|
|
// @ts-ignore
|
|
|
|
|
return attrs[index]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// get watch depth of prop (string or array)
|
|
|
|
|
function getPropWatchDepth(defaultWatch, prop) { |
|
|
|
|
function getPropWatchDepth(defaultWatch: string, prop: string | any[]) { |
|
|
|
|
const customWatchDepth = Array.isArray(prop) && angular.isObject(prop[1]) && prop[1].watchDepth; |
|
|
|
|
return customWatchDepth || defaultWatch; |
|
|
|
|
} |
|
|
|
@ -197,11 +200,11 @@ function getPropWatchDepth(defaultWatch, prop) { |
|
|
|
|
// }
|
|
|
|
|
// }));
|
|
|
|
|
//
|
|
|
|
|
const reactComponent = $injector => { |
|
|
|
|
const reactComponent = ($injector: any): any => { |
|
|
|
|
return { |
|
|
|
|
restrict: 'E', |
|
|
|
|
replace: true, |
|
|
|
|
link: function(scope, elem, attrs) { |
|
|
|
|
link: function(scope: any, elem: Element[], attrs: any) { |
|
|
|
|
const reactComponent = getReactComponent(attrs.name, $injector); |
|
|
|
|
|
|
|
|
|
const renderMyComponent = () => { |
|
|
|
@ -254,12 +257,12 @@ const reactComponent = $injector => { |
|
|
|
|
//
|
|
|
|
|
// <hello name="name"/>
|
|
|
|
|
//
|
|
|
|
|
const reactDirective = $injector => { |
|
|
|
|
return (reactComponentName, props, conf, injectableProps) => { |
|
|
|
|
const reactDirective = ($injector: auto.IInjectorService) => { |
|
|
|
|
return (reactComponentName: string, props: string[], conf: any, injectableProps: any) => { |
|
|
|
|
const directive = { |
|
|
|
|
restrict: 'E', |
|
|
|
|
replace: true, |
|
|
|
|
link: function(scope, elem, attrs) { |
|
|
|
|
link: function(scope: any, elem: Element[], attrs: any) { |
|
|
|
|
const reactComponent = getReactComponent(reactComponentName, $injector); |
|
|
|
|
|
|
|
|
|
// if props is not defined, fall back to use the React component's propTypes if present
|
|
|
|
@ -267,8 +270,8 @@ const reactDirective = $injector => { |
|
|
|
|
|
|
|
|
|
// for each of the properties, get their scope value and set it to scope.props
|
|
|
|
|
const renderMyComponent = () => { |
|
|
|
|
let scopeProps = {}; |
|
|
|
|
const config = {}; |
|
|
|
|
let scopeProps: any = {}; |
|
|
|
|
const config: any = {}; |
|
|
|
|
|
|
|
|
|
props.forEach(prop => { |
|
|
|
|
const propName = getPropName(prop); |
|
|
|
|