diff --git a/examples/typescript/index.tsx b/examples/typescript/index.tsx
index a41b0560..cdf131a3 100755
--- a/examples/typescript/index.tsx
+++ b/examples/typescript/index.tsx
@@ -55,17 +55,19 @@ const routerConfig = (router: UIRouterReact) => {
let el = document.getElementById('react-app');
let app = (
-
-
-
-
- Home
-
-
-
}>
- Content will load here
-
-
-
+
+
+
+
+
+ Home
+
+
+
}>
+ Content will load here
+
+
+
+
);
ReactDOM.render(app, el);
diff --git a/examples/typescript/package.json b/examples/typescript/package.json
index b907e96b..c096466b 100644
--- a/examples/typescript/package.json
+++ b/examples/typescript/package.json
@@ -17,6 +17,6 @@
"tsconfig-paths-webpack-plugin": "^3.0.4",
"typescript": "2.8.3",
"webpack": "^4.7.0",
- "webpack-dev-server": "^3.1.4"
+ "webpack-dev-server": "3.7.1"
}
}
diff --git a/package.json b/package.json
index faf2fad7..c711029b 100644
--- a/package.json
+++ b/package.json
@@ -71,6 +71,7 @@
"react": "^16.5.1",
"react-dom": "^16.5.1",
"react-test-renderer": "^16.5.1",
+ "tsconfig-paths-webpack-plugin": "^3.2.0",
"ts-jest": "^23.1.3",
"ts-loader": "^6.0.2",
"typescript": "^3.0.1",
@@ -96,7 +97,7 @@
"testRegex": "/__tests__/.*\\.(ts|tsx|js)$",
"globals": {
"ts-jest": {
- "tsConfigFile": "../tsconfig.jest.json"
+ "tsConfigFile": "./tsconfig.jest.json"
}
}
},
diff --git a/src/components/UIRouter.tsx b/src/components/UIRouter.tsx
index 98125cbe..a83f92c1 100644
--- a/src/components/UIRouter.tsx
+++ b/src/components/UIRouter.tsx
@@ -3,10 +3,10 @@
* @module components
*/ /** */
import * as React from 'react';
-import { Component, Children } from 'react';
+import { Component } from 'react';
import * as PropTypes from 'prop-types';
-import { UIRouterPlugin, servicesPlugin } from '@uirouter/core';
+import { servicesPlugin } from '@uirouter/core';
import { UIRouterReact, ReactStateDeclaration } from '../index';
@@ -44,21 +44,21 @@ export interface UIRouterState {
/** @hidden */
export const InstanceOrPluginsMissingError = new Error(`Router instance or plugins missing.
-You must either provide a location plugin via the plugins prop:
-
-
-
-
-
-or initialize the router yourself and pass the instance via props:
-
-const router = new UIRouterReact();
-router.plugin(pushStateLocationPlugin);
-···
-
-
-
-`);
+ You must either provide a location plugin via the plugins prop:
+
+
+
+
+
+ or initialize the router yourself and pass the instance via props:
+
+ const router = new UIRouterReact();
+ router.plugin(pushStateLocationPlugin);
+ ···
+
+
+
+ `);
/** @hidden */
export const UIRouterInstanceUndefinedError = new Error(
@@ -76,24 +76,27 @@ export class UIRouter extends Component {
router: UIRouterReact;
- constructor(props, context) {
- super(props, context);
- // check if a router instance is provided
- if (props.router) {
- this.router = props.router;
- } else if (props.plugins) {
- this.router = new UIRouterReact();
- this.router.plugin(servicesPlugin);
- props.plugins.forEach(plugin => this.router.plugin(plugin));
- if (props.config) props.config(this.router);
- (props.states || []).forEach(state => this.router.stateRegistry.register(state));
- } else {
- throw InstanceOrPluginsMissingError;
+ componentDidMount() {
+ if (!this.router) {
+ // check if a router instance is provided
+ if (this.props.router) {
+ this.router = this.props.router;
+ } else if (this.props.plugins) {
+ this.router = new UIRouterReact();
+ this.router.plugin(servicesPlugin);
+ this.props.plugins.forEach(plugin => this.router.plugin(plugin));
+ if (this.props.config) this.props.config(this.router);
+ (this.props.states || []).forEach(state => this.router.stateRegistry.register(state));
+ } else {
+ throw InstanceOrPluginsMissingError;
+ }
+
+ this.router.start();
+ this.forceUpdate();
}
- this.router.start();
}
render() {
- return {this.props.children};
+ return this.router ? {this.props.children} : null;
}
}
diff --git a/src/components/UISref.tsx b/src/components/UISref.tsx
index 213a5e30..09a5ef3d 100644
--- a/src/components/UISref.tsx
+++ b/src/components/UISref.tsx
@@ -44,7 +44,7 @@ class Sref extends Component {
className: PropTypes.string,
};
- componentWillMount() {
+ componentDidMount() {
const addStateInfo = this.props.addStateInfoToParentActive;
this.deregister = typeof addStateInfo === 'function' ? addStateInfo(this.props.to, this.props.params) : () => {};
const router = this.props.router;
@@ -54,7 +54,9 @@ class Sref extends Component {
}
componentWillUnmount() {
- this.deregister();
+ if (this.deregister) {
+ this.deregister();
+ }
}
getOptions = () => {
diff --git a/src/components/UISrefActive.tsx b/src/components/UISrefActive.tsx
index 94a9d08c..22b078ec 100644
--- a/src/components/UISrefActive.tsx
+++ b/src/components/UISrefActive.tsx
@@ -3,11 +3,11 @@
* @module components
*/ /** */
import * as React from 'react';
-import { Component, cloneElement, ValidationMap } from 'react';
+import { Component, cloneElement } from 'react';
import * as PropTypes from 'prop-types';
import * as _classNames from 'classnames';
-import { UIRouterReact, UISref, UIRouterConsumer } from '../index';
+import { UIRouterReact, UIRouterConsumer } from '../index';
import { UIViewAddress } from './UIView';
import { UIRouterInstanceUndefinedError } from './UIRouter';
@@ -59,7 +59,7 @@ class SrefActive extends Component {
activeClasses: '',
};
- componentWillMount() {
+ componentDidMount() {
const router = this.props.router;
if (typeof router === 'undefined') {
throw UIRouterInstanceUndefinedError;
@@ -69,7 +69,9 @@ class SrefActive extends Component {
}
componentWillUnmount() {
- this.deregister();
+ if (this.deregister) {
+ this.deregister();
+ }
}
addStateInfo = (stateName, stateParams) => {
diff --git a/src/components/UIView.tsx b/src/components/UIView.tsx
index afb80cfa..eaddbd1d 100644
--- a/src/components/UIView.tsx
+++ b/src/components/UIView.tsx
@@ -8,13 +8,15 @@ import {
ClassicComponentClass,
Component,
ComponentClass,
+ createContext,
SFC,
+ ReactNode,
StatelessComponent,
ValidationMap,
Validator,
cloneElement,
createElement,
- isValidElement,
+ isValidElement
} from 'react';
import * as PropTypes from 'prop-types';
@@ -78,6 +80,7 @@ export interface UIViewInjectedProps {
/** Component Props for `UIView` */
export interface UIViewProps {
+ children?: ReactNode;
router?: UIRouterReact;
parentUIView?: UIViewAddress;
name?: string;
@@ -100,7 +103,7 @@ export const TransitionPropCollisionError = new Error(
);
/** @internalapi */
-export const { Provider: UIViewProvider, Consumer: UIViewConsumer } = React.createContext(undefined);
+export const { Provider: UIViewProvider, Consumer: UIViewConsumer } = createContext(undefined);
class View extends Component {
// This object contains all the metadata for this UIView
@@ -168,7 +171,7 @@ class View extends Component {
return {ChildOrRenderFunction};
}
- componentWillMount() {
+ componentDidMount() {
const router = this.props.router;
if (typeof router === 'undefined') {
throw UIRouterInstanceUndefinedError;
@@ -199,7 +202,9 @@ class View extends Component {
}
componentWillUnmount() {
- this.deregister();
+ if (this.deregister) {
+ this.deregister();
+ }
}
/**
@@ -262,9 +267,18 @@ class View extends Component {
}
}
-export class UIView extends React.Component {
+View.propTypes = {
+ router: PropTypes.object.isRequired as Validator,
+ parentUIView: PropTypes.object as Validator,
+ name: PropTypes.string,
+ className: PropTypes.string,
+ style: PropTypes.object,
+ render: PropTypes.func,
+} as ValidationMap;
+
+export class UIView extends Component {
static displayName = 'UIView';
- static __internalViewComponent: React.ComponentClass = View;
+ static __internalViewComponent: ComponentClass = View;
render() {
return (
diff --git a/src/components/__tests__/UISref.test.tsx b/src/components/__tests__/UISref.test.tsx
index 5ba4a21d..b7235f59 100644
--- a/src/components/__tests__/UISref.test.tsx
+++ b/src/components/__tests__/UISref.test.tsx
@@ -139,7 +139,8 @@ describe('', () => {
);
await router.stateService.go('state');
wrapper.update();
- const stateServiceGoSpy = jest.spyOn(wrapper.instance().router.stateService, 'go');
+ // @ts-ignore
+ const stateServiceGoSpy = jest.spyOn(router.stateService, 'go');
const link = wrapper.find('a');
link.simulate('click');
link.simulate('click', { button: 1 });
@@ -162,6 +163,7 @@ describe('', () => {
.find('Sref')
.at(0);
expect(uiSref.instance().context.parentUIViewAddress).toBeUndefined();
+ // @ts-ignore
expect(uiSref.instance().getOptions().relative.name).toBe('');
});
});
diff --git a/src/components/__tests__/UISrefActive.test.tsx b/src/components/__tests__/UISrefActive.test.tsx
index b3323127..e09e081c 100644
--- a/src/components/__tests__/UISrefActive.test.tsx
+++ b/src/components/__tests__/UISrefActive.test.tsx
@@ -204,6 +204,7 @@ describe('', () => {
.at(0)
.instance();
expect(instance.context.parentUIViewAddress).toBeUndefined();
+ // @ts-ignore
expect(instance.states[0].state.name).toBe('parent.child1');
});
@@ -232,6 +233,7 @@ describe('', () => {
.at(0)
.instance();
expect(instance.context.parentUIViewAddress).toBeUndefined();
+ // @ts-ignore
expect(instance.states.length).toBe(3);
});
@@ -266,6 +268,7 @@ describe('', () => {
.find('SrefActive')
.at(0)
.instance();
+ // @ts-ignore
expect(instance.states.length).toBe(3);
router.stateRegistry.register({
@@ -340,8 +343,10 @@ describe('', () => {
.find('SrefActive')
.at(0)
.instance();
+ // @ts-ignore
expect(instance.states.length).toBe(1);
wrapper.setProps({ show: false });
+ // @ts-ignore
expect(instance.states.length).toBe(0);
});
diff --git a/src/components/__tests__/UIView.test.tsx b/src/components/__tests__/UIView.test.tsx
index 3c0e030a..1e150654 100644
--- a/src/components/__tests__/UIView.test.tsx
+++ b/src/components/__tests__/UIView.test.tsx
@@ -106,15 +106,14 @@ describe('', () => {
states.forEach(state => router.stateRegistry.register(state as ReactStateDeclaration));
});
- it('renders its State Component', () => {
+ it('renders its State Component', async () => {
const wrapper = mount(
);
- return router.stateService.go('parent').then(() => {
- expect(wrapper.html()).toEqual(``);
- });
+ await router.stateService.go('parent');
+ expect(wrapper.update().html()).toEqual(``);
});
it('injects the right props', async () => {
@@ -131,7 +130,9 @@ describe('', () => {
);
await router.stateService.go('__state');
wrapper.update();
+ // @ts-ignore
expect(wrapper.find(Comp).props().myresolve).not.toBeUndefined();
+ // @ts-ignore
expect(wrapper.find(Comp).props().transition).not.toBeUndefined();
});
@@ -149,6 +150,7 @@ describe('', () => {
);
await router.stateService.go('__state');
wrapper.update();
+ // @ts-ignore
expect(wrapper.find(Comp).props().foo).toBe('bar');
});
@@ -208,9 +210,9 @@ describe('', () => {
);
await router.stateService.go('parent.child');
- expect(wrapper.html()).toEqual(`parentchild
`);
+ expect(wrapper.update().html()).toEqual(`parentchild
`);
await router.stateService.go('parent');
- expect(wrapper.html()).toEqual(``);
+ expect(wrapper.update().html()).toEqual(``);
});
it('calls uiCanExit function of its State Component when unmounting', async () => {
@@ -239,9 +241,9 @@ describe('', () => {
);
await router.stateService.go('__state');
- expect(wrapper.html()).toEqual('UiCanExitHookComponent');
+ expect(wrapper.update().html()).toEqual('UiCanExitHookComponent');
await router.stateService.go('exit');
- expect(wrapper.html()).toEqual('exit');
+ expect(wrapper.update().html()).toEqual('exit');
expect(uiCanExitSpy).toBeCalled();
});
@@ -273,9 +275,9 @@ describe('', () => {
);
await router.stateService.go('__state');
console.log(wrapper.html());
- expect(wrapper.html()).toEqual('UiCanExitHookComponent');
+ expect(wrapper.update().html()).toEqual('UiCanExitHookComponent');
await router.stateService.go('exit');
- expect(wrapper.html()).toEqual('exit');
+ expect(wrapper.update().html()).toEqual('exit');
expect(uiCanExitSpy).toBeCalled();
});
@@ -300,7 +302,7 @@ describe('', () => {
);
await router.stateService.go('withrenderprop');
- expect(wrapper.html()).toEqual(`withrenderpropbar
`);
+ expect(wrapper.update().html()).toEqual(`withrenderpropbar
`);
});
it('unmounts the State Component when calling stateService.reload(true)', async () => {
diff --git a/src/core.ts b/src/core.ts
index 76d4bc0c..05e4b13d 100644
--- a/src/core.ts
+++ b/src/core.ts
@@ -2,8 +2,8 @@
* @reactapi
* @module react
*/ /** */
-import { UIRouter, PathNode, services } from '@uirouter/core';
-import { ReactViewDeclaration, ReactStateDeclaration } from './interface';
+import { UIRouter, PathNode } from '@uirouter/core';
+import { ReactViewDeclaration } from './interface';
import { ReactViewConfig, reactViewsBuilder } from './reactViews';
/**
diff --git a/src/interface.tsx b/src/interface.tsx
index 46a816e0..2a24b784 100644
--- a/src/interface.tsx
+++ b/src/interface.tsx
@@ -2,9 +2,9 @@
* @reactapi
* @module react
*/ /** */
-import { Component, ReactElement, StatelessComponent, ComponentClass, ClassicComponentClass } from 'react';
+import { StatelessComponent, ComponentClass, ClassicComponentClass } from 'react';
-import { StateDeclaration, _ViewDeclaration, ParamDeclaration, IInjectable, Transition } from '@uirouter/core';
+import { StateDeclaration, _ViewDeclaration, Transition } from '@uirouter/core';
/**
* The StateDeclaration object is used to define a state or nested state.
diff --git a/tsconfig.jest.json b/tsconfig.jest.json
index 02328abc..75a19593 100644
--- a/tsconfig.jest.json
+++ b/tsconfig.jest.json
@@ -1,5 +1,5 @@
{
- "compilerOption": {
+ "compilerOptions": {
"jsx": "react",
"module": "commonjs",
"target": "es6"