diff --git a/.babelrc b/.babelrc
new file mode 100644
index 0000000..118d755
--- /dev/null
+++ b/.babelrc
@@ -0,0 +1,9 @@
+{
+ "plugins": [
+ "add-module-exports",
+ "transform-es2015-modules-commonjs",
+ "transform-es2015-destructuring",
+ "transform-object-rest-spread",
+ ["transform-react-jsx", { "pragma": "h" }]
+ ]
+}
diff --git a/.eslintrc.json b/.eslintrc.json
new file mode 100644
index 0000000..7ebc82f
--- /dev/null
+++ b/.eslintrc.json
@@ -0,0 +1,54 @@
+{
+ // http://eslint.org/docs/rules/
+ "root": true,
+ "parser": "babel-eslint",
+ "extends": "eslint:recommended",
+ "parserOptions": {
+ "ecmaVersion": 7,
+ "sourceType": "module",
+ "ecmaFeatures": {
+ "jsx": [1, { "pragma": "h" }],
+ "globalReturn ": true,
+ "impliedStrict": true
+ }
+ },
+ "env": {
+ "browser": true,
+ "mocha": true,
+ "node": true,
+ "es6": true
+ },
+ "rules": {
+ "semi": 0,
+ "no-var": 0,
+ "vars-on-top": 0,
+ "spaced-comment": 0,
+ "prefer-template": 0,
+ "no-unused-vars": 0,
+ "no-inner-declarations": 0,
+ "consistent-return": 0,
+ "comma-dangle": 0,
+ "no-use-before-define": 0,
+ "no-return-assign": 0,
+ "no-console": 0,
+ "max-len": 0,
+ "arrow-body-style": 0,
+ "new-cap": 0,
+ "quotes": 0,
+ "quote-props": 0,
+ "prefer-arrow-callback": 0,
+ "func-names": 0,
+ "padded-blocks": 0,
+ "keyword-spacing": 0,
+ "no-global-assign": 0,
+ "no-trailing-spaces": 0,
+ "no-unused-expressions": 0,
+ "space-before-function-paren": 0,
+ "global-require": 0,
+ "react/jsx-no-bind": 0,
+ "react/jsx-space-before-closing": 0,
+ "react/jsx-closing-bracket-location": 0,
+ "react/prop-types": 0,
+ "react/prefer-stateless-function": 0
+ }
+}
diff --git a/DOM.js b/DOM.js
new file mode 100644
index 0000000..2af1b1b
--- /dev/null
+++ b/DOM.js
@@ -0,0 +1,40 @@
+/* eslint-disable */
+var jsdom = require('jsdom');
+
+// Setup the jsdom environment
+// @see https://github.com/facebook/react/issues/5046
+global.document = jsdom.jsdom('
');
+global.window = document.defaultView;
+global.navigator = global.window.navigator;
+global.usingJSDOM = true;
+
+global.chai = require('chai');
+global.expect = global.chai.expect;
+global.SVGElement = global.Element;
+
+//JSDOM doesn't support localStorage by default, so lets just fake it..
+if (!global.window.localStorage) {
+ global.window.localStorage = {
+ getItem() { return '{}'; },
+ setItem() {}
+ };
+}
+
+// take all properties of the window object and also attach it to the
+// mocha global object
+propagateToGlobal(global.window);
+
+// from mocha-jsdom https://github.com/rstacruz/mocha-jsdom/blob/master/index.js#L80
+function propagateToGlobal (window) {
+ for (var key in window) {
+ if (!window.hasOwnProperty(key)) continue;
+ if (key in global) continue;
+
+ global[key] = window[key];
+ }
+}
+if (!global.requestAnimationFrame) {
+ global.requestAnimationFrame = function (func) {
+ setTimeout(func, 1000 / 60);
+ }
+}
diff --git a/README.md b/README.md
index c8a5d9b..96fc50d 100644
--- a/README.md
+++ b/README.md
@@ -7,10 +7,15 @@
+
This is a fork of [mobx-react](https://github.com/mobxjs/mobx-react) for [Preact](https://preactjs.com/)
This package provides the bindings for [MobX](https://mobxjs.github.io/mobx).
+**_It's not really maintained, if someone wants to take over, ping me on github!_**
+
+Consider using [mobx-observer](https://www.npmjs.com/package/mobx-observer) or another library instead.
+
Exports the `connect` (or alias `observer`) decorator and some development utilities.
## Installation
diff --git a/mocha.opts b/mocha.opts
index 59735e6..a202fec 100644
--- a/mocha.opts
+++ b/mocha.opts
@@ -1,4 +1,6 @@
+-r babel-register
+--require ./DOM.js
--recursive
--colors
-test/**/*.js
+test/*.js
diff --git a/package.json b/package.json
index 905a9e6..a3225c4 100644
--- a/package.json
+++ b/package.json
@@ -36,10 +36,30 @@
"@types/core-js": "^0.9.35",
"@types/mocha": "^2.2.39",
"@types/node": "^7.0.5",
+ "babel-eslint": "^7.1.1",
+ "babel-plugin-add-module-exports": "0.2.1",
+ "babel-plugin-transform-es2015-arrow-functions": "6.8.0",
+ "babel-plugin-transform-es2015-block-scoped-functions": "6.8.0",
+ "babel-plugin-transform-es2015-block-scoping": "6.21.0",
+ "babel-plugin-transform-es2015-classes": "6.18.0",
+ "babel-plugin-transform-es2015-computed-properties": "6.8.0",
+ "babel-plugin-transform-es2015-destructuring": "6.19.0",
+ "babel-plugin-transform-es2015-literals": "6.8.0",
+ "babel-plugin-transform-es2015-modules-commonjs": "6.18.0",
+ "babel-plugin-transform-es2015-parameters": "6.21.0",
+ "babel-plugin-transform-es2015-shorthand-properties": "6.18.0",
+ "babel-plugin-transform-es2015-spread": "6.8.0",
+ "babel-plugin-transform-es2015-template-literals": "6.8.0",
+ "babel-plugin-transform-object-rest-spread": "^6.20.2",
+ "babel-plugin-transform-react-jsx": "^6.22.0",
+ "babel-register": "^6.22.0",
"chai": "^3.5.0",
+ "eslint": "^3.15.0",
+ "jsdom": "^9.10.0",
"mobx": "^3.1.0",
"mocha": "^3.2.0",
"preact": "^7.1.0",
+ "ts-node": "^2.0.0",
"tslint": "^4.4.2",
"typescript": "^2.1.5"
}
diff --git a/src/EventEmitter.ts b/src/EventEmitter.js
similarity index 57%
rename from src/EventEmitter.ts
rename to src/EventEmitter.js
index 5999713..4332326 100644
--- a/src/EventEmitter.ts
+++ b/src/EventEmitter.js
@@ -1,8 +1,9 @@
-export default class EventEmitter {
-
- private listeners: Function[] = [];
+class EventEmitter {
+ constructor() {
+ this.listeners = [];
+ }
- public on(cb: Function) {
+ on(cb) {
this.listeners.push(cb);
return () => {
const index = this.listeners.indexOf(cb);
@@ -12,15 +13,17 @@ export default class EventEmitter {
};
}
- public emit(data: any) {
+ emit(data) {
this.listeners.forEach((fn) => fn(data));
- };
+ }
- public getTotalListeners(): number {
+ getTotalListeners() {
return this.listeners.length;
}
- public clearListeners(): void {
+ clearListeners() {
this.listeners = [];
}
}
+
+export default EventEmitter
diff --git a/src/Provider.ts b/src/Provider.js
similarity index 76%
rename from src/Provider.ts
rename to src/Provider.js
index 9dd8a94..07f1fbf 100644
--- a/src/Provider.ts
+++ b/src/Provider.js
@@ -14,38 +14,24 @@ function childOnly(children) {
return children.length ? children[0] : children;
}
-export default class Provider extends Component {
- contextTypes: any = {
- mobxStores() {
- }
- };
- childContextTypes: any = {
- mobxStores() {
- }
- };
- private store: any;
-
- constructor(props?: any, context?: any) {
+class Provider extends Component {
+ constructor(props, context) {
super(props, context);
this.store = props.store;
}
- public render() {
- return childOnly(this.props.children);
- }
-
getChildContext() {
- let stores = {};
+ const stores = {};
// inherit stores
- let baseStores = this.context.mobxStores;
+ const baseStores = this.context.mobxStores;
if (baseStores) {
- for (let key in baseStores) {
+ for (const key in baseStores) {
stores[key] = baseStores[key];
}
}
// add own stores
- for (let key in this.props) {
+ for (const key in this.props) {
if (!specialKeys[key]) {
stores[key] = this.props[key];
}
@@ -54,6 +40,10 @@ export default class Provider extends Component {
mobxStores: stores
};
}
+
+ render() {
+ return childOnly(this.props.children);
+ }
}
if (process.env.NODE_ENV !== 'production') {
@@ -64,7 +54,7 @@ if (process.env.NODE_ENV !== 'production') {
'MobX Provider: The set of provided stores has changed. ' +
'Please avoid changing stores as the change might not propagate to all children'
);
- for (let key in nextProps) {
+ for (const key in nextProps) {
warning(specialKeys[key] || this.props[key] === nextProps[key],
`MobX Provider: Provided store '${key}' has changed. ` +
`Please avoid replacing stores as the change might not propagate to all children`
@@ -74,3 +64,12 @@ if (process.env.NODE_ENV !== 'production') {
};
}
+Provider.contextTypes = {
+ mobxStores() {}
+};
+
+Provider.childContextTypes = {
+ mobxStores() {}
+};
+
+export default Provider
diff --git a/src/connect.ts b/src/connect.js
similarity index 90%
rename from src/connect.ts
rename to src/connect.js
index 4ab8ac8..e65d5a5 100644
--- a/src/connect.ts
+++ b/src/connect.js
@@ -1,4 +1,3 @@
-import invariant = require('invariant');
import { Component } from 'preact';
import createClass from 'preact-classless-component';
import inject from './inject';
@@ -8,7 +7,7 @@ import { throwError } from './utils/shared';
/**
* Wraps a component and provides stores as props
*/
-function connect (arg1: any, arg2 = null): any {
+function connect (arg1, arg2 = null) {
if (typeof arg1 === 'string') {
throwError('Store names should be provided as array');
}
@@ -39,7 +38,7 @@ function connect (arg1: any, arg2 = null): any {
contextTypes: componentClass.contextTypes,
getDefaultProps: () => componentClass.defaultProps,
render() {
- return componentClass.call(this, this.props, this.state, this.context);
+ return componentClass.call(this, this.props, this.context, this.context);
}
});
diff --git a/src/index.ts b/src/index.js
similarity index 100%
rename from src/index.ts
rename to src/index.js
diff --git a/src/inject.ts b/src/inject.js
similarity index 74%
rename from src/inject.ts
rename to src/inject.js
index a43b617..7ffa655 100644
--- a/src/inject.ts
+++ b/src/inject.js
@@ -1,19 +1,15 @@
-import hoistStatics = require('hoist-non-react-statics');
+import hoistStatics from 'hoist-non-react-statics';
import { h } from 'preact';
import createComponent from 'preact-classless-component';
-interface IStoreProps {
- ref: any;
-}
-
/**
* Store Injection
*/
-function createStoreInjector(grabStoresFn: Function, component) {
- const Injector: any = createComponent({
+function createStoreInjector(grabStoresFn, component) {
+ const Injector = createComponent({
displayName: component.name,
render() {
- const newProps = {};
+ const newProps = {};
for (let key in this.props) {
if (this.props.hasOwnProperty(key)) {
newProps[key] = this.props[key];
@@ -41,8 +37,8 @@ function createStoreInjector(grabStoresFn: Function, component) {
return Injector;
}
-const grabStoresByName = function(storeNames: string[]): Function {
- return function(baseStores: Object, nextProps: Object): Object {
+const grabStoresByName = function(storeNames) {
+ return function(baseStores, nextProps) {
storeNames.forEach(function(storeName) {
// Prefer props over stores
@@ -69,11 +65,11 @@ const grabStoresByName = function(storeNames: string[]): Function {
* or a function that manually maps the available stores from the context to props:
* storesToProps(mobxStores, props, context) => newProps
*/
-export default function inject(grabStoresFn?: Function | string): any {
+export default function inject(grabStoresFn) {
if (typeof grabStoresFn !== 'function') {
- let storesNames: any = [];
+ let storesNames = [];
for (let i = 0; i < arguments.length; i++) {
storesNames[i] = arguments[i];
}
@@ -81,5 +77,5 @@ export default function inject(grabStoresFn?: Function | string): any {
grabStoresFn = grabStoresByName(storesNames);
}
- return (componentClass) => createStoreInjector(grabStoresFn as Function, componentClass);
+ return (componentClass) => createStoreInjector(grabStoresFn, componentClass);
}
diff --git a/src/makeReactive.ts b/src/makeReactive.js
similarity index 93%
rename from src/makeReactive.ts
rename to src/makeReactive.js
index 4dfe5bc..ddc5b1b 100644
--- a/src/makeReactive.ts
+++ b/src/makeReactive.js
@@ -8,7 +8,7 @@ import { throwError } from './utils/shared';
*/
let isDevtoolsEnabled = false;
-export const componentByNodeRegistery: WeakMap = new WeakMap();
+export const componentByNodeRegistery = new WeakMap();
export const renderReporter = new EventEmitter();
function reportRendering(component) {
@@ -35,11 +35,6 @@ export function trackComponents() {
}
}
-interface IReactiveRender {
- $mobx?: Reaction;
- (nextProps, nextState, nextContext): void;
-}
-
export default function makeReactive(componentClass) {
const target = componentClass.prototype || componentClass;
@@ -52,7 +47,7 @@ export default function makeReactive(componentClass) {
// Call original
baseWillMount && baseWillMount.call(this);
- let reaction: Reaction;
+ let reaction;
let isRenderingPending = false;
const initialName = this.displayName || this.name || (this.constructor && (this.constructor.displayName || this.constructor.name)) || '';
@@ -80,7 +75,7 @@ export default function makeReactive(componentClass) {
return reactiveRender(nextProps, nextState, nextContext);
};
- const reactiveRender: IReactiveRender = (nextProps, nextState, nextContext) => {
+ const reactiveRender = (nextProps, nextState, nextContext) => {
isRenderingPending = false;
let rendering = undefined;
reaction.track(() => {
diff --git a/src/utils/shared.ts b/src/utils/shared.js
similarity index 51%
rename from src/utils/shared.ts
rename to src/utils/shared.js
index 2037ab2..8d578a1 100644
--- a/src/utils/shared.ts
+++ b/src/utils/shared.js
@@ -1,9 +1,9 @@
-export function warning(condition, message: string) {
+export function warning(condition, message) {
if (!condition) {
console.error(message);
}
}
-export function throwError(message?: string) {
+export function throwError(message) {
throw new Error(`MobX-Preact Error: ${ message }`);
}
diff --git a/test/connect.spec.ts b/test/connect.spec.js
similarity index 92%
rename from test/connect.spec.ts
rename to test/connect.spec.js
index 3ad7d08..eaae0b9 100644
--- a/test/connect.spec.ts
+++ b/test/connect.spec.js
@@ -1,3 +1,4 @@
+import 'mocha';
import { expect } from 'chai';
import { h, render, Component } from 'preact';
import Provider from '../src/Provider';
@@ -27,7 +28,7 @@ describe('MobX inject()', () => {
let container;
beforeEach(() => {
- container = document.createElement('div') as HTMLElement;
+ container = document.createElement('div');
container.style.display = 'none';
document.body.appendChild(container);
});
@@ -37,7 +38,7 @@ describe('MobX inject()', () => {
render(null, container);
});
- class TestComponent extends Component {
+ class TestComponent extends Component {
render({ testStore }) {
return h('span', null, testStore);
}
@@ -91,16 +92,16 @@ describe('MobX inject()', () => {
it('should create class with injected stores', () => {
- class TestClass extends Component {
- static defaultProps = {
- world: 'world'
- };
-
+ class TestClass extends Component {
render({ hello, world }) {
return h('span', null, hello + ' ' + world);
}
}
+ TestClass.defaultProps = {
+ world: 'world'
+ }
+
function App() {
return h(Provider, {
hello: 'hello'
diff --git a/test/eventemitter.spec.ts b/test/eventemitter.spec.js
similarity index 88%
rename from test/eventemitter.spec.ts
rename to test/eventemitter.spec.js
index 619a340..f09325d 100644
--- a/test/eventemitter.spec.ts
+++ b/test/eventemitter.spec.js
@@ -1,15 +1,16 @@
+import 'mocha';
import { expect } from 'chai';
import EventEmitter from '../src/EventEmitter';
const testData = {
testKey: 'testData',
};
-const testListener = function(data: any) {
+const testListener = function(data) {
expect(data).to.equal(testData);
};
describe('mobx - EventEmitter', () => {
- it('should have an empty listner array on construction', () => {
+ it('should have an empty listeners array on construction', () => {
const unit = new EventEmitter();
expect(unit.getTotalListeners()).to.equal(0);
});
diff --git a/test/makeReactive.spec.tsx b/test/makeReactive.spec.js
similarity index 86%
rename from test/makeReactive.spec.tsx
rename to test/makeReactive.spec.js
index ed8ef19..5d3f5b0 100644
--- a/test/makeReactive.spec.tsx
+++ b/test/makeReactive.spec.js
@@ -1,11 +1,12 @@
+import 'mocha';
import { observable, extendObservable, toJS } from 'mobx';
import { expect } from 'chai';
-import { render, Component } from 'preact';
+import { h, render, Component } from 'preact';
import makeReactive from '../src/makeReactive';
let todoListRenderings = 0;
let todoListWillReactCount = 0;
-let store = {
+const store = {
todos: observable(['one', 'two']),
extra: observable({ test: 'observable!' })
};
@@ -14,7 +15,7 @@ describe('MobX Observer', () => {
let container;
beforeEach(() => {
- container = document.createElement('div') as HTMLElement;
+ container = document.createElement('div');
container.style.display = 'none';
document.body.appendChild(container);
});
@@ -28,14 +29,14 @@ describe('MobX Observer', () => {
return { todo };
});
- const TodoList = makeReactive(class extends Component {
+ const TodoList = makeReactive(class extends Component {
componentWillReact() {
todoListWillReactCount++;
}
render() {
todoListRenderings++;
- let todos = store.todos;
+ const todos = store.todos;
return {todos.map(todo => )}
;
}
});
@@ -56,7 +57,7 @@ describe('MobX Observer', () => {
});
it('should render a todo list with non observale item', () => {
- const FlatList = makeReactive(class extends Component {
+ const FlatList = makeReactive(class extends Component {
render({ extra }) {
return {store.todos.map(title =>
{ title }{ extra.test })};
}
diff --git a/test/provider.spec.tsx b/test/provider.spec.js
similarity index 88%
rename from test/provider.spec.tsx
rename to test/provider.spec.js
index 4a4c341..62d8754 100644
--- a/test/provider.spec.tsx
+++ b/test/provider.spec.js
@@ -1,6 +1,7 @@
+import 'mocha';
import { observable } from 'mobx';
import { expect } from 'chai';
-import { render, Component } from 'preact';
+import { h, render, Component } from 'preact';
import Provider from '../src/Provider';
import connect from '../src/connect';
@@ -8,7 +9,7 @@ describe('MobX Provider', () => {
let container;
beforeEach(() => {
- container = document.createElement('div') as HTMLElement;
+ container = document.createElement('div');
container.style.display = 'none';
document.body.appendChild(container);
});
@@ -19,7 +20,7 @@ describe('MobX Provider', () => {
});
describe('updating state', () => {
- let stores: any = observable({
+ const stores = observable({
store1: {
data: 'one'
},
@@ -28,7 +29,7 @@ describe('MobX Provider', () => {
}
});
- const Statefull = connect(['store1'], class extends Component {
+ const Statefull = connect(['store1'], class extends Component {
render({ store1 }) {
const update = () => store1.data = 'Statefull';
@@ -66,7 +67,7 @@ describe('MobX Provider', () => {
it('should update a statefull component', () => {
render(, container);
- const link = container.querySelector('#update') as HTMLElement;
+ const link = container.querySelector('#update');
link.click();
expect(container.innerHTML).to.equal('updateStatefull');
@@ -75,7 +76,7 @@ describe('MobX Provider', () => {
it('should update a stateless component', () => {
render(, container);
- const link = container.querySelector('#update') as HTMLElement;
+ const link = container.querySelector('#update');
link.click();
expect(container.innerHTML).to.equal('updateStateless');
@@ -84,7 +85,7 @@ describe('MobX Provider', () => {
it('should update a stateless component with stores', () => {
render(, container);
- const link = container.querySelector('#update') as HTMLElement;
+ const link = container.querySelector('#update');
link.click();
expect(container.innerHTML).to.equal('updatehello world');
@@ -92,7 +93,7 @@ describe('MobX Provider', () => {
});
describe('providing/updating stores', () => {
- let stores: any = observable({
+ const stores = observable({
store1: {
data: 'one'
},
diff --git a/test/tracking.spec.ts b/test/tracking.spec.js
similarity index 96%
rename from test/tracking.spec.ts
rename to test/tracking.spec.js
index 1a42f0c..3043a92 100644
--- a/test/tracking.spec.ts
+++ b/test/tracking.spec.js
@@ -1,3 +1,4 @@
+import 'mocha';
import { expect } from 'chai';
import { trackComponents } from '../src/makeReactive';
diff --git a/tsconfig.json b/tsconfig.json
deleted file mode 100644
index be5c272..0000000
--- a/tsconfig.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "compilerOptions": {
- "target": "es5",
- "module": "commonjs",
- "allowJs": true,
- "allowSyntheticDefaultImports": true,
- "sourceMap": false,
- "outDir": "./lib",
- "lib": [
- "es6",
- "es7",
- "dom"
- ],
- "types": [
- "node",
- "chai",
- "mocha"
- ],
- "jsx": "preserve",
- "noUnusedLocals": true,
- "strictNullChecks": false,
- "removeComments": false
- },
- "include": [
- "src/**/*"
- ],
- "exclude": [
- "node_modules"
- ]
-}
diff --git a/tslint.json b/tslint.json
deleted file mode 100644
index 900bbdf..0000000
--- a/tslint.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
- "extends": "tslint:latest",
- "rules": {
- "quotemark": ["single"],
- "forin": false,
- "no-empty": false,
- "indent": [
- "tabs"
- ],
- "arrow-parens": false,
- "trailing-comma": false,
- "ordered-imports": false,
- "no-namespace": false,
- "variable-name": [
- false
- ],
- "object-literal-sort-keys": false,
- "no-debugger": false,
- "interface-name": [
- false
- ],
- "max-classes-per-file": false,
- "max-line-length": [
- false
- ],
- "member-ordering": false,
- "only-arrow-functions": false,
- "member-access": [
- false
- ],
- "one-variable-per-declaration": false,
- "no-unused-expression": false,
- "no-bitwise": false,
- "prefer-for-of": false
- }
-}