Skip to content
Open
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
6 changes: 6 additions & 0 deletions .changeset/wise-pans-vanish.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@bigcommerce/big-design': minor
'@bigcommerce/docs': minor
---

Enhanced Panel component with extra features like Lozenge, Dropdown action and a new PanelContents component
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

exports[`it renders accordion panel header 1`] = `
<h2
class="styled__StyledH2-sc-218b28a9-2 styled__StyledH2-sc-93a30afd-1 hCxYWp jbcAKv"
class="styled__StyledH2-sc-218b28a9-2 styled__StyledH2-sc-eda6cb79-1 hCxYWp cMjtfK"
>
Accordion Panel Header
</h2>
Expand Down
22 changes: 22 additions & 0 deletions packages/big-design/src/components/Panel/Contents/Contents.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React, { memo, ReactNode } from 'react';

import { BoxProps } from '../../Box';

import { StyledPanelContents, StyledPanelContentsWrapper } from './styled';

export interface PanelContentProps extends BoxProps {
children?: ReactNode;
padded?: boolean;
height?: string;
scrollable?: boolean;
Comment on lines +10 to +11
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would we ever want to support a scenario where the height is fixed, but scrolling is disabled?

would this just result in content being abruptly cropped and unreachable?

}

export const PanelContents: React.FC<PanelContentProps> = memo(({ children, ...props }) => {
return (
<StyledPanelContentsWrapper {...props}>
<StyledPanelContents {...props}>{children}</StyledPanelContents>
</StyledPanelContentsWrapper>
);
});

PanelContents.displayName = 'PanelContents';
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`PanelContents renders StyledPanelContents with correct props 1`] = `
<div
class="styled__StyledBox-sc-12d4dbf-0 imudcb styled__StyledPanelContents-sc-dd60c8b6-1 fnisvI"
height="auto"
>
Test string
</div>
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { PanelContents, type PanelContentProps } from './Contents';
53 changes: 53 additions & 0 deletions packages/big-design/src/components/Panel/Contents/spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { theme } from '@bigcommerce/big-design-theme';
import { render } from '@testing-library/react';
import React from 'react';

import { PanelContents } from './Contents';

describe('PanelContents', () => {
it('renders children correctly', () => {
const { getByText } = render(
<PanelContents>
<div>Test Content</div>
</PanelContents>,
);

expect(getByText('Test Content')).toBeInTheDocument();
});

it('applies default props to StyledPanelContentsWrapper', () => {
const { container } = render(<PanelContents />);
const wrapper = container.firstChild;

expect(wrapper).toHaveStyle('height: auto');
});

it('applies the `padded` prop correctly', () => {
const { container } = render(<PanelContents padded={false} />);
const wrapper = container.firstChild;

expect(wrapper).toHaveStyle(`margin-inline: -${theme.spacing.medium}`);
});

it('applies the `height` prop correctly', () => {
const { container } = render(<PanelContents height="200px">Test string</PanelContents>);
const wrapper = container.firstChild;

expect(wrapper).toHaveStyle('height: 200px');
});

it('applies the `scrollable` prop correctly', () => {
const { container } = render(<PanelContents scrollable>Test string</PanelContents>);
const wrapper = container.firstChild;

expect(wrapper).toHaveStyle('overflow: auto');
});

it('renders StyledPanelContents with correct props', () => {
const { getByText } = render(<PanelContents scrollable>Test string</PanelContents>);
const contents = getByText('Test string');

expect(contents).toBeInTheDocument();
expect(contents).toMatchSnapshot();
});
});
66 changes: 66 additions & 0 deletions packages/big-design/src/components/Panel/Contents/styled.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { theme as defaultTheme } from '@bigcommerce/big-design-theme';
import styled, { css } from 'styled-components';

import { Box } from '../../Box';

import { PanelContentProps } from './Contents';

export const StyledPanelContentsWrapper = styled(Box)<Omit<PanelContentProps, 'children'>>`
${({ theme, scrollable }) =>
scrollable &&
css`
background-image: linear-gradient(
0deg,
${theme.colors.secondary40} 0%,
transparent 1px,
transparent 100%
),
linear-gradient(180deg, ${theme.colors.secondary40} 0%, transparent 1px, transparent 100%);
overflow: auto;
`}
${({ height }) =>
height &&
css`
height: ${height};
`}
${({ theme, padded }) =>
padded !== true &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we normally just do negative boolean checks like !padded

css`
margin-inline: -${theme.spacing.medium};
`}
${({ theme }) => theme.breakpoints.tablet} {
${({ theme, padded }) =>
padded !== true &&
css`
margin-inline: -${theme.spacing.xLarge};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these minus margins are a bit awkward

both the technique, plus they're trying to undo the Panel's padding, without referencing the Panel's padding value
so the values could get out of sync

I'm also guessing that we wouldn't want PanelContents ever being used outside of a Panel
So I'm wondering why not hide it as an implementation detail, rather than expose it as its own component

e.g.

<Panel
  header="Panel header"
  fullWidthContents
>
  <Text>
    Hello there
  </Text>
</Panel>

or with a contents namespace to absorb the other new settings (scroll behaviour etc)

<Panel
  header="Panel header"
  contents={{ fullWidth: true }}
>
  <Text>
    Hello there
  </Text>
</Panel>

`}
}
`;
StyledPanelContentsWrapper.defaultProps = {
theme: defaultTheme,
padded: true,
scrollable: false,
height: 'auto',
};

export const StyledPanelContents = styled(Box)<Omit<PanelContentProps, 'children'>>`
min-height: 100%;
${({ theme, scrollable }) =>
scrollable &&
css`
border-block-start: ${theme.border.box};
border-block-end: ${theme.border.box};
border-block-start-color: ${theme.colors.white};
border-block-end-color: ${theme.colors.white};
`}
`;
StyledPanelContents.defaultProps = {
theme: defaultTheme,
padded: true,
scrollable: false,
height: 'auto',
};
57 changes: 48 additions & 9 deletions packages/big-design/src/components/Panel/Panel.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import React, { ComponentPropsWithoutRef, forwardRef, isValidElement, memo, Ref } from 'react';

import { MarginProps } from '../../helpers';
import { excludeMarginProps, MarginProps } from '../../helpers';
import { excludePaddingProps } from '../../helpers/paddings/paddings';
import { warning } from '../../utils';
import { Badge, BadgeProps } from '../Badge/Badge';
import { Box } from '../Box';
import { Button, ButtonProps } from '../Button';
import { Dropdown, DropdownProps } from '../Dropdown';
import { Flex } from '../Flex';
import { Lozenge, LozengeProps } from '../Lozenge';
import { Text } from '../Typography';

import { StyledH2, StyledPanel } from './styled';
Expand All @@ -15,22 +17,56 @@ interface PrivateProps {
forwardedRef: Ref<HTMLDivElement>;
}

export interface PanelAction extends Omit<ButtonProps, 'children'> {
export interface PanelActionProps extends Omit<ButtonProps, 'children' | 'mobileWidth'> {
text?: string;
}

export interface PanelDropdownProps extends Omit<DropdownProps, 'toggle'> {
toggle: PanelActionProps;
}
Comment on lines +24 to +26
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not just stick to DropdownProps entirely? What benefit are we looking for by overwriting the concept of the toggle?


export type PanelAction = PanelActionProps | PanelDropdownProps;

export interface PanelProps extends ComponentPropsWithoutRef<'div'>, MarginProps {
children?: React.ReactNode;
description?: React.ReactNode;
header?: string;
headerId?: string;
action?: PanelAction;
badge?: BadgeProps;
lozenge?: LozengeProps;
}

const Action = (action: PanelAction) => {
if ('toggle' in action) {
const { toggle, ...dropdownProps } = action;
const { text, ...buttonProps } = toggle;

return (
<Dropdown
{...dropdownProps}
toggle={
<Button {...excludeMarginProps(buttonProps)} mobileWidth="auto">
{text}
</Button>
}
/>
);
}

const { text, ...buttonProps } = action;

return (
<Button {...excludeMarginProps(buttonProps)} mobileWidth="auto">
{text}
</Button>
);
};

export const RawPanel: React.FC<PanelProps & PrivateProps> = memo(({ forwardedRef, ...props }) => {
const filteredProps = excludePaddingProps(props);
const { action, children, description, header, headerId, badge, ...rest } = filteredProps;
const { action, children, description, header, headerId, badge, lozenge, ...rest } =
filteredProps;

const renderHeader = () => {
if (!header && !action) {
Expand All @@ -42,14 +78,17 @@ export const RawPanel: React.FC<PanelProps & PrivateProps> = memo(({ forwardedRe
}

return (
<Flex flexDirection="row">
<Flex alignItems="center" flexDirection="row" flexGap="0.5rem" justifyContent="space-between">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

anything we can do with these 0.5rem magic numbers?

{Boolean(header) && (
<StyledH2 id={headerId} marginBottom="none">
{header}
{badge && <Badge marginLeft="xSmall" {...badge} />}
</StyledH2>
<Flex alignItems="center" flexDirection="row" flexGap="0.5rem">
<StyledH2 id={headerId} marginBottom="none">
{header}
</StyledH2>
{lozenge && <Lozenge {...lozenge} />}
{badge && <Badge {...badge} />}
</Flex>
)}
{action && <Button {...action}>{action.text}</Button>}
{action && <Action {...action} />}
</Flex>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ exports[`render panel 1`] = `
`;

exports[`render panel with only a heading and no content 1`] = `
.c4 {
.c5 {
color: #313440;
margin: 0 0 1rem;
font-size: 1.5rem;
Expand All @@ -73,13 +73,39 @@ exports[`render panel with only a heading and no content 1`] = `
-webkit-align-content: stretch;
-ms-flex-line-pack: stretch;
align-content: stretch;
-webkit-align-items: stretch;
-webkit-box-align: stretch;
-ms-flex-align: stretch;
align-items: stretch;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
gap: 0.5rem;
-webkit-flex-wrap: nowrap;
-ms-flex-wrap: nowrap;
flex-wrap: nowrap;
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
-ms-flex-pack: justify;
justify-content: space-between;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}

.c4 {
-webkit-align-content: stretch;
-ms-flex-line-pack: stretch;
align-content: stretch;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
gap: 0.5rem;
-webkit-flex-wrap: nowrap;
-ms-flex-wrap: nowrap;
flex-wrap: nowrap;
Expand All @@ -97,14 +123,17 @@ exports[`render panel with only a heading and no content 1`] = `
border-radius: 0;
}

.c5 {
.c6 {
-webkit-box-flex: 1;
-webkit-flex-grow: 1;
-ms-flex-positive: 1;
flex-grow: 1;
-webkit-flex-shrink: 1;
-ms-flex-negative: 1;
flex-shrink: 1;
}

.c5 ~ .bd-button {
.c6 ~ .bd-button {
width: auto;
margin-top: 0;
}
Expand Down Expand Up @@ -133,11 +162,15 @@ exports[`render panel with only a heading and no content 1`] = `
<div
class="c2 c3"
>
<h2
class="c4 c5"
<div
class="c2 c4"
>
Test Header
</h2>
<h2
class="c5 c6"
>
Test Header
</h2>
</div>
</div>
</div>
`;
1 change: 1 addition & 0 deletions packages/big-design/src/components/Panel/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { Panel, type PanelProps } from './Panel';
export { PanelContents, type PanelContentProps } from './Contents';
Loading