diff --git a/packages/card/ActionButtons.js b/packages/card/ActionButtons.js deleted file mode 100644 index bed3f43ea..000000000 --- a/packages/card/ActionButtons.js +++ /dev/null @@ -1,64 +0,0 @@ -// The MIT License -// -// Copyright (c) 2018 Google, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -import React from 'react'; -import classnames from 'classnames'; -import PropTypes from 'prop-types'; - -export default class ActionButtons extends React.Component { - addButtonClassToChildren = () => { - return React.Children.map(this.props.children, (item) => { - const className = classnames( - item.props.className, 'mdc-card__action', 'mdc-card__action--button'); - const props = Object.assign({}, item.props, {className}); - return React.cloneElement(item, props); - }); - }; - - render() { - const { - className, - children, // eslint-disable-line no-unused-vars - ...otherProps - } = this.props; - const classes = classnames('mdc-card__action-buttons', className); - - return ( -
- {this.addButtonClassToChildren()} -
- ); - } -} - -ActionButtons.propTypes = { - className: PropTypes.string, - children: PropTypes.node, -}; - -ActionButtons.defaultProps = { - className: '', - children: null, -}; diff --git a/packages/card/ActionButtons.tsx b/packages/card/ActionButtons.tsx new file mode 100644 index 000000000..876bf7059 --- /dev/null +++ b/packages/card/ActionButtons.tsx @@ -0,0 +1,57 @@ +// The MIT License +// +// Copyright (c) 2018 Google, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import * as React from 'react'; +import * as classnames from 'classnames'; + +type ChildType = React.ReactElement>; + +export interface ActionButtonsProps extends React.HTMLProps { + className?: string; + children?: ChildType | ChildType[]; +}; + +const addButtonClassToChildren = (children: ChildType | ChildType[]) => { + return React.Children.map((children as ChildType | ChildType[]), (item) => { + const className = classnames( + (item as ChildType).props.className, + 'mdc-card__action', + 'mdc-card__action--button' + ); + const props = Object.assign({}, (item as ChildType).props, {className}); + return React.cloneElement((item as ChildType), props); + }); +}; + +const ActionButtons: React.FunctionComponent = ({ + className = '', children, ...otherProps // eslint-disable-line react/prop-types +}) => { + const classes = classnames('mdc-card__action-buttons', className); + if (!children) return null; + return ( +
+ {addButtonClassToChildren(children)} +
+ ); +}; + +export default ActionButtons; diff --git a/packages/card/ActionIcons.js b/packages/card/ActionIcons.tsx similarity index 50% rename from packages/card/ActionIcons.js rename to packages/card/ActionIcons.tsx index d9bc9faad..3ec8a1439 100644 --- a/packages/card/ActionIcons.js +++ b/packages/card/ActionIcons.tsx @@ -20,45 +20,38 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -import React from 'react'; -import classnames from 'classnames'; -import PropTypes from 'prop-types'; +import * as React from 'react'; +import * as classnames from 'classnames'; -export default class ActionIcons extends React.Component { - addIconClassToChildren = () => { - return React.Children.map(this.props.children, (item) => { - const className = classnames( - item.props.className, 'mdc-card__action', 'mdc-card__action--icon'); - const props = Object.assign({}, item.props, {className}); - return React.cloneElement(item, props); - }); - }; +type ChildType = React.ReactElement>; - render() { - const { - className, - children, // eslint-disable-line no-unused-vars - ...otherProps - } = this.props; - const classes = classnames('mdc-card__action-icons', className); +export interface ActionIconsProps extends React.HTMLProps { + className?: string; + children?: ChildType | ChildType[]; +}; - return ( -
- {this.addIconClassToChildren()} -
+const addIconClassToChildren = (children: ChildType | ChildType[]) => { + return React.Children.map((children as ChildType | ChildType[]), (item) => { + const className = classnames( + (item as ChildType).props.className, + 'mdc-card__action', + 'mdc-card__action--icon' ); - } -} - -ActionIcons.propTypes = { - className: PropTypes.string, - children: PropTypes.node, + const props = Object.assign({}, (item as ChildType).props, {className}); + return React.cloneElement((item as ChildType), props); + }); }; -ActionIcons.defaultProps = { - className: '', - children: null, +const ActionIcons: React.FunctionComponent = ({ + className = '', children, ...otherProps // eslint-disable-line react/prop-types +}) => { + const classes = classnames('mdc-card__action-icons', className); + if (!children) return null; + return ( +
+ {addIconClassToChildren(children)} +
+ ); }; + +export default ActionIcons; diff --git a/packages/card/Actions.js b/packages/card/Actions.tsx similarity index 61% rename from packages/card/Actions.js rename to packages/card/Actions.tsx index ccd12ab4e..7bf24254c 100644 --- a/packages/card/Actions.js +++ b/packages/card/Actions.tsx @@ -20,41 +20,25 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -import React from 'react'; -import classnames from 'classnames'; -import PropTypes from 'prop-types'; +import * as React from 'react'; +import * as classnames from 'classnames'; -export default class Actions extends React.Component { - render() { - const { - className, - children, - fullBleed, - ...otherProps - } = this.props; - const classes = classnames('mdc-card__actions', className, { - 'mdc-card__actions--full-bleed': fullBleed, - }); - - return ( -
- {children} -
- ); - } -} - -Actions.propTypes = { - className: PropTypes.string, - children: PropTypes.node, - fullBleed: PropTypes.bool, +export interface ActionsProps extends React.HTMLProps { + className?: string; + fullBleed?: boolean; }; -Actions.defaultProps = { - className: '', - children: null, - fullBleed: false, +const Actions: React.FunctionComponent = ({ + className = '', children, fullBleed = false, ...otherProps // eslint-disable-line react/prop-types +}) => { + const classes = classnames('mdc-card__actions', className, { + 'mdc-card__actions--full-bleed': fullBleed, + }); + return ( +
+ {children} +
+ ); }; + +export default Actions; diff --git a/packages/card/Media.js b/packages/card/Media.js deleted file mode 100644 index b1044543c..000000000 --- a/packages/card/Media.js +++ /dev/null @@ -1,96 +0,0 @@ -// The MIT License -// -// Copyright (c) 2018 Google, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -import React from 'react'; -import classnames from 'classnames'; -import PropTypes from 'prop-types'; - -export default class Media extends React.Component { - getStyles = () => { - const {imageUrl, style} = this.props; - return Object.assign({}, { - backgroundImage: `url(${imageUrl})`, - }, style); - } - - render() { - const { - className, - children, // eslint-disable-line no-unused-vars - contentClassName, // eslint-disable-line no-unused-vars - square, - imageUrl, // eslint-disable-line no-unused-vars - style, // eslint-disable-line no-unused-vars - wide, - ...otherProps - } = this.props; - const classes = classnames('mdc-card__media', className, { - 'mdc-card__media--square': square, - 'mdc-card__media--16-9': wide, - }); - - return ( -
- {this.renderChildren()} -
- ); - } - - renderChildren() { - const {children, contentClassName} = this.props; - if (!children) { - return; - } - - const classes = classnames('mdc-card__media-content', contentClassName); - - return ( -
- {children} -
- ); - } -} - -Media.propTypes = { - className: PropTypes.string, - children: PropTypes.node, - square: PropTypes.bool, - wide: PropTypes.bool, - contentClassName: PropTypes.string, - imageUrl: PropTypes.string, - style: PropTypes.object, -}; - -Media.defaultProps = { - className: '', - contentClassName: '', - children: null, - square: false, - wide: false, - imageUrl: '', - style: {}, -}; diff --git a/packages/card/Media.tsx b/packages/card/Media.tsx new file mode 100644 index 000000000..85bc34f84 --- /dev/null +++ b/packages/card/Media.tsx @@ -0,0 +1,86 @@ +// The MIT License +// +// Copyright (c) 2018 Google, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import * as React from 'react'; +import * as classnames from 'classnames'; + +export interface MediaProps extends React.HTMLProps { + className?: string; + square?: boolean; + wide?: boolean; + contentClassName?: string; + imageUrl?: string; + style?: React.CSSProperties; +} + +interface MediaChildren { + children?: React.ReactNode; + contentClassName?: string; +}; + +interface StyleValues { + imageUrl: string; + style: React.CSSProperties; +}; + +const renderChildren: (mediaChildren: MediaChildren) => React.ReactElement | undefined = ({ + children, contentClassName, // eslint-disable-line react/prop-types +}) => { + if (!children) { + return; + } + const classes = classnames('mdc-card__media-content', contentClassName); + return
{children}
; +}; + +const getStyles: (styleValues: StyleValues) => React.CSSProperties = ({imageUrl, style}) => { + return Object.assign({}, + {backgroundImage: `url(${imageUrl})`}, + style + ); +}; + +const Media: React.FunctionComponent = ({ + /* eslint-disable react/prop-types */ + className = '', + contentClassName = '', + children, + square = false, + wide = false, + imageUrl = '', + style = {}, + /* eslint-enable react/prop-types */ + ...otherProps +}) => { + const classes = classnames('mdc-card__media', className, { + 'mdc-card__media--square': square, + 'mdc-card__media--16-9': wide, + }); + + return ( +
+ {renderChildren({children, contentClassName})} +
+ ); +}; + +export default Media; diff --git a/packages/card/PrimaryContent.js b/packages/card/PrimaryContent.tsx similarity index 61% rename from packages/card/PrimaryContent.js rename to packages/card/PrimaryContent.tsx index a4ac0344c..6e8c90dee 100644 --- a/packages/card/PrimaryContent.js +++ b/packages/card/PrimaryContent.tsx @@ -20,45 +20,31 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -import React from 'react'; -import classnames from 'classnames'; -import PropTypes from 'prop-types'; +import * as React from 'react'; +import * as classnames from 'classnames'; +import * as Ripple from '@material/react-ripple'; -import {withRipple} from '@material/react-ripple'; - -export const PrimaryContentBase = (props) => { - const { - className, - initRipple, - children, - unbounded, // eslint-disable-line no-unused-vars - ...otherProps - } = props; +export interface PrimaryContentBaseProps extends React.HTMLProps, Ripple.InjectedProps{ + className: string; + unbounded?: boolean; +}; +export const PrimaryContentBase: React.FunctionComponent = ({ + /* eslint-disable react/prop-types */ + className = '', + initRipple, + children, + unbounded, // eslint-disable-line no-unused-vars + /* eslint-enable react/prop-types */ + ...otherProps +}) => { const classes = classnames('mdc-card__primary-action', className); + return ( -
+
{children}
); }; - -PrimaryContentBase.propTypes = { - className: PropTypes.string, - children: PropTypes.node, - // The following props are handled by withRipple and do not require defaults. - initRipple: PropTypes.func, - unbounded: PropTypes.bool, -}; - -PrimaryContentBase.defaultProps = { - className: '', - children: null, -}; - -export default withRipple(PrimaryContentBase); +export default Ripple.withRipple(PrimaryContentBase); diff --git a/packages/card/index.js b/packages/card/index.tsx similarity index 68% rename from packages/card/index.js rename to packages/card/index.tsx index adfb460e5..480b876b8 100644 --- a/packages/card/index.js +++ b/packages/card/index.tsx @@ -20,51 +20,32 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -import React from 'react'; -import classnames from 'classnames'; -import PropTypes from 'prop-types'; +import * as React from 'react'; +import * as classnames from 'classnames'; import ActionButtons from './ActionButtons'; import ActionIcons from './ActionIcons'; import Actions from './Actions'; import PrimaryContent from './PrimaryContent'; import Media from './Media'; -export default class Card extends React.Component { - render() { - const { - className, - children, - outlined, - ...otherProps - } = this.props; - const classes = classnames('mdc-card', className, { - 'mdc-card--outlined': outlined, - }); - - return ( -
- {children} -
- ); - } +export interface CardProps extends React.HTMLProps { + className?: string, + outlined?: boolean } -Card.propTypes = { - children: PropTypes.node, - className: PropTypes.string, - outlined: PropTypes.bool, -}; - -Card.defaultProps = { - children: null, - className: '', - outlined: false, +const Card: React.FunctionComponent = ({ + children, className = '', outlined = false, ...otherProps // eslint-disable-line react/prop-types +}) => { + const classes = classnames('mdc-card', className, { + 'mdc-card--outlined': outlined, + }); + return ( +
+ {children} +
+ ); }; - export { ActionButtons as CardActionButtons, ActionIcons as CardActionIcons, @@ -72,3 +53,5 @@ export { PrimaryContent as CardPrimaryContent, Media as CardMedia, }; + +export default Card; diff --git a/test/screenshot/card/index.js b/test/screenshot/card/index.tsx similarity index 65% rename from test/screenshot/card/index.js rename to test/screenshot/card/index.tsx index cba54a3f0..4716ad6cb 100644 --- a/test/screenshot/card/index.js +++ b/test/screenshot/card/index.tsx @@ -1,16 +1,15 @@ -import React from 'react'; +import * as React from 'react'; import '@material/button/mdc-button.scss'; import '@material/list/mdc-list.scss'; import '../../../packages/card/index.scss'; import './index.scss'; - import Card, { CardActionButtons, CardActionIcons, CardActions, CardPrimaryContent, CardMedia, -} from '../../../packages/card'; +} from '../../../packages/card/index'; import MaterialIcon from '../../../packages/material-icon'; const imageUrl = './../images/1-1.jpg'; @@ -26,8 +25,8 @@ const BasicCard = () => { - - + + @@ -39,7 +38,11 @@ const HorizontalCard = () => {
- +

Khalid

Silence

@@ -47,45 +50,50 @@ const HorizontalCard = () => {
-
+
- - - - - + + + + +
); }; -const newsContent = [{ - title: 'Baboons escape', - snippet: 'Four baboons, having clearly read too much dystopian fiction...', -}, { - title: 'Copper on the rise', - snippet: 'Located within the lower crescent of...', -}, { - title: 'Is coffee heatlhy?', - snippet: 'The reduction in risk was more significant once people reached...', -}]; +const newsContent = [ + { + title: 'Baboons escape', + snippet: 'Four baboons, having clearly read too much dystopian fiction...', + }, + { + title: 'Copper on the rise', + snippet: 'Located within the lower crescent of...', + }, + { + title: 'Is coffee heatlhy?', + snippet: 'The reduction in risk was more significant once people reached...', + }, +]; const NewsCard = () => { return ( - {newsContent.map((content, index) => - )} -
+ {newsContent.map((content, index) => ( + + ))} +
@@ -93,14 +101,18 @@ const NewsCard = () => { ); }; -const NewsRow = ({title, snippet, index}) => { - return ([ -
, -
-

{title}

-

{snippet}

-
, - ]); +const NewsRow: React.FunctionComponent<{title: string, snippet: string, index: number}> = ({ + title, snippet, index, // eslint-disable-line react/prop-types +}) => { + return ( + +
+
+

{title}

+

{snippet}

+
+
+ ); }; const ContentOnMediaCard = () => { @@ -120,9 +132,9 @@ const ContentOnMediaCard = () => { - - - + + +
@@ -139,5 +151,4 @@ const CardScreenshotTest = () => {
); }; - export default CardScreenshotTest; diff --git a/test/screenshot/text-field/TextFieldPermutations.tsx b/test/screenshot/text-field/TextFieldPermutations.tsx index 3ad1c1ba3..a9342195d 100644 --- a/test/screenshot/text-field/TextFieldPermutations.tsx +++ b/test/screenshot/text-field/TextFieldPermutations.tsx @@ -11,9 +11,6 @@ import { isValidationMsg, } from './attributesMap'; import TestField from './TestTextField'; -// @ts-ignore -import HelperText from '../../../packages/text-field/helper-text'; // eslint-disable-line no-unused-vars - const textFields = (variantProps: {variant?: string}) => { return iconsMap.map((icon: {leadingIcon?: React.ReactNode, trailingIcon?: React.ReactNode}) => { diff --git a/test/unit/card/ActionButton.test.js b/test/unit/card/ActionButton.test.tsx similarity index 64% rename from test/unit/card/ActionButton.test.js rename to test/unit/card/ActionButton.test.tsx index a5e5059e1..887721b48 100644 --- a/test/unit/card/ActionButton.test.js +++ b/test/unit/card/ActionButton.test.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import * as React from 'react'; import {assert} from 'chai'; import {shallow} from 'enzyme'; import {CardActionButtons} from '../../../packages/card/index'; @@ -6,16 +6,20 @@ import {CardActionButtons} from '../../../packages/card/index'; suite('CardActionButtons'); test('classNames adds classes', () => { - const wrapper = shallow(); + const wrapper = shallow( +
test
+
); assert.isTrue(wrapper.hasClass('test-class-name')); assert.isTrue(wrapper.hasClass('mdc-card__action-buttons')); }); test('adds correct classes to children', () => { - const wrapper = shallow( - - - ); + const wrapper = shallow( + + - ); + const wrapper = shallow( + +