From ca1626d03f9c4453a221e242591a900af93dc372 Mon Sep 17 00:00:00 2001 From: xkxd Date: Tue, 5 Mar 2019 16:03:50 +0100 Subject: [PATCH 1/2] Add AvatarStack --- .eslintrc | 1 + config/styleguide.config.json | 1 + source/components/AvatarStack/README.md | 35 ++++++ .../__snapshots__/index.spec.js.snap | 100 ++++++++++++++++++ source/components/AvatarStack/index.js | 49 +++++++++ source/components/AvatarStack/index.spec.js | 48 +++++++++ source/components/AvatarStack/styles.scss | 3 + source/components/index.js | 1 + 8 files changed, 238 insertions(+) create mode 100644 source/components/AvatarStack/README.md create mode 100644 source/components/AvatarStack/__snapshots__/index.spec.js.snap create mode 100644 source/components/AvatarStack/index.js create mode 100644 source/components/AvatarStack/index.spec.js create mode 100644 source/components/AvatarStack/styles.scss diff --git a/.eslintrc b/.eslintrc index cce1bf41..b1374b34 100644 --- a/.eslintrc +++ b/.eslintrc @@ -54,6 +54,7 @@ "no-restricted-imports": 0, "class-methods-use-this": 0, "no-use-before-define": 0, + "object-curly-newline": 0, "react/destructuring-assignment": 0, "react/no-access-state-in-setstate": "error", "react/jsx-filename-extension": 0, diff --git a/config/styleguide.config.json b/config/styleguide.config.json index fc1bc999..867765b9 100644 --- a/config/styleguide.config.json +++ b/config/styleguide.config.json @@ -39,6 +39,7 @@ "description": "React components", "components": [ "Avatar", + "AvatarStack", "BannerNotification", "BannerNotifications", "Button", diff --git a/source/components/AvatarStack/README.md b/source/components/AvatarStack/README.md new file mode 100644 index 00000000..d5fd6b4f --- /dev/null +++ b/source/components/AvatarStack/README.md @@ -0,0 +1,35 @@ +Defaults: +```js + +``` + +With maxStackSize + +```js + +``` + +With hidden overflow + +```js + +``` + +With overridden counter + +```js + +``` diff --git a/source/components/AvatarStack/__snapshots__/index.spec.js.snap b/source/components/AvatarStack/__snapshots__/index.spec.js.snap new file mode 100644 index 00000000..b74fc790 --- /dev/null +++ b/source/components/AvatarStack/__snapshots__/index.spec.js.snap @@ -0,0 +1,100 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AvatarStack renders when there are less avatars than specified by maxStackSize 1`] = ` +
+ + + 0 +
+`; + +exports[`AvatarStack renders when there are more avatars than specified by maxStackSize 1`] = ` +
+ +
+ +1 +
+
+`; + +exports[`AvatarStack renders with default props 1`] = ` +
+ + + 0 +
+`; + +exports[`AvatarStack renders with hideOverflow set to true 1`] = ` +
+ +
+`; + +exports[`AvatarStack renders with overrideCount 1`] = ` +
+ + + 0 +
+`; diff --git a/source/components/AvatarStack/index.js b/source/components/AvatarStack/index.js new file mode 100644 index 00000000..cfe58930 --- /dev/null +++ b/source/components/AvatarStack/index.js @@ -0,0 +1,49 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; + +import Avatar from '../Avatar'; + +import './styles.scss'; + +/* eslint-disable react/no-array-index-key */ +const AvatarStack = ({ avatars, overrideCount, maxStackSize, hideOverflow, className }) => { + const count = overrideCount || avatars.length; + const overflow = !hideOverflow && (count > maxStackSize ? count - maxStackSize : 0); + + return ( +
+ { + avatars + .slice(0, maxStackSize) + .map(({ src, alt, link, badge = '' }, index) => ( + + )) + } + { + overflow && ( +
+ {`+${overflow}`} +
+ ) + } +
+ ); +}; + +AvatarStack.propTypes = { + avatars: PropTypes.arrayOf(PropTypes.shape()).isRequired, + className: PropTypes.string, + hideOverflow: PropTypes.bool, + maxStackSize: PropTypes.number, + overrideCount: PropTypes.number, +}; + +AvatarStack.defaultProps = { + className: '', + hideOverflow: false, + maxStackSize: 5, + overrideCount: 0, +}; + +export default AvatarStack; diff --git a/source/components/AvatarStack/index.spec.js b/source/components/AvatarStack/index.spec.js new file mode 100644 index 00000000..b3dfa08c --- /dev/null +++ b/source/components/AvatarStack/index.spec.js @@ -0,0 +1,48 @@ +import { shallow } from 'enzyme'; +import React from 'react'; +import merge from 'lodash/merge'; + +import AvatarStack from './index'; + +const defaultProps = { + avatars: [ + { src: 'some.url', alt: 'User', link: 'some.link', badge: 'admin' }, + { src: 'some.other.url', alt: 'Other user', link: 'some.other.link' }, + ], +}; + +function renderComponent(props) { + const computedProps = merge({}, defaultProps, props); + + return shallow(); +} + +test('AvatarStack renders with default props', () => { + const wrapper = renderComponent(); + + expect(wrapper).toMatchSnapshot(); +}); + +test('AvatarStack renders with overrideCount', () => { + const wrapper = renderComponent({ overrideCount: 1 }); + + expect(wrapper).toMatchSnapshot(); +}); + +test('AvatarStack renders when there are less avatars than specified by maxStackSize', () => { + const wrapper = renderComponent({ maxStackSize: 3 }); + + expect(wrapper).toMatchSnapshot(); +}); + +test('AvatarStack renders when there are more avatars than specified by maxStackSize', () => { + const wrapper = renderComponent({ maxStackSize: 1 }); + + expect(wrapper).toMatchSnapshot(); +}); + +test('AvatarStack renders with hideOverflow set to true', () => { + const wrapper = renderComponent({ hideOverflow: true, maxStackSize: 1 }); + + expect(wrapper).toMatchSnapshot(); +}); diff --git a/source/components/AvatarStack/styles.scss b/source/components/AvatarStack/styles.scss new file mode 100644 index 00000000..d877cec0 --- /dev/null +++ b/source/components/AvatarStack/styles.scss @@ -0,0 +1,3 @@ +@import "~design-system/dist/scss/wds-mixins/index.scss"; +@import "~design-system/dist/scss/wds-variables/index.scss"; +@import "~design-system/dist/scss/wds-components/_avatar-stack.scss"; diff --git a/source/components/index.js b/source/components/index.js index 81081b37..c09b7c87 100644 --- a/source/components/index.js +++ b/source/components/index.js @@ -26,6 +26,7 @@ export { default as FandomContentWell } from './FandomContentWell'; export { default as List } from './List'; // Other UI export { default as Avatar } from './Avatar'; +export { default as AvatarStack } from './AvatarStack'; export { default as ExpandableText } from './ExpandableText'; export { default as Switch } from './Switch'; export { default as Timeago } from './Timeago'; From e588ce9c0ab6d18df9eeae46c515555b67fd00bc Mon Sep 17 00:00:00 2001 From: "Bartosz V. Bentkowski" Date: Tue, 5 Mar 2019 12:44:01 -0800 Subject: [PATCH 2/2] (opportunistic) Fix Avatar and BannerNotification; Add prop descriptions --- source/components/Avatar/index.js | 7 +--- source/components/Avatar/utils.js | 9 +++++ source/components/AvatarStack/README.md | 10 +++--- source/components/AvatarStack/index.js | 5 +++ .../components/BannerNotification/README.md | 2 +- source/components/BannerNotification/index.js | 33 ++----------------- source/components/BannerNotification/utils.js | 32 ++++++++++++++++++ 7 files changed, 56 insertions(+), 42 deletions(-) create mode 100644 source/components/Avatar/utils.js create mode 100644 source/components/BannerNotification/utils.js diff --git a/source/components/Avatar/index.js b/source/components/Avatar/index.js index 6918d1cb..38b687c1 100644 --- a/source/components/Avatar/index.js +++ b/source/components/Avatar/index.js @@ -2,16 +2,11 @@ import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import AvatarImage from './AvatarImage'; import Badge from './Badge'; +import { getAvatarImage } from './utils'; import './styles.scss'; -const getAvatarImage = (href, alt, src) => { - const avatarImage = ; - return href ? {avatarImage} : avatarImage; -}; - const Avatar = ({ alt, badge, diff --git a/source/components/Avatar/utils.js b/source/components/Avatar/utils.js new file mode 100644 index 00000000..ffd10468 --- /dev/null +++ b/source/components/Avatar/utils.js @@ -0,0 +1,9 @@ +import React from 'react'; + +import AvatarImage from './AvatarImage'; + +// eslint-disable-next-line +export function getAvatarImage(href, alt, src) { + const avatarImage = ; + return href ? {avatarImage} : avatarImage; +} diff --git a/source/components/AvatarStack/README.md b/source/components/AvatarStack/README.md index d5fd6b4f..4def761b 100644 --- a/source/components/AvatarStack/README.md +++ b/source/components/AvatarStack/README.md @@ -1,6 +1,6 @@ Defaults: ```js - ``` @@ -8,7 +8,7 @@ Defaults: With maxStackSize ```js - @@ -17,17 +17,17 @@ With maxStackSize With hidden overflow ```js - ``` With overridden counter ```js - alert('Click')}> + alert('Click')}> This is a text with a link ``` diff --git a/source/components/BannerNotification/index.js b/source/components/BannerNotification/index.js index 828cf51a..2893eb7a 100644 --- a/source/components/BannerNotification/index.js +++ b/source/components/BannerNotification/index.js @@ -2,38 +2,10 @@ import React from 'react'; import PropTypes from 'prop-types'; import IconCloseTiny from '../../icons/IconCloseTiny'; -import IconAlertSmall from '../../icons/IconAlertSmall'; -import IconCheckmarkSmall from '../../icons/IconCheckmarkSmall'; -import IconErrorSmall from '../../icons/IconErrorSmall'; -import IconFlagSmall from '../../icons/IconFlagSmall'; -import './styles.scss'; - -function getIcon(type) { - switch (type) { - case ('alert'): - return ; - case ('warning'): - return ; - case ('success'): - return ; - default: - return ; - } -} +import { getClassName, getIcon } from './utils'; -function getClassName(type) { - switch (type) { - case ('alert'): - return 'wds-alert'; - case ('warning'): - return 'wds-warning'; - case ('success'): - return 'wds-success'; - default: - return 'wds-message'; - } -} +import './styles.scss'; /** * This is a single component used in `BannerNotifications` component. @@ -48,6 +20,7 @@ const BannerNotification = ({ ); + BannerNotification.propTypes = { /** Children to display */ children: PropTypes.node, diff --git a/source/components/BannerNotification/utils.js b/source/components/BannerNotification/utils.js new file mode 100644 index 00000000..2fe18df8 --- /dev/null +++ b/source/components/BannerNotification/utils.js @@ -0,0 +1,32 @@ +import React from 'react'; + +import IconAlertSmall from '../../icons/IconAlertSmall'; +import IconCheckmarkSmall from '../../icons/IconCheckmarkSmall'; +import IconErrorSmall from '../../icons/IconErrorSmall'; +import IconFlagSmall from '../../icons/IconFlagSmall'; + +export function getIcon(type) { + switch (type) { + case ('alert'): + return ; + case ('warning'): + return ; + case ('success'): + return ; + default: + return ; + } +} + +export function getClassName(type) { + switch (type) { + case ('alert'): + return 'wds-alert'; + case ('warning'): + return 'wds-warning'; + case ('success'): + return 'wds-success'; + default: + return 'wds-message'; + } +}