Skip to content
This repository has been archived by the owner on Jun 5, 2023. It is now read-only.

Commit

Permalink
feat(Stack): New withDividers prop, noissue
Browse files Browse the repository at this point in the history
  • Loading branch information
diondiondion committed Apr 6, 2022
1 parent f247a5a commit 9cfac3f
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 11 deletions.
51 changes: 46 additions & 5 deletions src/Stack/README.stories.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ import Stack, {StackWrapper, StackItem} from './';
import Stack from 'base5-ui/Stack';
```

Control vertical spacing between Stack items. Supports all `Box` style props.
Control vertical spacing and dividers between Stack items. Supports all `Box` style props.

## Examples
## Spacing

Use the `spacing` prop with responsive theme tokens to control the distance between each list item.

<Canvas>
<Story
name="Simple"
args={{spacing: 'xxs'}}
args={{spacing: 's', withDividers: false}}
argTypes={{
spacing: {
control: {type: 'radio'},
Expand All @@ -33,6 +35,35 @@ Control vertical spacing between Stack items. Supports all `Box` style props.
<Stack {...props}>
<TextLink href="#">Home</TextLink>
<TextLink href="#">Projects</TextLink>
<TextLink href="#">Pricing</TextLink>
<TextLink href="#">About us</TextLink>
</Stack>
)}
</Story>
</Canvas>

## Dividers

Use the `withDividers` prop to add a simple divider between each list item.

> Note that this also adds `overflow: hidden` to the `Stack` container.
<Canvas>
<Story
name="With dividers"
args={{spacing: 's', withDividers: true}}
argTypes={{
spacing: {
control: {type: 'radio'},
options: [0, 'xxs', 'xs', 's', 'm', 'xl', 'xxl'],
},
}}
>
{props => (
<Stack {...props}>
<TextLink href="#">Home</TextLink>
<TextLink href="#">Projects</TextLink>
<TextLink href="#">Pricing</TextLink>
<TextLink href="#">About us</TextLink>
</Stack>
)}
Expand Down Expand Up @@ -70,7 +101,12 @@ The following list has a third list item that will be hidden on larger screens.
<Canvas>
<Story
name="Hiding items"
args={{as: 'list', spacing: [0, 's', 'xl'], breakpoints: ['m', 'l']}}
args={{
as: 'list',
spacing: [0, 's', 'xl'],
withDividers: false,
breakpoints: ['m', 'l'],
}}
>
{props => (
<Stack {...props}>
Expand Down Expand Up @@ -101,7 +137,12 @@ Instead of using the `Hidden` component to responsively hide items, you can pass
<Canvas>
<Story
name="Granular rendering"
args={{as: 'list', spacing: [0, 's', 'xl'], breakpoints: ['m', 'l']}}
args={{
as: 'list',
spacing: [0, 's', 'xl'],
withDividers: false,
breakpoints: ['m', 'l'],
}}
>
{props => (
<StackWrapper {...props}>
Expand Down
56 changes: 50 additions & 6 deletions src/Stack/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,55 @@ import PropTypes from 'prop-types';
import {getSpacing, createStyleFunction} from '../utils';

import Box from '../Box';
import Divider from '../Divider';
import Hidden from '../Hidden';

export const spacingCompensationProp = createStyleFunction([
const spacingCompensationProp = createStyleFunction([
{
styleProp: 'compensateSpacing',
properties: ['marginBottom'],
getValue: (value, theme) => `-${getSpacing(value, theme)}`,
},
]);

const dividerCompensationProp = createStyleFunction([
{
styleProp: 'compensateSpacing',
properties: ['marginBottom'],
getValue: (value, theme) => {
const spacing = getSpacing(value, theme);
if (Number(spacing) === 0) {
return '-1px';
} else {
return `calc(-${spacing} * 2 - 1px)`;
}
},
},
]);

/**
* Using a pseudo element to compensate for the spacing
* between items (instead of negative margin) to allow
* for the wrapper to seamlessly accept any `Box` props.
* E.g., if a negative margin-top was used instead, it would
* clash with the `mt` prop.
*/

const Wrapper = styled(Box).withConfig({
shouldForwardProp: prop => prop !== 'compensateSpacing',
})`
${p =>
p.withDividers &&
`
overflow: hidden;
`}
&::before {
content: '';
display: block;
height: 0;
${spacingCompensationProp}
${p =>
p.withDividers ? dividerCompensationProp : spacingCompensationProp}
}
`;

Expand All @@ -49,12 +73,20 @@ function getHiddenChildProps(child) {
} else return null;
}

function Stack({children, spacing, breakpoints, as, ...otherProps}) {
function Stack({
children,
spacing,
withDividers,
breakpoints,
as,
...otherProps
}) {
const [wrapperAs, itemAs] = getRoles(as);

return (
<Wrapper
{...otherProps}
withDividers={withDividers}
compensateSpacing={spacing}
as={wrapperAs}
breakpoints={breakpoints}
Expand All @@ -80,6 +112,7 @@ function Stack({children, spacing, breakpoints, as, ...otherProps}) {
pt={spacing}
breakpoints={breakpoints}
>
{withDividers && <Divider mb={spacing} />}
{hiddenChildProps ? hiddenChildProps.children : child}
</Component>
);
Expand All @@ -102,6 +135,10 @@ Stack.propTypes = {
PropTypes.number,
PropTypes.array,
]),
/**
* Add dividers between each Stack item
*/
withDividers: PropTypes.bool,
/**
* Breakpoints to use when responsive spacing values are provided
*/
Expand All @@ -120,18 +157,22 @@ Stack.propTypes = {
const StandaloneStackContext = createContext();

const StackWrapper = forwardRef(
({children, as, spacing, breakpoints, ...otherProps}, ref) => {
(
{children, as, spacing, withDividers, breakpoints, ...otherProps},
ref
) => {
const [wrapperAs, itemAs] = getRoles(as);
return (
<Wrapper
{...otherProps}
ref={ref}
as={wrapperAs}
compensateSpacing={spacing}
withDividers={withDividers}
breakpoints={breakpoints}
>
<StandaloneStackContext.Provider
value={{as: itemAs, spacing, breakpoints}}
value={{as: itemAs, spacing, breakpoints, withDividers}}
>
{children}
</StandaloneStackContext.Provider>
Expand All @@ -147,7 +188,9 @@ const StackItem = forwardRef(
{children, hiddenAbove, hiddenBelow, allowUnknownProps, ...otherProps},
ref
) => {
const {as, spacing, breakpoints} = useContext(StandaloneStackContext);
const {as, spacing, withDividers, breakpoints} = useContext(
StandaloneStackContext
);

const Component = hiddenAbove || hiddenBelow ? Hidden : Box;

Expand All @@ -161,6 +204,7 @@ const StackItem = forwardRef(
above={hiddenAbove}
breakpoints={breakpoints}
>
{withDividers && <Divider mb={spacing} />}
{children}
</Component>
);
Expand Down

0 comments on commit 9cfac3f

Please sign in to comment.