├── .gitignore ├── .travis-deploy.sh ├── .travis.yml ├── LICENSE ├── README.md ├── assets ├── architecture.jpg ├── architecture.psd ├── screenshot.png └── screenshot1.png ├── dev └── index.html ├── package.json ├── server.js ├── src ├── auth │ ├── auth.app.service.ts │ ├── auth.interceptor.ts │ ├── auth.interface.ts │ ├── auth.model.ts │ ├── auth.service.ts │ └── ui │ │ └── auth.component.tsx ├── common │ ├── loading │ │ ├── loading.component.css │ │ ├── loading.component.tsx │ │ └── loading.interceptor.ts │ └── observable-factory.ts ├── index.html ├── main.app.service.ts ├── main.component.tsx ├── main.css ├── main.tsx └── todo │ ├── todo.interface.ts │ ├── todo.model.ts │ ├── todo.persistence-ls.ts │ ├── todo.persistence.ts │ ├── todo.service.ts │ └── ui │ ├── todo.component.tsx │ ├── todo.container.tsx │ ├── todo.counter.tsx │ ├── todo.item.tsx │ └── todo.list.tsx ├── tsconfig.json ├── tslint.json ├── typings ├── auth0.lock │ └── auth0.lock.d.ts ├── auth0 │ └── auth0.d.ts ├── axios │ └── axios.d.ts ├── bluebird │ └── bluebird.d.ts ├── classnames │ └── classnames.d.ts ├── es6-promise │ └── es6-promise.d.ts ├── history │ └── history.d.ts ├── lodash │ └── lodash.d.ts ├── material-ui │ └── material-ui.d.ts ├── react-bootstrap │ └── react-bootstrap.d.ts ├── react-dom │ └── react-dom.d.ts ├── react-router │ └── react-router.d.ts ├── react │ └── react.d.ts └── uuid │ └── uuid.d.ts └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules 3 | bower_components 4 | build 5 | dist 6 | 7 | src/*.js 8 | src/*.js.map 9 | src/**/*.js 10 | src/**/*.js.map 11 | src/**/**/*.js 12 | src/**/**/*.js.map 13 | -------------------------------------------------------------------------------- /.travis-deploy.sh: -------------------------------------------------------------------------------- 1 | # go to the out directory and create a *new* Git repo 2 | cd build 3 | git init 4 | 5 | # inside this git repo we'll pretend to be a new user 6 | git config user.name "Travis CI" 7 | git config user.email "tomas.trajan@gmail.com" 8 | 9 | # The first and only commit to this new Git repo contains all the 10 | # files present with the commit message "Deploy to GitHub Pages". 11 | git add . 12 | git commit -m "Deploy to GitHub Pages" 13 | 14 | # Force push from the current repo's master branch to the remote 15 | # repo's gh-pages branch. (All previous history on the gh-pages branch 16 | # will be lost, since we are overwriting it.) We redirect any output to 17 | # /dev/null to hide any sensitive credential data that might otherwise be exposed. 18 | git push --force --quiet "https://${GH_TOKEN}@${GH_REF}" master:gh-pages > /dev/null 2>&1 -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "4.1" 4 | script: 5 | - npm run ci 6 | - bash ./.travis-deploy.sh -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Tomas Trajan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Typescript Webpack *FLUXless* Todo Example [![Build Status](https://travis-ci.org/tomastrajan/react-typescript-webpack.svg)](https://travis-ci.org/tomastrajan/react-typescript-webpack) 2 | Seed for building React apps using *FLUXless* architecture, Typescript and Webpack build 3 | 4 | Check out the [Demo](http://tomastrajan.github.io/react-typescript-webpack/) 5 | 6 | ## Features 7 | This is a simple Todos application with some sweet extra features like authentication (using Auth0) 8 | and persistence (separate node.js backend application - check out the gihub repository of 9 | [todos-server](https://github.com/tomastrajan/todos-server)) 10 | 11 | * **FLUXless architecture** - simple one way data flow (just components, services, models) 12 | * **guest mode** - local storage persistence 13 | * **persistence** - separate node.js backend application for authenticated users 14 | * **authentication** - [Auth0](https://auth0.com/) 3rd party API with Google+ social login 15 | * **material design** - material-ui, react-bootstrap, material bootswatch theme 16 | * **[continuous deployment](https://medium.com/@tomastrajan/continuous-deployment-of-client-side-apps-with-github-pages-travis-ci-10e9d641a889)** - travis ci build + deployment to gh-pages branch fo the repository (GitHub Pages) 17 | * **webpack build** - with react hot loader 18 | 19 | #### How to run the project 20 | 1. `npm i` - install npm dependencies 21 | 2. `npm start` - run webpack build in `DEV` mode, open `http://localhost:8081` in browser 22 | 23 | #### Other build targets 24 | 25 | - `npm run build` - run build and store artifacts in `build` folder 26 | - `npm run dist` - run production build and stores artifacts in `dist` folder 27 | - `npm run ci` - build for Travis CI 28 | - `npm run test` - run lint & test 29 | 30 | ## Preview 31 | 32 | ![Components](/assets/screenshot1.png?raw=true "React Typescript Webpack FLUXless Example") 33 | 34 | 35 | > **Disclaimer**: I think Flux architecture and it's multiple implementations are great 36 | idea but it is always good to understand the bigger picture and related trade-offs... 37 | 38 | 39 | ## Motivation for FLUXless architecture 40 | In software development, we should strive to attain deeper understanding of 41 | concepts instead of falling for the ever-changing _HypeOfThe~~Month~~Year_. I was 42 | [interested](https://medium.com/@tomastrajan/introduction-to-react-and-flux-6043d63610cd) 43 | and a bit skeptical about the latest Flux hype and all the different 44 | libraries it spawned during relatively short period of time. Researching the topic 45 | brought fruit pretty quickly. In my opinion, this thread on 46 | [reddit](https://www.reddit.com/r/programming/comments/25nrb5/facebook_mvc_does_not_scale_use_flux_instead/) 47 | contains lot of insight into the situation. 48 | 49 | 50 | > TLDR; MVC done incorrectly doesn't scale so we replaced it with MVC done correctly and gave it a cooler name. 51 | 52 | or 53 | 54 | > As far as I can tell (and as others have said) - FB seems to have missed the boat here. Their FLUX diagram 55 | is what I understood proper MVC to be... 56 | 57 | 58 | These and many other similar comments are hinting that Flux may be just a specific implementation of MVC 59 | and that the main point (or constraint) is that the data must **ALWAYS** flow in one direction. 60 | Flux implementations usually achieve that by decoupling of all logic calls (in `Actions`) 61 | by event bus (`Dispatcher`) from their execution (in `Stores`). As it turned out, 62 | one way data flow is also easily achievable by using more familiar architecture with 63 | React components, services and models (check 64 | [todo.container.ts](https://github.com/tomastrajan/react-typescript-webpack/blob/master/src/todo/ui/todo.container.tsx), 65 | [todo.service.ts](https://github.com/tomastrajan/react-typescript-webpack/blob/master/src/todo/todo.service.ts), 66 | [todo.model.ts](https://github.com/tomastrajan/react-typescript-webpack/blob/master/src/todo/todo.model.ts) 67 | to get an idea). 68 | 69 | 70 | ### Architecture 71 | The main concept at the core of all Flux implementations is that the data must always flow 72 | in one direction. This is a worthy cause and it brings a lot of benefits to the table 73 | during development and maintenance of projects. With such an architecture project state 74 | becomes predictable, easier to reason about and debug. 75 | 76 | ##### Event bus vs explicit calls 77 | Flux decouples logic by implementing event bus with the `Dispatcher` 78 | being responsible for dispatching `Action` generated events to all the `Stores`. 79 | As everything, `events` too come with a trade-off. They enforce decoupling of application logic 80 | by their very nature. The cost of that is that it is usually much harder to track and 81 | debug event-heavy code. Yes you can store complete event history to see what happened 82 | in your application but you lose ability to easily comprehend scope of all the logic 83 | that will be executed as a result of producing single event. Another problem is 84 | assuring that the dependent operations happen in correct order (`waitsFor` from original 85 | Facebook's Flux example'). It might be matter of subjective preference but if you 86 | need to orchestrate complex business flows through various domains, nothing beats explicit calls. 87 | 88 | ![Architecture](/assets/architecture.jpg?raw=true "FLUXless Architecture Diagram") 89 | 90 | ## UI 91 | #### React components 92 | In this example we are using two types of React components with different set 93 | of responsibilities. 94 | 95 | #### Container components 96 | Container components are handling following tasks: 97 | * hold current (rendered) application state 98 | * register model change listeners to get notified on model data change 99 | * retrieve actual data on model change 100 | * pass state to children components through their props 101 | * implement calls to domain & application services (and pass them to children) 102 | 103 | Template of container components consist purely of other React components 104 | (no own layout or functionality). 105 | 106 | ```typescript 107 | export default class TodoContainer extends React.Component<{}, {}> { 108 | 109 | constructor(props) { 110 | super(props); 111 | this.state = this._buildState(); 112 | } 113 | 114 | // register model data change listeners 115 | componentDidMount() { TodoModel.observable.addListener(this._onModelUpdate.bind(this)); } 116 | componentWillUnmount() { TodoModel.observable.removeListener(this._onModelUpdate.bind(this)); } 117 | 118 | // handle model data change 119 | _onModelUpdate() { 120 | this.setState(this._buildState()); 121 | } 122 | 123 | // helper function for retrieving state on model data change 124 | _buildState() { 125 | return { 126 | todos: TodoModel.getTodos() 127 | } 128 | } 129 | 130 | addTodo(description: string) { /* ... */ } 131 | 132 | // simplified for brevity 133 | 134 | render() { 135 | return( 136 | 137 | ); 138 | } 139 | 140 | } 141 | 142 | ``` 143 | 144 | #### Simple components 145 | Simple components receive all their data and functionality through props (from parent component). 146 | They can implement their own local `state` and logic for handling of internal UI interactions 147 | but all mutations to the application state stored in `models` can only be achieved by executing 148 | functions received from parent through props (which are in turn calling domain and application services). 149 | 150 | 151 | ## Logic 152 | #### Domain separation 153 | As applications grow larger it is usually a good idea to split functionality into 154 | multiple folders (packages) by their respective concern. In the perfect world these 155 | concerns would be perfectly orthogonal so we didn't have to implement any cross 156 | domain orchestration or cross-cutting concerns. Unfortunately, that's rarely 157 | the case and we usually have to deal with cross-domain coordination when 158 | implementing our business flows. 159 | 160 | #### Application services 161 | Application services (`~Actions`) are used to implement cross-domain orchestration. They are the 162 | only type of service which are allowed to `import` services from other domain packages. 163 | They only execute functionality of imported domain services and contain no business logic on their own. 164 | 165 | #### (Domain) Services 166 | Services (~`Actions` / `Stores`) are used to implement domain specific business and 167 | infrastructure logic. Services of particular domain can `import` only other services 168 | belonging to that domain. All inter-domain orchestration must be implemented using 169 | `application services`. Logic can be separated into multiple services based on concern 170 | (eg: business logic, persistence, ...). 171 | 172 | #### Models 173 | Models (~`Stores`) are responsible for holding app state during it's runtime. They implement 174 | observe/notify design pattern so that all interested `container components` can use model's 175 | `addListener` method to register callback to be notified when the model data change. 176 | This implementation enables **one way data flow**. 177 | Model has full control of the (possibly custom) notification behaviour, while component 178 | knows what kind of data it needs to retrieve from model after being notified. 179 | 180 | All `get` data functions of the model create copy of the retrieved data so that 181 | they prevent direct mutation of model's data through shared reference. 182 | Also, while it is theoretically possible for component to directly call 183 | other model's methods, as guideline only `listener` and `get` methods are allowed. 184 | 185 | ## Contributing 186 | Don't hesitate to fork / submit PR with enhancements if you found this example useful. 187 | 188 | #### TODO 189 | - [x] tslint 190 | - [ ] unit tests 191 | - [ ] integration tests 192 | - [ ] add notifications / alerts for operation's outcomes 193 | - [ ] cleanup of styling (select just one component library) 194 | - [ ] add form validation messages -------------------------------------------------------------------------------- /assets/architecture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomastrajan/react-typescript-webpack/8ca03085a1fde70c87b7baba0152755a1cb9c6e3/assets/architecture.jpg -------------------------------------------------------------------------------- /assets/architecture.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomastrajan/react-typescript-webpack/8ca03085a1fde70c87b7baba0152755a1cb9c6e3/assets/architecture.psd -------------------------------------------------------------------------------- /assets/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomastrajan/react-typescript-webpack/8ca03085a1fde70c87b7baba0152755a1cb9c6e3/assets/screenshot.png -------------------------------------------------------------------------------- /assets/screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomastrajan/react-typescript-webpack/8ca03085a1fde70c87b7baba0152755a1cb9c6e3/assets/screenshot1.png -------------------------------------------------------------------------------- /dev/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React Typescript Webpack Seed 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-typescript-webpack", 3 | "version": "1.0.0", 4 | "description": "Seed for building React app using Typescript and Webpack", 5 | "main": "src/main.js", 6 | "scripts": { 7 | "start": "webpack-dev-server --inline --hot --TARGET=DEV", 8 | "build": "webpack && node server.js", 9 | "dist": "webpack --TARGET=DIST && node server.js --TARGET=DIST", 10 | "ci": "npm run test && webpack", 11 | "lint": "tslint src/**/*.ts", 12 | "test": "npm run lint" 13 | }, 14 | "dependencies": { 15 | "axios": "0.7.0", 16 | "bluebird": "2.10.2", 17 | "bootswatch": "3.3.5", 18 | "classnames": "2.2.0", 19 | "fbjs": "0.2.1", 20 | "font-awesome": "4.4.0", 21 | "history": "1.17", 22 | "lodash": "3.10.1", 23 | "material-ui": "0.13.1", 24 | "react": "0.14.2", 25 | "react-addons-create-fragment": "0.14.2", 26 | "react-addons-pure-render-mixin": "0.14.2", 27 | "react-addons-transition-group": "0.14.2", 28 | "react-addons-update": "0.14.2", 29 | "react-bootstrap": "0.27.2", 30 | "react-dom": "0.14.2", 31 | "react-router": "1.0.3", 32 | "react-tap-event-plugin": "0.2.0", 33 | "uuid": "2.0.1" 34 | }, 35 | "devDependencies": { 36 | "chalk": "1.1.1", 37 | "clean-webpack-plugin": "0.1.3", 38 | "connect": "3.4.0", 39 | "css-loader": "0.20.1", 40 | "file-loader": "0.8.4", 41 | "html-webpack-plugin": "1.6.2", 42 | "minimist": "1.2.0", 43 | "open-browser-webpack-plugin": "0.0.1", 44 | "react-hot-loader": "1.3.0", 45 | "style-loader": "0.12.4", 46 | "svg-loader": "0.0.2", 47 | "ts-loader": "0.7.2", 48 | "tslint": "3.2.1", 49 | "typescript": "1.7", 50 | "url-loader": "0.5.6", 51 | "webpack": "1.12.2", 52 | "webpack-dev-server": "1.12.0" 53 | }, 54 | "repository": { 55 | "type": "git", 56 | "url": "git+https://github.com/tomastrajan/react-typescript-webpack.git" 57 | }, 58 | "keywords": [ 59 | "react", 60 | "webpack", 61 | "typescript", 62 | "seed", 63 | "flux" 64 | ], 65 | "author": "Tomas Trajan ", 66 | "license": "MIT", 67 | "bugs": { 68 | "url": "https://github.com/tomastrajan/react-typescript-webpack/issues" 69 | }, 70 | "homepage": "https://github.com/tomastrajan/react-typescript-webpack#readme" 71 | } 72 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | var minimist = require('minimist'); 2 | var connect = require('connect'); 3 | var serveStatic = require('serve-static'); 4 | 5 | 6 | var PORT = 8082; 7 | var TARGET_PATH_MAPPING = { 8 | BUILD: './build', 9 | DIST: './dist' 10 | }; 11 | 12 | var TARGET = minimist(process.argv.slice(2)).TARGET || 'BUILD'; 13 | 14 | connect() 15 | .use(serveStatic(TARGET_PATH_MAPPING[TARGET])) 16 | .listen(PORT); 17 | 18 | console.log('Created server for: ' + TARGET + ', listening on port ' + PORT); -------------------------------------------------------------------------------- /src/auth/auth.app.service.ts: -------------------------------------------------------------------------------- 1 | import * as AuthService from './auth.service'; 2 | import * as AuthModel from './auth.model'; 3 | import * as TodoService from '../todo/todo.service'; 4 | 5 | 6 | export function login() { 7 | return AuthService.login() 8 | .then(() => { TodoService.init(AuthModel.isAuthenticated()); }); 9 | } 10 | 11 | export function logout() { 12 | return AuthService.logout() 13 | .then(() => { TodoService.init(AuthModel.isAuthenticated()); }); 14 | } 15 | -------------------------------------------------------------------------------- /src/auth/auth.interceptor.ts: -------------------------------------------------------------------------------- 1 | import * as Promise from 'bluebird'; 2 | import * as axios from 'axios'; 3 | 4 | let authTokenInterceptor: any; 5 | let userInterceptor: any; 6 | let unauthorizedInterceptor: any; 7 | 8 | export function registerAuthTokenInterceptor(token: string) { 9 | authTokenInterceptor = axios.interceptors.request.use(function (config: any) { 10 | config.headers.Authorization = 'Bearer ' + token; 11 | return config; 12 | }, function (error: any) { 13 | return Promise.reject(error); 14 | }); 15 | } 16 | 17 | export function deregisterAuthTokenInterceptor() { 18 | axios.interceptors.request.eject(authTokenInterceptor); 19 | } 20 | 21 | export function registerUserInterceptor(userId: string) { 22 | userInterceptor = axios.interceptors.request.use(function (config: any) { 23 | if (config.url.indexOf('todos-server') > 0) { 24 | config.headers['X-USER-ID'] = userId; 25 | } 26 | return config; 27 | }, function (error: any) { 28 | return Promise.reject(error); 29 | }); 30 | } 31 | 32 | export function deregisterUserInterceptor() { 33 | axios.interceptors.request.eject(userInterceptor); 34 | } 35 | 36 | export function registerUnauthorizedInterceptor(handler: any) { 37 | unauthorizedInterceptor = axios.interceptors.response.use(function (response: any) { 38 | return response; 39 | }, function (error: any) { 40 | if (error && error.status === 401) { 41 | handler(); 42 | } 43 | return Promise.reject(error); 44 | }); 45 | } 46 | 47 | export function deregisterUnauthorizedInterceptor() { 48 | axios.interceptors.request.eject(unauthorizedInterceptor); 49 | } 50 | -------------------------------------------------------------------------------- /src/auth/auth.interface.ts: -------------------------------------------------------------------------------- 1 | export interface Profile { 2 | _id: string; 3 | aud: string; 4 | clientID: string; 5 | created_at: string; 6 | email: string; 7 | email_verified: boolean; 8 | exp: number; 9 | family_name: string; 10 | gender: string; 11 | given_name: string; 12 | global_client_id: string; 13 | iat: number; 14 | identities: Identity[]; 15 | iss: string; 16 | locale: string; 17 | name: string; 18 | nickname: string; 19 | picture: string; 20 | sub: string; 21 | updated_at: string; 22 | user_id: string; 23 | } 24 | 25 | interface Identity { 26 | access_token: string; 27 | connection: string; 28 | expires_in: number; 29 | isSocial: boolean; 30 | provider: string; 31 | user_id: string; 32 | } 33 | -------------------------------------------------------------------------------- /src/auth/auth.model.ts: -------------------------------------------------------------------------------- 1 | import * as _ from 'lodash'; 2 | 3 | import observableFactory, { Observable } from '../common/observable-factory'; 4 | 5 | import { Profile } from './auth.interface'; 6 | 7 | let userProfile: Profile; 8 | 9 | export const observable: Observable = observableFactory(); 10 | 11 | export function isAuthenticated(): boolean { 12 | return !!userProfile; 13 | } 14 | 15 | export function getProfile(): Profile { 16 | return _.cloneDeep(userProfile); 17 | } 18 | 19 | export function setProfile(profile: Profile) { 20 | userProfile = profile; 21 | observable.notifyAll(); 22 | } 23 | -------------------------------------------------------------------------------- /src/auth/auth.service.ts: -------------------------------------------------------------------------------- 1 | import * as axios from 'axios'; 2 | import * as Auth0Lock from 'auth0-lock'; 3 | import * as Promise from 'bluebird'; 4 | 5 | import * as model from './auth.model'; 6 | import * as interceptor from './auth.interceptor'; 7 | 8 | import { Profile } from './auth.interface'; 9 | 10 | const lock: any = new Auth0Lock('A9xnMR5yCNlOs0HbLB17OeOUZpCYnG4G', 'tomastrajan.eu.auth0.com'); 11 | const LOGOUT_URL: string = 'https://tomastrajan.eu.auth0.com/v2/logout'; 12 | 13 | 14 | export function login() { 15 | return new Promise((resolve: any, reject: any) => { 16 | let options: any = {authParams: { scope: 'openid profile' }}; 17 | lock.show(options, function(err: any, profile: Profile, token: any) { 18 | if (err) { 19 | console.log(err); 20 | return reject(err); 21 | } 22 | localStorage.setItem('id_token', token); 23 | interceptor.registerAuthTokenInterceptor(token); 24 | interceptor.registerUserInterceptor(profile.user_id); 25 | model.setProfile(profile as Profile); 26 | resolve(); 27 | }); 28 | }); 29 | } 30 | 31 | export function logout() { 32 | return axios.get(LOGOUT_URL) 33 | .then(() => { 34 | interceptor.deregisterAuthTokenInterceptor(); 35 | interceptor.deregisterUserInterceptor(); 36 | localStorage.removeItem('id_token'); 37 | model.setProfile(undefined); 38 | }); 39 | } 40 | 41 | export function init() { 42 | return new Promise((resolve: any, reject: any) => { 43 | let token: string = localStorage.getItem('id_token'); 44 | if (token) { 45 | interceptor.registerAuthTokenInterceptor(token); 46 | lock.getProfile(token, function (err: any, profile: Profile) { 47 | if (err) { 48 | console.log(err); 49 | return reject(err); 50 | } 51 | interceptor.registerUserInterceptor(profile.user_id); 52 | model.setProfile(profile as Profile); 53 | resolve(); 54 | }); 55 | } else { 56 | resolve(); 57 | } 58 | }); 59 | } 60 | -------------------------------------------------------------------------------- /src/auth/ui/auth.component.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Avatar } from 'material-ui'; 3 | import { Button, NavDropdown, MenuItem } from 'react-bootstrap'; 4 | 5 | import * as AuthModel from './../auth.model.ts'; 6 | import * as AuthAppService from '../auth.app.service.ts'; 7 | 8 | export default class AuthComponent extends React.Component<{}, AuthState> { 9 | 10 | constructor(props) { 11 | super(props); 12 | this.state = this._buildState(); 13 | } 14 | 15 | componentDidMount() { AuthModel.observable.addListener(this._onModelUpdate.bind(this)); } 16 | componentWillUnmount() { AuthModel.observable.removeListener(this._onModelUpdate.bind(this)); } 17 | 18 | _onModelUpdate() { 19 | this.setState(this._buildState()); 20 | } 21 | 22 | _buildState() { 23 | return { 24 | isAuthenticated: AuthModel.isAuthenticated(), 25 | profile: AuthModel.getProfile() 26 | } 27 | } 28 | 29 | login() { 30 | AuthAppService.login(); 31 | } 32 | 33 | logout() { 34 | AuthAppService.logout(); 35 | } 36 | 37 | render() { 38 | return ((() => { 39 | if (this.state.isAuthenticated) { 40 | return 50 | } else { 51 | return 59 | } 60 | })()); 61 | } 62 | 63 | } 64 | 65 | interface AuthState { 66 | isAuthenticated?: boolean; 67 | profile?: any; 68 | } -------------------------------------------------------------------------------- /src/common/loading/loading.component.css: -------------------------------------------------------------------------------- 1 | .loading { 2 | z-index: 1000; 3 | position: absolute; 4 | top: 50%; 5 | left: 50%; 6 | margin-top: -25px; 7 | margin-left: -25px; 8 | } 9 | 10 | .loading-overlay { 11 | z-index: 1000; 12 | position: absolute; 13 | top: 0px; 14 | left: 0px; 15 | height: 100%; 16 | width: 100%; 17 | background-color: #fff; 18 | opacity: 0.3; 19 | } -------------------------------------------------------------------------------- /src/common/loading/loading.component.tsx: -------------------------------------------------------------------------------- 1 | import './loading.component.css'; 2 | 3 | import * as React from 'react'; 4 | import { CircularProgress } from 'material-ui'; 5 | 6 | import * as LoadingInterceptor from './loading.interceptor.ts'; 7 | 8 | export default class LoadingComponent extends React.Component<{}, { isLoading: boolean; }> { 9 | 10 | constructor(props) { 11 | super(props); 12 | this.state = { isLoading: false }; 13 | } 14 | 15 | componentDidMount() { LoadingInterceptor.observable.addListener(this._onModelUpdate.bind(this)); } 16 | componentWillUnmount() { LoadingInterceptor.observable.removeListener(this._onModelUpdate.bind(this)); } 17 | 18 | _onModelUpdate() { 19 | this.setState({isLoading: LoadingInterceptor.isLoading()}); 20 | } 21 | 22 | render() { 23 | return ((() => { 24 | if (this.state.isLoading) { 25 | return 26 |
27 |
28 | 29 |
30 | 31 |
32 | } else { 33 | return ; 34 | } 35 | })()); 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /src/common/loading/loading.interceptor.ts: -------------------------------------------------------------------------------- 1 | import * as Promise from 'bluebird'; 2 | import * as axios from 'axios'; 3 | 4 | import observableFactory from '../observable-factory'; 5 | 6 | let requestLoadingInterceptor; 7 | let responseLoadingInterceptor; 8 | let outstandingRequestCount = 0; 9 | 10 | export const observable = observableFactory(); 11 | 12 | export function isLoading() { 13 | return outstandingRequestCount > 0; 14 | } 15 | 16 | export function registerLoadingInterceptor() { 17 | requestLoadingInterceptor = axios.interceptors.request.use(function (config) { 18 | outstandingRequestCount++; 19 | observable.notifyAll(); 20 | return config; 21 | }, function (error) { 22 | return Promise.reject(error); 23 | }); 24 | 25 | responseLoadingInterceptor = axios.interceptors.response.use(function (response) { 26 | _decrementOutstandingRequestCount(); 27 | return response; 28 | }, function (error) { 29 | _decrementOutstandingRequestCount(); 30 | return Promise.reject(error); 31 | }); 32 | 33 | } 34 | 35 | export function deregisterLoadingInterceptor() { 36 | axios.interceptors.request.eject(requestLoadingInterceptor); 37 | axios.interceptors.request.eject(responseLoadingInterceptor); 38 | } 39 | 40 | function _decrementOutstandingRequestCount() { 41 | setTimeout(() => { 42 | outstandingRequestCount--; 43 | observable.notifyAll(); 44 | }); 45 | } 46 | -------------------------------------------------------------------------------- /src/common/observable-factory.ts: -------------------------------------------------------------------------------- 1 | import * as _ from 'lodash'; 2 | 3 | export default function createObservable(): Observable { 4 | const listeners: Listener[] = []; 5 | return { 6 | addListener: addListener.bind(undefined, listeners), 7 | removeListener: removeListener.bind(undefined, listeners), 8 | notifyAll: notifyAll.bind(undefined, listeners) 9 | }; 10 | } 11 | 12 | function addListener(listeners: Listener[], listener: Listener) { 13 | listeners.push(listener); 14 | } 15 | 16 | function removeListener(listeners: Listener[], listener: Listener) { 17 | _.remove(listeners, (l: Listener) => l === listener); 18 | } 19 | 20 | function notifyAll(listeners: Listener[]) { 21 | _.forEach(listeners, (l: Listener) => l()); 22 | } 23 | 24 | interface Listener { 25 | (): any; 26 | } 27 | 28 | export interface Observable { 29 | addListener(listener: Listener); 30 | removeListener(listener: Listener); 31 | notifyAll(); 32 | } 33 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React Typescript Webpack Seed 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 25 | -------------------------------------------------------------------------------- /src/main.app.service.ts: -------------------------------------------------------------------------------- 1 | import * as AuthAppService from './auth/auth.app.service.ts'; 2 | import * as AuthService from './auth/auth.service.ts'; 3 | import * as AuthModel from './auth/auth.model.ts'; 4 | import * as AuthInterceptor from './auth/auth.interceptor.ts'; 5 | import * as LoadingInterceptor from './common/loading/loading.interceptor.ts'; 6 | import * as TodoService from './todo/todo.service.ts'; 7 | 8 | export function init() { 9 | return AuthService.init() 10 | .then(() => { LoadingInterceptor.registerLoadingInterceptor(); }) 11 | .then(() => { AuthInterceptor.registerUnauthorizedInterceptor(AuthAppService.logout); }) 12 | .then(() => { TodoService.init(AuthModel.isAuthenticated()); }); 13 | } -------------------------------------------------------------------------------- /src/main.component.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Link } from 'react-router'; 3 | import { Paper } from 'material-ui'; 4 | 5 | import AuthComponent from './auth/ui/auth.component.tsx'; 6 | import TodoCounter from './todo/ui/todo.counter.tsx'; 7 | import LoadingComponent from './common/loading/loading.component.tsx'; 8 | 9 | export default class MainComponent extends React.Component<{ children: any }, {}> { 10 | 11 | constructor(props) { 12 | super(props); 13 | } 14 | 15 | render() { 16 | return( 17 |
18 | 31 |
32 | 33 | {this.props.children} 34 |
35 |
36 | 37 |
38 |
39 |
40 | 41 | Medium 42 |
43 | 44 |
45 | 46 | Github 47 |
48 |
49 | 50 | Twitter 51 |
52 |
53 | 54 | StackOverflow 55 |
56 |
57 |
58 |
59 |
60 |

Tomas Trajan 2015

61 |
62 |
63 |
64 |
65 |
66 |
67 | ); 68 | } 69 | 70 | } -------------------------------------------------------------------------------- /src/main.css: -------------------------------------------------------------------------------- 1 | .noselect { 2 | user-select: none; 3 | } 4 | 5 | .btn:focus { 6 | outline: 0 !important; 7 | } 8 | 9 | .btn:active { 10 | outline: 0 !important; 11 | } 12 | 13 | html { 14 | position: relative; 15 | min-height: 100%; 16 | } 17 | body { 18 | margin-bottom: 250px; 19 | padding-top: 70px; 20 | } 21 | .footer { 22 | position: absolute; 23 | bottom: 0; 24 | width: 100%; 25 | height: auto; 26 | background-color: #f5f5f5; 27 | } 28 | 29 | .footer .container { 30 | padding: 15px; 31 | text-align: center; 32 | } 33 | 34 | .footer .container a { 35 | font-weight: bold; 36 | font-size: 15px; 37 | margin-left: 5px; 38 | } 39 | 40 | .footer .container a:hover { 41 | text-decoration: none; 42 | } 43 | 44 | .footer .row div { 45 | padding: 10px 0px 0px 0px; 46 | } -------------------------------------------------------------------------------- /src/main.tsx: -------------------------------------------------------------------------------- 1 | import 'bootswatch/paper/bootstrap.css'; 2 | import 'font-awesome/css/font-awesome.css'; 3 | import './main.css'; 4 | 5 | import * as React from 'react'; 6 | import * as ReactDOM from 'react-dom'; 7 | import { Router, Route, Redirect, IndexRoute } from 'react-router'; 8 | 9 | import * as InitAppService from './main.app.service'; 10 | 11 | import MainComponent from './main.component'; 12 | import TodoContainer from './todo/ui/todo.container'; 13 | 14 | InitAppService.init().then(renderRouter); 15 | 16 | function renderRouter() { 17 | ReactDOM.render(( 18 | 19 | 20 | 21 | 22 | 23 | 24 | ), document.getElementById('content')); 25 | } 26 | -------------------------------------------------------------------------------- /src/todo/todo.interface.ts: -------------------------------------------------------------------------------- 1 | export interface Todo { 2 | id: string; 3 | description: string; 4 | done: boolean; 5 | userId?: string; 6 | createdAt?: string; 7 | updatedAt?: string; 8 | } 9 | -------------------------------------------------------------------------------- /src/todo/todo.model.ts: -------------------------------------------------------------------------------- 1 | import * as _ from 'lodash'; 2 | 3 | import observableFactory, { Observable } from '../common/observable-factory'; 4 | 5 | import { Todo } from './todo.interface'; 6 | 7 | let todos: Todo[] = []; 8 | 9 | export const observable: Observable = observableFactory(); 10 | 11 | export function getTodo(id: string): Todo { 12 | return _.cloneDeep(_.find(todos, (t: Todo) => t.id === id)); 13 | } 14 | 15 | export function getTodos(): Todo[] { 16 | return _.cloneDeep(todos); 17 | } 18 | 19 | export function getDoneTodos(): number { 20 | return _.reduce(todos, (sum: number, t: Todo) => { return t.done ? ++sum : sum; }, 0); 21 | } 22 | 23 | export function getPendingTodos(): number { 24 | return _.reduce(todos, (sum: number, t: Todo) => { return !t.done ? ++sum : sum; }, 0); 25 | } 26 | 27 | export function setTodos(newTodos: Todo[]) { 28 | todos = _.cloneDeep(newTodos); 29 | observable.notifyAll(); 30 | } 31 | 32 | export function addTodo(todo: Todo) { 33 | todos.push(todo); 34 | observable.notifyAll(); 35 | } 36 | 37 | export function replaceTodo(todo: Todo) { 38 | _.forEach(todos, (t: Todo, index: number) => { 39 | if (t.id === todo.id) { 40 | todos[index] = todo; 41 | } 42 | }); 43 | observable.notifyAll(); 44 | } 45 | 46 | export function removeTodo(id: string) { 47 | _.remove(todos, (t: Todo) => t.id === id); 48 | observable.notifyAll(); 49 | } 50 | -------------------------------------------------------------------------------- /src/todo/todo.persistence-ls.ts: -------------------------------------------------------------------------------- 1 | import { Todo } from './todo.interface'; 2 | 3 | const STORAGE_KEY: string = 'todos'; 4 | 5 | export function getTodos() { 6 | let result: string = localStorage.getItem(STORAGE_KEY); 7 | return result ? JSON.parse(result) : []; 8 | } 9 | 10 | export function setTodos(todos: Todo[]) { 11 | localStorage.setItem(STORAGE_KEY, JSON.stringify(todos)); 12 | } 13 | -------------------------------------------------------------------------------- /src/todo/todo.persistence.ts: -------------------------------------------------------------------------------- 1 | import * as axios from 'axios'; 2 | 3 | import { Todo } from './todo.interface'; 4 | 5 | const SERVER: string = 'https://todos-server.herokuapp.com'; 6 | const RESOURCE: string = '/todos'; 7 | 8 | export function findAll() { 9 | return axios.get(SERVER + RESOURCE). 10 | then(_unwrapResponse); 11 | } 12 | 13 | export function create(todo: Todo) { 14 | return axios.post(SERVER + RESOURCE, todo); 15 | } 16 | 17 | export function update(todo: Todo) { 18 | return axios.put(SERVER + RESOURCE + '/' + todo.id, todo); 19 | } 20 | 21 | export function remove(id: string) { 22 | return axios.delete(SERVER + RESOURCE + '/' + id); 23 | } 24 | 25 | function _unwrapResponse(response: any): Todo[] { 26 | return response.data; 27 | } 28 | -------------------------------------------------------------------------------- /src/todo/todo.service.ts: -------------------------------------------------------------------------------- 1 | import * as uuid from 'uuid'; 2 | import * as Promise from 'bluebird'; 3 | import * as model from './todo.model'; 4 | import * as persistence from './todo.persistence'; 5 | import * as persistenceLs from './todo.persistence-ls'; 6 | 7 | import { Todo } from './todo.interface'; 8 | 9 | const defaultTodos: Todo[] = [ 10 | {id: uuid.v4(), description: 'Explore todo example', done: true}, 11 | {id: uuid.v4(), description: 'Sing in to persist todos to backend', done: false}, 12 | {id: uuid.v4(), description: 'Check sources on Github', done: false} 13 | ]; 14 | 15 | let isAuthenticated: boolean = false; 16 | 17 | export function init(isAuth: boolean) { 18 | isAuthenticated = isAuth; 19 | if (isAuthenticated) { 20 | persistence.findAll() 21 | .then(_sortTodosByCreatedAt) 22 | .then(model.setTodos); 23 | } else { 24 | let todosLs: Todo[] = persistenceLs.getTodos(); 25 | model.setTodos(todosLs.length ? todosLs : defaultTodos); 26 | } 27 | } 28 | 29 | export function createTodo(description: string) { 30 | let todo: Todo = { 31 | id: uuid.v4(), 32 | description: description, 33 | done: false 34 | }; 35 | 36 | if (isAuthenticated) { 37 | persistence.create(todo) 38 | .then(persistence.findAll) 39 | .then(_sortTodosByCreatedAt) 40 | .then(model.setTodos); 41 | } else { 42 | model.addTodo(todo); 43 | persistenceLs.setTodos(model.getTodos()); 44 | } 45 | } 46 | 47 | export function toggleTodo(id: string) { 48 | let todo: Todo = model.getTodo(id); 49 | todo.done = !todo.done; 50 | 51 | if (isAuthenticated) { 52 | persistence.update(todo) 53 | .then(persistence.findAll) 54 | .then(_sortTodosByCreatedAt) 55 | .then(model.setTodos); 56 | } else { 57 | model.replaceTodo(todo); 58 | persistenceLs.setTodos(model.getTodos()); 59 | } 60 | } 61 | 62 | export function editTodo(id: string, description: string) { 63 | let todo: Todo = model.getTodo(id); 64 | todo.description = description; 65 | 66 | if (isAuthenticated) { 67 | persistence.update(todo) 68 | .then(persistence.findAll) 69 | .then(_sortTodosByCreatedAt) 70 | .then(model.setTodos); 71 | } else { 72 | model.replaceTodo(todo); 73 | persistenceLs.setTodos(model.getTodos()); 74 | } 75 | } 76 | 77 | export function removeTodo(id: string) { 78 | if (isAuthenticated) { 79 | persistence.remove(id) 80 | .then(persistence.findAll) 81 | .then(_sortTodosByCreatedAt) 82 | .then(model.setTodos); 83 | } else { 84 | model.removeTodo(id); 85 | persistenceLs.setTodos(model.getTodos()); 86 | } 87 | } 88 | 89 | export function removeDoneTodos() { 90 | let todos: Todo[] = model.getTodos(); 91 | if (isAuthenticated) { 92 | let promises: Promise[] = []; 93 | _.forEach(todos, (t: Todo) => t.done ? promises.push(persistence.remove(t.id)) : undefined); 94 | Promise.all(promises) 95 | .then(persistence.findAll) 96 | .then(_sortTodosByCreatedAt) 97 | .then(model.setTodos); 98 | } else { 99 | _.forEach(todos, (t: Todo) => t.done ? model.removeTodo(t.id) : undefined); 100 | persistenceLs.setTodos(model.getTodos()); 101 | } 102 | } 103 | 104 | 105 | function _sortTodosByCreatedAt(todos: Todo[]) { 106 | return todos.sort((a: Todo, b: Todo) => { 107 | if (a.createdAt > b.createdAt) { 108 | return 1; 109 | } 110 | if (a.createdAt < b.createdAt) { 111 | return -1; 112 | } 113 | return 0; 114 | }); 115 | } 116 | -------------------------------------------------------------------------------- /src/todo/ui/todo.component.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import * as classNames from 'classnames'; 3 | 4 | import TodoList from './todo.list.tsx'; 5 | 6 | import { Todo } from './../todo.interface.ts'; 7 | 8 | const KEYCODE_ENTER = 13; 9 | 10 | export default class TodoComponent extends React.Component { 11 | 12 | constructor(props) { 13 | super(props); 14 | this.state = { 15 | description: '', 16 | valid: true 17 | }; 18 | } 19 | 20 | setDescription(event) { 21 | this.setState({valid: true, description: event.target.value}); 22 | } 23 | 24 | addTodo(event) { 25 | if (event && event.keyCode !== KEYCODE_ENTER && event.type !== 'click') { 26 | return; 27 | } 28 | if (!this.state.description.length || this.state.description.length > 50) { 29 | this.setState({valid: false}); 30 | } else { 31 | this.props.addTodo(this.state.description); 32 | this.setState({description: ''}); 33 | } 34 | } 35 | 36 | render() { 37 | let inputClass = classNames('form-group', { 38 | 'has-error': !this.state.valid 39 | }); 40 | 41 | return( 42 |
43 |
44 |
45 |

What do you need to do?

46 |
47 |
48 |
49 |
50 |
51 | 52 | 53 |
54 |
55 |
56 | 59 |
60 |
61 | 64 |
65 |
66 | 67 |
68 |
69 | 70 |
71 |
72 | 73 |
74 |
75 |
76 | ); 77 | } 78 | 79 | } 80 | 81 | interface TodoComponentProps { 82 | todos: Todo[]; 83 | addTodo(description: string): void; 84 | toggleTodo: React.MouseEventHandler; 85 | editTodo: React.MouseEventHandler; 86 | removeTodo: React.MouseEventHandler; 87 | removeDoneTodos: React.MouseEventHandler; 88 | } 89 | 90 | 91 | interface TodoComponentState { 92 | description?: string; 93 | valid?: boolean; 94 | } 95 | -------------------------------------------------------------------------------- /src/todo/ui/todo.container.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | import TodoComponent from './todo.component.tsx'; 4 | 5 | import * as TodoModel from './../todo.model.ts'; 6 | import * as TodoService from './../todo.service.ts'; 7 | 8 | import { Todo } from './../todo.interface.ts'; 9 | 10 | export default class TodoContainer extends React.Component<{}, TodoContainerState> { 11 | 12 | constructor(props) { 13 | super(props); 14 | this.state = this._buildState(); 15 | } 16 | 17 | componentDidMount() { TodoModel.observable.addListener(this._onModelUpdate.bind(this)); } 18 | componentWillUnmount() { TodoModel.observable.removeListener(this._onModelUpdate.bind(this)); } 19 | 20 | _onModelUpdate() { 21 | this.setState(this._buildState()); 22 | } 23 | 24 | _buildState() { 25 | return { 26 | todos: TodoModel.getTodos() 27 | } 28 | } 29 | 30 | addTodo(description: string) { 31 | TodoService.createTodo(description); 32 | } 33 | 34 | toggleTodo(id: string) { 35 | TodoService.toggleTodo(id); 36 | } 37 | 38 | editTodo(id: string, description: string) { 39 | TodoService.editTodo(id, description); 40 | } 41 | 42 | removeTodo(id: string) { 43 | TodoService.removeTodo(id); 44 | } 45 | 46 | removeDoneTodos() { 47 | TodoService.removeDoneTodos(); 48 | } 49 | 50 | render() { 51 | return( 52 | 55 | ); 56 | } 57 | 58 | } 59 | 60 | interface TodoContainerState { 61 | todos: Todo[] 62 | } -------------------------------------------------------------------------------- /src/todo/ui/todo.counter.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | import * as TodoModel from '../todo.model.ts'; 4 | 5 | import { Todo } from '../todo.interface.ts'; 6 | 7 | export default class TodoCounter extends React.Component<{}, TodoCounterState> { 8 | 9 | constructor(props) { 10 | super(props); 11 | this.state = this._buildState(); 12 | } 13 | 14 | componentDidMount() { TodoModel.observable.addListener(this._onModelUpdate.bind(this)); } 15 | componentWillUnmount() { TodoModel.observable.removeListener(this._onModelUpdate.bind(this)); } 16 | 17 | _onModelUpdate() { 18 | this.setState(this._buildState()); 19 | } 20 | 21 | _buildState() { 22 | return { 23 | doneTodos: TodoModel.getDoneTodos(), 24 | pendingTodos: TodoModel.getPendingTodos() 25 | } 26 | } 27 | 28 | render() { 29 | let containerStyle = { 30 | paddingBottom: 0 31 | }; 32 | 33 | let valueStyle = { 34 | color: '#fff', 35 | fontWeight: 'bold', 36 | fontSize: 20, 37 | position: 'relative', 38 | top: 2 39 | }; 40 | 41 | let iconStyle = { 42 | marginRight: 5 43 | }; 44 | 45 | return( 46 | 58 | ); 59 | } 60 | 61 | } 62 | 63 | interface TodoCounterState { 64 | doneTodos: number; 65 | pendingTodos: number; 66 | } 67 | -------------------------------------------------------------------------------- /src/todo/ui/todo.item.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as classNames from 'classnames'; 3 | 4 | import { Todo } from './../todo.interface.ts'; 5 | 6 | export default class TodoItem extends React.Component { 7 | 8 | constructor(props) { 9 | super(props); 10 | this.state = { 11 | isEdited: false 12 | }; 13 | } 14 | 15 | setDescription(event) { 16 | this.setState({valid: true, description: event.target.value}); 17 | } 18 | 19 | editTodo() { 20 | this.setState({ 21 | isEdited: true, 22 | valid: true, 23 | description: this.props.description 24 | }); 25 | } 26 | 27 | cancelEditTodo() { 28 | this.setState({ 29 | isEdited: false, 30 | valid: true 31 | }); 32 | } 33 | 34 | saveTodo() { 35 | if (!this.state.description.length || this.state.description.length > 50) { 36 | this.setState({ valid: false }); 37 | } else { 38 | this.props.editTodo(this.state.description); 39 | this.setState({ 40 | isEdited: false, 41 | valid: true, 42 | description: '' 43 | }); 44 | } 45 | } 46 | 47 | render() { 48 | let inputClass = classNames('form-group', { 49 | 'form-group': true, 50 | 'has-error': !this.state.valid 51 | }); 52 | let deleteButtonStyle = { 53 | color: '#ff0000', 54 | marginLeft: 5 55 | }; 56 | let descriptionStyle = { 57 | paddingTop: 4, 58 | cursor: 'pointer' 59 | }; 60 | return( 61 |
62 |
63 |
64 |
65 | 68 |
69 |
70 | {(() => { 71 | if (this.state.isEdited) { 72 | return
73 | 74 |
75 | } else { 76 | return
{this.props.description}
77 | } 78 | })()} 79 |
80 |
81 | {(() => { 82 | if (this.state.isEdited) { 83 | return 84 | 87 | 90 | 91 | } else { 92 | return 93 | 96 | 99 | 100 | } 101 | })()} 102 |
103 |
104 |
105 |
106 | ); 107 | } 108 | 109 | } 110 | 111 | interface TodoItemProps { 112 | key: string; 113 | description: string; 114 | done: boolean; 115 | toggleTodo: React.MouseEventHandler; 116 | editTodo: any; 117 | removeTodo: React.MouseEventHandler; 118 | } 119 | 120 | interface TodoComponentState { 121 | isEdited? : boolean 122 | description?: string; 123 | valid?: boolean; 124 | } 125 | 126 | -------------------------------------------------------------------------------- /src/todo/ui/todo.list.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | import TodoItem from './todo.item.tsx'; 4 | 5 | import { Todo } from './../todo.interface.ts'; 6 | 7 | export default class TodoList extends React.Component { 8 | 9 | constructor(props) { 10 | super(props); 11 | } 12 | 13 | render() { 14 | return( 15 |
16 | {this.props.todos.map((todo) => { 17 | return ; 24 | })} 25 | {(() => { 26 | if (!this.props.todos.length) { 27 | return

No todos added yet...

28 | } 29 | })()} 30 |
31 | ); 32 | } 33 | 34 | } 35 | 36 | interface TodoListProps { 37 | todos: Todo[]; 38 | toggleTodo: React.MouseEventHandler; 39 | editTodo: React.MouseEventHandler; 40 | removeTodo: React.MouseEventHandler; 41 | } 42 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es5", 5 | "sourceMap": true, 6 | "jsx": "react" 7 | }, 8 | "files": [ 9 | "src/main.tsx", 10 | "src/main.app.service.ts", 11 | "src/auth/auth.app.service.ts", 12 | "src/auth/ui/auth.component.tsx", 13 | "src/auth/auth.interceptor.ts", 14 | "src/auth/auth.model.ts", 15 | "src/auth/auth.service.ts", 16 | "src/auth/auth.interface.ts", 17 | "src/todo/todo.interface.ts", 18 | "src/todo/ui/todo.component.tsx", 19 | "src/todo/ui/todo.counter.tsx", 20 | "src/todo/ui/todo.container.tsx", 21 | "src/todo/ui/todo.item.tsx", 22 | "src/todo/ui/todo.list.tsx", 23 | "src/todo/todo.model.ts", 24 | "src/todo/todo.persistence.ts", 25 | "src/todo/todo.persistence-ls.ts", 26 | "src/todo/todo.service.ts", 27 | "src/common/observable-factory.ts", 28 | "src/common/loading/loading.component.tsx", 29 | "src/common/loading/loading.interceptor.ts", 30 | "typings/axios/axios.d.ts", 31 | "typings/auth0/auth0.d.ts", 32 | "typings/auth0.lock/auth0.lock.d.ts", 33 | "typings/bluebird/bluebird.d.ts", 34 | "typings/classnames/classnames.d.ts", 35 | "typings/es6-promise/es6-promise.d.ts", 36 | "typings/history/history.d.ts", 37 | "typings/lodash/lodash.d.ts", 38 | "typings/material-ui/material-ui.d.ts", 39 | "typings/react/react.d.ts", 40 | "typings/react-bootstrap/react-bootstrap.d.ts", 41 | "typings/react-dom/react-dom.d.ts", 42 | "typings/react-router/react-router.d.ts", 43 | "typings/uuid/uuid.d.ts" 44 | ], 45 | "filesGlob": [ 46 | "src/**/*.tsx", 47 | "src/**/*.ts", 48 | "typings/**/*d.ts" 49 | ], 50 | "exclude": [] 51 | } 52 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "align": [ 4 | true, 5 | "parameters", 6 | "statements" 7 | ], 8 | "ban": false, 9 | "class-name": true, 10 | "comment-format": [ 11 | true, 12 | "check-space", 13 | "check-lowercase" 14 | ], 15 | "curly": true, 16 | "eofline": true, 17 | "forin": true, 18 | "indent": [ 19 | true, 20 | "spaces" 21 | ], 22 | "interface-name": false, 23 | "jsdoc-format": true, 24 | "label-position": true, 25 | "label-undefined": true, 26 | "max-line-length": [ 27 | true, 28 | 140 29 | ], 30 | "member-access": true, 31 | "member-ordering": [ 32 | true, 33 | "public-before-private", 34 | "static-before-instance", 35 | "variables-before-functions" 36 | ], 37 | "no-any": false, 38 | "no-arg": true, 39 | "no-bitwise": true, 40 | "no-conditional-assignment": true, 41 | "no-consecutive-blank-lines": false, 42 | "no-console": [ 43 | true, 44 | "debug", 45 | "info", 46 | "time", 47 | "timeEnd", 48 | "trace" 49 | ], 50 | "no-construct": true, 51 | "no-constructor-vars": true, 52 | "no-debugger": true, 53 | "no-duplicate-key": true, 54 | "no-duplicate-variable": true, 55 | "no-empty": true, 56 | "no-eval": true, 57 | "no-inferrable-types": false, 58 | "no-internal-module": true, 59 | "no-null-keyword": true, 60 | "no-require-imports": true, 61 | "no-shadowed-variable": true, 62 | "no-string-literal": true, 63 | "no-switch-case-fall-through": true, 64 | "no-trailing-whitespace": true, 65 | "no-unreachable": true, 66 | "no-unused-expression": true, 67 | "no-unused-variable": true, 68 | "no-use-before-declare": true, 69 | "no-var-keyword": true, 70 | "no-var-requires": true, 71 | "object-literal-sort-keys": false, 72 | "one-line": [ 73 | true, 74 | "check-open-brace", 75 | "check-catch", 76 | "check-else", 77 | "check-whitespace" 78 | ], 79 | "quotemark": [ 80 | true, 81 | "single", 82 | "avoid-escape" 83 | ], 84 | "radix": true, 85 | "semicolon": true, 86 | "switch-default": true, 87 | "trailing-comma": [ 88 | true, 89 | { 90 | "multiline": "never", 91 | "singleline": "never" 92 | } 93 | ], 94 | "triple-equals": [ 95 | true, 96 | "allow-null-check" 97 | ], 98 | "typedef": [ 99 | true, 100 | "parameter", 101 | "variable-declaration", 102 | "member-variable-declaration" 103 | ], 104 | "typedef-whitespace": [ 105 | true, 106 | { 107 | "call-signature": "nospace", 108 | "index-signature": "nospace", 109 | "parameter": "nospace", 110 | "property-declaration": "nospace", 111 | "variable-declaration": "nospace" 112 | } 113 | ], 114 | "use-strict": [ 115 | true, 116 | "check-module" 117 | ], 118 | "variable-name": [ 119 | true, 120 | "check-format", 121 | "allow-leading-underscore", 122 | "ban-keywords" 123 | ], 124 | "whitespace": [ 125 | true, 126 | "check-branch", 127 | "check-decl", 128 | "check-operator", 129 | "check-separator", 130 | "check-type" 131 | ] 132 | } 133 | } -------------------------------------------------------------------------------- /typings/auth0.lock/auth0.lock.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for Auth0Widget.js 2 | // Project: http://auth0.com 3 | // Definitions by: Robert McLaws 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /// 7 | 8 | interface Auth0LockPopupOptions { 9 | width: number; 10 | height: number; 11 | left: number; 12 | top: number; 13 | } 14 | 15 | interface Auth0LockOptions { 16 | authParams?: any; 17 | callbackURL?: string; 18 | connections?: string[]; 19 | container?: string; 20 | closable?: boolean; 21 | dict?: any; 22 | defaultUserPasswordConnection?: string; 23 | defaultADUsernameFromEmailPrefix?: boolean; 24 | disableResetAction?: boolean; 25 | disableSignupAction?: boolean; 26 | focusInput?: boolean; 27 | forceJSONP?: boolean; 28 | gravatar?: boolean; 29 | integratedWindowsLogin?: boolean; 30 | icon?: string; 31 | loginAfterSignup?: boolean; 32 | popup?: boolean; 33 | popupOptions?: Auth0LockPopupOptions; 34 | rememberLastLogin?: boolean; 35 | resetLink?: string; 36 | responseType?: string; 37 | signupLink?: string; 38 | socialBigButtons?: boolean; 39 | sso?: boolean; 40 | theme?: string; 41 | usernameStyle?: any; 42 | } 43 | 44 | interface Auth0LockConstructorOptions { 45 | cdn?: string; 46 | assetsUrl?: string; 47 | useCordovaSocialPlugins?: boolean; 48 | } 49 | 50 | interface Auth0LockStatic { 51 | new (clientId: string, domain: string, options?: Auth0LockConstructorOptions): Auth0LockStatic; 52 | 53 | show(): void; 54 | show(options: Auth0LockOptions): void; 55 | show(callback: (error?: Auth0Error, profile?: Auth0UserProfile, token?: string) => void) : void; 56 | show(options: Auth0LockOptions, callback: (error?: Auth0Error, profile?: Auth0UserProfile, token?: string) => void) : void; 57 | 58 | showSignin(): void; 59 | showSignin(options: Auth0LockOptions): void; 60 | showSignin(callback: (error?: Auth0Error, profile?: Auth0UserProfile, token?: string) => void) : void; 61 | showSignin(options: Auth0LockOptions, callback: (error?: Auth0Error, profile?: Auth0UserProfile, token?: string) => void) : void; 62 | 63 | showSignup(): void; 64 | showSignup(options: Auth0LockOptions): void; 65 | showSignup(callback: (error?: Auth0Error) => void) : void; 66 | showSignup(options: Auth0LockOptions, callback: (error?: Auth0Error) => void) : void; 67 | 68 | showReset(): void; 69 | showReset(options: Auth0LockOptions): void; 70 | showReset(callback: (error?: Auth0Error) => void) : void; 71 | showReset(options: Auth0LockOptions, callback: (error?: Auth0Error) => void) : void; 72 | 73 | hide(callback: () => void): void; 74 | logout(options: any): void; 75 | 76 | parseHash(hash: string): any; 77 | getProfile(id_token: string, callback: Callback): any; 78 | } 79 | 80 | interface Callback { 81 | (err: any, profile: any): any; 82 | } 83 | 84 | declare var Auth0Lock: Auth0LockStatic; 85 | 86 | declare module "auth0-lock" { 87 | export = Auth0Lock; 88 | } 89 | -------------------------------------------------------------------------------- /typings/auth0/auth0.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for Auth0.js 2 | // Project: http://auth0.com 3 | // Definitions by: Robert McLaws 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /** Extensions to the browser Window object. */ 7 | interface Window { 8 | /** Allows you to pass the id_token to other APIs, as specified in https://docs.auth0.com/apps-apis */ 9 | token: string; 10 | } 11 | 12 | /** This is the interface for the main Auth0 client. */ 13 | interface Auth0Static { 14 | 15 | new(options: Auth0ClientOptions): Auth0Static; 16 | changePassword(options: any, callback?: Function): void; 17 | decodeJwt(jwt: string): any; 18 | login(options: any, callback: (error?: Auth0Error, profile?: Auth0UserProfile, id_token?: string, access_token?: string, state?: string) => any): void; 19 | loginWithPopup(options: Auth0LoginOptions, callback: (error?: Auth0Error, profile?: Auth0UserProfile, id_token?: string, access_token?: string, state?: string) => any): void; 20 | loginWithResourceOwner(options: Auth0LoginOptions, callback: (error?: Auth0Error, profile?: Auth0UserProfile, id_token?: string, access_token?: string, state?: any) => any): void; 21 | loginWithUsernamePassword(options: Auth0LoginOptions, callback: (error?: Auth0Error, profile?: Auth0UserProfile, id_token?: string, access_token?: string, state?: string) => any): void; 22 | logout(query: string): void; 23 | getConnections(callback?: Function): void; 24 | getDelegationToken(targetClientId: string, id_token: string, options: any, callback: (error?: Auth0Error, delegationResult?: Auth0DelegationToken) => any): void; 25 | getProfile(id_token: string, callback?: Function): Auth0UserProfile; 26 | getSSOData(withActiveDirectories: any, callback?: Function): void; 27 | parseHash(hash: string): Auth0DecodedHash; 28 | signup(options: Auth0SignupOptions, callback: Function): void; 29 | validateUser(options: any, callback: (error?: Auth0Error, valid?: any) => any): void; 30 | } 31 | 32 | /** Represents constructor options for the Auth0 client. */ 33 | interface Auth0ClientOptions { 34 | clientID: string; 35 | callbackURL: string; 36 | callbackOnLocationHash?: boolean; 37 | domain: string; 38 | forceJSONP?: boolean; 39 | } 40 | 41 | /** Represents a normalized UserProfile. */ 42 | interface Auth0UserProfile { 43 | email: string; 44 | family_name: string; 45 | gender: string; 46 | given_name: string; 47 | locale: string; 48 | name: string; 49 | nickname: string; 50 | picture: string; 51 | user_id: string; 52 | /** Represents one or more Identities that may be associated with the User. */ 53 | identities: Auth0Identity[]; 54 | } 55 | 56 | /** Represents an Auth0UserProfile that has a Microsoft Account as the primary identity. */ 57 | interface MicrosoftUserProfile extends Auth0UserProfile { 58 | emails: string[]; 59 | } 60 | 61 | /** Represents an Auth0UserProfile that has an Office365 account as the primary identity. */ 62 | interface Office365UserProfile extends Auth0UserProfile { 63 | tenantid: string; 64 | upn: string; 65 | } 66 | 67 | /** Represents an Auth0UserProfile that has an Active Directory account as the primary identity. */ 68 | interface AdfsUserProfile extends Auth0UserProfile { 69 | issuer: string; 70 | } 71 | 72 | /** Represents multiple identities assigned to a user. */ 73 | interface Auth0Identity { 74 | access_token: string; 75 | connection: string; 76 | isSocial: boolean; 77 | provider: string; 78 | user_id: string; 79 | } 80 | 81 | interface Auth0DecodedHash { 82 | access_token: string; 83 | id_token: string; 84 | profile: Auth0UserProfile; 85 | state: any; 86 | } 87 | 88 | interface Auth0PopupOptions { 89 | width: number; 90 | height: number; 91 | } 92 | 93 | interface Auth0LoginOptions { 94 | auto_login?: boolean; 95 | connection?: string; 96 | email?: string; 97 | username?: string; 98 | password?: string; 99 | popup?: boolean; 100 | popupOptions?: Auth0PopupOptions; 101 | } 102 | 103 | interface Auth0SignupOptions extends Auth0LoginOptions { 104 | auto_login: boolean; 105 | } 106 | 107 | interface Auth0Error { 108 | code: any; 109 | details: any; 110 | name: string; 111 | message: string; 112 | status: any; 113 | } 114 | 115 | /** Represents the response from an API Token Delegation request. */ 116 | interface Auth0DelegationToken { 117 | /** The length of time in seconds the token is valid for. */ 118 | expires_in: string; 119 | /** The JWT for delegated access. */ 120 | id_token: string; 121 | /** The type of token being returned. Possible values: "Bearer" */ 122 | token_type: string; 123 | } 124 | 125 | declare var Auth0: Auth0Static; 126 | 127 | declare module "auth0" { 128 | export = Auth0 129 | } 130 | -------------------------------------------------------------------------------- /typings/axios/axios.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for axios 0.5.2 2 | // Project: https://github.com/mzabriskie/axios 3 | // Definitions by: Marcel Buesing 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /// 7 | 8 | declare module Axios { 9 | 10 | /** 11 | * - request body data type 12 | */ 13 | interface AxiosXHRConfigBase { 14 | 15 | /** 16 | * Change the request data before it is sent to the server. 17 | * This is only applicable for request methods 'PUT', 'POST', and 'PATCH' 18 | * The last function in the array must return a string or an ArrayBuffer 19 | */ 20 | transformRequest?: (data:T) => U; 21 | 22 | /** 23 | * change the response data to be made before it is passed to then/catch 24 | */ 25 | transformResponse?: (data:T) => U; 26 | 27 | /** 28 | * custom headers to be sent 29 | */ 30 | headers?: Object; 31 | 32 | /** 33 | * URL parameters to be sent with the request 34 | */ 35 | params?: Object; 36 | 37 | /** 38 | * indicates whether or not cross-site Access-Control requests 39 | * should be made using credentials 40 | */ 41 | withCredentials?: boolean; 42 | 43 | /** 44 | * indicates the type of data that the server will respond with 45 | * options are 'arraybuffer', 'blob', 'document', 'json', 'text' 46 | */ 47 | responseType?: string; 48 | 49 | /** 50 | * name of the cookie to use as a value for xsrf token 51 | */ 52 | xsrfCookieName?: string; 53 | 54 | /** 55 | * name of the http header that carries the xsrf token value 56 | */ 57 | xsrfHeaderName?: string; 58 | 59 | } 60 | 61 | /** 62 | * - request body data type 63 | */ 64 | interface AxiosXHRConfig extends AxiosXHRConfigBase { 65 | /** 66 | * server URL that will be used for the request, options are: 67 | * GET, PUT, POST, DELETE, CONNECT, HEAD, OPTIONS, TRACE, PATCH 68 | */ 69 | url: string; 70 | 71 | /** 72 | * request method to be used when making the request 73 | */ 74 | method?: string; 75 | 76 | /** 77 | * data to be sent as the request body 78 | * Only applicable for request methods 'PUT', 'POST', and 'PATCH' 79 | * When no `transformRequest` is set, must be a string, an ArrayBuffer or a hash 80 | */ 81 | data?: T; 82 | } 83 | 84 | /** 85 | * - expected response type, 86 | * - request body data type 87 | */ 88 | interface AxiosXHR { 89 | /** 90 | * Response that was provided by the server 91 | */ 92 | data: T; 93 | 94 | /** 95 | * HTTP status code from the server response 96 | */ 97 | status: number; 98 | 99 | /** 100 | * HTTP status message from the server response 101 | */ 102 | statusText: string; 103 | 104 | /** 105 | * headers that the server responded with 106 | */ 107 | headers: Object; 108 | 109 | /** 110 | * config that was provided to `axios` for the request 111 | */ 112 | config: AxiosXHRConfig; 113 | } 114 | 115 | /** 116 | * - expected response type, 117 | * - request body data type 118 | */ 119 | interface AxiosStatic { 120 | 121 | (config: AxiosXHRConfig): Promise>; 122 | 123 | new (config: AxiosXHRConfig): Promise>; 124 | 125 | /** 126 | * convenience alias, method = GET 127 | */ 128 | get(url: string, config?: AxiosXHRConfigBase): Promise>; 129 | 130 | 131 | /** 132 | * convenience alias, method = DELETE 133 | */ 134 | delete(url: string, config?: AxiosXHRConfigBase): Promise>; 135 | 136 | /** 137 | * convenience alias, method = HEAD 138 | */ 139 | head(url: string, config?: AxiosXHRConfigBase): Promise>; 140 | 141 | /** 142 | * convenience alias, method = POST 143 | */ 144 | post(url: string, data?: any, config?: AxiosXHRConfigBase): Promise>; 145 | 146 | /** 147 | * convenience alias, method = PUT 148 | */ 149 | put(url: string, data?: any, config?: AxiosXHRConfigBase): Promise>; 150 | 151 | /** 152 | * convenience alias, method = PATCH 153 | */ 154 | patch(url: string, data?: any, config?: AxiosXHRConfigBase): Promise>; 155 | 156 | interceptors: any; 157 | } 158 | } 159 | 160 | declare var axios: Axios.AxiosStatic; 161 | 162 | declare module "axios" { 163 | export = axios; 164 | } 165 | -------------------------------------------------------------------------------- /typings/bluebird/bluebird.d.ts: -------------------------------------------------------------------------------- 1 | declare let Bluebird: any; 2 | 3 | declare module 'bluebird' { 4 | export = Bluebird; 5 | } -------------------------------------------------------------------------------- /typings/classnames/classnames.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for classnames 2 | // Project: https://github.com/JedWatson/classnames 3 | // Definitions by: Dave Keen , Adi Dahiya , Jason Killian 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | declare type ClassValue = string | number | ClassDictionary | ClassArray; 7 | 8 | interface ClassDictionary { 9 | [id: string]: boolean; 10 | } 11 | 12 | interface ClassArray extends Array { } 13 | 14 | interface ClassNamesFn { 15 | (...classes: ClassValue[]): string; 16 | } 17 | 18 | declare var classNames: ClassNamesFn; 19 | 20 | declare module "classnames" { 21 | export = classNames 22 | } 23 | -------------------------------------------------------------------------------- /typings/es6-promise/es6-promise.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for es6-promise 2 | // Project: https://github.com/jakearchibald/ES6-Promise 3 | // Definitions by: François de Campredon , vvakame 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | interface Thenable { 7 | then(onFulfilled?: (value: R) => U | Thenable, onRejected?: (error: any) => U | Thenable): Thenable; 8 | then(onFulfilled?: (value: R) => U | Thenable, onRejected?: (error: any) => void): Thenable; 9 | } 10 | 11 | declare class Promise implements Thenable { 12 | /** 13 | * If you call resolve in the body of the callback passed to the constructor, 14 | * your promise is fulfilled with result object passed to resolve. 15 | * If you call reject your promise is rejected with the object passed to resolve. 16 | * For consistency and debugging (eg stack traces), obj should be an instanceof Error. 17 | * Any errors thrown in the constructor callback will be implicitly passed to reject(). 18 | */ 19 | constructor(callback: (resolve : (value?: R | Thenable) => void, reject: (error?: any) => void) => void); 20 | 21 | /** 22 | * onFulfilled is called when/if "promise" resolves. onRejected is called when/if "promise" rejects. 23 | * Both are optional, if either/both are omitted the next onFulfilled/onRejected in the chain is called. 24 | * Both callbacks have a single parameter , the fulfillment value or rejection reason. 25 | * "then" returns a new promise equivalent to the value you return from onFulfilled/onRejected after being passed through Promise.resolve. 26 | * If an error is thrown in the callback, the returned promise rejects with that error. 27 | * 28 | * @param onFulfilled called when/if "promise" resolves 29 | * @param onRejected called when/if "promise" rejects 30 | */ 31 | then(onFulfilled?: (value: R) => U | Thenable, onRejected?: (error: any) => U | Thenable): Promise; 32 | then(onFulfilled?: (value: R) => U | Thenable, onRejected?: (error: any) => void): Promise; 33 | 34 | /** 35 | * Sugar for promise.then(undefined, onRejected) 36 | * 37 | * @param onRejected called when/if "promise" rejects 38 | */ 39 | catch(onRejected?: (error: any) => U | Thenable): Promise; 40 | } 41 | 42 | declare module Promise { 43 | /** 44 | * Make a new promise from the thenable. 45 | * A thenable is promise-like in as far as it has a "then" method. 46 | */ 47 | function resolve(value?: R | Thenable): Promise; 48 | 49 | /** 50 | * Make a promise that rejects to obj. For consistency and debugging (eg stack traces), obj should be an instanceof Error 51 | */ 52 | function reject(error: any): Promise; 53 | 54 | /** 55 | * Make a promise that fulfills when every item in the array fulfills, and rejects if (and when) any item rejects. 56 | * the array passed to all can be a mixture of promise-like objects and other objects. 57 | * The fulfillment value is an array (in order) of fulfillment values. The rejection value is the first rejection value. 58 | */ 59 | function all(promises: (R | Thenable)[]): Promise; 60 | 61 | /** 62 | * Make a Promise that fulfills when any item fulfills, and rejects if any item rejects. 63 | */ 64 | function race(promises: (R | Thenable)[]): Promise; 65 | } 66 | 67 | declare module 'es6-promise' { 68 | var foo: typeof Promise; // Temp variable to reference Promise in local context 69 | module rsvp { 70 | export var Promise: typeof foo; 71 | } 72 | export = rsvp; 73 | } 74 | -------------------------------------------------------------------------------- /typings/history/history.d.ts: -------------------------------------------------------------------------------- 1 | declare var hist: any; 2 | 3 | declare module 'history' { 4 | export = hist; 5 | } -------------------------------------------------------------------------------- /typings/react-bootstrap/react-bootstrap.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare module ReactBootstrap { 4 | let Button: any; 5 | let NavDropdown: any; 6 | let MenuItem: any; 7 | } 8 | 9 | declare module 'react-bootstrap' { 10 | export = ReactBootstrap; 11 | } -------------------------------------------------------------------------------- /typings/react-dom/react-dom.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for React-DOM v0.14.0-rc 2 | // Project: https://www.npmjs.com/package/react-dom 3 | // Definitions by: Stefan-Bieliauskas 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /// 7 | 8 | declare namespace __ReactDom { 9 | function render

( 10 | element: __React.DOMElement

, 11 | container: Element, 12 | callback?: () => any): __React.DOMComponent

; 13 | function render( 14 | element: __React.ClassicElement

, 15 | container: Element, 16 | callback?: () => any): __React.ClassicComponent; 17 | function render( 18 | element: __React.ReactElement

, 19 | container: Element, 20 | callback?: () => any): __React.Component; 21 | 22 | function findDOMNode( 23 | componentOrElement: __React.Component | Element): TElement; 24 | function findDOMNode( 25 | componentOrElement: __React.Component | Element): Element; 26 | 27 | function unmountComponentAtNode(container: Element): boolean; 28 | } 29 | 30 | declare namespace __ReactDomServer { 31 | function renderToString(element: __React.ReactElement): string; 32 | function renderToStaticMarkup(element: __React.ReactElement): string; 33 | } 34 | declare module "react-dom" { 35 | export = __ReactDom 36 | } 37 | 38 | declare module "react-dom/server" { 39 | export = __ReactDomServer 40 | } 41 | -------------------------------------------------------------------------------- /typings/react-router/react-router.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for React Router 0.13.3 2 | // Project: https://github.com/rackt/react-router 3 | // Definitions by: Yuichi Murata , Václav Ostrožlík 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /// 7 | 8 | declare module ReactRouter { 9 | import React = __React; 10 | 11 | // 12 | // Transition 13 | // ---------------------------------------------------------------------- 14 | interface Transition { 15 | path: string; 16 | abortReason: any; 17 | retry(): void; 18 | abort(reason?: any): void; 19 | redirect(to: string, params?: {}, query?: {}): void; 20 | cancel(): void; 21 | from: (transition: Transition, routes: Route[], components?: React.ReactElement[], callback?: (error?: any) => void) => void; 22 | to: (transition: Transition, routes: Route[], params?: {}, query?: {}, callback?: (error?: any) => void) => void; 23 | } 24 | 25 | interface TransitionStaticLifecycle { 26 | willTransitionTo?( 27 | transition: Transition, 28 | params: {}, 29 | query: {}, 30 | callback: Function 31 | ): void; 32 | 33 | willTransitionFrom?( 34 | transition: Transition, 35 | component: React.ReactElement, 36 | callback: Function 37 | ): void; 38 | } 39 | 40 | // 41 | // Route Configuration 42 | // ---------------------------------------------------------------------- 43 | // DefaultRoute 44 | interface DefaultRouteProp { 45 | name?: string; 46 | handler: React.ComponentClass; 47 | } 48 | interface DefaultRoute extends React.ReactElement {} 49 | interface DefaultRouteClass extends React.ComponentClass {} 50 | 51 | // NotFoundRoute 52 | interface NotFoundRouteProp { 53 | name?: string; 54 | handler: React.ComponentClass; 55 | } 56 | interface NotFoundRoute extends React.ReactElement {} 57 | interface NotFoundRouteClass extends React.ComponentClass {} 58 | 59 | // Redirect 60 | interface RedirectProp { 61 | path?: string; 62 | from?: string; 63 | to?: string; 64 | } 65 | interface Redirect extends React.ReactElement {} 66 | interface RedirectClass extends React.ComponentClass {} 67 | 68 | // Route 69 | interface RouteProp { 70 | name?: string; 71 | path?: string; 72 | handler?: React.ComponentClass; 73 | ignoreScrollBehavior?: boolean; 74 | component?: React.ComponentClass; 75 | } 76 | interface Route extends React.ReactElement {} 77 | interface RouteClass extends React.ComponentClass {} 78 | 79 | // Route 80 | interface IndexRouteProp { 81 | name?: string; 82 | path?: string; 83 | handler?: React.ComponentClass; 84 | ignoreScrollBehavior?: boolean; 85 | component?: React.ComponentClass; 86 | } 87 | interface IndexRoute extends React.ReactElement {} 88 | interface IndexRouteClass extends React.ComponentClass {} 89 | 90 | // Router 91 | interface RouterProp { 92 | name?: string; 93 | path?: string; 94 | handler?: React.ComponentClass; 95 | ignoreScrollBehavior?: boolean; 96 | history?: any; 97 | } 98 | interface Router extends React.ReactElement {} 99 | interface RouterClass extends React.ComponentClass {} 100 | 101 | var DefaultRoute: DefaultRouteClass; 102 | var NotFoundRoute: NotFoundRouteClass; 103 | var Redirect: RedirectClass; 104 | var Route: RouteClass; 105 | var IndexRoute: IndexRouteClass; 106 | var Router: RouterClass; 107 | 108 | interface CreateRouteOptions { 109 | name?: string; 110 | path?: string; 111 | ignoreScrollBehavior?: boolean; 112 | isDefault?: boolean; 113 | isNotFound?: boolean; 114 | onEnter?: (transition: Transition, params: {}, query: {}, callback: Function) => void; 115 | onLeave?: (transition: Transition, wtf: any, callback: Function) => void; 116 | handler?: Function; 117 | parentRoute?: Route; 118 | } 119 | 120 | type CreateRouteCallback = (route: Route) => void; 121 | 122 | function createRoute(callback: CreateRouteCallback): Route; 123 | function createRoute(options: CreateRouteOptions | string, callback: CreateRouteCallback): Route; 124 | function createDefaultRoute(options?: CreateRouteOptions | string): Route; 125 | function createNotFoundRoute(options?: CreateRouteOptions | string): Route; 126 | 127 | interface CreateRedirectOptions extends CreateRouteOptions { 128 | path?: string; 129 | from?: string; 130 | to: string; 131 | params?: {}; 132 | query?: {}; 133 | } 134 | function createRedirect(options: CreateRedirectOptions): Redirect; 135 | function createRoutesFromReactChildren(children: Route): Route[]; 136 | 137 | // 138 | // Components 139 | // ---------------------------------------------------------------------- 140 | // Link 141 | interface LinkProp extends React.HTMLAttributes { 142 | activeClassName?: string; 143 | activeStyle?: {}; 144 | to: string; 145 | params?: {}; 146 | query?: {}; 147 | } 148 | interface Link extends React.ReactElement, Navigation, State { 149 | handleClick(event: any): void; 150 | getHref(): string; 151 | getClassName(): string; 152 | getActiveState(): boolean; 153 | } 154 | interface LinkClass extends React.ComponentClass {} 155 | 156 | // RouteHandler 157 | interface RouteHandlerProp { } 158 | interface RouteHandlerChildContext { 159 | routeDepth: number; 160 | } 161 | interface RouteHandler extends React.ReactElement { 162 | getChildContext(): RouteHandlerChildContext; 163 | getRouteDepth(): number; 164 | createChildRouteHandler(props: {}): RouteHandler; 165 | } 166 | interface RouteHandlerClass extends React.ComponentClass {} 167 | 168 | var Link: LinkClass; 169 | var RouteHandler: RouteHandlerClass; 170 | 171 | 172 | // 173 | // Top-Level 174 | // ---------------------------------------------------------------------- 175 | //interface Router extends React.ReactElement { 176 | // run(callback: RouterRunCallback): void; 177 | //} 178 | // 179 | //interface RouterState { 180 | // path: string; 181 | // action: string; 182 | // pathname: string; 183 | // params: {}; 184 | // query: {}; 185 | // routes: Route[]; 186 | //} 187 | // 188 | //interface RouterCreateOption { 189 | // routes: Route; 190 | // location?: LocationBase; 191 | // scrollBehavior?: ScrollBehaviorBase; 192 | // onError?: (error: any) => void; 193 | // onAbort?: (error: any) => void; 194 | //} 195 | // 196 | //type RouterRunCallback = (Handler: RouteClass, state: RouterState) => void; 197 | // 198 | //function create(options: RouterCreateOption): Router; 199 | //function run(routes: Route, callback: RouterRunCallback): Router; 200 | //function run(routes: Route, location: LocationBase | string, callback: RouterRunCallback): Router; 201 | 202 | // 203 | // Location 204 | // ---------------------------------------------------------------------- 205 | interface LocationBase { 206 | getCurrentPath(): void; 207 | toString(): string; 208 | } 209 | interface Location extends LocationBase { 210 | push(path: string): void; 211 | replace(path: string): void; 212 | pop(): void; 213 | } 214 | 215 | interface LocationListener { 216 | addChangeListener(listener: Function): void; 217 | removeChangeListener(listener: Function): void; 218 | } 219 | 220 | interface HashLocation extends Location, LocationListener { } 221 | interface HistoryLocation extends Location, LocationListener { } 222 | interface RefreshLocation extends Location { } 223 | interface StaticLocation extends LocationBase { } 224 | interface TestLocation extends Location, LocationListener { } 225 | 226 | var HashLocation: HashLocation; 227 | var HistoryLocation: HistoryLocation; 228 | var RefreshLocation: RefreshLocation; 229 | var StaticLocation: StaticLocation; 230 | var TestLocation: TestLocation; 231 | 232 | 233 | // 234 | // Behavior 235 | // ---------------------------------------------------------------------- 236 | interface ScrollBehaviorBase { 237 | updateScrollPosition(position: { x: number; y: number; }, actionType: string): void; 238 | } 239 | interface ImitateBrowserBehavior extends ScrollBehaviorBase { } 240 | interface ScrollToTopBehavior extends ScrollBehaviorBase { } 241 | 242 | var ImitateBrowserBehavior: ImitateBrowserBehavior; 243 | var ScrollToTopBehavior: ScrollToTopBehavior; 244 | 245 | 246 | // 247 | // Mixin 248 | // ---------------------------------------------------------------------- 249 | interface Navigation { 250 | makePath(to: string, params?: {}, query?: {}): string; 251 | makeHref(to: string, params?: {}, query?: {}): string; 252 | transitionTo(to: string, params?: {}, query?: {}): void; 253 | replaceWith(to: string, params?: {}, query?: {}): void; 254 | goBack(): void; 255 | } 256 | 257 | interface State { 258 | getPath(): string; 259 | getRoutes(): Route[]; 260 | getPathname(): string; 261 | getParams(): {}; 262 | getQuery(): {}; 263 | isActive(to: string, params?: {}, query?: {}): boolean; 264 | } 265 | 266 | var Navigation: Navigation; 267 | var State: State; 268 | 269 | 270 | // 271 | // History 272 | // ---------------------------------------------------------------------- 273 | interface History { 274 | back(): void; 275 | length: number; 276 | } 277 | var History: History; 278 | 279 | 280 | // 281 | // Context 282 | // ---------------------------------------------------------------------- 283 | interface Context { 284 | makePath(to: string, params?: {}, query?: {}): string; 285 | makeHref(to: string, params?: {}, query?: {}): string; 286 | transitionTo(to: string, params?: {}, query?: {}): void; 287 | replaceWith(to: string, params?: {}, query?: {}): void; 288 | goBack(): void; 289 | 290 | getCurrentPath(): string; 291 | getCurrentRoutes(): Route[]; 292 | getCurrentPathname(): string; 293 | getCurrentParams(): {}; 294 | getCurrentQuery(): {}; 295 | isActive(to: string, params?: {}, query?: {}): boolean; 296 | } 297 | } 298 | 299 | declare module "react-router" { 300 | export = ReactRouter; 301 | } 302 | 303 | declare module __React { 304 | 305 | // for DefaultRoute 306 | function createElement( 307 | type: ReactRouter.DefaultRouteClass, 308 | props: ReactRouter.DefaultRouteProp, 309 | ...children: __React.ReactNode[]): ReactRouter.DefaultRoute; 310 | 311 | // for Link 312 | function createElement( 313 | type: ReactRouter.LinkClass, 314 | props: ReactRouter.LinkProp, 315 | ...children: __React.ReactNode[]): ReactRouter.Link; 316 | 317 | // for NotFoundRoute 318 | function createElement( 319 | type: ReactRouter.NotFoundRouteClass, 320 | props: ReactRouter.NotFoundRouteProp, 321 | ...children: __React.ReactNode[]): ReactRouter.NotFoundRoute; 322 | 323 | // for Redirect 324 | function createElement( 325 | type: ReactRouter.RedirectClass, 326 | props: ReactRouter.RedirectProp, 327 | ...children: __React.ReactNode[]): ReactRouter.Redirect; 328 | 329 | // for Route 330 | function createElement( 331 | type: ReactRouter.RouteClass, 332 | props: ReactRouter.RouteProp, 333 | ...children: __React.ReactNode[]): ReactRouter.Route; 334 | 335 | // for RouteHandler 336 | function createElement( 337 | type: ReactRouter.RouteHandlerClass, 338 | props: ReactRouter.RouteHandlerProp, 339 | ...children: __React.ReactNode[]): ReactRouter.RouteHandler; 340 | } 341 | 342 | declare module "react/addons" { 343 | // for DefaultRoute 344 | function createElement( 345 | type: ReactRouter.DefaultRouteClass, 346 | props: ReactRouter.DefaultRouteProp, 347 | ...children: __React.ReactNode[]): ReactRouter.DefaultRoute; 348 | 349 | // for Link 350 | function createElement( 351 | type: ReactRouter.LinkClass, 352 | props: ReactRouter.LinkProp, 353 | ...children: __React.ReactNode[]): ReactRouter.Link; 354 | 355 | // for NotFoundRoute 356 | function createElement( 357 | type: ReactRouter.NotFoundRouteClass, 358 | props: ReactRouter.NotFoundRouteProp, 359 | ...children: __React.ReactNode[]): ReactRouter.NotFoundRoute; 360 | 361 | // for Redirect 362 | function createElement( 363 | type: ReactRouter.RedirectClass, 364 | props: ReactRouter.RedirectProp, 365 | ...children: __React.ReactNode[]): ReactRouter.Redirect; 366 | 367 | // for Route 368 | function createElement( 369 | type: ReactRouter.RouteClass, 370 | props: ReactRouter.RouteProp, 371 | ...children: __React.ReactNode[]): ReactRouter.Route; 372 | 373 | // for RouteHandler 374 | function createElement( 375 | type: ReactRouter.RouteHandlerClass, 376 | props: ReactRouter.RouteHandlerProp, 377 | ...children: __React.ReactNode[]): ReactRouter.RouteHandler; 378 | } 379 | 380 | 381 | declare var activeComponent: any; 382 | 383 | declare module "react-router-active-component" { 384 | export = activeComponent; 385 | } -------------------------------------------------------------------------------- /typings/react/react.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for React v0.13.3 2 | // Project: http://facebook.github.io/react/ 3 | // Definitions by: Asana , AssureSign , Microsoft 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | declare namespace __React { 7 | // 8 | // React Elements 9 | // ---------------------------------------------------------------------- 10 | 11 | type ReactType = ComponentClass | string; 12 | 13 | interface ReactElement

{ 14 | type: string | ComponentClass

; 15 | props: P; 16 | key: string | number; 17 | ref: string | ((component: Component) => any); 18 | } 19 | 20 | interface ClassicElement

extends ReactElement

{ 21 | type: string | ClassicComponentClass

; 22 | ref: string | ((component: ClassicComponent) => any); 23 | } 24 | 25 | interface DOMElement

extends ClassicElement

{ 26 | type: string; 27 | ref: string | ((component: DOMComponent

) => any); 28 | } 29 | 30 | type HTMLElement = DOMElement; 31 | type SVGElement = DOMElement; 32 | 33 | // 34 | // Factories 35 | // ---------------------------------------------------------------------- 36 | 37 | interface Factory

{ 38 | (props?: P, ...children: ReactNode[]): ReactElement

; 39 | } 40 | 41 | interface ClassicFactory

extends Factory

{ 42 | (props?: P, ...children: ReactNode[]): ClassicElement

; 43 | } 44 | 45 | interface DOMFactory

extends ClassicFactory

{ 46 | (props?: P, ...children: ReactNode[]): DOMElement

; 47 | } 48 | 49 | type HTMLFactory = DOMFactory; 50 | type SVGFactory = DOMFactory; 51 | type SVGElementFactory = DOMFactory; 52 | 53 | // 54 | // React Nodes 55 | // http://facebook.github.io/react/docs/glossary.html 56 | // ---------------------------------------------------------------------- 57 | 58 | type ReactText = string | number; 59 | type ReactChild = ReactElement | ReactText; 60 | 61 | // Should be Array but type aliases cannot be recursive 62 | type ReactFragment = {} | Array; 63 | type ReactNode = ReactChild | ReactFragment | boolean; 64 | 65 | // 66 | // Top Level API 67 | // ---------------------------------------------------------------------- 68 | 69 | function createClass(spec: ComponentSpec): ClassicComponentClass

; 70 | 71 | function createFactory

(type: string): DOMFactory

; 72 | function createFactory

(type: ClassicComponentClass

| string): ClassicFactory

; 73 | function createFactory

(type: ComponentClass

): Factory

; 74 | 75 | function createElement

( 76 | type: string, 77 | props?: P, 78 | ...children: ReactNode[]): DOMElement

; 79 | function createElement

( 80 | type: ClassicComponentClass

| string, 81 | props?: P, 82 | ...children: ReactNode[]): ClassicElement

; 83 | function createElement

( 84 | type: ComponentClass

, 85 | props?: P, 86 | ...children: ReactNode[]): ReactElement

; 87 | 88 | function cloneElement

( 89 | element: DOMElement

, 90 | props?: P, 91 | ...children: ReactNode[]): DOMElement

; 92 | function cloneElement

( 93 | element: ClassicElement

, 94 | props?: P, 95 | ...children: ReactNode[]): ClassicElement

; 96 | function cloneElement

( 97 | element: ReactElement

, 98 | props?: P, 99 | ...children: ReactNode[]): ReactElement

; 100 | 101 | function render

( 102 | element: DOMElement

, 103 | container: Element, 104 | callback?: () => any): DOMComponent

; 105 | function render( 106 | element: ClassicElement

, 107 | container: Element, 108 | callback?: () => any): ClassicComponent; 109 | function render( 110 | element: ReactElement

, 111 | container: Element, 112 | callback?: () => any): Component; 113 | 114 | function unmountComponentAtNode(container: Element): boolean; 115 | function renderToString(element: ReactElement): string; 116 | function renderToStaticMarkup(element: ReactElement): string; 117 | function isValidElement(object: {}): boolean; 118 | function initializeTouchEvents(shouldUseTouch: boolean): void; 119 | 120 | function findDOMNode( 121 | componentOrElement: Component | Element): TElement; 122 | function findDOMNode( 123 | componentOrElement: Component | Element): Element; 124 | 125 | var DOM: ReactDOM; 126 | var PropTypes: ReactPropTypes; 127 | var Children: ReactChildren; 128 | 129 | // 130 | // Component API 131 | // ---------------------------------------------------------------------- 132 | 133 | // Base component for plain JS classes 134 | class Component implements ComponentLifecycle { 135 | static propTypes: ValidationMap; 136 | static contextTypes: ValidationMap; 137 | static childContextTypes: ValidationMap; 138 | static defaultProps: Props; 139 | 140 | constructor(props?: P, context?: any); 141 | setState(f: (prevState: S, props: P) => S, callback?: () => any): void; 142 | setState(state: S, callback?: () => any): void; 143 | forceUpdate(callBack?: () => any): void; 144 | render(): JSX.Element; 145 | props: P; 146 | state: S; 147 | context: {}; 148 | refs: { 149 | [key: string]: Component 150 | }; 151 | } 152 | 153 | interface ClassicComponent extends Component { 154 | replaceState(nextState: S, callback?: () => any): void; 155 | getDOMNode(): TElement; 156 | getDOMNode(): Element; 157 | isMounted(): boolean; 158 | getInitialState?(): S; 159 | setProps(nextProps: P, callback?: () => any): void; 160 | replaceProps(nextProps: P, callback?: () => any): void; 161 | } 162 | 163 | interface DOMComponent

extends ClassicComponent { 164 | tagName: string; 165 | } 166 | 167 | type HTMLComponent = DOMComponent; 168 | type SVGComponent = DOMComponent; 169 | 170 | interface ChildContextProvider { 171 | getChildContext(): CC; 172 | } 173 | 174 | // 175 | // Class Interfaces 176 | // ---------------------------------------------------------------------- 177 | 178 | interface ComponentClass

{ 179 | new(props?: P, context?: any): Component; 180 | propTypes?: ValidationMap

; 181 | contextTypes?: ValidationMap; 182 | childContextTypes?: ValidationMap; 183 | defaultProps?: P; 184 | } 185 | 186 | interface ClassicComponentClass

extends ComponentClass

{ 187 | new(props?: P, context?: any): ClassicComponent; 188 | getDefaultProps?(): P; 189 | displayName?: string; 190 | } 191 | 192 | // 193 | // Component Specs and Lifecycle 194 | // ---------------------------------------------------------------------- 195 | 196 | interface ComponentLifecycle { 197 | componentWillMount?(): void; 198 | componentDidMount?(): void; 199 | componentWillReceiveProps?(nextProps: P, nextContext: any): void; 200 | shouldComponentUpdate?(nextProps: P, nextState: S, nextContext: any): boolean; 201 | componentWillUpdate?(nextProps: P, nextState: S, nextContext: any): void; 202 | componentDidUpdate?(prevProps: P, prevState: S, prevContext: any): void; 203 | componentWillUnmount?(): void; 204 | } 205 | 206 | interface Mixin extends ComponentLifecycle { 207 | mixins?: Mixin; 208 | statics?: { 209 | [key: string]: any; 210 | }; 211 | 212 | displayName?: string; 213 | propTypes?: ValidationMap; 214 | contextTypes?: ValidationMap; 215 | childContextTypes?: ValidationMap 216 | 217 | getDefaultProps?(): P; 218 | getInitialState?(): S; 219 | } 220 | 221 | interface ComponentSpec extends Mixin { 222 | render(): ReactElement; 223 | 224 | [propertyName: string]: any; 225 | } 226 | 227 | // 228 | // Event System 229 | // ---------------------------------------------------------------------- 230 | 231 | interface SyntheticEvent { 232 | bubbles: boolean; 233 | cancelable: boolean; 234 | currentTarget: EventTarget; 235 | defaultPrevented: boolean; 236 | eventPhase: number; 237 | isTrusted: boolean; 238 | nativeEvent: Event; 239 | preventDefault(): void; 240 | stopPropagation(): void; 241 | target: EventTarget; 242 | timeStamp: Date; 243 | type: string; 244 | } 245 | 246 | interface DragEvent extends SyntheticEvent { 247 | dataTransfer: DataTransfer; 248 | } 249 | 250 | interface ClipboardEvent extends SyntheticEvent { 251 | clipboardData: DataTransfer; 252 | } 253 | 254 | interface KeyboardEvent extends SyntheticEvent { 255 | altKey: boolean; 256 | charCode: number; 257 | ctrlKey: boolean; 258 | getModifierState(key: string): boolean; 259 | key: string; 260 | keyCode: number; 261 | locale: string; 262 | location: number; 263 | metaKey: boolean; 264 | repeat: boolean; 265 | shiftKey: boolean; 266 | which: number; 267 | } 268 | 269 | interface FocusEvent extends SyntheticEvent { 270 | relatedTarget: EventTarget; 271 | } 272 | 273 | interface FormEvent extends SyntheticEvent { 274 | } 275 | 276 | interface MouseEvent extends SyntheticEvent { 277 | altKey: boolean; 278 | button: number; 279 | buttons: number; 280 | clientX: number; 281 | clientY: number; 282 | ctrlKey: boolean; 283 | getModifierState(key: string): boolean; 284 | metaKey: boolean; 285 | pageX: number; 286 | pageY: number; 287 | relatedTarget: EventTarget; 288 | screenX: number; 289 | screenY: number; 290 | shiftKey: boolean; 291 | } 292 | 293 | interface TouchEvent extends SyntheticEvent { 294 | altKey: boolean; 295 | changedTouches: TouchList; 296 | ctrlKey: boolean; 297 | getModifierState(key: string): boolean; 298 | metaKey: boolean; 299 | shiftKey: boolean; 300 | targetTouches: TouchList; 301 | touches: TouchList; 302 | } 303 | 304 | interface UIEvent extends SyntheticEvent { 305 | detail: number; 306 | view: AbstractView; 307 | } 308 | 309 | interface WheelEvent extends SyntheticEvent { 310 | deltaMode: number; 311 | deltaX: number; 312 | deltaY: number; 313 | deltaZ: number; 314 | } 315 | 316 | // 317 | // Event Handler Types 318 | // ---------------------------------------------------------------------- 319 | 320 | interface EventHandler { 321 | (event: E): void; 322 | } 323 | 324 | interface DragEventHandler extends EventHandler {} 325 | interface ClipboardEventHandler extends EventHandler {} 326 | interface KeyboardEventHandler extends EventHandler {} 327 | interface FocusEventHandler extends EventHandler {} 328 | interface FormEventHandler extends EventHandler {} 329 | interface MouseEventHandler extends EventHandler {} 330 | interface TouchEventHandler extends EventHandler {} 331 | interface UIEventHandler extends EventHandler {} 332 | interface WheelEventHandler extends EventHandler {} 333 | 334 | // 335 | // Props / DOM Attributes 336 | // ---------------------------------------------------------------------- 337 | 338 | interface Props { 339 | children?: ReactNode; 340 | key?: string | number; 341 | ref?: string | ((component: T) => any); 342 | } 343 | 344 | interface DOMAttributesBase extends Props { 345 | onCopy?: ClipboardEventHandler; 346 | onCut?: ClipboardEventHandler; 347 | onPaste?: ClipboardEventHandler; 348 | onKeyDown?: KeyboardEventHandler; 349 | onKeyPress?: KeyboardEventHandler; 350 | onKeyUp?: KeyboardEventHandler; 351 | onFocus?: FocusEventHandler; 352 | onBlur?: FocusEventHandler; 353 | onChange?: FormEventHandler; 354 | onInput?: FormEventHandler; 355 | onSubmit?: FormEventHandler; 356 | onClick?: MouseEventHandler; 357 | onContextMenu?: MouseEventHandler; 358 | onDoubleClick?: MouseEventHandler; 359 | onDrag?: DragEventHandler; 360 | onDragEnd?: DragEventHandler; 361 | onDragEnter?: DragEventHandler; 362 | onDragExit?: DragEventHandler; 363 | onDragLeave?: DragEventHandler; 364 | onDragOver?: DragEventHandler; 365 | onDragStart?: DragEventHandler; 366 | onDrop?: DragEventHandler; 367 | onMouseDown?: MouseEventHandler; 368 | onMouseEnter?: MouseEventHandler; 369 | onMouseLeave?: MouseEventHandler; 370 | onMouseMove?: MouseEventHandler; 371 | onMouseOut?: MouseEventHandler; 372 | onMouseOver?: MouseEventHandler; 373 | onMouseUp?: MouseEventHandler; 374 | onTouchCancel?: TouchEventHandler; 375 | onTouchEnd?: TouchEventHandler; 376 | onTouchMove?: TouchEventHandler; 377 | onTouchStart?: TouchEventHandler; 378 | onScroll?: UIEventHandler; 379 | onWheel?: WheelEventHandler; 380 | 381 | className?: string; 382 | id?: string; 383 | 384 | dangerouslySetInnerHTML?: { 385 | __html: string; 386 | }; 387 | } 388 | 389 | interface DOMAttributes extends DOMAttributesBase> { 390 | } 391 | 392 | // This interface is not complete. Only properties accepting 393 | // unitless numbers are listed here (see CSSProperty.js in React) 394 | interface CSSProperties { 395 | boxFlex?: number; 396 | boxFlexGroup?: number; 397 | columnCount?: number; 398 | flex?: number | string; 399 | flexGrow?: number; 400 | flexShrink?: number; 401 | fontWeight?: number | string; 402 | lineClamp?: number; 403 | lineHeight?: number | string; 404 | opacity?: number; 405 | order?: number; 406 | orphans?: number; 407 | widows?: number; 408 | zIndex?: number; 409 | zoom?: number; 410 | 411 | fontSize?: number | string; 412 | 413 | // SVG-related properties 414 | fillOpacity?: number; 415 | strokeOpacity?: number; 416 | strokeWidth?: number; 417 | 418 | [propertyName: string]: any; 419 | } 420 | 421 | interface HTMLAttributesBase extends DOMAttributesBase { 422 | accept?: string; 423 | acceptCharset?: string; 424 | accessKey?: string; 425 | action?: string; 426 | allowFullScreen?: boolean; 427 | allowTransparency?: boolean; 428 | alt?: string; 429 | async?: boolean; 430 | autoComplete?: boolean; 431 | autoFocus?: boolean; 432 | autoPlay?: boolean; 433 | cellPadding?: number | string; 434 | cellSpacing?: number | string; 435 | charSet?: string; 436 | checked?: boolean; 437 | classID?: string; 438 | cols?: number; 439 | colSpan?: number; 440 | content?: string; 441 | contentEditable?: boolean; 442 | contextMenu?: string; 443 | controls?: any; 444 | coords?: string; 445 | crossOrigin?: string; 446 | data?: string; 447 | dateTime?: string; 448 | defaultChecked?: boolean; 449 | defaultValue?: string; 450 | defer?: boolean; 451 | dir?: string; 452 | disabled?: boolean; 453 | download?: any; 454 | draggable?: boolean; 455 | encType?: string; 456 | form?: string; 457 | formAction?: string; 458 | formEncType?: string; 459 | formMethod?: string; 460 | formNoValidate?: boolean; 461 | formTarget?: string; 462 | frameBorder?: number | string; 463 | headers?: string; 464 | height?: number | string; 465 | hidden?: boolean; 466 | high?: number; 467 | href?: string; 468 | hrefLang?: string; 469 | htmlFor?: string; 470 | httpEquiv?: string; 471 | icon?: string; 472 | label?: string; 473 | lang?: string; 474 | list?: string; 475 | loop?: boolean; 476 | low?: number; 477 | manifest?: string; 478 | marginHeight?: number; 479 | marginWidth?: number; 480 | max?: number | string; 481 | maxLength?: number; 482 | media?: string; 483 | mediaGroup?: string; 484 | method?: string; 485 | min?: number | string; 486 | multiple?: boolean; 487 | muted?: boolean; 488 | name?: string; 489 | noValidate?: boolean; 490 | open?: boolean; 491 | optimum?: number; 492 | pattern?: string; 493 | placeholder?: string; 494 | poster?: string; 495 | preload?: string; 496 | radioGroup?: string; 497 | readOnly?: boolean; 498 | rel?: string; 499 | required?: boolean; 500 | role?: string; 501 | rows?: number; 502 | rowSpan?: number; 503 | sandbox?: string; 504 | scope?: string; 505 | scoped?: boolean; 506 | scrolling?: string; 507 | seamless?: boolean; 508 | selected?: boolean; 509 | shape?: string; 510 | size?: number; 511 | sizes?: string; 512 | span?: number; 513 | spellCheck?: boolean; 514 | src?: string; 515 | srcDoc?: string; 516 | srcSet?: string; 517 | start?: number; 518 | step?: number | string; 519 | style?: CSSProperties; 520 | tabIndex?: number; 521 | target?: string; 522 | title?: string; 523 | type?: string; 524 | useMap?: string; 525 | value?: string; 526 | width?: number | string; 527 | wmode?: string; 528 | 529 | // Non-standard Attributes 530 | autoCapitalize?: boolean; 531 | autoCorrect?: boolean; 532 | property?: string; 533 | itemProp?: string; 534 | itemScope?: boolean; 535 | itemType?: string; 536 | unselectable?: boolean; 537 | } 538 | 539 | interface HTMLAttributes extends HTMLAttributesBase { 540 | } 541 | 542 | interface SVGElementAttributes extends HTMLAttributes { 543 | viewBox?: string; 544 | preserveAspectRatio?: string; 545 | } 546 | 547 | interface SVGAttributes extends DOMAttributes { 548 | ref?: string | ((component: SVGComponent) => void); 549 | 550 | cx?: number | string; 551 | cy?: number | string; 552 | d?: string; 553 | dx?: number | string; 554 | dy?: number | string; 555 | fill?: string; 556 | fillOpacity?: number | string; 557 | fontFamily?: string; 558 | fontSize?: number | string; 559 | fx?: number | string; 560 | fy?: number | string; 561 | gradientTransform?: string; 562 | gradientUnits?: string; 563 | height?: number | string; 564 | markerEnd?: string; 565 | markerMid?: string; 566 | markerStart?: string; 567 | offset?: number | string; 568 | opacity?: number | string; 569 | patternContentUnits?: string; 570 | patternUnits?: string; 571 | points?: string; 572 | preserveAspectRatio?: string; 573 | r?: number | string; 574 | rx?: number | string; 575 | ry?: number | string; 576 | spreadMethod?: string; 577 | stopColor?: string; 578 | stopOpacity?: number | string; 579 | stroke?: string; 580 | strokeDasharray?: string; 581 | strokeLinecap?: string; 582 | strokeMiterlimit?: string; 583 | strokeOpacity?: number | string; 584 | strokeWidth?: number | string; 585 | textAnchor?: string; 586 | transform?: string; 587 | version?: string; 588 | viewBox?: string; 589 | width?: number | string; 590 | x1?: number | string; 591 | x2?: number | string; 592 | x?: number | string; 593 | y1?: number | string; 594 | y2?: number | string 595 | y?: number | string; 596 | } 597 | 598 | // 599 | // React.DOM 600 | // ---------------------------------------------------------------------- 601 | 602 | interface ReactDOM { 603 | // HTML 604 | a: HTMLFactory; 605 | abbr: HTMLFactory; 606 | address: HTMLFactory; 607 | area: HTMLFactory; 608 | article: HTMLFactory; 609 | aside: HTMLFactory; 610 | audio: HTMLFactory; 611 | b: HTMLFactory; 612 | base: HTMLFactory; 613 | bdi: HTMLFactory; 614 | bdo: HTMLFactory; 615 | big: HTMLFactory; 616 | blockquote: HTMLFactory; 617 | body: HTMLFactory; 618 | br: HTMLFactory; 619 | button: HTMLFactory; 620 | canvas: HTMLFactory; 621 | caption: HTMLFactory; 622 | cite: HTMLFactory; 623 | code: HTMLFactory; 624 | col: HTMLFactory; 625 | colgroup: HTMLFactory; 626 | data: HTMLFactory; 627 | datalist: HTMLFactory; 628 | dd: HTMLFactory; 629 | del: HTMLFactory; 630 | details: HTMLFactory; 631 | dfn: HTMLFactory; 632 | dialog: HTMLFactory; 633 | div: HTMLFactory; 634 | dl: HTMLFactory; 635 | dt: HTMLFactory; 636 | em: HTMLFactory; 637 | embed: HTMLFactory; 638 | fieldset: HTMLFactory; 639 | figcaption: HTMLFactory; 640 | figure: HTMLFactory; 641 | footer: HTMLFactory; 642 | form: HTMLFactory; 643 | h1: HTMLFactory; 644 | h2: HTMLFactory; 645 | h3: HTMLFactory; 646 | h4: HTMLFactory; 647 | h5: HTMLFactory; 648 | h6: HTMLFactory; 649 | head: HTMLFactory; 650 | header: HTMLFactory; 651 | hr: HTMLFactory; 652 | html: HTMLFactory; 653 | i: HTMLFactory; 654 | iframe: HTMLFactory; 655 | img: HTMLFactory; 656 | input: HTMLFactory; 657 | ins: HTMLFactory; 658 | kbd: HTMLFactory; 659 | keygen: HTMLFactory; 660 | label: HTMLFactory; 661 | legend: HTMLFactory; 662 | li: HTMLFactory; 663 | link: HTMLFactory; 664 | main: HTMLFactory; 665 | map: HTMLFactory; 666 | mark: HTMLFactory; 667 | menu: HTMLFactory; 668 | menuitem: HTMLFactory; 669 | meta: HTMLFactory; 670 | meter: HTMLFactory; 671 | nav: HTMLFactory; 672 | noscript: HTMLFactory; 673 | object: HTMLFactory; 674 | ol: HTMLFactory; 675 | optgroup: HTMLFactory; 676 | option: HTMLFactory; 677 | output: HTMLFactory; 678 | p: HTMLFactory; 679 | param: HTMLFactory; 680 | picture: HTMLFactory; 681 | pre: HTMLFactory; 682 | progress: HTMLFactory; 683 | q: HTMLFactory; 684 | rp: HTMLFactory; 685 | rt: HTMLFactory; 686 | ruby: HTMLFactory; 687 | s: HTMLFactory; 688 | samp: HTMLFactory; 689 | script: HTMLFactory; 690 | section: HTMLFactory; 691 | select: HTMLFactory; 692 | small: HTMLFactory; 693 | source: HTMLFactory; 694 | span: HTMLFactory; 695 | strong: HTMLFactory; 696 | style: HTMLFactory; 697 | sub: HTMLFactory; 698 | summary: HTMLFactory; 699 | sup: HTMLFactory; 700 | table: HTMLFactory; 701 | tbody: HTMLFactory; 702 | td: HTMLFactory; 703 | textarea: HTMLFactory; 704 | tfoot: HTMLFactory; 705 | th: HTMLFactory; 706 | thead: HTMLFactory; 707 | time: HTMLFactory; 708 | title: HTMLFactory; 709 | tr: HTMLFactory; 710 | track: HTMLFactory; 711 | u: HTMLFactory; 712 | ul: HTMLFactory; 713 | "var": HTMLFactory; 714 | video: HTMLFactory; 715 | wbr: HTMLFactory; 716 | 717 | // SVG 718 | svg: SVGElementFactory; 719 | circle: SVGFactory; 720 | defs: SVGFactory; 721 | ellipse: SVGFactory; 722 | g: SVGFactory; 723 | line: SVGFactory; 724 | linearGradient: SVGFactory; 725 | mask: SVGFactory; 726 | path: SVGFactory; 727 | pattern: SVGFactory; 728 | polygon: SVGFactory; 729 | polyline: SVGFactory; 730 | radialGradient: SVGFactory; 731 | rect: SVGFactory; 732 | stop: SVGFactory; 733 | text: SVGFactory; 734 | tspan: SVGFactory; 735 | } 736 | 737 | // 738 | // React.PropTypes 739 | // ---------------------------------------------------------------------- 740 | 741 | interface Validator { 742 | (object: T, key: string, componentName: string): Error; 743 | } 744 | 745 | interface Requireable extends Validator { 746 | isRequired: Validator; 747 | } 748 | 749 | interface ValidationMap { 750 | [key: string]: Validator; 751 | } 752 | 753 | interface ReactPropTypes { 754 | any: Requireable; 755 | array: Requireable; 756 | bool: Requireable; 757 | func: Requireable; 758 | number: Requireable; 759 | object: Requireable; 760 | string: Requireable; 761 | node: Requireable; 762 | element: Requireable; 763 | instanceOf(expectedClass: {}): Requireable; 764 | oneOf(types: any[]): Requireable; 765 | oneOfType(types: Validator[]): Requireable; 766 | arrayOf(type: Validator): Requireable; 767 | objectOf(type: Validator): Requireable; 768 | shape(type: ValidationMap): Requireable; 769 | } 770 | 771 | // 772 | // React.Children 773 | // ---------------------------------------------------------------------- 774 | 775 | interface ReactChildren { 776 | map(children: ReactNode, fn: (child: ReactChild, index: number) => T): { [key:string]: T }; 777 | forEach(children: ReactNode, fn: (child: ReactChild, index: number) => any): void; 778 | count(children: ReactNode): number; 779 | only(children: ReactNode): ReactChild; 780 | } 781 | 782 | // 783 | // Browser Interfaces 784 | // https://github.com/nikeee/2048-typescript/blob/master/2048/js/touch.d.ts 785 | // ---------------------------------------------------------------------- 786 | 787 | interface AbstractView { 788 | styleMedia: StyleMedia; 789 | document: Document; 790 | } 791 | 792 | interface Touch { 793 | identifier: number; 794 | target: EventTarget; 795 | screenX: number; 796 | screenY: number; 797 | clientX: number; 798 | clientY: number; 799 | pageX: number; 800 | pageY: number; 801 | } 802 | 803 | interface TouchList { 804 | [index: number]: Touch; 805 | length: number; 806 | item(index: number): Touch; 807 | identifiedTouch(identifier: number): Touch; 808 | } 809 | } 810 | 811 | declare module "react" { 812 | export = __React; 813 | } 814 | 815 | declare module "react/addons" { 816 | // 817 | // React Elements 818 | // ---------------------------------------------------------------------- 819 | 820 | type ReactType = ComponentClass | string; 821 | 822 | interface ReactElement

{ 823 | type: string | ComponentClass

; 824 | props: P; 825 | key: string | number; 826 | ref: string | ((component: Component) => any); 827 | } 828 | 829 | interface ClassicElement

extends ReactElement

{ 830 | type: string | ClassicComponentClass

; 831 | ref: string | ((component: ClassicComponent) => any); 832 | } 833 | 834 | interface DOMElement

extends ClassicElement

{ 835 | type: string; 836 | ref: string | ((component: DOMComponent

) => any); 837 | } 838 | 839 | type HTMLElement = DOMElement; 840 | type SVGElement = DOMElement; 841 | 842 | // 843 | // Factories 844 | // ---------------------------------------------------------------------- 845 | 846 | interface Factory

{ 847 | (props?: P, ...children: ReactNode[]): ReactElement

; 848 | } 849 | 850 | interface ClassicFactory

extends Factory

{ 851 | (props?: P, ...children: ReactNode[]): ClassicElement

; 852 | } 853 | 854 | interface DOMFactory

extends ClassicFactory

{ 855 | (props?: P, ...children: ReactNode[]): DOMElement

; 856 | } 857 | 858 | type HTMLFactory = DOMFactory; 859 | type SVGFactory = DOMFactory; 860 | type SVGElementFactory = DOMFactory; 861 | 862 | // 863 | // React Nodes 864 | // http://facebook.github.io/react/docs/glossary.html 865 | // ---------------------------------------------------------------------- 866 | 867 | type ReactText = string | number; 868 | type ReactChild = ReactElement | ReactText; 869 | 870 | // Should be Array but type aliases cannot be recursive 871 | type ReactFragment = {} | Array; 872 | type ReactNode = ReactChild | ReactFragment | boolean; 873 | 874 | // 875 | // Top Level API 876 | // ---------------------------------------------------------------------- 877 | 878 | function createClass(spec: ComponentSpec): ClassicComponentClass

; 879 | 880 | function createFactory

(type: string): DOMFactory

; 881 | function createFactory

(type: ClassicComponentClass

| string): ClassicFactory

; 882 | function createFactory

(type: ComponentClass

): Factory

; 883 | 884 | function createElement

( 885 | type: string, 886 | props?: P, 887 | ...children: ReactNode[]): DOMElement

; 888 | function createElement

( 889 | type: ClassicComponentClass

| string, 890 | props?: P, 891 | ...children: ReactNode[]): ClassicElement

; 892 | function createElement

( 893 | type: ComponentClass

, 894 | props?: P, 895 | ...children: ReactNode[]): ReactElement

; 896 | 897 | function cloneElement

( 898 | element: DOMElement

, 899 | props?: P, 900 | ...children: ReactNode[]): DOMElement

; 901 | function cloneElement

( 902 | element: ClassicElement

, 903 | props?: P, 904 | ...children: ReactNode[]): ClassicElement

; 905 | function cloneElement

( 906 | element: ReactElement

, 907 | props?: P, 908 | ...children: ReactNode[]): ReactElement

; 909 | 910 | function render

( 911 | element: DOMElement

, 912 | container: Element, 913 | callback?: () => any): DOMComponent

; 914 | function render( 915 | element: ClassicElement

, 916 | container: Element, 917 | callback?: () => any): ClassicComponent; 918 | function render( 919 | element: ReactElement

, 920 | container: Element, 921 | callback?: () => any): Component; 922 | 923 | function unmountComponentAtNode(container: Element): boolean; 924 | function renderToString(element: ReactElement): string; 925 | function renderToStaticMarkup(element: ReactElement): string; 926 | function isValidElement(object: {}): boolean; 927 | function initializeTouchEvents(shouldUseTouch: boolean): void; 928 | 929 | function findDOMNode( 930 | componentOrElement: Component | Element): TElement; 931 | function findDOMNode( 932 | componentOrElement: Component | Element): Element; 933 | 934 | var DOM: ReactDOM; 935 | var PropTypes: ReactPropTypes; 936 | var Children: ReactChildren; 937 | 938 | // 939 | // Component API 940 | // ---------------------------------------------------------------------- 941 | 942 | // Base component for plain JS classes 943 | class Component implements ComponentLifecycle { 944 | static propTypes: ValidationMap; 945 | static contextTypes: ValidationMap; 946 | static childContextTypes: ValidationMap; 947 | static defaultProps: Props; 948 | 949 | constructor(props?: P, context?: any); 950 | setState(f: (prevState: S, props: P) => S, callback?: () => any): void; 951 | setState(state: S, callback?: () => any): void; 952 | forceUpdate(callBack?: () => any): void; 953 | render(): JSX.Element; 954 | props: P; 955 | state: S; 956 | context: {}; 957 | refs: { 958 | [key: string]: Component 959 | }; 960 | } 961 | 962 | interface ClassicComponent extends Component { 963 | replaceState(nextState: S, callback?: () => any): void; 964 | getDOMNode(): TElement; 965 | getDOMNode(): Element; 966 | isMounted(): boolean; 967 | getInitialState?(): S; 968 | setProps(nextProps: P, callback?: () => any): void; 969 | replaceProps(nextProps: P, callback?: () => any): void; 970 | } 971 | 972 | interface DOMComponent

extends ClassicComponent { 973 | tagName: string; 974 | } 975 | 976 | type HTMLComponent = DOMComponent; 977 | type SVGComponent = DOMComponent; 978 | 979 | interface ChildContextProvider { 980 | getChildContext(): CC; 981 | } 982 | 983 | // 984 | // Class Interfaces 985 | // ---------------------------------------------------------------------- 986 | 987 | interface ComponentClass

{ 988 | new(props?: P, context?: any): Component; 989 | propTypes?: ValidationMap

; 990 | contextTypes?: ValidationMap; 991 | childContextTypes?: ValidationMap; 992 | defaultProps?: P; 993 | } 994 | 995 | interface ClassicComponentClass

extends ComponentClass

{ 996 | new(props?: P, context?: any): ClassicComponent; 997 | getDefaultProps?(): P; 998 | displayName?: string; 999 | } 1000 | 1001 | // 1002 | // Component Specs and Lifecycle 1003 | // ---------------------------------------------------------------------- 1004 | 1005 | interface ComponentLifecycle { 1006 | componentWillMount?(): void; 1007 | componentDidMount?(): void; 1008 | componentWillReceiveProps?(nextProps: P, nextContext: any): void; 1009 | shouldComponentUpdate?(nextProps: P, nextState: S, nextContext: any): boolean; 1010 | componentWillUpdate?(nextProps: P, nextState: S, nextContext: any): void; 1011 | componentDidUpdate?(prevProps: P, prevState: S, prevContext: any): void; 1012 | componentWillUnmount?(): void; 1013 | } 1014 | 1015 | interface Mixin extends ComponentLifecycle { 1016 | mixins?: Mixin; 1017 | statics?: { 1018 | [key: string]: any; 1019 | }; 1020 | 1021 | displayName?: string; 1022 | propTypes?: ValidationMap; 1023 | contextTypes?: ValidationMap; 1024 | childContextTypes?: ValidationMap 1025 | 1026 | getDefaultProps?(): P; 1027 | getInitialState?(): S; 1028 | } 1029 | 1030 | interface ComponentSpec extends Mixin { 1031 | render(): ReactElement; 1032 | 1033 | [propertyName: string]: any; 1034 | } 1035 | 1036 | // 1037 | // Event System 1038 | // ---------------------------------------------------------------------- 1039 | 1040 | interface SyntheticEvent { 1041 | bubbles: boolean; 1042 | cancelable: boolean; 1043 | currentTarget: EventTarget; 1044 | defaultPrevented: boolean; 1045 | eventPhase: number; 1046 | isTrusted: boolean; 1047 | nativeEvent: Event; 1048 | preventDefault(): void; 1049 | stopPropagation(): void; 1050 | target: EventTarget; 1051 | timeStamp: Date; 1052 | type: string; 1053 | } 1054 | 1055 | interface DragEvent extends SyntheticEvent { 1056 | dataTransfer: DataTransfer; 1057 | } 1058 | 1059 | interface ClipboardEvent extends SyntheticEvent { 1060 | clipboardData: DataTransfer; 1061 | } 1062 | 1063 | interface KeyboardEvent extends SyntheticEvent { 1064 | altKey: boolean; 1065 | charCode: number; 1066 | ctrlKey: boolean; 1067 | getModifierState(key: string): boolean; 1068 | key: string; 1069 | keyCode: number; 1070 | locale: string; 1071 | location: number; 1072 | metaKey: boolean; 1073 | repeat: boolean; 1074 | shiftKey: boolean; 1075 | which: number; 1076 | } 1077 | 1078 | interface FocusEvent extends SyntheticEvent { 1079 | relatedTarget: EventTarget; 1080 | } 1081 | 1082 | interface FormEvent extends SyntheticEvent { 1083 | } 1084 | 1085 | interface MouseEvent extends SyntheticEvent { 1086 | altKey: boolean; 1087 | button: number; 1088 | buttons: number; 1089 | clientX: number; 1090 | clientY: number; 1091 | ctrlKey: boolean; 1092 | getModifierState(key: string): boolean; 1093 | metaKey: boolean; 1094 | pageX: number; 1095 | pageY: number; 1096 | relatedTarget: EventTarget; 1097 | screenX: number; 1098 | screenY: number; 1099 | shiftKey: boolean; 1100 | } 1101 | 1102 | interface TouchEvent extends SyntheticEvent { 1103 | altKey: boolean; 1104 | changedTouches: TouchList; 1105 | ctrlKey: boolean; 1106 | getModifierState(key: string): boolean; 1107 | metaKey: boolean; 1108 | shiftKey: boolean; 1109 | targetTouches: TouchList; 1110 | touches: TouchList; 1111 | } 1112 | 1113 | interface UIEvent extends SyntheticEvent { 1114 | detail: number; 1115 | view: AbstractView; 1116 | } 1117 | 1118 | interface WheelEvent extends SyntheticEvent { 1119 | deltaMode: number; 1120 | deltaX: number; 1121 | deltaY: number; 1122 | deltaZ: number; 1123 | } 1124 | 1125 | // 1126 | // Event Handler Types 1127 | // ---------------------------------------------------------------------- 1128 | 1129 | interface EventHandler { 1130 | (event: E): void; 1131 | } 1132 | 1133 | interface DragEventHandler extends EventHandler {} 1134 | interface ClipboardEventHandler extends EventHandler {} 1135 | interface KeyboardEventHandler extends EventHandler {} 1136 | interface FocusEventHandler extends EventHandler {} 1137 | interface FormEventHandler extends EventHandler {} 1138 | interface MouseEventHandler extends EventHandler {} 1139 | interface TouchEventHandler extends EventHandler {} 1140 | interface UIEventHandler extends EventHandler {} 1141 | interface WheelEventHandler extends EventHandler {} 1142 | 1143 | // 1144 | // Props / DOM Attributes 1145 | // ---------------------------------------------------------------------- 1146 | 1147 | interface Props { 1148 | children?: ReactNode; 1149 | key?: string | number; 1150 | ref?: string | ((component: T) => any); 1151 | } 1152 | 1153 | interface DOMAttributesBase extends Props { 1154 | onCopy?: ClipboardEventHandler; 1155 | onCut?: ClipboardEventHandler; 1156 | onPaste?: ClipboardEventHandler; 1157 | onKeyDown?: KeyboardEventHandler; 1158 | onKeyPress?: KeyboardEventHandler; 1159 | onKeyUp?: KeyboardEventHandler; 1160 | onFocus?: FocusEventHandler; 1161 | onBlur?: FocusEventHandler; 1162 | onChange?: FormEventHandler; 1163 | onInput?: FormEventHandler; 1164 | onSubmit?: FormEventHandler; 1165 | onClick?: MouseEventHandler; 1166 | onDoubleClick?: MouseEventHandler; 1167 | onDrag?: DragEventHandler; 1168 | onDragEnd?: DragEventHandler; 1169 | onDragEnter?: DragEventHandler; 1170 | onDragExit?: DragEventHandler; 1171 | onDragLeave?: DragEventHandler; 1172 | onDragOver?: DragEventHandler; 1173 | onDragStart?: DragEventHandler; 1174 | onDrop?: DragEventHandler; 1175 | onMouseDown?: MouseEventHandler; 1176 | onMouseEnter?: MouseEventHandler; 1177 | onMouseLeave?: MouseEventHandler; 1178 | onMouseMove?: MouseEventHandler; 1179 | onMouseOut?: MouseEventHandler; 1180 | onMouseOver?: MouseEventHandler; 1181 | onMouseUp?: MouseEventHandler; 1182 | onTouchCancel?: TouchEventHandler; 1183 | onTouchEnd?: TouchEventHandler; 1184 | onTouchMove?: TouchEventHandler; 1185 | onTouchStart?: TouchEventHandler; 1186 | onScroll?: UIEventHandler; 1187 | onWheel?: WheelEventHandler; 1188 | 1189 | className?: string; 1190 | id?: string; 1191 | 1192 | dangerouslySetInnerHTML?: { 1193 | __html: string; 1194 | }; 1195 | } 1196 | 1197 | interface DOMAttributes extends DOMAttributesBase> { 1198 | } 1199 | 1200 | // This interface is not complete. Only properties accepting 1201 | // unitless numbers are listed here (see CSSProperty.js in React) 1202 | interface CSSProperties { 1203 | boxFlex?: number; 1204 | boxFlexGroup?: number; 1205 | columnCount?: number; 1206 | flex?: number | string; 1207 | flexGrow?: number; 1208 | flexShrink?: number; 1209 | fontWeight?: number | string; 1210 | lineClamp?: number; 1211 | lineHeight?: number | string; 1212 | opacity?: number; 1213 | order?: number; 1214 | orphans?: number; 1215 | widows?: number; 1216 | zIndex?: number; 1217 | zoom?: number; 1218 | 1219 | fontSize?: number | string; 1220 | 1221 | // SVG-related properties 1222 | fillOpacity?: number; 1223 | strokeOpacity?: number; 1224 | strokeWidth?: number; 1225 | 1226 | [propertyName: string]: any; 1227 | } 1228 | 1229 | interface HTMLAttributesBase extends DOMAttributesBase { 1230 | accept?: string; 1231 | acceptCharset?: string; 1232 | accessKey?: string; 1233 | action?: string; 1234 | allowFullScreen?: boolean; 1235 | allowTransparency?: boolean; 1236 | alt?: string; 1237 | async?: boolean; 1238 | autoComplete?: boolean; 1239 | autoFocus?: boolean; 1240 | autoPlay?: boolean; 1241 | cellPadding?: number | string; 1242 | cellSpacing?: number | string; 1243 | charSet?: string; 1244 | checked?: boolean; 1245 | classID?: string; 1246 | cols?: number; 1247 | colSpan?: number; 1248 | content?: string; 1249 | contentEditable?: boolean; 1250 | contextMenu?: string; 1251 | controls?: any; 1252 | coords?: string; 1253 | crossOrigin?: string; 1254 | data?: string; 1255 | dateTime?: string; 1256 | defaultChecked?: boolean; 1257 | defaultValue?: string; 1258 | defer?: boolean; 1259 | dir?: string; 1260 | disabled?: boolean; 1261 | download?: any; 1262 | draggable?: boolean; 1263 | encType?: string; 1264 | form?: string; 1265 | formAction?: string; 1266 | formEncType?: string; 1267 | formMethod?: string; 1268 | formNoValidate?: boolean; 1269 | formTarget?: string; 1270 | frameBorder?: number | string; 1271 | headers?: string; 1272 | height?: number | string; 1273 | hidden?: boolean; 1274 | high?: number; 1275 | href?: string; 1276 | hrefLang?: string; 1277 | htmlFor?: string; 1278 | httpEquiv?: string; 1279 | icon?: string; 1280 | label?: string; 1281 | lang?: string; 1282 | list?: string; 1283 | loop?: boolean; 1284 | low?: number; 1285 | manifest?: string; 1286 | marginHeight?: number; 1287 | marginWidth?: number; 1288 | max?: number | string; 1289 | maxLength?: number; 1290 | media?: string; 1291 | mediaGroup?: string; 1292 | method?: string; 1293 | min?: number | string; 1294 | multiple?: boolean; 1295 | muted?: boolean; 1296 | name?: string; 1297 | noValidate?: boolean; 1298 | open?: boolean; 1299 | optimum?: number; 1300 | pattern?: string; 1301 | placeholder?: string; 1302 | poster?: string; 1303 | preload?: string; 1304 | radioGroup?: string; 1305 | readOnly?: boolean; 1306 | rel?: string; 1307 | required?: boolean; 1308 | role?: string; 1309 | rows?: number; 1310 | rowSpan?: number; 1311 | sandbox?: string; 1312 | scope?: string; 1313 | scoped?: boolean; 1314 | scrolling?: string; 1315 | seamless?: boolean; 1316 | selected?: boolean; 1317 | shape?: string; 1318 | size?: number; 1319 | sizes?: string; 1320 | span?: number; 1321 | spellCheck?: boolean; 1322 | src?: string; 1323 | srcDoc?: string; 1324 | srcSet?: string; 1325 | start?: number; 1326 | step?: number | string; 1327 | style?: CSSProperties; 1328 | tabIndex?: number; 1329 | target?: string; 1330 | title?: string; 1331 | type?: string; 1332 | useMap?: string; 1333 | value?: string; 1334 | width?: number | string; 1335 | wmode?: string; 1336 | 1337 | // Non-standard Attributes 1338 | autoCapitalize?: boolean; 1339 | autoCorrect?: boolean; 1340 | property?: string; 1341 | itemProp?: string; 1342 | itemScope?: boolean; 1343 | itemType?: string; 1344 | unselectable?: boolean; 1345 | } 1346 | 1347 | interface HTMLAttributes extends HTMLAttributesBase { 1348 | } 1349 | 1350 | interface SVGElementAttributes extends HTMLAttributes { 1351 | viewBox?: string; 1352 | preserveAspectRatio?: string; 1353 | } 1354 | 1355 | interface SVGAttributes extends DOMAttributes { 1356 | ref?: string | ((component: SVGComponent) => void); 1357 | 1358 | cx?: number | string; 1359 | cy?: number | string; 1360 | d?: string; 1361 | dx?: number | string; 1362 | dy?: number | string; 1363 | fill?: string; 1364 | fillOpacity?: number | string; 1365 | fontFamily?: string; 1366 | fontSize?: number | string; 1367 | fx?: number | string; 1368 | fy?: number | string; 1369 | gradientTransform?: string; 1370 | gradientUnits?: string; 1371 | height?: number | string; 1372 | markerEnd?: string; 1373 | markerMid?: string; 1374 | markerStart?: string; 1375 | offset?: number | string; 1376 | opacity?: number | string; 1377 | patternContentUnits?: string; 1378 | patternUnits?: string; 1379 | points?: string; 1380 | preserveAspectRatio?: string; 1381 | r?: number | string; 1382 | rx?: number | string; 1383 | ry?: number | string; 1384 | spreadMethod?: string; 1385 | stopColor?: string; 1386 | stopOpacity?: number | string; 1387 | stroke?: string; 1388 | strokeDasharray?: string; 1389 | strokeLinecap?: string; 1390 | strokeMiterlimit?: string; 1391 | strokeOpacity?: number | string; 1392 | strokeWidth?: number | string; 1393 | textAnchor?: string; 1394 | transform?: string; 1395 | version?: string; 1396 | viewBox?: string; 1397 | width?: number | string; 1398 | x1?: number | string; 1399 | x2?: number | string; 1400 | x?: number | string; 1401 | y1?: number | string; 1402 | y2?: number | string 1403 | y?: number | string; 1404 | } 1405 | 1406 | // 1407 | // React.DOM 1408 | // ---------------------------------------------------------------------- 1409 | 1410 | interface ReactDOM { 1411 | // HTML 1412 | a: HTMLFactory; 1413 | abbr: HTMLFactory; 1414 | address: HTMLFactory; 1415 | area: HTMLFactory; 1416 | article: HTMLFactory; 1417 | aside: HTMLFactory; 1418 | audio: HTMLFactory; 1419 | b: HTMLFactory; 1420 | base: HTMLFactory; 1421 | bdi: HTMLFactory; 1422 | bdo: HTMLFactory; 1423 | big: HTMLFactory; 1424 | blockquote: HTMLFactory; 1425 | body: HTMLFactory; 1426 | br: HTMLFactory; 1427 | button: HTMLFactory; 1428 | canvas: HTMLFactory; 1429 | caption: HTMLFactory; 1430 | cite: HTMLFactory; 1431 | code: HTMLFactory; 1432 | col: HTMLFactory; 1433 | colgroup: HTMLFactory; 1434 | data: HTMLFactory; 1435 | datalist: HTMLFactory; 1436 | dd: HTMLFactory; 1437 | del: HTMLFactory; 1438 | details: HTMLFactory; 1439 | dfn: HTMLFactory; 1440 | dialog: HTMLFactory; 1441 | div: HTMLFactory; 1442 | dl: HTMLFactory; 1443 | dt: HTMLFactory; 1444 | em: HTMLFactory; 1445 | embed: HTMLFactory; 1446 | fieldset: HTMLFactory; 1447 | figcaption: HTMLFactory; 1448 | figure: HTMLFactory; 1449 | footer: HTMLFactory; 1450 | form: HTMLFactory; 1451 | h1: HTMLFactory; 1452 | h2: HTMLFactory; 1453 | h3: HTMLFactory; 1454 | h4: HTMLFactory; 1455 | h5: HTMLFactory; 1456 | h6: HTMLFactory; 1457 | head: HTMLFactory; 1458 | header: HTMLFactory; 1459 | hr: HTMLFactory; 1460 | html: HTMLFactory; 1461 | i: HTMLFactory; 1462 | iframe: HTMLFactory; 1463 | img: HTMLFactory; 1464 | input: HTMLFactory; 1465 | ins: HTMLFactory; 1466 | kbd: HTMLFactory; 1467 | keygen: HTMLFactory; 1468 | label: HTMLFactory; 1469 | legend: HTMLFactory; 1470 | li: HTMLFactory; 1471 | link: HTMLFactory; 1472 | main: HTMLFactory; 1473 | map: HTMLFactory; 1474 | mark: HTMLFactory; 1475 | menu: HTMLFactory; 1476 | menuitem: HTMLFactory; 1477 | meta: HTMLFactory; 1478 | meter: HTMLFactory; 1479 | nav: HTMLFactory; 1480 | noscript: HTMLFactory; 1481 | object: HTMLFactory; 1482 | ol: HTMLFactory; 1483 | optgroup: HTMLFactory; 1484 | option: HTMLFactory; 1485 | output: HTMLFactory; 1486 | p: HTMLFactory; 1487 | param: HTMLFactory; 1488 | picture: HTMLFactory; 1489 | pre: HTMLFactory; 1490 | progress: HTMLFactory; 1491 | q: HTMLFactory; 1492 | rp: HTMLFactory; 1493 | rt: HTMLFactory; 1494 | ruby: HTMLFactory; 1495 | s: HTMLFactory; 1496 | samp: HTMLFactory; 1497 | script: HTMLFactory; 1498 | section: HTMLFactory; 1499 | select: HTMLFactory; 1500 | small: HTMLFactory; 1501 | source: HTMLFactory; 1502 | span: HTMLFactory; 1503 | strong: HTMLFactory; 1504 | style: HTMLFactory; 1505 | sub: HTMLFactory; 1506 | summary: HTMLFactory; 1507 | sup: HTMLFactory; 1508 | table: HTMLFactory; 1509 | tbody: HTMLFactory; 1510 | td: HTMLFactory; 1511 | textarea: HTMLFactory; 1512 | tfoot: HTMLFactory; 1513 | th: HTMLFactory; 1514 | thead: HTMLFactory; 1515 | time: HTMLFactory; 1516 | title: HTMLFactory; 1517 | tr: HTMLFactory; 1518 | track: HTMLFactory; 1519 | u: HTMLFactory; 1520 | ul: HTMLFactory; 1521 | "var": HTMLFactory; 1522 | video: HTMLFactory; 1523 | wbr: HTMLFactory; 1524 | 1525 | // SVG 1526 | svg: SVGElementFactory; 1527 | circle: SVGFactory; 1528 | defs: SVGFactory; 1529 | ellipse: SVGFactory; 1530 | g: SVGFactory; 1531 | line: SVGFactory; 1532 | linearGradient: SVGFactory; 1533 | mask: SVGFactory; 1534 | path: SVGFactory; 1535 | pattern: SVGFactory; 1536 | polygon: SVGFactory; 1537 | polyline: SVGFactory; 1538 | radialGradient: SVGFactory; 1539 | rect: SVGFactory; 1540 | stop: SVGFactory; 1541 | text: SVGFactory; 1542 | tspan: SVGFactory; 1543 | } 1544 | 1545 | // 1546 | // React.PropTypes 1547 | // ---------------------------------------------------------------------- 1548 | 1549 | interface Validator { 1550 | (object: T, key: string, componentName: string): Error; 1551 | } 1552 | 1553 | interface Requireable extends Validator { 1554 | isRequired: Validator; 1555 | } 1556 | 1557 | interface ValidationMap { 1558 | [key: string]: Validator; 1559 | } 1560 | 1561 | interface ReactPropTypes { 1562 | any: Requireable; 1563 | array: Requireable; 1564 | bool: Requireable; 1565 | func: Requireable; 1566 | number: Requireable; 1567 | object: Requireable; 1568 | string: Requireable; 1569 | node: Requireable; 1570 | element: Requireable; 1571 | instanceOf(expectedClass: {}): Requireable; 1572 | oneOf(types: any[]): Requireable; 1573 | oneOfType(types: Validator[]): Requireable; 1574 | arrayOf(type: Validator): Requireable; 1575 | objectOf(type: Validator): Requireable; 1576 | shape(type: ValidationMap): Requireable; 1577 | } 1578 | 1579 | // 1580 | // React.Children 1581 | // ---------------------------------------------------------------------- 1582 | 1583 | interface ReactChildren { 1584 | map(children: ReactNode, fn: (child: ReactChild, index: number) => T): { [key:string]: T }; 1585 | forEach(children: ReactNode, fn: (child: ReactChild, index: number) => any): void; 1586 | count(children: ReactNode): number; 1587 | only(children: ReactNode): ReactChild; 1588 | } 1589 | 1590 | // 1591 | // Browser Interfaces 1592 | // https://github.com/nikeee/2048-typescript/blob/master/2048/js/touch.d.ts 1593 | // ---------------------------------------------------------------------- 1594 | 1595 | interface AbstractView { 1596 | styleMedia: StyleMedia; 1597 | document: Document; 1598 | } 1599 | 1600 | interface Touch { 1601 | identifier: number; 1602 | target: EventTarget; 1603 | screenX: number; 1604 | screenY: number; 1605 | clientX: number; 1606 | clientY: number; 1607 | pageX: number; 1608 | pageY: number; 1609 | } 1610 | 1611 | interface TouchList { 1612 | [index: number]: Touch; 1613 | length: number; 1614 | item(index: number): Touch; 1615 | identifiedTouch(identifier: number): Touch; 1616 | } 1617 | 1618 | // 1619 | // React.addons 1620 | // ---------------------------------------------------------------------- 1621 | 1622 | export module addons { 1623 | export var CSSTransitionGroup: CSSTransitionGroup; 1624 | export var TransitionGroup: TransitionGroup; 1625 | 1626 | export var LinkedStateMixin: LinkedStateMixin; 1627 | export var PureRenderMixin: PureRenderMixin; 1628 | 1629 | export function batchedUpdates( 1630 | callback: (a: A, b: B) => any, a: A, b: B): void; 1631 | export function batchedUpdates(callback: (a: A) => any, a: A): void; 1632 | export function batchedUpdates(callback: () => any): void; 1633 | 1634 | // deprecated: use petehunt/react-classset or JedWatson/classnames 1635 | export function classSet(cx: { [key: string]: boolean }): string; 1636 | export function classSet(...classList: string[]): string; 1637 | 1638 | export function cloneWithProps

( 1639 | element: DOMElement

, props: P): DOMElement

; 1640 | export function cloneWithProps

( 1641 | element: ClassicElement

, props: P): ClassicElement

; 1642 | export function cloneWithProps

( 1643 | element: ReactElement

, props: P): ReactElement

; 1644 | 1645 | export function createFragment( 1646 | object: { [key: string]: ReactNode }): ReactFragment; 1647 | 1648 | export function update(value: any[], spec: UpdateArraySpec): any[]; 1649 | export function update(value: {}, spec: UpdateSpec): any; 1650 | 1651 | // Development tools 1652 | export import Perf = ReactPerf; 1653 | export import TestUtils = ReactTestUtils; 1654 | } 1655 | 1656 | // 1657 | // React.addons (Transitions) 1658 | // ---------------------------------------------------------------------- 1659 | 1660 | interface TransitionGroupProps { 1661 | component?: ReactType; 1662 | childFactory?: (child: ReactElement) => ReactElement; 1663 | } 1664 | 1665 | interface CSSTransitionGroupProps extends TransitionGroupProps { 1666 | transitionName: string; 1667 | transitionAppear?: boolean; 1668 | transitionEnter?: boolean; 1669 | transitionLeave?: boolean; 1670 | } 1671 | 1672 | type CSSTransitionGroup = ComponentClass; 1673 | type TransitionGroup = ComponentClass; 1674 | 1675 | // 1676 | // React.addons (Mixins) 1677 | // ---------------------------------------------------------------------- 1678 | 1679 | interface ReactLink { 1680 | value: T; 1681 | requestChange(newValue: T): void; 1682 | } 1683 | 1684 | interface LinkedStateMixin extends Mixin { 1685 | linkState(key: string): ReactLink; 1686 | } 1687 | 1688 | interface PureRenderMixin extends Mixin { 1689 | } 1690 | 1691 | // 1692 | // Reat.addons.update 1693 | // ---------------------------------------------------------------------- 1694 | 1695 | interface UpdateSpecCommand { 1696 | $set?: any; 1697 | $merge?: {}; 1698 | $apply?(value: any): any; 1699 | } 1700 | 1701 | interface UpdateSpecPath { 1702 | [key: string]: UpdateSpec; 1703 | } 1704 | 1705 | type UpdateSpec = UpdateSpecCommand | UpdateSpecPath; 1706 | 1707 | interface UpdateArraySpec extends UpdateSpecCommand { 1708 | $push?: any[]; 1709 | $unshift?: any[]; 1710 | $splice?: any[][]; 1711 | } 1712 | 1713 | // 1714 | // React.addons.Perf 1715 | // ---------------------------------------------------------------------- 1716 | 1717 | interface ComponentPerfContext { 1718 | current: string; 1719 | owner: string; 1720 | } 1721 | 1722 | interface NumericPerfContext { 1723 | [key: string]: number; 1724 | } 1725 | 1726 | interface Measurements { 1727 | exclusive: NumericPerfContext; 1728 | inclusive: NumericPerfContext; 1729 | render: NumericPerfContext; 1730 | counts: NumericPerfContext; 1731 | writes: NumericPerfContext; 1732 | displayNames: { 1733 | [key: string]: ComponentPerfContext; 1734 | }; 1735 | totalTime: number; 1736 | } 1737 | 1738 | module ReactPerf { 1739 | export function start(): void; 1740 | export function stop(): void; 1741 | export function printInclusive(measurements: Measurements[]): void; 1742 | export function printExclusive(measurements: Measurements[]): void; 1743 | export function printWasted(measurements: Measurements[]): void; 1744 | export function printDOM(measurements: Measurements[]): void; 1745 | export function getLastMeasurements(): Measurements[]; 1746 | } 1747 | 1748 | // 1749 | // React.addons.TestUtils 1750 | // ---------------------------------------------------------------------- 1751 | 1752 | interface MockedComponentClass { 1753 | new(): any; 1754 | } 1755 | 1756 | module ReactTestUtils { 1757 | export import Simulate = ReactSimulate; 1758 | 1759 | export function renderIntoDocument

( 1760 | element: ReactElement

): Component; 1761 | export function renderIntoDocument>( 1762 | element: ReactElement): C; 1763 | 1764 | export function mockComponent( 1765 | mocked: MockedComponentClass, mockTagName?: string): typeof ReactTestUtils; 1766 | 1767 | export function isElementOfType( 1768 | element: ReactElement, type: ReactType): boolean; 1769 | export function isTextComponent(instance: Component): boolean; 1770 | export function isDOMComponent(instance: Component): boolean; 1771 | export function isCompositeComponent(instance: Component): boolean; 1772 | export function isCompositeComponentWithType( 1773 | instance: Component, 1774 | type: ComponentClass): boolean; 1775 | 1776 | export function findAllInRenderedTree( 1777 | tree: Component, 1778 | fn: (i: Component) => boolean): Component; 1779 | 1780 | export function scryRenderedDOMComponentsWithClass( 1781 | tree: Component, 1782 | className: string): DOMComponent[]; 1783 | export function findRenderedDOMComponentWithClass( 1784 | tree: Component, 1785 | className: string): DOMComponent; 1786 | 1787 | export function scryRenderedDOMComponentsWithTag( 1788 | tree: Component, 1789 | tagName: string): DOMComponent[]; 1790 | export function findRenderedDOMComponentWithTag( 1791 | tree: Component, 1792 | tagName: string): DOMComponent; 1793 | 1794 | export function scryRenderedComponentsWithType

( 1795 | tree: Component, 1796 | type: ComponentClass

): Component[]; 1797 | export function scryRenderedComponentsWithType>( 1798 | tree: Component, 1799 | type: ComponentClass): C[]; 1800 | 1801 | export function findRenderedComponentWithType

( 1802 | tree: Component, 1803 | type: ComponentClass

): Component; 1804 | export function findRenderedComponentWithType>( 1805 | tree: Component, 1806 | type: ComponentClass): C; 1807 | 1808 | export function createRenderer(): ShallowRenderer; 1809 | } 1810 | 1811 | interface SyntheticEventData { 1812 | altKey?: boolean; 1813 | button?: number; 1814 | buttons?: number; 1815 | clientX?: number; 1816 | clientY?: number; 1817 | changedTouches?: TouchList; 1818 | charCode?: boolean; 1819 | clipboardData?: DataTransfer; 1820 | ctrlKey?: boolean; 1821 | deltaMode?: number; 1822 | deltaX?: number; 1823 | deltaY?: number; 1824 | deltaZ?: number; 1825 | detail?: number; 1826 | getModifierState?(key: string): boolean; 1827 | key?: string; 1828 | keyCode?: number; 1829 | locale?: string; 1830 | location?: number; 1831 | metaKey?: boolean; 1832 | pageX?: number; 1833 | pageY?: number; 1834 | relatedTarget?: EventTarget; 1835 | repeat?: boolean; 1836 | screenX?: number; 1837 | screenY?: number; 1838 | shiftKey?: boolean; 1839 | targetTouches?: TouchList; 1840 | touches?: TouchList; 1841 | view?: AbstractView; 1842 | which?: number; 1843 | } 1844 | 1845 | interface EventSimulator { 1846 | (element: Element, eventData?: SyntheticEventData): void; 1847 | (component: Component, eventData?: SyntheticEventData): void; 1848 | } 1849 | 1850 | module ReactSimulate { 1851 | export var blur: EventSimulator; 1852 | export var change: EventSimulator; 1853 | export var click: EventSimulator; 1854 | export var cut: EventSimulator; 1855 | export var doubleClick: EventSimulator; 1856 | export var drag: EventSimulator; 1857 | export var dragEnd: EventSimulator; 1858 | export var dragEnter: EventSimulator; 1859 | export var dragExit: EventSimulator; 1860 | export var dragLeave: EventSimulator; 1861 | export var dragOver: EventSimulator; 1862 | export var dragStart: EventSimulator; 1863 | export var drop: EventSimulator; 1864 | export var focus: EventSimulator; 1865 | export var input: EventSimulator; 1866 | export var keyDown: EventSimulator; 1867 | export var keyPress: EventSimulator; 1868 | export var keyUp: EventSimulator; 1869 | export var mouseDown: EventSimulator; 1870 | export var mouseEnter: EventSimulator; 1871 | export var mouseLeave: EventSimulator; 1872 | export var mouseMove: EventSimulator; 1873 | export var mouseOut: EventSimulator; 1874 | export var mouseOver: EventSimulator; 1875 | export var mouseUp: EventSimulator; 1876 | export var paste: EventSimulator; 1877 | export var scroll: EventSimulator; 1878 | export var submit: EventSimulator; 1879 | export var touchCancel: EventSimulator; 1880 | export var touchEnd: EventSimulator; 1881 | export var touchMove: EventSimulator; 1882 | export var touchStart: EventSimulator; 1883 | export var wheel: EventSimulator; 1884 | } 1885 | 1886 | class ShallowRenderer { 1887 | getRenderOutput>(): E; 1888 | getRenderOutput(): ReactElement; 1889 | render(element: ReactElement, context?: any): void; 1890 | unmount(): void; 1891 | } 1892 | } 1893 | 1894 | declare namespace JSX { 1895 | import React = __React; 1896 | 1897 | interface Element extends React.ReactElement { } 1898 | interface ElementClass extends React.Component { 1899 | render(): JSX.Element; 1900 | } 1901 | interface ElementAttributesProperty { props: {}; } 1902 | 1903 | interface IntrinsicElements { 1904 | // HTML 1905 | a: React.HTMLAttributes; 1906 | abbr: React.HTMLAttributes; 1907 | address: React.HTMLAttributes; 1908 | area: React.HTMLAttributes; 1909 | article: React.HTMLAttributes; 1910 | aside: React.HTMLAttributes; 1911 | audio: React.HTMLAttributes; 1912 | b: React.HTMLAttributes; 1913 | base: React.HTMLAttributes; 1914 | bdi: React.HTMLAttributes; 1915 | bdo: React.HTMLAttributes; 1916 | big: React.HTMLAttributes; 1917 | blockquote: React.HTMLAttributes; 1918 | body: React.HTMLAttributes; 1919 | br: React.HTMLAttributes; 1920 | button: React.HTMLAttributes; 1921 | canvas: React.HTMLAttributes; 1922 | caption: React.HTMLAttributes; 1923 | cite: React.HTMLAttributes; 1924 | code: React.HTMLAttributes; 1925 | col: React.HTMLAttributes; 1926 | colgroup: React.HTMLAttributes; 1927 | data: React.HTMLAttributes; 1928 | datalist: React.HTMLAttributes; 1929 | dd: React.HTMLAttributes; 1930 | del: React.HTMLAttributes; 1931 | details: React.HTMLAttributes; 1932 | dfn: React.HTMLAttributes; 1933 | dialog: React.HTMLAttributes; 1934 | div: React.HTMLAttributes; 1935 | dl: React.HTMLAttributes; 1936 | dt: React.HTMLAttributes; 1937 | em: React.HTMLAttributes; 1938 | embed: React.HTMLAttributes; 1939 | fieldset: React.HTMLAttributes; 1940 | figcaption: React.HTMLAttributes; 1941 | figure: React.HTMLAttributes; 1942 | footer: React.HTMLAttributes; 1943 | form: React.HTMLAttributes; 1944 | h1: React.HTMLAttributes; 1945 | h2: React.HTMLAttributes; 1946 | h3: React.HTMLAttributes; 1947 | h4: React.HTMLAttributes; 1948 | h5: React.HTMLAttributes; 1949 | h6: React.HTMLAttributes; 1950 | head: React.HTMLAttributes; 1951 | header: React.HTMLAttributes; 1952 | hr: React.HTMLAttributes; 1953 | html: React.HTMLAttributes; 1954 | i: React.HTMLAttributes; 1955 | iframe: React.HTMLAttributes; 1956 | img: React.HTMLAttributes; 1957 | input: React.HTMLAttributes; 1958 | ins: React.HTMLAttributes; 1959 | kbd: React.HTMLAttributes; 1960 | keygen: React.HTMLAttributes; 1961 | label: React.HTMLAttributes; 1962 | legend: React.HTMLAttributes; 1963 | li: React.HTMLAttributes; 1964 | link: React.HTMLAttributes; 1965 | main: React.HTMLAttributes; 1966 | map: React.HTMLAttributes; 1967 | mark: React.HTMLAttributes; 1968 | menu: React.HTMLAttributes; 1969 | menuitem: React.HTMLAttributes; 1970 | meta: React.HTMLAttributes; 1971 | meter: React.HTMLAttributes; 1972 | nav: React.HTMLAttributes; 1973 | noscript: React.HTMLAttributes; 1974 | object: React.HTMLAttributes; 1975 | ol: React.HTMLAttributes; 1976 | optgroup: React.HTMLAttributes; 1977 | option: React.HTMLAttributes; 1978 | output: React.HTMLAttributes; 1979 | p: React.HTMLAttributes; 1980 | param: React.HTMLAttributes; 1981 | picture: React.HTMLAttributes; 1982 | pre: React.HTMLAttributes; 1983 | progress: React.HTMLAttributes; 1984 | q: React.HTMLAttributes; 1985 | rp: React.HTMLAttributes; 1986 | rt: React.HTMLAttributes; 1987 | ruby: React.HTMLAttributes; 1988 | s: React.HTMLAttributes; 1989 | samp: React.HTMLAttributes; 1990 | script: React.HTMLAttributes; 1991 | section: React.HTMLAttributes; 1992 | select: React.HTMLAttributes; 1993 | small: React.HTMLAttributes; 1994 | source: React.HTMLAttributes; 1995 | span: React.HTMLAttributes; 1996 | strong: React.HTMLAttributes; 1997 | style: React.HTMLAttributes; 1998 | sub: React.HTMLAttributes; 1999 | summary: React.HTMLAttributes; 2000 | sup: React.HTMLAttributes; 2001 | table: React.HTMLAttributes; 2002 | tbody: React.HTMLAttributes; 2003 | td: React.HTMLAttributes; 2004 | textarea: React.HTMLAttributes; 2005 | tfoot: React.HTMLAttributes; 2006 | th: React.HTMLAttributes; 2007 | thead: React.HTMLAttributes; 2008 | time: React.HTMLAttributes; 2009 | title: React.HTMLAttributes; 2010 | tr: React.HTMLAttributes; 2011 | track: React.HTMLAttributes; 2012 | u: React.HTMLAttributes; 2013 | ul: React.HTMLAttributes; 2014 | "var": React.HTMLAttributes; 2015 | video: React.HTMLAttributes; 2016 | wbr: React.HTMLAttributes; 2017 | 2018 | // SVG 2019 | svg: React.SVGElementAttributes; 2020 | 2021 | circle: React.SVGAttributes; 2022 | defs: React.SVGAttributes; 2023 | ellipse: React.SVGAttributes; 2024 | g: React.SVGAttributes; 2025 | line: React.SVGAttributes; 2026 | linearGradient: React.SVGAttributes; 2027 | mask: React.SVGAttributes; 2028 | path: React.SVGAttributes; 2029 | pattern: React.SVGAttributes; 2030 | polygon: React.SVGAttributes; 2031 | polyline: React.SVGAttributes; 2032 | radialGradient: React.SVGAttributes; 2033 | rect: React.SVGAttributes; 2034 | stop: React.SVGAttributes; 2035 | text: React.SVGAttributes; 2036 | tspan: React.SVGAttributes; 2037 | } 2038 | } 2039 | -------------------------------------------------------------------------------- /typings/uuid/uuid.d.ts: -------------------------------------------------------------------------------- 1 | declare let uuid: uuid; 2 | 3 | interface uuid { 4 | v1(): string; 5 | v4(): string; 6 | } 7 | 8 | declare module "uuid" { 9 | export = uuid; 10 | } 11 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash'); 2 | var minimist = require('minimist'); 3 | var chalk = require('chalk'); 4 | var webpack = require('webpack'); 5 | 6 | var HtmlWebpackPlugin = require('html-webpack-plugin'); 7 | var CleanWebpackPlugin = require('clean-webpack-plugin'); 8 | var OpenBrowserWebpackPlugin = require('open-browser-webpack-plugin'); 9 | 10 | var DEFAULT_TARGET = 'BUILD'; 11 | 12 | var DEFAULT_PARAMS = { 13 | resolve: { 14 | extensions: ['', '.ts', '.tsx', '.js'] 15 | }, 16 | entry: { 17 | main: './src/main.tsx' 18 | }, 19 | output: { 20 | publicPath: '', 21 | filename: '[name].[chunkhash].js', 22 | sourceMapFilename: '[name].[chunkhash].map' 23 | }, 24 | externals: { 25 | 'auth0-lock': 'Auth0Lock' 26 | }, 27 | module: { 28 | loaders: [ 29 | {test: /\.tsx?$/, loader: 'react-hot!ts-loader?jsx=true', exclude: /(\.test.ts$|node_modules)/}, 30 | {test: /\.css$/, loader: 'style!css'}, 31 | {test: /\.tpl.html/, loader: 'html'}, 32 | {test: /\.(ico|png|jpg|gif|svg|eot|ttf|woff|woff2)(\?.+)?$/, loader: 'url?limit=50000'} 33 | ] 34 | }, 35 | plugins: [ 36 | new HtmlWebpackPlugin({ 37 | template: './src/index.html', 38 | inject: 'body' 39 | }), 40 | new webpack.optimize.DedupePlugin() 41 | ].concat(_bootswatchWorkaround()), 42 | devServer: { 43 | contentBase: 'dev/', 44 | port: 8081 45 | }, 46 | debug: true, 47 | progress: true, 48 | colors: true 49 | }; 50 | 51 | var PARAMS_PER_TARGET = { 52 | 53 | DEV: { 54 | devtool: 'inline-source-map', 55 | output: { 56 | filename: '[name].js' 57 | }, 58 | plugins: [ 59 | new OpenBrowserWebpackPlugin({ url: 'http://localhost:8081/' }) 60 | ] 61 | }, 62 | 63 | BUILD: { 64 | output: { 65 | path: './build' 66 | }, 67 | devtool: 'source-map', 68 | plugins: [ 69 | new CleanWebpackPlugin(['build']) 70 | ] 71 | }, 72 | 73 | DIST: { 74 | debug: false, 75 | output: { 76 | path: './dist' 77 | }, 78 | plugins: [ 79 | new CleanWebpackPlugin(['dist']), 80 | new webpack.optimize.UglifyJsPlugin() 81 | ] 82 | } 83 | 84 | }; 85 | 86 | var target = _resolveBuildTarget(DEFAULT_TARGET); 87 | var params = _.merge(DEFAULT_PARAMS, PARAMS_PER_TARGET[target], _mergeArraysCustomizer); 88 | 89 | _printBuildInfo(target, params); 90 | 91 | module.exports = params; 92 | 93 | function _resolveBuildTarget(defaultTarget) { 94 | var target = minimist(process.argv.slice(2)).TARGET; 95 | if (!target) { 96 | console.log('No build target provided, using default target instead\n\n'); 97 | target = defaultTarget; 98 | } 99 | return target; 100 | } 101 | 102 | function _printBuildInfo(target, params) { 103 | console.log('\nStarting ' + chalk.bold.green('"' + target + '"') + ' build'); 104 | if (target === 'DEV') { 105 | console.log('Dev server: ' + chalk.bold.yellow('http://localhost:' + params.devServer.port) + '\n\n'); 106 | } else { 107 | console.log('\n\n'); 108 | } 109 | } 110 | 111 | function _mergeArraysCustomizer(a, b) { 112 | if (_.isArray(a)) { 113 | return a.concat(b); 114 | } 115 | } 116 | 117 | function _bootswatchWorkaround() { 118 | var extensions = ['eot', 'woff', 'woff2', 'ttf', 'svg']; 119 | 120 | return extensions.map(function(ext) { 121 | var regexp = new RegExp('^\.\.\/fonts\/glyphicons-halflings-regular\.' + ext + '$'); 122 | var dest = 'bootswatch/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.' + ext; 123 | return new webpack.NormalModuleReplacementPlugin(regexp, dest); 124 | }); 125 | } 126 | --------------------------------------------------------------------------------