diff --git a/package-lock.json b/package-lock.json
index b8f11cf..7d6f728 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -7960,8 +7960,7 @@
"hoist-non-react-statics": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.0.tgz",
- "integrity": "sha512-6Bl6XsDT1ntE0lHbIhr4Kp2PGcleGZ66qu5Jqk8lc0Xc/IeG6gVLmwUGs/K0Us+L8VWoKgj0uWdPMataOsm31w==",
- "dev": true
+ "integrity": "sha512-6Bl6XsDT1ntE0lHbIhr4Kp2PGcleGZ66qu5Jqk8lc0Xc/IeG6gVLmwUGs/K0Us+L8VWoKgj0uWdPMataOsm31w=="
},
"home-or-tmp": {
"version": "2.0.0",
@@ -12224,6 +12223,20 @@
"minimist": "0.0.8"
}
},
+ "mobx": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/mobx/-/mobx-5.0.3.tgz",
+ "integrity": "sha1-U7l/Kg+bDdd3TJYkn4G/LVE9jhw="
+ },
+ "mobx-react": {
+ "version": "5.2.3",
+ "resolved": "https://registry.npmjs.org/mobx-react/-/mobx-react-5.2.3.tgz",
+ "integrity": "sha512-OuSlF2nJEa1PGookZcZnINbvEK4iWNNYiqUh6aebk2AkWxj3sG8OafDOQMcMYApQALTHRsrBIjOx/K8TFxcz7w==",
+ "requires": {
+ "hoist-non-react-statics": "^2.5.0",
+ "react-lifecycles-compat": "^3.0.2"
+ }
+ },
"moment": {
"version": "2.22.2",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz",
@@ -15694,6 +15707,11 @@
}
}
},
+ "react-lifecycles-compat": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
+ "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
+ },
"read-all-stream": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.1.0.tgz",
diff --git a/package.json b/package.json
index 19ec5f1..14815b9 100644
--- a/package.json
+++ b/package.json
@@ -19,8 +19,8 @@
"build": "npm run clean-dist && webpack -p --config=configs/webpack/prod.js",
"clean-dist": "rm -f -r -d dist",
"lint": "npm run lint:ts && npm run lint:sass",
- "lint:ts": "tslint './src/**/*.ts*' --format stylish --force",
- "lint:sass": "stylelint ./src/**/*.scss",
+ "lint:ts": "tslint './src/**/**/*.ts*' './src/**/*.ts*' './src/*.ts*' './*.ts*' --format stylish --force",
+ "lint:sass": "stylelint ./src/**/**/*.scss ./src/**/*.scss ./src/*.scss",
"start": "npm run start-dev",
"start-dev": "webpack-dev-server --config=configs/webpack/dev.js",
"test": "npm-run-all test:unit test:e2e",
@@ -72,6 +72,9 @@
"webpack-dev-server": "^3.1.4",
"webpack-merge": "^4.1.2"
},
- "dependencies": {},
+ "dependencies": {
+ "mobx": "^5.0.3",
+ "mobx-react": "^5.2.3"
+ },
"postcss": {}
}
diff --git a/plop-templates/component.tsx b/plop-templates/component.tsx
index 4511667..6351779 100644
--- a/plop-templates/component.tsx
+++ b/plop-templates/component.tsx
@@ -1,14 +1,24 @@
-import * as React from 'react';
-import './{{ properCase name}}.scss';
+import * as React from "react";
+{{#if observer}}
+import { observer } from "mobx-react";
+import {{ camelCase store_name }} from "../../stores/{{ properCase store_name }}";
+{{/if}}
+import "./{{ properCase name}}.scss";
export interface {{ properCase name }}Props {}
-export default class {{ properCase name }} extends React.Component<{{ properCase name }}Props, undefined> {
- render() {
- return (
-
+{{#if observer}}@observer{{/if}} class {{ properCase name }} extends React.Component<{{ properCase name }}Props, undefined> {
+ render() {
+ return (
+
{{ titleCase name }}
-
- );
- }
+
+ );
+ }
}
+
+{{#if observer}}
+export default (props) => <{{ properCase name }} {{ camelCase store_name }}={ {{ camelCase store_name }} } { ...props } />;
+{{else}}
+export default <{{ properCase name }} />;
+{{/if}}
\ No newline at end of file
diff --git a/plop-templates/index.ts b/plop-templates/index.ts
index 2955f8c..e909ea6 100644
--- a/plop-templates/index.ts
+++ b/plop-templates/index.ts
@@ -1,2 +1,2 @@
-import {{ properCase name }} from './{{ properCase name }}';
-export default {{ properCase name }};
\ No newline at end of file
+import {{ properCase name }} from "./{{ properCase name }}";
+export default {{ properCase name }};
diff --git a/plop-templates/store.ts b/plop-templates/store.ts
new file mode 100644
index 0000000..1615f02
--- /dev/null
+++ b/plop-templates/store.ts
@@ -0,0 +1,13 @@
+import { observable, action } from "mobx";
+import { observer } from "mobx-react";
+
+class {{ properCase name }} {
+ @observable counter = 0;
+
+ @action.bound
+ increment() {
+ this.counter += 1;
+ }
+}
+
+export default new {{ properCase name }}();
diff --git a/plopfile.ts b/plopfile.ts
index de772b3..6291b3c 100644
--- a/plopfile.ts
+++ b/plopfile.ts
@@ -1,33 +1,63 @@
module.exports = function(plop) {
- // create your generators here
- plop.setGenerator('New component', {
- description: 'Create a new TSX + SCSS component for React.',
- prompts: [
- {
- type: 'input',
- name: 'name',
- message: 'Component name'
- }
- ], // array of inquirer prompts
- actions: [
- {
- type: 'add',
- path: 'src/components/{{ properCase name }}/{{ properCase name }}.tsx',
- templateFile: 'plop-templates/component.tsx',
- abortOnFail: true
- },
- {
- type: 'add',
- path: 'src/components/{{ properCase name }}/{{ properCase name }}.scss',
- templateFile: 'plop-templates/component.scss',
- abortOnFail: true
- },
- {
- type: 'add',
- path: 'src/components/{{ properCase name }}/index.ts',
- templateFile: 'plop-templates/index.ts',
- abortOnFail: true
- }
- ] // array of actions
- });
+ // create your generators here
+ plop.setGenerator("New component", {
+ description: "Create a new TSX + SCSS component for React.",
+ prompts: [
+ {
+ type: "input",
+ name: "name",
+ message: "Component name:"
+ },
+ {
+ type: "list",
+ choices: [{ name: "No, it does not observe a store", value: false }, { name: "Yes, it observes a store", value: true }],
+ name: "observer",
+ message: "Is the component a MobX observer?"
+ },
+ {
+ type: "input",
+ name: "store_name",
+ message: "MobX store name:",
+ when: answers => answers.observer
+ },
+ ], // array of inquirer prompts
+ actions: [
+ {
+ type: "add",
+ path: "src/components/{{ properCase name }}/{{ properCase name }}.tsx",
+ templateFile: "plop-templates/component.tsx",
+ abortOnFail: true
+ },
+ {
+ type: "add",
+ path: "src/components/{{ properCase name }}/{{ properCase name }}.scss",
+ templateFile: "plop-templates/component.scss",
+ abortOnFail: true
+ },
+ {
+ type: "add",
+ path: "src/components/{{ properCase name }}/index.ts",
+ templateFile: "plop-templates/index.ts",
+ abortOnFail: true
+ }
+ ] // array of actions
+ });
+ plop.setGenerator("New MobX state store", {
+ description: "Create a new store for MobX.",
+ prompts: [
+ {
+ type: "input",
+ name: "name",
+ message: "Store name:"
+ }
+ ], // array of inquirer prompts
+ actions: [
+ {
+ type: "add",
+ path: "src/stores/{{ properCase name }}.ts",
+ templateFile: "plop-templates/store.ts",
+ abortOnFail: true
+ }
+ ] // array of actions
+ });
};
diff --git a/src/components/App/App.tsx b/src/components/App/App.tsx
index 367760d..ffda586 100644
--- a/src/components/App/App.tsx
+++ b/src/components/App/App.tsx
@@ -1,18 +1,28 @@
import * as React from "react";
+import { observer } from "mobx-react";
import "./App.scss";
-
-const reactLogo = require("../../assets/img/react_logo.svg");
+import appState from "../../stores/AppStore";
+import Button from "../Button";
export interface AppProps {
+ appState: {
+ increment: () => string,
+ counter: number
+ };
}
-export default class App extends React.Component {
- render() {
- return (
-
-
Aalto-yliopiston sähköinsinöörikilta!
-
Sähköä, viinaa, naisia.
-
- );
- }
+@observer class App extends React.Component {
+ constructor(props) {
+ super(props);
+ }
+
+ render() {
+ return
+
Aalto-yliopiston sähköinsinöörikilta!
+
Sähköä, viinaa, naisia.
+
+
;
+ }
}
+
+export default props => ;
\ No newline at end of file
diff --git a/src/components/Button/Button.scss b/src/components/Button/Button.scss
new file mode 100644
index 0000000..df61ff2
--- /dev/null
+++ b/src/components/Button/Button.scss
@@ -0,0 +1,20 @@
+@import "../../index.scss";
+
+.button {
+ -webkit-appearance: none;
+ border-radius: none;
+ padding: 0.5rem 1rem;
+ margin: 0.5rem;
+ border: 2px solid $blue;
+ font-size: 1rem;
+ font-weight: 500;
+
+ &:hover {
+ border: 2px solid $dark-blue;
+ }
+
+ &:active,
+ &:focus {
+ outline: none;
+ }
+}
diff --git a/src/components/Button/Button.tsx b/src/components/Button/Button.tsx
new file mode 100644
index 0000000..27d76cd
--- /dev/null
+++ b/src/components/Button/Button.tsx
@@ -0,0 +1,16 @@
+import * as React from "react";
+import "./Button.scss";
+
+export interface ButtonProps {
+ onClick: () => void;
+}
+
+export default class Button extends React.Component {
+ render() {
+ return (
+
+ );
+ }
+}
diff --git a/src/components/Button/index.ts b/src/components/Button/index.ts
new file mode 100644
index 0000000..846ff85
--- /dev/null
+++ b/src/components/Button/index.ts
@@ -0,0 +1,2 @@
+import Button from "./Button";
+export default Button;
\ No newline at end of file
diff --git a/src/stores/AppStore.ts b/src/stores/AppStore.ts
new file mode 100644
index 0000000..cd3d386
--- /dev/null
+++ b/src/stores/AppStore.ts
@@ -0,0 +1,13 @@
+import { observable, action } from "mobx";
+import { observer } from "mobx-react";
+
+class AppStore {
+ @observable counter = 0;
+
+ @action.bound
+ increment() {
+ this.counter += 1;
+ }
+}
+
+export default new AppStore();
diff --git a/tsconfig.json b/tsconfig.json
index 46c2bb6..665fd83 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -6,7 +6,8 @@
"module": "commonjs",
"target": "es5",
"jsx": "react",
- "lib": ["es5", "es6", "dom"]
+ "lib": ["es5", "es6", "dom"],
+ "experimentalDecorators": true
},
"include": [
"./src/**/*"