diff --git a/.gitignore b/.gitignore index 5aba682b..6be2ae85 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ node_modules npm-debug.log .idea .DS_Store +.vscode diff --git a/.travis.yml b/.travis.yml index a2133b95..73da3307 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,4 +8,5 @@ node_js: script: - npm run lint + - npm run ts - npm test diff --git a/components/autocomplete/readme.md b/components/autocomplete/readme.md index 5da6b8ba..9b2e925e 100644 --- a/components/autocomplete/readme.md +++ b/components/autocomplete/readme.md @@ -45,7 +45,7 @@ If you want to provide a theme via context, the component key is `RTAutocomplete |:-----|:-----|:-----|:-----| | `allowCreate` | `Bool` | `false` | Determines if user can create a new option with the current typed value | | `className` | `String` | `''` | Sets a class to style of the Component.| -| `direction` | `String` | `auto` | Determines the opening direction. It can be `auto`, `top` or `down`. | +| `direction` | `String` | `auto` | Determines the opening direction. It can be `auto`, `up` or `down`. | | `disabled` | `Bool` | `false` | If true, component will be disabled. | | `error` | `String` or `Node` | | Sets the error string for the internal input element. | | `keepFocusOnChange` | `Bool` | `false` | Whether component should keep focus after value change. | diff --git a/components/autocomplete/theme.css b/components/autocomplete/theme.css index 5a7f88c9..5b175727 100644 --- a/components/autocomplete/theme.css +++ b/components/autocomplete/theme.css @@ -13,8 +13,8 @@ & .suggestions { box-shadow: var(--zdepth-shadow-1); max-height: var(--autocomplete-overflow-max-height); + -ms-overflow-style: none; visibility: visible; - -ms-overflow-style:none; } } } diff --git a/components/button/BrowseButton.js b/components/button/BrowseButton.js index 8eb9e5b9..dbbfd0dc 100644 --- a/components/button/BrowseButton.js +++ b/components/button/BrowseButton.js @@ -23,6 +23,7 @@ const factory = (ripple, FontIcon) => { inverse: PropTypes.bool, label: PropTypes.string, mini: PropTypes.bool, + multiple: PropTypes.bool, neutral: PropTypes.bool, onChange: PropTypes.func, onMouseLeave: PropTypes.func, @@ -53,6 +54,7 @@ const factory = (ripple, FontIcon) => { flat: false, floating: false, mini: false, + multiple: false, neutral: true, primary: false, raised: false, @@ -96,6 +98,7 @@ const factory = (ripple, FontIcon) => { inverse, label, mini, + multiple, neutral, primary, // eslint-disable-line raised, // eslint-disable-line @@ -130,6 +133,7 @@ const factory = (ripple, FontIcon) => { className={classes} type="file" accept={accept} + multiple={multiple} onChange={this.handleFileChange} />, children, diff --git a/components/button/Button.d.ts b/components/button/Button.d.ts index 22eb2a69..6fcba2f7 100644 --- a/components/button/Button.d.ts +++ b/components/button/Button.d.ts @@ -1,8 +1,9 @@ import * as React from "react"; import ReactToolbox from "../index"; +import { RippleProps } from '../ripple/index'; import { ButtonBaseProps, ButtonTheme } from './base'; -export interface ButtonProps extends ButtonBaseProps { +export interface ButtonProps extends ButtonBaseProps, RippleProps { /** * If true, the button will have a flat look. * @default false @@ -31,6 +32,10 @@ export interface ButtonProps extends ButtonBaseProps { * @default false */ raised?: boolean; + /** + * Passed down to the root element + */ + target?: string; /** * Classnames object defining the component style. */ diff --git a/components/drawer/Drawer.d.ts b/components/drawer/Drawer.d.ts index 37cd30d1..6ae297e4 100644 --- a/components/drawer/Drawer.d.ts +++ b/components/drawer/Drawer.d.ts @@ -28,7 +28,7 @@ export interface DrawerTheme { wrapper?: string; } -export interface DrawerProps extends ReactToolbox.Props { +export interface DrawerCommonProps { /** * If true, the drawer will be visible. * @default false @@ -47,10 +47,6 @@ export interface DrawerProps extends ReactToolbox.Props { * Callback function to be invoked when the overlay is clicked. */ onOverlayClick?: Function; - /** - * Classnames object defining the component style. - */ - theme?: DrawerTheme; /** * Type of drawer. It can be left or right to display the drawer on the left or right side of the screen. * @default left @@ -63,6 +59,13 @@ export interface DrawerProps extends ReactToolbox.Props { withOverlay?: boolean; } +export interface DrawerProps extends ReactToolbox.Props, DrawerCommonProps { + /** + * Classnames object defining the component style. + */ + theme?: DrawerTheme; +} + export class Drawer extends React.Component { } export default Drawer; diff --git a/components/hoc/Portal.js b/components/hoc/Portal.js index f1ca7273..1a9a5357 100644 --- a/components/hoc/Portal.js +++ b/components/hoc/Portal.js @@ -1,13 +1,14 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import ReactDOM from 'react-dom'; +import styleShape from 'react-style-proptype'; class Portal extends Component { static propTypes = { children: PropTypes.node, className: PropTypes.string, container: PropTypes.node, - style: PropTypes.style, + style: styleShape, } static defaultProps = { diff --git a/components/input/Input.d.ts b/components/input/Input.d.ts index 6bddadc5..dc12e0fc 100644 --- a/components/input/Input.d.ts +++ b/components/input/Input.d.ts @@ -132,7 +132,7 @@ export interface InputProps extends ReactToolbox.Props { /** * The number of rows the multiline input field has. */ - rows?:number; + rows?: number; /** * Classnames object defining the component style. */ diff --git a/components/layout/Layout.d.ts b/components/layout/Layout.d.ts index 477b57b9..afc943e7 100644 --- a/components/layout/Layout.d.ts +++ b/components/layout/Layout.d.ts @@ -1,8 +1,5 @@ import * as React from "react"; import ReactToolbox from "../index"; -import { NavDrawer } from './NavDrawer'; -import { Panel } from './Panel'; -import { Sidebar } from './Sidebar'; export interface LayoutTheme { appbarFixed?: string; @@ -54,7 +51,7 @@ export interface LayoutProps extends ReactToolbox.Props { /** * Children to pass through the component. */ - children?: [NavDrawer | Panel | Sidebar]; + children?: JSX.Element | JSX.Element[]; /** * Classnames object defining the component style. */ diff --git a/components/layout/NavDrawer.d.ts b/components/layout/NavDrawer.d.ts index c6cb5650..16e78173 100644 --- a/components/layout/NavDrawer.d.ts +++ b/components/layout/NavDrawer.d.ts @@ -1,5 +1,5 @@ import * as React from "react"; -import { DrawerProps } from '../drawer/Drawer'; +import { DrawerCommonProps } from '../drawer/Drawer'; export interface NavDrawerTheme { /** @@ -12,7 +12,7 @@ export interface NavDrawerTheme { clipped?: string; } -export interface NavDrawerProps extends DrawerProps { +export interface NavDrawerProps extends DrawerCommonProps { /** * If true, the drawer will be shown as an overlay. * @default false diff --git a/components/layout/Sidebar.d.ts b/components/layout/Sidebar.d.ts index 56d2075c..e8c2a5b6 100644 --- a/components/layout/Sidebar.d.ts +++ b/components/layout/Sidebar.d.ts @@ -1,5 +1,5 @@ import * as React from "react"; -import { DrawerProps } from '../drawer/Drawer'; +import { DrawerCommonProps } from '../drawer/Drawer'; export interface SidebarTheme { /** @@ -12,7 +12,7 @@ export interface SidebarTheme { pinned?: string; } -export interface SidebarProps extends DrawerProps { +export interface SidebarProps extends DrawerCommonProps { /** * If true, when the `AppBar` gets pinned, it will stand over the `Drawer`. * @default false diff --git a/components/menu/MenuItem.d.ts b/components/menu/MenuItem.d.ts index 265f0576..325e8505 100644 --- a/components/menu/MenuItem.d.ts +++ b/components/menu/MenuItem.d.ts @@ -59,6 +59,10 @@ export interface MenuItemProps extends ReactToolbox.Props { * Classnames object defining the component style. */ theme?: MenuItemTheme; + /** + * Passed down to the root element + */ + value?: any; } export class MenuItem extends React.Component { } diff --git a/components/tabs/Tab.d.ts b/components/tabs/Tab.d.ts index c7cf99b2..59c1e027 100644 --- a/components/tabs/Tab.d.ts +++ b/components/tabs/Tab.d.ts @@ -52,9 +52,9 @@ export interface TabProps extends ReactToolbox.Props { */ icon?: React.ReactNode; /** - * Label text for navigation header. Required. + * Label text for navigation header. */ - label: string; + label?: string; /** * Callback function that is fired when the tab is activated. */ diff --git a/components/tooltip/index.d.ts b/components/tooltip/index.d.ts index 3b4cfae1..ad93abab 100644 --- a/components/tooltip/index.d.ts +++ b/components/tooltip/index.d.ts @@ -70,10 +70,21 @@ declare class TooltipComponent extends React.Component { props: P & TooltipProps; } -interface TooltippedComponentClass

extends TooltipProps { +declare interface TooltippedComponentClass

extends TooltipProps { new (props?: P, context?: any): TooltipComponent; } -export function Tooltip

(componentClass: React.ComponentClass

): TooltippedComponentClass

; +declare interface TooltipOptions { + className?: string; + delay?: number; + hideOnClick?: boolean; + passthrough?: boolean; + showOnClick?: boolean; + position?: 'bottom' | 'horizontal' | 'left' | 'right' | 'top' | 'vertical' +} -export default Tooltip; +declare type tooltipHOC

= (componentClass: React.ComponentClass

) => TooltippedComponentClass

+ +export function tooltipFactory

(options?: TooltipOptions): tooltipHOC

; + +export default function Tooltip

(component: React.ReactType): TooltippedComponentClass

; diff --git a/package.json b/package.json index 4081c22d..2baa3fb3 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,8 @@ "react-transition-group": "^1.1.3" }, "devDependencies": { + "@types/node": "^7.0.4", + "@types/react": "^15.0.0", "babel-cli": "^6.24.1", "babel-core": "^6.24.1", "babel-eslint": "^7.2.3", @@ -86,10 +88,12 @@ "react-transform-hmr": "^1.0.4", "redbox-react": "^1.3.6", "rimraf": "^2.6.1", + "sinon": "^2.0.0-pre.2", "style-loader": "^0.18.1", "stylelint": "^7.10.1", "stylelint-config-standard": "^16.0.0", "stylelint-order": "^0.4.4", + "typescript": "^2.1.5", "webpack": "^2.6.0", "webpack-dev-middleware": "^1.10.2", "webpack-hot-middleware": "^2.18.0" @@ -111,6 +115,8 @@ "prepublish": "npm run build", "release": "bumped release", "start": "cross-env NODE_ENV=development UV_THREADPOOL_SIZE=100 node ./server", + "ts": "tsc", + "tsd": "cpx \"./components/**/*.d.ts\" ./lib", "test": "jest", "test:watch": "jest --watch --no-watchman" }, diff --git a/spec/ts/app_bar.tsx b/spec/ts/app_bar.tsx new file mode 100644 index 00000000..14df0dc6 --- /dev/null +++ b/spec/ts/app_bar.tsx @@ -0,0 +1,22 @@ +import * as React from 'react'; +import AppBar, {AppBar as NamedAppBar} from 'components/app_bar'; + +const AppBarTest: React.SFC = () => ( +

+
AppBar
+
+ +
+ +
+ +
+ + Custom content + +
+ +
+) + +export default AppBarTest; diff --git a/spec/ts/autocomplete.tsx b/spec/ts/autocomplete.tsx new file mode 100644 index 00000000..edcfc42e --- /dev/null +++ b/spec/ts/autocomplete.tsx @@ -0,0 +1,96 @@ +import * as React from 'react'; +import Autocomplete from 'components/autocomplete'; + +class AutocompleteTest extends React.Component { + state: any = { + simple: 'Spain', + simpleShowAll: 'England', + multipleArray: ['ES-es', 'TH-th'], + multipleObject: {'ES-es': 'Spain', 'TH-th': 'Thailand'}, + countriesArray: ['Spain', 'England', 'USA', 'Thailand', 'Tongo', 'Slovenia'], + countriesObject: { + 'EN-gb': 'England', + 'EN-en': 'United States of America', 'EN-nz': 'New Zealand' + } + }; + + handleFocus = (event: React.MouseEvent) => { + console.log('This is focused'); + console.log(event); + }; + + handleMultipleArrayChange = (value: any) => { + this.setState({ + multipleArray: value, + countriesObject: { + ...this.state.countriesObject, + ...(value[0] && !this.state.countriesObject[value[0]]) ? {[value[0]]: value[0]} : {} + } + }); + }; + + handleMultipleObjectChange = (value: any) => { + this.setState({ + multipleObject: value + }); + }; + + handleSimpleChange = (value: any) => { + this.setState({simple: value}); + }; + + handleSimpleShowAllChange = (value: any) => { + this.setState({simpleShowAll: value}); + }; + + render () { + return ( +
+
Autocomplete
+

You can have a multiple or simple autocomplete.

+ + + + + + + + +
+ ); + } +} + +export default AutocompleteTest; diff --git a/spec/ts/avatar.tsx b/spec/ts/avatar.tsx new file mode 100644 index 00000000..87dfab0e --- /dev/null +++ b/spec/ts/avatar.tsx @@ -0,0 +1,22 @@ +import * as React from 'react'; +import Avatar from '../../components/avatar'; +import GithubIcon from './github_icon'; + +const AvatarTest = () => ( +
+
Avatars
+

Provide an image source or object, a font icon, children or a title to use its first letter.

+ + } /> + foobar + + + + +
+); + +export default AvatarTest; diff --git a/spec/ts/button.tsx b/spec/ts/button.tsx new file mode 100644 index 00000000..9a7c51ac --- /dev/null +++ b/spec/ts/button.tsx @@ -0,0 +1,51 @@ +import * as React from 'react'; +import GithubIcon from './github_icon'; +import { Button, IconButton, BrowseButton } from '../../components/button'; + +const ButtonTest = () => ( +
+
Buttons
+

lorem ipsum...

+ + +
+); + +function rippleEnded() { + console.log('Ripple animation ended!'); +} + +export default ButtonTest; diff --git a/spec/ts/card.tsx b/spec/ts/card.tsx new file mode 100644 index 00000000..a119f7aa --- /dev/null +++ b/spec/ts/card.tsx @@ -0,0 +1,247 @@ +/* eslint-disable react/prop-types */ +import * as React from 'react'; +import Button, { IconButton } from '../../components/button'; +import Card, { CardActions, CardMedia, CardText, CardTitle } from '../../components/card'; + +const style = require('../style.css'); + +const dummyText = 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.'; + +const Spacer: React.SFC = () =>
; +const CardList: React.SFC = ({ children }) =>
    {children}
; +const CardListItem: React.SFC = ({ component, name }) => ( +
  • +
    {component}
    +
    {name}
    +
  • +); + +const cards: any = { + basic: [{ + name: 'Basic Card', + component: ( + + + {dummyText} + +