Skip to content

Commit

Permalink
PageBlock: Add new component (#1307)
Browse files Browse the repository at this point in the history
  • Loading branch information
michaeltaranto authored May 26, 2023
1 parent e5e671f commit 042b841
Show file tree
Hide file tree
Showing 13 changed files with 323 additions and 3 deletions.
19 changes: 19 additions & 0 deletions .changeset/brave-singers-knock.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
'braid-design-system': minor
---

---
new:
- PageBlock
---

**PageBlock:** Add new component

Provides a top-level page container, constraining the content width (using `ContentBlock`) while establishing common screen gutters on smaller devices.

**EXAMPLE USAGE:**
```jsx
<PageBlock width="large">
...
</PageBlock>
```
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ const docs: ComponentDocs = {
the content it wraps.
</Text>
),
alternatives: [],
alternatives: [
{ name: 'PageBlock', description: 'For page-level layout blocks' },
],
additional: [
{
label: 'Maximum width',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import React, { Fragment } from 'react';
import type { ComponentDocs } from 'site/types';
import { Placeholder } from '../private/Placeholder/Placeholder';
import { Box, PageBlock, TextLink } from '../';
import source from '../../utils/source.macro';
import { Strong } from '../Strong/Strong';
import { Text } from '../Text/Text';
import { gutters, validPageBlockComponents } from './PageBlock';

const docs: ComponentDocs = {
category: 'Layout',
migrationGuide: true,
Example: () =>
source(
<PageBlock width="medium">
<Placeholder height={100} />
</PageBlock>,
),
description: (
<Text>
Provides a top-level page container, constraining the content width (using{' '}
<TextLink href="/components/ContentBlock">ContentBlock</TextLink>) while
establishing common screen gutters on smaller devices.
</Text>
),
alternatives: [
{
name: 'ContentBlock',
description: 'For controlled width layout blocks',
},
],
additional: [
{
label: 'Maximum width',
description: (
<Text>
Use the <Strong>width</Strong> prop to adjust the maximum width of the
page container. Choose from either <Strong>medium</Strong> or{' '}
<Strong>large</Strong>.
</Text>
),
Example: () =>
source(
<PageBlock width="medium">
<Placeholder height={100} />
</PageBlock>,
),
},
{
label: 'Screen gutters',
description: (
<>
<Text>
Establishes consistent responsive gutters between the content and
the screen edge.
</Text>
<Text>
Uses <Strong>{gutters.mobile}</Strong> space on{' '}
<TextLink href="/css/breakpoints">mobile</TextLink> and the semantic{' '}
<Strong>{gutters.tablet}</Strong> on{' '}
<TextLink href="/css/breakpoints">tablet</TextLink> and above.
</Text>
</>
),
playroom: false,
code: false,
Example: () =>
source(
<Box background="formAccent">
<PageBlock width="medium">
<Box background="surface">
<Placeholder height={100} />
</Box>
</PageBlock>
</Box>,
),
},

{
label: 'Custom semantics',
description: (
<Text>
The HTML tag can be customised to ensure the underlying document
semantics are meaningful. This can be done using the{' '}
<Strong>component</Strong> prop and supports{' '}
{validPageBlockComponents.map((c, i) => {
const notLastTwo = validPageBlockComponents.length - 2;
const joiningLastElements = i === notLastTwo ? ' and ' : '.';

return (
<Fragment key={c}>
<Strong>{c}</Strong>
{c === 'div' ? ' (default)' : ''}
{i < notLastTwo ? ', ' : joiningLastElements}
</Fragment>
);
})}
</Text>
),
},
],
};

export default docs;
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react';
import type { ComponentExample } from 'site/types';
import { Placeholder } from '../private/Placeholder/Placeholder';
import { PageBlock } from '../';
import source from '../../utils/source.macro';

export const galleryItems: ComponentExample[] = [
{
label: 'Medium width',
Example: () =>
source(
<PageBlock width="medium">
<Placeholder height={100} />
</PageBlock>,
),
},
{
label: 'Large width',
Example: () =>
source(
<PageBlock width="large">
<Placeholder height={100} />
</PageBlock>,
),
},
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';
import type { ComponentScreenshot } from 'site/types';
import { Placeholder } from '../private/Placeholder/Placeholder';
import { PageBlock } from '../';

export const screenshots: ComponentScreenshot = {
screenshotWidths: [320, 1200],
examples: [
{
label: 'Default',
Example: () => (
<PageBlock>
<Placeholder height={100} />
</PageBlock>
),
},
{
label: 'Medium',
Example: () => (
<PageBlock width="medium">
<Placeholder height={100} />
</PageBlock>
),
},
{
label: 'Large',
Example: () => (
<PageBlock width="large">
<Placeholder height={100} />
</PageBlock>
),
},
],
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';
import type { Snippets } from '../private/Snippets';
import { PageBlock, Placeholder } from '../../playroom/components';
import source from '../../utils/source.macro';

export const snippets: Snippets = [
{
name: 'Medium',
code: source(
<PageBlock width="medium">
<Placeholder height={100} />
</PageBlock>,
),
},
{
name: 'Large',
code: source(
<PageBlock width="large">
<Placeholder height={100} />
</PageBlock>,
),
},
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React, { type ReactNode } from 'react';
import {
ContentBlock,
type ContentBlockProps,
} from '../ContentBlock/ContentBlock';
import { Box } from '../Box/Box';
import buildDataAttributes, {
type DataAttributeMap,
} from '../private/buildDataAttributes';

export const validPageBlockComponents = [
'div',
'article',
'aside',
'main',
'section',
'nav',
] as const;

export const gutters = { mobile: 'xsmall', tablet: 'gutter' } as const;

interface Props {
children: ReactNode;
width?: Extract<ContentBlockProps['width'], 'medium' | 'large'>;
component?: (typeof validPageBlockComponents)[number];
data?: DataAttributeMap;
}

export const PageBlock = ({
children,
width = 'large',
component: componentProp,
data,
...restProps
}: Props) => {
const component =
componentProp && validPageBlockComponents.includes(componentProp)
? componentProp
: 'div';

return (
<Box
component={component}
paddingX={gutters}
{...buildDataAttributes({ data, validateRestProps: restProps })}
>
<ContentBlock width={width}>{children}</ContentBlock>
</Box>
);
};
1 change: 1 addition & 0 deletions packages/braid-design-system/src/lib/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export { MenuItemLink } from './MenuItem/MenuItemLink';
export { OverflowMenu } from './OverflowMenu/OverflowMenu';
export { MonthPicker } from './MonthPicker/MonthPicker';
export { Notice } from './Notice/Notice';
export { PageBlock } from './PageBlock/PageBlock';
export { Pagination } from './Pagination/Pagination';
export { PasswordField } from './PasswordField/PasswordField';
export { Radio } from './Radio/Radio';
Expand Down
2 changes: 2 additions & 0 deletions packages/braid-design-system/src/lib/playroom/snippets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { snippets as Loader } from './snippets/Loader';
import { snippets as MonthPicker } from './snippets/MonthPicker';
import { snippets as Notice } from './snippets/Notice';
import { snippets as OverflowMenu } from './snippets/OverflowMenu';
import { snippets as PageBlock } from './snippets/PageBlock';
import { snippets as Pagination } from './snippets/Pagination';
import { snippets as PasswordField } from './snippets/PasswordField';
import { snippets as RadioGroup } from './snippets/RadioGroup';
Expand Down Expand Up @@ -70,6 +71,7 @@ export default Object.entries({
MonthPicker,
Notice,
OverflowMenu,
PageBlock,
Pagination,
PasswordField,
RadioGroup,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6797,6 +6797,26 @@ exports[`OverflowMenu 1`] = `
}
`;

exports[`PageBlock 1`] = `
{
exportType: component,
props: {
children: ReactNode
component?:
| "article"
| "aside"
| "div"
| "main"
| "nav"
| "section"
data?: DataAttributeMap
width?:
| "large"
| "medium"
},
}
`;

exports[`Pagination 1`] = `
{
exportType: component,
Expand Down
2 changes: 1 addition & 1 deletion site/src/App/DocNavigation/DocExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const DocExample = ({
<Container>{value}</Container>
</ThemedExample>
) : null}
{codeAsString ? (
{code !== false && codeAsString ? (
<Code collapsedByDefault={!showCodeByDefault} playroom={playroom}>
{codeAsString}
</Code>
Expand Down
39 changes: 39 additions & 0 deletions site/src/App/routes/foundations/layout/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
Hidden,
Strong,
Bleed,
PageBlock,
} from 'braid-src/lib/components';
import { TextStack } from '../../../TextStack/TextStack';
import Code from '../../../Code/Code';
Expand Down Expand Up @@ -85,6 +86,9 @@ const page: Page = {
<Text>
<TextLink href="#contentblock">ContentBlock</TextLink>
</Text>
<Text>
<TextLink href="#pageblock">PageBlock</TextLink>
</Text>
<Text>
<TextLink href="#bleed">Bleed</TextLink>
</Text>
Expand Down Expand Up @@ -773,6 +777,41 @@ const page: Page = {

<Divider />

<LinkableHeading>PageBlock</LinkableHeading>
<Text>
For top-level sections, in addition to limiting the width of content on
the screen, it is also important to standardise the gutter between
content and the edge of the screen. For this Braid provides the{' '}
<TextLink href="/components/PageBlock">PageBlock</TextLink> component,
which defines responsive gutters around a{' '}
<TextLink href="#contentblock">ContentBlock</TextLink>.
</Text>
<Code>
{source(
<PageBlock>
<Card>
<Text>Hello World</Text>
</Card>
</PageBlock>,
)}
</Code>
<Text>
To standardise our page-level block widths, the{' '}
<TextLink href="/components/PageBlock#maximum-width">width</TextLink>{' '}
prop accepts either <Strong>medium</Strong> or <Strong>large</Strong>.
</Text>
<Code>
{source(
<PageBlock width="large">
<Card>
<Text>Hello World</Text>
</Card>
</PageBlock>,
)}
</Code>

<Divider />

<LinkableHeading>Bleed</LinkableHeading>
<Text>
Sometimes it is necessary for a component to extend out into it&rsquo;s
Expand Down
Loading

0 comments on commit 042b841

Please sign in to comment.