Skip to content

Allow custom container with styles #152

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 17 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,28 +60,26 @@ import '@sandstreamdev/react-swipeable-list/dist/styles.css';
</SwipeableList>
```

or use function as children pattern if other container is needed (check animation example)
or use function as children pattern if other container is needed (check animation and styled container examples). Note that in this case you need to provide list wrapper and pass default `className` props to have same behaviour. Default `SwipeableList` styles are passed in `className` prop.

```jsx
<SwipeableList>
{props => (
<TransitionGroup>
<CSSTransition>
<SwipeableListItem
swipeLeft={{
content: <div>Revealed content during swipe</div>,
action: () => console.info('swipe action triggered')
}}
swipeRight={{
content: <div>Revealed content during swipe</div>,
action: () => console.info('swipe action triggered')
}}
{...props}
>
<div>Item name</div>
</SwipeableListItem>
</CSSTransition>
</TransitionGroup>
{({ className, ...rest }) => (
<div className={className}>
<SwipeableListItem
swipeLeft={{
content: <div>Revealed content during swipe</div>,
action: () => console.info('swipe action triggered')
}}
swipeRight={{
content: <div>Revealed content during swipe</div>,
action: () => console.info('swipe action triggered')
}}
{...rest}
>
<div>Item name</div>
</SwipeableListItem>
</div>
)}
</SwipeableList>
```
Expand Down
9 changes: 7 additions & 2 deletions examples/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ import BasicList from './basic/List';
import ComplexList from './complex/List';
import SizeToContentList from './size-to-content/List';
import AnimationsList from './animations/List';
import StyledList from './styled/List';

import styles from './app.module.css';

const ExampleType = enumerable(
'BASIC',
'COMPLEX',
'SIZE_TO_CONTENT',
'ANIMATIONS'
'ANIMATIONS',
'STYLED'
);

const Examples = [
Expand All @@ -22,7 +24,8 @@ const Examples = [
id: ExampleType.SIZE_TO_CONTENT,
text: 'List in size to content container'
},
{ id: ExampleType.ANIMATIONS, text: 'Animations' }
{ id: ExampleType.ANIMATIONS, text: 'Animations' },
{ id: ExampleType.STYLED, text: 'Custom container' }
];

class App extends PureComponent {
Expand All @@ -46,6 +49,8 @@ class App extends PureComponent {
return <SizeToContentList />;
case ExampleType.ANIMATIONS:
return <AnimationsList />;
case ExampleType.STYLED:
return <StyledList />;
}

return null;
Expand Down
9 changes: 7 additions & 2 deletions examples/src/animations/List.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,14 @@ const SimpleList = () => {
</span>
<div className={styles.listContainer}>
<SwipeableList threshold={threshold}>
{({ scrollStartThreshold, swipeStartThreshold, threshold }) => (
{({
className,
scrollStartThreshold,
swipeStartThreshold,
threshold
}) => (
<TransitionGroup
className="todo-list"
className={className}
enter={listAnimations}
exit={listAnimations}
>
Expand Down
6 changes: 3 additions & 3 deletions examples/src/size-to-content/List.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
SwipeableListItem
} from '@sandstreamdev/react-swipeable-list';
import '@sandstreamdev/react-swipeable-list/dist/styles.css';
import { identity } from '@sandstreamdev/std/function';
import { noOp } from '@sandstreamdev/std/function';

import ListItem from '../complex/ListItem';
import ItemContent from '../complex/ItemContent';
Expand Down Expand Up @@ -37,7 +37,7 @@ const SizeToContentList = () => {
side="right"
/>
),
action: identity
action: noOp
});

const swipeLeftOptions = () => ({
Expand All @@ -49,7 +49,7 @@ const SizeToContentList = () => {
side="left"
/>
),
action: identity
action: noOp
});

return (
Expand Down
71 changes: 71 additions & 0 deletions examples/src/styled/List.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React from 'react';
import { v4 as uuidv4 } from 'uuid';
import {
SwipeableList,
SwipeableListItem
} from '@sandstreamdev/react-swipeable-list';
import '@sandstreamdev/react-swipeable-list/dist/styles.css';
import { classNames } from '@sandstreamdev/std/web';
import { noOp } from '@sandstreamdev/std/function';

import styles from '../app.module.css';
import customStyles from './custom.module.css';

const itemContent = name => (
<div className={styles.listItem}>
<span>{name}</span>
</div>
);

const StyledList = () => {
const items = [
{ id: uuidv4(), text: 'Item 1' },
{ id: uuidv4(), text: 'Item 2' },
{ id: uuidv4(), text: 'Item 3' },
{ id: uuidv4(), text: 'Item 4' }
];

const swipeRightOptions = () => ({
content: (
<div className={styles.contentLeft}>
<span>Delete</span>
</div>
),
action: noOp
});

const swipeLeftOptions = () => ({
content: (
<div className={styles.contentRight}>
<span>Delete</span>
</div>
),
action: noOp
});

return (
<>
<span className={styles.actionInfo}>Custom styled list wrapper</span>
<div className={styles.listContainer}>
<SwipeableList>
{({ className, ...rest }) => (
<div className={classNames(className, customStyles.customList)}>
{items.map(({ id, text }) => (
<SwipeableListItem
key={id}
swipeLeft={swipeLeftOptions(id)}
swipeRight={swipeRightOptions(id)}
{...rest}
>
{itemContent(text)}
</SwipeableListItem>
))}
</div>
)}
</SwipeableList>
</div>
</>
);
};

export default StyledList;
4 changes: 4 additions & 0 deletions examples/src/styled/custom.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.customList {
height: 320px;
background-color: cornsilk;
}
32 changes: 19 additions & 13 deletions src/SwipeableList.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,25 @@ const SwipeableList = ({
scrollStartThreshold,
swipeStartThreshold,
threshold
}) => (
<div className={styles.swipeableList} data-testid="list-wrapper">
{typeof children === 'function'
? children({ scrollStartThreshold, swipeStartThreshold, threshold })
: React.Children.map(children, child =>
React.cloneElement(child, {
scrollStartThreshold,
swipeStartThreshold,
threshold
})
)}
</div>
);
}) =>
typeof children === 'function' ? (
children({
className: styles.swipeableList,
scrollStartThreshold,
swipeStartThreshold,
threshold
})
) : (
<div className={styles.swipeableList}>
{React.Children.map(children, child =>
React.cloneElement(child, {
scrollStartThreshold,
swipeStartThreshold,
threshold
})
)}
</div>
);

SwipeableList.propTypes = {
children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
Expand Down
21 changes: 19 additions & 2 deletions src/__tests__/SwipeableList.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
afterEach(cleanup);

test('list rendering with items', () => {
const { getByText } = render(
const { container, getByText } = render(
<SwipeableList>
<SwipeableListItem>
<span>Item content 1</span>
Expand All @@ -27,10 +27,11 @@ test('list rendering with items', () => {

expect(getByText('Item content 1')).toBeInTheDocument();
expect(getByText('Item content 2')).toBeInTheDocument();
expect(container.firstChild).toHaveClass('swipeableList');
});

test('list rendering with items when child as function', () => {
const { getByText } = render(
const { container, getByText } = render(
<SwipeableList>
{props => (
<>
Expand All @@ -47,6 +48,22 @@ test('list rendering with items when child as function', () => {

expect(getByText('Item content 1')).toBeInTheDocument();
expect(getByText('Item content 2')).toBeInTheDocument();
expect(container.firstChild).not.toHaveClass('swipeableList');
});

test('passing className to child function', () => {
const { container, getByTestId } = render(
<SwipeableList>
{({ className }) => (
<div>
<div className={className} data-testid="tested-div" />
</div>
)}
</SwipeableList>
);

expect(container.firstChild).not.toHaveClass('swipeableList');
expect(getByTestId('tested-div')).toHaveClass('swipeableList');
});

test('blocking swipe on scroll', () => {
Expand Down
6 changes: 5 additions & 1 deletion src/module.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,13 @@ interface IBaseSwipeableListProps {
threshold?: number;
}

interface IStyledSwipeableListProps extends IBaseSwipeableListProps {
className: string;
}

type SwipeableListChildren =
| ReactNode
| ((props: IBaseSwipeableListProps) => ReactNode);
| ((props: IStyledSwipeableListProps) => ReactNode);

interface ISwipeableListProps extends IBaseSwipeableListProps {
/**
Expand Down