From 828b062c40e23e46360c7bea33873abec60a1f9b Mon Sep 17 00:00:00 2001 From: Franco Correa Date: Mon, 19 Nov 2018 17:47:38 -0300 Subject: [PATCH 01/14] Sortable Resource List --- .../molecules/resource-list/index.js | 3 +- .../molecules/resource-list/resource-list.js | 49 +++++-- .../resource-list/resource-list.story.js | 123 ++++++++++++------ core/components/package.json | 3 +- yarn.lock | 11 +- 5 files changed, 131 insertions(+), 58 deletions(-) diff --git a/core/components/molecules/resource-list/index.js b/core/components/molecules/resource-list/index.js index 6ffa60240..405004362 100644 --- a/core/components/molecules/resource-list/index.js +++ b/core/components/molecules/resource-list/index.js @@ -1,3 +1,4 @@ -import ResourceList from './resource-list' +import ResourceList, { arrayMove } from './resource-list' export default ResourceList +export { arrayMove } diff --git a/core/components/molecules/resource-list/resource-list.js b/core/components/molecules/resource-list/resource-list.js index c868519be..f15cf0bc0 100644 --- a/core/components/molecules/resource-list/resource-list.js +++ b/core/components/molecules/resource-list/resource-list.js @@ -5,26 +5,50 @@ import ResourceListItem from './item' import { spacing } from '@auth0/cosmos-tokens' import { actionShapeWithRequiredIcon } from '@auth0/cosmos/_helpers/action-shape' import Automation from '../../_helpers/automation-attribute' +import { SortableContainer, SortableElement, arrayMove } from 'react-sortable-hoc' const StyledList = styled.ul` margin: ${spacing.large} 0; padding: 0; ` -const defaultItemRenderer = (item, index) => +const defaultItemRenderer = (item, index) => +const defaultChildrenRenderer = ({ items, actions, onItemClick, renderItem }) => + items.map((item, index) => { + const itemRenderer = renderItem || defaultItemRenderer + return React.cloneElement(itemRenderer(item, index), { + key: item.key || index, + actions: item.actions || actions, + onClick: item.onClick || onItemClick, + item + }) + }) + +const sortableChildrenRenderer = ({ items, actions, onItemClick, renderItem, onSortEnd }) => { + const Container = SortableContainer(({ items: sortableItems }) => + sortableItems.map((item, index) => { + const itemRenderer = renderItem || defaultItemRenderer + const SortableResourceListItem = SortableElement(value => itemRenderer(item, index, value)) + + return ( + + ) + }) + ) + return +} + +const resolveChildrenRenderer = props => + props.sortable ? sortableChildrenRenderer(props) : defaultChildrenRenderer(props) const ResourceList = props => ( - - {props.items.map((item, index) => { - const itemRenderer = props.renderItem || defaultItemRenderer - return React.cloneElement(itemRenderer(item, index), { - key: item.key || index, - actions: item.actions || props.actions, - onClick: item.onClick || props.onItemClick, - item - }) - })} - + {resolveChildrenRenderer(props)} ) ResourceList.Item = ResourceListItem @@ -41,3 +65,4 @@ ResourceList.propTypes = { } export default ResourceList +export { arrayMove } diff --git a/core/components/molecules/resource-list/resource-list.story.js b/core/components/molecules/resource-list/resource-list.story.js index 83ddf3abd..e73c74df3 100644 --- a/core/components/molecules/resource-list/resource-list.story.js +++ b/core/components/molecules/resource-list/resource-list.story.js @@ -2,6 +2,7 @@ import React from 'react' import { storiesOf } from '@storybook/react' import { Example } from '@auth0/cosmos/_helpers/story-helpers' import { Avatar, Code, Icon, Image, ResourceList } from '@auth0/cosmos' +import { arrayMove } from '@auth0/cosmos/molecules/resource-list' const IMAGE_URLS = [ 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48cGF0aCBkPSJNMCAwaDQ4djQ4SDB6Ii8+PGcgZmlsbC1ydWxlPSJub256ZXJvIj48cGF0aCBkPSJNMjcuMjQ2IDM5SDEwLjc1NEExLjc1NCAxLjc1NCAwIDAgMSA5IDM3LjI0NlYyMC43NTRDOSAxOS43ODUgOS43ODUgMTkgMTAuNzU0IDE5aDE2LjQ5MmMuOTY5IDAgMS43NTQuNzg1IDEuNzU0IDEuNzU0djE2LjQ5MmMwIC45NjktLjc4NSAxLjc1NC0xLjc1NCAxLjc1NCIgZmlsbD0iIzE2MjE0RCIvPjxwYXRoIGQ9Ik0zMi4yNDYgMzRIMTUuNzU0QTEuNzU0IDEuNzU0IDAgMCAxIDE0IDMyLjI0NlYxNS43NTRjMC0uOTY5Ljc4NS0xLjc1NCAxLjc1NC0xLjc1NGgxNi40OTJjLjk2OSAwIDEuNzU0Ljc4NSAxLjc1NCAxLjc1NHYxNi40OTJjMCAuOTY5LS43ODUgMS43NTQtMS43NTQgMS43NTQiIGZpbGw9IiNFQzU0MjQiLz48cGF0aCBkPSJNMzcuMjQ2IDI5SDIwLjc1NEExLjc1NCAxLjc1NCAwIDAgMSAxOSAyNy4yNDZWMTAuNzU0QzE5IDkuNzg1IDE5Ljc4NSA5IDIwLjc1NCA5aDE2LjQ5MkMzOC4yMTUgOSAzOSA5Ljc4NSAzOSAxMC43NTR2MTYuNDkyYzAgLjk2OS0uNzg1IDEuNzU0LTEuNzU0IDEuNzU0IiBmaWxsPSIjNDRDN0Y0Ii8+PC9nPjwvZz48L3N2Zz4=', @@ -29,6 +30,26 @@ storiesOf('Resource List').add('titles and subtitles', () => ( )) +class SortableResourceListExample extends React.Component { + state = { + items: [ + { title: 'Title One', subtitle: 'Subtitle One', href: 'https://auth0.com/' }, + { title: 'Title Two', subtitle: 'Subtitle Two', href: 'https://auth0.com/' }, + { title: 'Title Three', subtitle: 'Subtitle Three', href: 'https://auth0.com/' } + ] + } + onSortEnd({ oldIndex, newIndex }) { + this.setState({ + items: arrayMove(this.state.items, oldIndex, newIndex) + }) + } + render() { + return ( + this.onSortEnd(event)} /> + ) + } +} + storiesOf('Resource List').add('titles with links', () => ( ( )) +storiesOf('Resource List').add('sortable', () => ( + + + +)) + storiesOf('Resource List').add('with images', () => ( ( )} actions={[ - { label: 'Delete', icon: 'delete', handler: function () { } }, - { label: 'Settings', icon: 'settings', handler: function () { } } + { label: 'Delete', icon: 'delete', handler: function() {} }, + { label: 'Settings', icon: 'settings', handler: function() {} } ]} /> @@ -114,7 +141,7 @@ storiesOf('Resource List').add('action overrides', () => ( subtitle: 'Subtitle Three', image: IMAGE_URLS[2], id: 'ghi789', - actions: [{ label: 'Settings', icon: 'settings', handler: function () { } }] + actions: [{ label: 'Settings', icon: 'settings', handler: function() {} }] } ]} renderItem={item => ( @@ -123,8 +150,8 @@ storiesOf('Resource List').add('action overrides', () => ( )} actions={[ - { label: 'Delete', icon: 'delete', handler: function () { } }, - { label: 'Settings', icon: 'settings', handler: function () { } } + { label: 'Delete', icon: 'delete', handler: function() {} }, + { label: 'Settings', icon: 'settings', handler: function() {} } ]} /> @@ -133,43 +160,53 @@ storiesOf('Resource List').add('action overrides', () => ( storiesOf('Resource List').add('stressed', () => ( -)) \ No newline at end of file +)) diff --git a/core/components/package.json b/core/components/package.json index 4eaf53587..4a4799679 100644 --- a/core/components/package.json +++ b/core/components/package.json @@ -10,9 +10,10 @@ "license": "MIT", "types": "meta/index.d.ts", "dependencies": { - "md5": "^2.2.1", "@auth0/cosmos-tokens": "0.7.2", + "md5": "^2.2.1", "prop-types": "15.6.1", + "react-sortable-hoc": "^0.8.3", "styled-components": "3.1.6" }, "peerDependencies": { diff --git a/yarn.lock b/yarn.lock index 3fa5b3826..94c8772e2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8789,7 +8789,7 @@ prop-types@15.6.1: loose-envify "^1.3.1" object-assign "^4.1.1" -prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.8, prop-types@^15.5.9, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2: +prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@^15.5.9, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2: version "15.6.2" resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" integrity sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ== @@ -9223,6 +9223,15 @@ react-side-effect@^1.1.0: exenv "^1.2.1" shallowequal "^1.0.1" +react-sortable-hoc@^0.8.3: + version "0.8.3" + resolved "https://registry.yarnpkg.com/react-sortable-hoc/-/react-sortable-hoc-0.8.3.tgz#8537e8ab8d6bad6829885755a0f847817ed78648" + integrity sha512-vt2qQ9DnPLjGZ9osM2jBULdi7WfFXtYVuHvjHX8o2em7Rcla9FXIG60aWFbvvpFC1iXyATw5PWZX0B57EUOYfQ== + dependencies: + babel-runtime "^6.11.6" + invariant "^2.2.1" + prop-types "^15.5.7" + react-split-pane@^0.1.77: version "0.1.84" resolved "https://registry.npmjs.org/react-split-pane/-/react-split-pane-0.1.84.tgz#b9c1499cbc40b09cf29953ee6f5ff1039d31906e" From cd73dead578d1fcbaccfb5e131a2b5bc261a62c6 Mon Sep 17 00:00:00 2001 From: Franco Correa Date: Fri, 23 Nov 2018 13:35:49 -0300 Subject: [PATCH 02/14] Finish implementing sortable resource list --- .../molecules/resource-list/resource-list.js | 30 +++++++++-------- .../molecules/resource-list/resource-list.md | 32 +++++++++++++++++++ 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/core/components/molecules/resource-list/resource-list.js b/core/components/molecules/resource-list/resource-list.js index f15cf0bc0..964253167 100644 --- a/core/components/molecules/resource-list/resource-list.js +++ b/core/components/molecules/resource-list/resource-list.js @@ -1,11 +1,11 @@ import React from 'react' import PropTypes from 'prop-types' import styled from 'styled-components' -import ResourceListItem from './item' +import { SortableContainer, SortableElement, arrayMove } from 'react-sortable-hoc' import { spacing } from '@auth0/cosmos-tokens' import { actionShapeWithRequiredIcon } from '@auth0/cosmos/_helpers/action-shape' import Automation from '../../_helpers/automation-attribute' -import { SortableContainer, SortableElement, arrayMove } from 'react-sortable-hoc' +import ResourceListItem from './item' const StyledList = styled.ul` margin: ${spacing.large} 0; @@ -17,31 +17,35 @@ const defaultChildrenRenderer = ({ items, actions, onItemClick, renderItem }) => items.map((item, index) => { const itemRenderer = renderItem || defaultItemRenderer return React.cloneElement(itemRenderer(item, index), { - key: item.key || index, actions: item.actions || actions, onClick: item.onClick || onItemClick, item }) }) -const sortableChildrenRenderer = ({ items, actions, onItemClick, renderItem, onSortEnd }) => { - const Container = SortableContainer(({ items: sortableItems }) => - sortableItems.map((item, index) => { - const itemRenderer = renderItem || defaultItemRenderer - const SortableResourceListItem = SortableElement(value => itemRenderer(item, index, value)) +const SortableResourceListItem = SortableElement(({ item, index, value, itemRenderer }) => + itemRenderer(item, index, value) +) - return ( +const SortableResourceList = SortableContainer( + ({ items: sortableItems, actions, onItemClick, renderItem, onSortEnd }) => ( +
+ {sortableItems.map((item, index) => ( - ) - }) + ))} +
) - return +) + +const sortableChildrenRenderer = props => { + return } const resolveChildrenRenderer = props => diff --git a/core/components/molecules/resource-list/resource-list.md b/core/components/molecules/resource-list/resource-list.md index c048e887e..d9c4b0130 100644 --- a/core/components/molecules/resource-list/resource-list.md +++ b/core/components/molecules/resource-list/resource-list.md @@ -96,3 +96,35 @@ If you need more control over the rendering of list items, you can pass a `rende ]} /> ``` + +## Advanced: Drag and sort items + +You can use the `sortable` prop to make the list sortable by dragging and dropping the items. +You will need to implement the `onSortEnd` method in order to reorder the items using the provided +`arrayMove` function + +```js +class SortableResourceListExample extends React.Component { + constructor(props) { + super(props) + this.state = { + items: [ + { title: 'Title One', subtitle: 'Subtitle One', href: 'https://auth0.com/' }, + { title: 'Title Two', subtitle: 'Subtitle Two', href: 'https://auth0.com/' }, + { title: 'Title Three', subtitle: 'Subtitle Three', href: 'https://auth0.com/' } + ] + } + } + onSortEnd({ oldIndex, newIndex }) { + // The arrayMove example does not work on docs + this.setState({ + items: arrayMove(this.state.items, oldIndex, newIndex) + }) + } + render() { + return ( + this.onSortEnd(event)} /> + ) + } +} +``` From c4b5ec40872f4eb9c2743d2f21b40a9990953818 Mon Sep 17 00:00:00 2001 From: Franco Correa Date: Fri, 23 Nov 2018 13:59:27 -0300 Subject: [PATCH 03/14] Fixes --- .../molecules/resource-list/resource-list.js | 28 +++++++++++-------- .../molecules/resource-list/resource-list.md | 10 ++++++- .../resource-list/resource-list.story.js | 10 ++++++- 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/core/components/molecules/resource-list/resource-list.js b/core/components/molecules/resource-list/resource-list.js index 964253167..5a30cda02 100644 --- a/core/components/molecules/resource-list/resource-list.js +++ b/core/components/molecules/resource-list/resource-list.js @@ -13,22 +13,26 @@ const StyledList = styled.ul` ` const defaultItemRenderer = (item, index) => -const defaultChildrenRenderer = ({ items, actions, onItemClick, renderItem }) => - items.map((item, index) => { - const itemRenderer = renderItem || defaultItemRenderer - return React.cloneElement(itemRenderer(item, index), { - actions: item.actions || actions, - onClick: item.onClick || onItemClick, - item - }) + +const itemRendererBuilder = ({ item, index, renderItem, onItemClick, actions }) => { + const itemRenderer = renderItem || defaultItemRenderer + return React.cloneElement(itemRenderer(item, index), { + actions: item.actions || actions, + onClick: item.onClick || onItemClick, + item }) +} + +const defaultChildrenRenderer = ({ items, actions, onItemClick, renderItem }) => + items.map((item, index) => itemRendererBuilder({ item, index, renderItem, onItemClick, actions })) -const SortableResourceListItem = SortableElement(({ item, index, value, itemRenderer }) => - itemRenderer(item, index, value) +const SortableResourceListItem = SortableElement( + ({ item, index, renderItem, actions, onClick: onItemClick }) => + itemRendererBuilder({ item, index, renderItem, actions, onItemClick }) ) const SortableResourceList = SortableContainer( - ({ items: sortableItems, actions, onItemClick, renderItem, onSortEnd }) => ( + ({ items: sortableItems, actions, onItemClick, renderItem }) => (
{sortableItems.map((item, index) => ( ))}
diff --git a/core/components/molecules/resource-list/resource-list.md b/core/components/molecules/resource-list/resource-list.md index d9c4b0130..00fbca6ee 100644 --- a/core/components/molecules/resource-list/resource-list.md +++ b/core/components/molecules/resource-list/resource-list.md @@ -123,7 +123,15 @@ class SortableResourceListExample extends React.Component { } render() { return ( - this.onSortEnd(event)} /> + this.onSortEnd(event)} + /> ) } } diff --git a/core/components/molecules/resource-list/resource-list.story.js b/core/components/molecules/resource-list/resource-list.story.js index e73c74df3..3a6b09036 100644 --- a/core/components/molecules/resource-list/resource-list.story.js +++ b/core/components/molecules/resource-list/resource-list.story.js @@ -45,7 +45,15 @@ class SortableResourceListExample extends React.Component { } render() { return ( - this.onSortEnd(event)} /> + this.onSortEnd(event)} + /> ) } } From 920023f76c89f040d9d01e3ab645dd171e157e6c Mon Sep 17 00:00:00 2001 From: Franco Correa Date: Mon, 3 Dec 2018 16:36:50 -0300 Subject: [PATCH 04/14] Add reorder drag handle --- .../molecules/resource-list/item/item.js | 5 ++++ .../molecules/resource-list/resource-list.js | 24 +++++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/core/components/molecules/resource-list/item/item.js b/core/components/molecules/resource-list/item/item.js index 339006c77..6761c46ad 100644 --- a/core/components/molecules/resource-list/item/item.js +++ b/core/components/molecules/resource-list/item/item.js @@ -57,6 +57,7 @@ const ResourceListItem = props => { let title let subtitle let actions + let SortableHandler if (props.image) { // TODO: We might want a way to control the type of the avatar, but we don't @@ -96,12 +97,16 @@ const ResourceListItem = props => { ) } + if (props.reorderHandle) SortableHandler = props.reorderHandle + return ( + {SortableHandler && } + {image}
{title} diff --git a/core/components/molecules/resource-list/resource-list.js b/core/components/molecules/resource-list/resource-list.js index 5a30cda02..98b2a5eeb 100644 --- a/core/components/molecules/resource-list/resource-list.js +++ b/core/components/molecules/resource-list/resource-list.js @@ -1,18 +1,34 @@ import React from 'react' import PropTypes from 'prop-types' import styled from 'styled-components' -import { SortableContainer, SortableElement, arrayMove } from 'react-sortable-hoc' -import { spacing } from '@auth0/cosmos-tokens' +import { SortableContainer, SortableElement, SortableHandle, arrayMove } from 'react-sortable-hoc' +import { spacing, colors } from '@auth0/cosmos-tokens' import { actionShapeWithRequiredIcon } from '@auth0/cosmos/_helpers/action-shape' import Automation from '../../_helpers/automation-attribute' import ResourceListItem from './item' +import Tooltip from '../../atoms/tooltip' +import Icon from '../../atoms/icon' const StyledList = styled.ul` margin: ${spacing.large} 0; padding: 0; ` -const defaultItemRenderer = (item, index) => +const SortableListHandle = SortableHandle(() => ( + + + + + +)) + +SortableListHandle.Element = styled.div` + margin-right: ${spacing.small}; +` + +const defaultItemRenderer = (item, index) => ( + +) const itemRendererBuilder = ({ item, index, renderItem, onItemClick, actions }) => { const itemRenderer = renderItem || defaultItemRenderer @@ -49,7 +65,7 @@ const SortableResourceList = SortableContainer( ) const sortableChildrenRenderer = props => { - return + return } const resolveChildrenRenderer = props => From 81b551c9c4b277abc21c6c9d91fcdc9e8b4e7b09 Mon Sep 17 00:00:00 2001 From: Franco Correa Date: Tue, 4 Dec 2018 13:54:15 -0300 Subject: [PATCH 05/14] Drag handle --- .../molecules/resource-list/item/item.js | 3 +-- .../molecules/resource-list/resource-list.js | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/core/components/molecules/resource-list/item/item.js b/core/components/molecules/resource-list/item/item.js index 6761c46ad..da62555fd 100644 --- a/core/components/molecules/resource-list/item/item.js +++ b/core/components/molecules/resource-list/item/item.js @@ -104,9 +104,8 @@ const ResourceListItem = props => { onClick={props.onClick ? callHandler(props.onClick) : null} {...Automation('resource-list.item')} > + {SortableHandler && } - {SortableHandler && } - {image}
{title} diff --git a/core/components/molecules/resource-list/resource-list.js b/core/components/molecules/resource-list/resource-list.js index 98b2a5eeb..991c9e7e2 100644 --- a/core/components/molecules/resource-list/resource-list.js +++ b/core/components/molecules/resource-list/resource-list.js @@ -12,6 +12,11 @@ import Icon from '../../atoms/icon' const StyledList = styled.ul` margin: ${spacing.large} 0; padding: 0; + + &.cosmos-dragging { + background-color: red; + box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.2); + } ` const SortableListHandle = SortableHandle(() => ( @@ -23,7 +28,12 @@ const SortableListHandle = SortableHandle(() => ( )) SortableListHandle.Element = styled.div` - margin-right: ${spacing.small}; + display: flex; + align-items: center; + justify-content: center; + width: ${spacing.large}; + margin-right: ${spacing.xsmall}; + height: 100%; ` const defaultItemRenderer = (item, index) => ( @@ -65,7 +75,7 @@ const SortableResourceList = SortableContainer( ) const sortableChildrenRenderer = props => { - return + return } const resolveChildrenRenderer = props => From 5ec2e6a7a61d80fa5e1e5600d823808a33c3fbcd Mon Sep 17 00:00:00 2001 From: Franco Correa Date: Tue, 4 Dec 2018 18:14:54 -0300 Subject: [PATCH 06/14] Adjust drag handle and style dragging state resourcelist item --- .../molecules/resource-list/item/item.js | 5 + .../molecules/resource-list/resource-list.js | 103 +++++++++--------- 2 files changed, 58 insertions(+), 50 deletions(-) diff --git a/core/components/molecules/resource-list/item/item.js b/core/components/molecules/resource-list/item/item.js index ef8a49ab9..dec62def5 100644 --- a/core/components/molecules/resource-list/item/item.js +++ b/core/components/molecules/resource-list/item/item.js @@ -96,6 +96,11 @@ ListItem.Element = styled.li` &:hover { background: ${colors.list.backgroundHover}; } + + &.cosmos-dragging { + opacity: 0.9; + box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.2); + } ` ListItem.Header = styled.div` diff --git a/core/components/molecules/resource-list/resource-list.js b/core/components/molecules/resource-list/resource-list.js index 8afc842ee..c0cd164de 100644 --- a/core/components/molecules/resource-list/resource-list.js +++ b/core/components/molecules/resource-list/resource-list.js @@ -21,73 +21,76 @@ const SortableListHandle = SortableHandle(() => ( SortableListHandle.Element = styled.div` display: flex; align-items: center; - justify-content: center; + justify-content: flex-start; width: ${spacing.large}; - margin-right: ${spacing.xsmall}; - height: 100%; + margin-right: ${spacing.xxsmall}; + min-height: 100%; ` -const defaultItemRenderer = (item, index) => ( - -) +const ResourceList = props => { + const defaultItemRenderer = (item, index) => ( + + ) -const itemRendererBuilder = ({ item, index, renderItem, onItemClick, actions }) => { - const itemRenderer = renderItem || defaultItemRenderer - return React.cloneElement(itemRenderer(item, index), { - actions: item.actions || actions, - onClick: item.onClick || onItemClick, - item - }) -} + const itemRendererBuilder = ({ item, index, renderItem, onItemClick, actions }) => { + const itemRenderer = renderItem || defaultItemRenderer + return React.cloneElement(itemRenderer(item, index), { + actions: item.actions || actions, + onClick: item.onClick || onItemClick, + item + }) + } -const defaultChildrenRenderer = ({ items, actions, onItemClick, renderItem }) => - items.map((item, index) => itemRendererBuilder({ item, index, renderItem, onItemClick, actions })) + const defaultChildrenRenderer = ({ items, actions, onItemClick, renderItem }) => + items.map((item, index) => + itemRendererBuilder({ item, index, renderItem, onItemClick, actions }) + ) -const SortableResourceListItem = SortableElement( - ({ item, index, renderItem, actions, onClick: onItemClick }) => - itemRendererBuilder({ item, index, renderItem, actions, onItemClick }) -) + const SortableResourceListItem = SortableElement( + ({ item, index, renderItem, actions, onClick: onItemClick }) => + itemRendererBuilder({ item, index, renderItem, actions, onItemClick }) + ) -const SortableResourceList = SortableContainer( - ({ items: sortableItems, actions, onItemClick, renderItem }) => ( -
- {sortableItems.map((item, index) => ( - - ))} -
+ const SortableResourceList = SortableContainer( + ({ items: sortableItems, actions, onItemClick, renderItem }) => ( +
+ {sortableItems.map((item, index) => ( + + ))} +
+ ) ) -) -const sortableChildrenRenderer = props => { - return -} + const sortableChildrenRenderer = props => { + return + } -const resolveChildrenRenderer = props => - props.sortable ? sortableChildrenRenderer(props) : defaultChildrenRenderer(props) + const resolveChildrenRenderer = props => + props.sortable ? sortableChildrenRenderer(props) : defaultChildrenRenderer(props) -const ResourceList = props => ( - - {resolveChildrenRenderer(props)} - -) + return ( + + {resolveChildrenRenderer(props)} + + ) +} ResourceList.Element = styled.ul` ${containerStyles}; margin: ${spacing.large} 0; padding: 0; - - & .cosmos-dragging { - background-color: red; - box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.2); - } ` ResourceList.Item = ResourceListItem From c2ffea961762e9ac46944b4133c9ebc709e48b5c Mon Sep 17 00:00:00 2001 From: Franco Correa Date: Tue, 4 Dec 2018 18:18:07 -0300 Subject: [PATCH 07/14] Fix background color on dragging --- core/components/molecules/resource-list/item/item.js | 1 + 1 file changed, 1 insertion(+) diff --git a/core/components/molecules/resource-list/item/item.js b/core/components/molecules/resource-list/item/item.js index dec62def5..416eeea75 100644 --- a/core/components/molecules/resource-list/item/item.js +++ b/core/components/molecules/resource-list/item/item.js @@ -98,6 +98,7 @@ ListItem.Element = styled.li` } &.cosmos-dragging { + background-color: ${colors.base.white}; opacity: 0.9; box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.2); } From 569f0b4608f8164f4facbf37b0ed39b212b60a99 Mon Sep 17 00:00:00 2001 From: Franco Correa Date: Fri, 7 Dec 2018 14:47:10 -0300 Subject: [PATCH 08/14] Accessibility WIP --- .../molecules/resource-list/item/item.js | 128 +++++++++++------- .../molecules/resource-list/resource-list.js | 54 +++++++- .../resource-list/resource-list.story.js | 64 +++++---- yarn.lock | 4 - 4 files changed, 162 insertions(+), 88 deletions(-) diff --git a/core/components/molecules/resource-list/item/item.js b/core/components/molecules/resource-list/item/item.js index 416eeea75..87bb8380b 100644 --- a/core/components/molecules/resource-list/item/item.js +++ b/core/components/molecules/resource-list/item/item.js @@ -33,58 +33,79 @@ const resolveAction = (item, action, key) => { */ const resolveActions = (actions, item) => actions.map(resolveAction.bind(this, item)) -const ListItem = props => { - let image - let title - let subtitle - let actions - let SortableHandler - - const callHandler = handler => evt => handler(evt, props.item) - - if (props.image) { - // TODO: We might want a way to control the type of the avatar, but we don't - // want to leak every prop from Avatar into the ListItem... - image = - } else if (props.icon) { - image = - } +class ListItem extends React.Component { + constructor(props) { + super(props) - if (props.title) { - if (props.href) { - title = {props.title} - } else { - title = props.title - } + this.state = { inSortingMode: false } } - if (props.subtitle) { - subtitle = {props.subtitle} + setSortingMode(inSortingMode) { + this.setState({ inSortingMode }) } - if (props.actions) { - actions = {resolveActions(props.actions, props.item)} - } + render() { + const props = this.props + + let image + let title + let subtitle + let actions + let SortableHandler - if (props.reorderHandle) SortableHandler = props.reorderHandle - - return ( - - {SortableHandler && } - - {image} -
- {title} - {subtitle} -
-
- {props.children} - {actions} -
- ) + const callHandler = handler => evt => handler(evt, props.item) + + if (props.image) { + // TODO: We might want a way to control the type of the avatar, but we don't + // want to leak every prop from Avatar into the ListItem... + image = + } else if (props.icon) { + image = + } + + if (props.title) { + if (props.href) { + title = {props.title} + } else { + title = props.title + } + } + + if (props.subtitle) { + subtitle = {props.subtitle} + } + + if (props.actions) { + actions = {resolveActions(props.actions, props.item)} + } + + if (props.reorderHandle) SortableHandler = props.reorderHandle + + return ( + + {SortableHandler && ( + + console.log({ onFocus }) || this.setSortingMode(onFocus) + } + /> + )} + + {image} +
+ {title} + {subtitle} +
+
+ {props.children} + {actions} +
+ ) + } } ListItem.Element = styled.li` @@ -93,6 +114,10 @@ ListItem.Element = styled.li` border-top: 1px solid ${colors.list.borderColor}; padding: ${spacing.small} ${spacing.xsmall}; cursor: ${props => (props.onClick ? 'pointer' : 'inherit')}; + border: ${props => + console.log({ props }) || + (props.inSortingMode ? `2px solid ${colors.input.borderFocus}` : 'none')} + &:hover { background: ${colors.list.backgroundHover}; } @@ -161,11 +186,12 @@ ListItem.propTypes = { const firstAction = props.actions[0] if (!React.isValidElement(firstAction)) { - return deprecate(props, { - name: 'actions', - oldAPI: 'passing objects in actions', - replacement: ', + ]} /> @@ -170,7 +174,7 @@ storiesOf('Resource List').add('action overrides', () => ( subtitle: 'Subtitle Three', image: IMAGE_URLS[2], id: 'ghi789', - actions: [{ label: 'Settings', icon: 'settings', handler: function() {} }] + actions: [, + ]} /> @@ -196,13 +204,13 @@ storiesOf('Resource List').add('stressed', () => ( subtitle: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras vehicula massa augue, in consectetur tellus tristique ut.', actions: [ - { label: 'Settings', icon: 'settings', handler: function() {} }, - { label: 'Settings', icon: 'settings', handler: function() {} }, - { label: 'Settings', icon: 'settings', handler: function() {} }, - { label: 'Settings', icon: 'settings', handler: function() {} }, - { label: 'Settings', icon: 'settings', handler: function() {} }, - { label: 'Settings', icon: 'settings', handler: function() {} }, - { label: 'Settings', icon: 'settings', handler: function() {} } + , - + , - +