diff --git a/.changeset/proud-moles-exist.md b/.changeset/proud-moles-exist.md
new file mode 100644
index 00000000000..e85f675e3f9
--- /dev/null
+++ b/.changeset/proud-moles-exist.md
@@ -0,0 +1,42 @@
+---
+'braid-design-system': minor
+---
+
+---
+new:
+ - Spread
+---
+
+**Spread:** Add new layout component
+
+Introduce a new layout component, `Spread`, used to justify content with both an equally distributed and a specified minimum amount of space in between each child.
+
+**EXAMPLE USAGE:**
+
+The `Spread` component works horizontally by default:
+
+```jsx
+
+ Heading
+
+
+
+
+
+
+```
+
+But can be switched to `vertical` via the `direction` prop:
+
+```jsx
+
+
+ Heading
+ Text
+
+
+
+ Date
+
+
+```
diff --git a/packages/braid-design-system/src/lib/components/Card/Card.snippets.tsx b/packages/braid-design-system/src/lib/components/Card/Card.snippets.tsx
index f3aaa4c17c9..d1e88e75f5a 100644
--- a/packages/braid-design-system/src/lib/components/Card/Card.snippets.tsx
+++ b/packages/braid-design-system/src/lib/components/Card/Card.snippets.tsx
@@ -5,8 +5,7 @@ import {
Stack,
Heading,
Text,
- Columns,
- Column,
+ Spread,
OverflowMenu,
MenuItem,
Placeholder,
@@ -18,8 +17,8 @@ export const snippets: Snippets = [
name: 'With Heading',
code: source(
-
- Heading
+
+ Heading
Text
,
@@ -29,7 +28,7 @@ export const snippets: Snippets = [
name: 'With promote tone',
code: source(
-
+
,
@@ -39,7 +38,7 @@ export const snippets: Snippets = [
name: 'With formAccent tone',
code: source(
-
+
,
@@ -49,7 +48,7 @@ export const snippets: Snippets = [
name: 'With rounded corners',
code: source(
-
+
,
@@ -59,17 +58,13 @@ export const snippets: Snippets = [
name: 'With Overflow Menu',
code: source(
-
-
-
- Heading
-
-
-
-
-
-
-
+
+
+ Heading
+
+
+
+
Text
,
diff --git a/packages/braid-design-system/src/lib/components/Columns/Columns.docs.tsx b/packages/braid-design-system/src/lib/components/Columns/Columns.docs.tsx
index aa2ede2b582..16b4d28fbfe 100644
--- a/packages/braid-design-system/src/lib/components/Columns/Columns.docs.tsx
+++ b/packages/braid-design-system/src/lib/components/Columns/Columns.docs.tsx
@@ -33,6 +33,11 @@ const docs: ComponentDocs = {
name: 'Inline',
description: 'For laying out flowing content that is allowed to wrap.',
},
+ {
+ name: 'Spread',
+ description:
+ 'For justifying content with equally distributed space in between.',
+ },
{
name: 'Tiles',
description: 'For laying out content over many columns and rows.',
diff --git a/packages/braid-design-system/src/lib/components/MenuRenderer/MenuRenderer.docs.tsx b/packages/braid-design-system/src/lib/components/MenuRenderer/MenuRenderer.docs.tsx
index 4cb72353293..8a45b76dcfc 100644
--- a/packages/braid-design-system/src/lib/components/MenuRenderer/MenuRenderer.docs.tsx
+++ b/packages/braid-design-system/src/lib/components/MenuRenderer/MenuRenderer.docs.tsx
@@ -19,8 +19,7 @@ import {
IconBookmark,
IconProfile,
MenuItemDivider,
- Column,
- Columns,
+ Spread,
Badge,
List,
} from '..';
@@ -379,71 +378,65 @@ const docs: ComponentDocs = {
{setDefaultState('closeReason', {})}
{setDefaultState('action', '')}
-
-
-
- {
- setState('action', 'open');
- setState('closeReason', {});
- }}
- onClose={(closeReason) => {
- setState('action', 'close');
- setState('closeReason', closeReason);
- }}
- trigger={(triggerProps, { open }) => (
-
-
- Menu{' '}
-
-
-
- )}
- >
-
-
-
-
-
-
-
-
- {getState('action') ? (
- {`Action: ${getState('action')}`}
- ) : null}
- {getState('closeReason').reason ? (
-
- {`Reason: ${getState('closeReason').reason}`}
-
- ) : null}
- {typeof getState('closeReason').index !== 'undefined' ? (
-
- {`Selected index: ${getState('closeReason').index}`}
-
- ) : null}
- {getState('closeReason').id ? (
-
- {`Selected ID: ${getState('closeReason').id}`}
-
- ) : null}
-
-
-
+
+ {
+ setState('action', 'open');
+ setState('closeReason', {});
+ }}
+ onClose={(closeReason) => {
+ setState('action', 'close');
+ setState('closeReason', closeReason);
+ }}
+ trigger={(triggerProps, { open }) => (
+
+
+ Menu{' '}
+
+
+
+ )}
+ >
+
+
+
+
+
+ {getState('action') ? (
+ {`Action: ${getState('action')}`}
+ ) : null}
+ {getState('closeReason').reason ? (
+
+ {`Reason: ${getState('closeReason').reason}`}
+
+ ) : null}
+ {typeof getState('closeReason').index !== 'undefined' ? (
+
+ {`Selected index: ${getState('closeReason').index}`}
+
+ ) : null}
+ {getState('closeReason').id ? (
+
+ {`Selected ID: ${getState('closeReason').id}`}
+
+ ) : null}
+
+
>,
),
},
diff --git a/packages/braid-design-system/src/lib/components/OverflowMenu/OverflowMenu.docs.tsx b/packages/braid-design-system/src/lib/components/OverflowMenu/OverflowMenu.docs.tsx
index 1e7ec65caf7..4518f9deb11 100644
--- a/packages/braid-design-system/src/lib/components/OverflowMenu/OverflowMenu.docs.tsx
+++ b/packages/braid-design-system/src/lib/components/OverflowMenu/OverflowMenu.docs.tsx
@@ -15,8 +15,7 @@ import {
Button,
IconDelete,
Badge,
- Column,
- Columns,
+ Spread,
Inline,
List,
} from '../';
@@ -138,60 +137,56 @@ const docs: ComponentDocs = {
{setDefaultState('closeReason', {})}
{setDefaultState('action', '')}
-
-
-
- {
- setState('action', 'open');
- setState('closeReason', {});
- }}
- onClose={(closeReason) => {
- setState('action', 'close');
- setState('closeReason', closeReason);
- }}
- >
-
-
-
-
-
-
-
-
- {getState('action') ? (
- {`Action: ${getState('action')}`}
- ) : null}
- {getState('closeReason').reason ? (
-
- {`Reason: ${getState('closeReason').reason}`}
-
- ) : null}
- {typeof getState('closeReason').index !== 'undefined' ? (
-
- {`Selected index: ${getState('closeReason').index}`}
-
- ) : null}
- {getState('closeReason').id ? (
-
- {`Selected ID: ${getState('closeReason').id}`}
-
- ) : null}
-
-
-
+
+
+ {
+ setState('action', 'open');
+ setState('closeReason', {});
+ }}
+ onClose={(closeReason) => {
+ setState('action', 'close');
+ setState('closeReason', closeReason);
+ }}
+ >
+
+
+
+
+
+
+ {getState('action') ? (
+ {`Action: ${getState('action')}`}
+ ) : null}
+ {getState('closeReason').reason ? (
+
+ {`Reason: ${getState('closeReason').reason}`}
+
+ ) : null}
+ {typeof getState('closeReason').index !== 'undefined' ? (
+
+ {`Selected index: ${getState('closeReason').index}`}
+
+ ) : null}
+ {getState('closeReason').id ? (
+
+ {`Selected ID: ${getState('closeReason').id}`}
+
+ ) : null}
+
+
>,
),
},
diff --git a/packages/braid-design-system/src/lib/components/Spread/Spread.css.ts b/packages/braid-design-system/src/lib/components/Spread/Spread.css.ts
new file mode 100644
index 00000000000..0c0bb728502
--- /dev/null
+++ b/packages/braid-design-system/src/lib/components/Spread/Spread.css.ts
@@ -0,0 +1,31 @@
+import {
+ defineProperties,
+ createSprinkles,
+ type RequiredConditionalValue,
+} from '@vanilla-extract/sprinkles';
+import { breakpoints } from '../../css/breakpoints';
+import { space } from '../../css/atoms/atomicProperties';
+
+const responsiveGapProperties = defineProperties({
+ defaultCondition: 'mobile',
+ conditions: {
+ mobile: {},
+ tablet: {
+ '@media': `screen and (min-width: ${breakpoints.tablet}px)`,
+ },
+ desktop: {
+ '@media': `screen and (min-width: ${breakpoints.desktop}px)`,
+ },
+ wide: {
+ '@media': `screen and (min-width: ${breakpoints.wide}px)`,
+ },
+ },
+ properties: {
+ gap: space,
+ },
+});
+
+export const responsiveGap = createSprinkles(responsiveGapProperties);
+
+export type RequiredResponsiveValue =
+ RequiredConditionalValue;
diff --git a/packages/braid-design-system/src/lib/components/Spread/Spread.docs.tsx b/packages/braid-design-system/src/lib/components/Spread/Spread.docs.tsx
new file mode 100644
index 00000000000..cbb96ca1385
--- /dev/null
+++ b/packages/braid-design-system/src/lib/components/Spread/Spread.docs.tsx
@@ -0,0 +1,129 @@
+import React from 'react';
+import type { ComponentDocs } from 'site/types';
+import { Spread, Stack, Strong, Text, Tiles } from '../';
+import { Placeholder } from '../private/Placeholder/Placeholder';
+import source from '@braid-design-system/source.macro';
+
+const docs: ComponentDocs = {
+ category: 'Layout',
+ Example: () =>
+ source(
+
+
+
+ ,
+ ),
+ description: (
+
+ Spread is a layout component used to justify content with
+ both an equally distributed and a specified minimum amount of space in
+ between each child.
+
+ ),
+ alternatives: [
+ {
+ name: 'Columns',
+ description: 'For fine-grained control of widths, spacing and alignment.',
+ },
+ {
+ name: 'Inline',
+ description: 'For laying out flowing content that is allowed to wrap.',
+ },
+ ],
+ additional: [
+ {
+ label: 'Direction',
+ description: (
+
+ By default, children are spread horizontally. Setting the{' '}
+ direction prop to vertical will
+ spread children vertically, consuming the full height of its
+ container.
+
+ ),
+ Example: () =>
+ source(
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ,
+ ),
+ },
+ {
+ label: 'Vertical alignment',
+ description: (
+ <>
+
+ When spreading content of varying height, vertical alignment can be
+ controlled using the alignY prop. Responsive values
+ are supported.
+
+
+ Note: Only applies when spreading horizontally.
+
+ >
+ ),
+ Example: () =>
+ source(
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ,
+ ),
+ },
+ {
+ label: 'Horizontal alignment',
+ description: (
+ <>
+
+ When spreading content of varying widths, horizontal alignment can
+ be controlled using the align prop. Responsive
+ values are supported.
+
+
+ Note: Only applies when spreading vertically.
+
+ >
+ ),
+ Example: () =>
+ source(
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ,
+ ),
+ },
+ ],
+};
+
+export default docs;
diff --git a/packages/braid-design-system/src/lib/components/Spread/Spread.gallery.tsx b/packages/braid-design-system/src/lib/components/Spread/Spread.gallery.tsx
new file mode 100644
index 00000000000..3d8b5cf8530
--- /dev/null
+++ b/packages/braid-design-system/src/lib/components/Spread/Spread.gallery.tsx
@@ -0,0 +1,80 @@
+import React from 'react';
+import type { GalleryComponent } from 'site/types';
+import { Spread, Stack, Tiles } from '../';
+import source from '@braid-design-system/source.macro';
+import { Placeholder } from '../private/Placeholder/Placeholder';
+
+export const galleryItems: GalleryComponent = {
+ examples: [
+ {
+ label: 'Horizontal direction',
+ Example: () =>
+ source(
+
+
+
+ ,
+ ),
+ },
+ {
+ label: 'Vertical direction',
+ Example: () =>
+ source(
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ,
+ ),
+ },
+ {
+ label: 'Vertical alignment',
+ Example: () =>
+ source(
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ,
+ ),
+ },
+ {
+ label: 'Horizontal alignment',
+ Example: () =>
+ source(
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ,
+ ),
+ },
+ ],
+};
diff --git a/packages/braid-design-system/src/lib/components/Spread/Spread.playroom.tsx b/packages/braid-design-system/src/lib/components/Spread/Spread.playroom.tsx
new file mode 100644
index 00000000000..5e38b6dc64a
--- /dev/null
+++ b/packages/braid-design-system/src/lib/components/Spread/Spread.playroom.tsx
@@ -0,0 +1,11 @@
+import React from 'react';
+import { type SpreadProps, Spread as BraidSpread } from './Spread';
+import { cleanSpaceValue } from '../../playroom/cleanSpaceValue';
+import type { RequiredResponsiveValue } from './Spread.css';
+import type { Space } from '../../css/atoms/atoms';
+
+export const Spread = ({ space, ...restProps }: SpreadProps) => {
+ /* Temporary cast to satisfy `cleanSpaceValue`. Wont be required when `gap` moves to core atoms */
+ const cleanSpace = cleanSpaceValue(space) as RequiredResponsiveValue;
+ return ;
+};
diff --git a/packages/braid-design-system/src/lib/components/Spread/Spread.screenshots.tsx b/packages/braid-design-system/src/lib/components/Spread/Spread.screenshots.tsx
new file mode 100644
index 00000000000..32476ca63d5
--- /dev/null
+++ b/packages/braid-design-system/src/lib/components/Spread/Spread.screenshots.tsx
@@ -0,0 +1,179 @@
+import React from 'react';
+import type { ComponentScreenshot } from 'site/types';
+import { Spread, Tiles } from '../';
+import { Placeholder } from '../private/Placeholder/Placeholder';
+
+export const screenshots: ComponentScreenshot = {
+ screenshotWidths: [320, 768, 992, 1200],
+ screenshotOnlyInWireframe: true,
+ examples: [
+ {
+ label: 'Horizontal',
+ Example: () => (
+
+
+
+
+ ),
+ },
+ {
+ label: 'Horizontal single full width',
+ Example: () => (
+
+
+
+
+ ),
+ },
+ {
+ label: 'Horizontal both full width',
+ Example: () => (
+
+
+
+
+ ),
+ },
+ {
+ label: 'Horizontal single child full width',
+ Example: () => (
+
+
+
+ ),
+ },
+ {
+ label: 'Horizontal responsive space',
+ Example: () => (
+
+
+
+
+ ),
+ },
+ {
+ label: 'Horizontal alignY top',
+ Example: () => (
+
+
+
+
+ ),
+ },
+ {
+ label: 'Horizontal alignY center',
+ Example: () => (
+
+
+
+
+ ),
+ },
+ {
+ label: 'Horizontal alignY bottom',
+ Example: () => (
+
+
+
+
+ ),
+ },
+ {
+ label: 'Horizontal align center (no impact)',
+ Example: () => (
+
+
+
+
+ ),
+ },
+ {
+ label: 'Vertical',
+ Example: () => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ),
+ },
+ {
+ label: 'Vertical single full width',
+ Example: () => (
+
+
+
+
+ ),
+ },
+ {
+ label: 'Vertical responsive space',
+ Example: () => (
+
+
+
+
+ ),
+ },
+ {
+ label: 'Vertical align left',
+ Example: () => (
+
+
+
+
+ ),
+ },
+ {
+ label: 'Vertical align center',
+ Example: () => (
+
+
+
+
+ ),
+ },
+ {
+ label: 'Vertical align right',
+ Example: () => (
+
+
+
+
+ ),
+ },
+ {
+ label: 'Vertical alignY center (no impact)',
+ Example: () => (
+
+
+
+
+ ),
+ },
+ ],
+};
diff --git a/packages/braid-design-system/src/lib/components/Spread/Spread.snippets.tsx b/packages/braid-design-system/src/lib/components/Spread/Spread.snippets.tsx
new file mode 100644
index 00000000000..063e6d0569f
--- /dev/null
+++ b/packages/braid-design-system/src/lib/components/Spread/Spread.snippets.tsx
@@ -0,0 +1,59 @@
+import React from 'react';
+import type { Snippets } from '../private/Snippets';
+import {
+ Heading,
+ MenuItem,
+ OverflowMenu,
+ Placeholder,
+ Spread,
+ Stack,
+ Text,
+} from '../../playroom/components';
+import source from '@braid-design-system/source.macro';
+
+export const snippets: Snippets = [
+ {
+ name: 'Horizontal direction',
+ code: source(
+
+
+
+ ,
+ ),
+ },
+ {
+ name: 'Vertical direction',
+ code: source(
+
+
+
+ ,
+ ),
+ },
+ {
+ name: 'Heading and action',
+ code: source(
+
+ Heading
+
+
+
+
+ ,
+ ),
+ },
+ {
+ name: 'Content stack and date stamp',
+ code: source(
+
+
+ Heading
+ Text
+
+
+ Date
+
+ ,
+ ),
+ },
+];
diff --git a/packages/braid-design-system/src/lib/components/Spread/Spread.tsx b/packages/braid-design-system/src/lib/components/Spread/Spread.tsx
new file mode 100644
index 00000000000..f14ba68dff8
--- /dev/null
+++ b/packages/braid-design-system/src/lib/components/Spread/Spread.tsx
@@ -0,0 +1,51 @@
+import type { Space } from '../../css/atoms/atoms';
+import { Box, type BoxProps } from '../Box/Box';
+import type { ReactNodeNoStrings } from '../private/ReactNodeNoStrings';
+import type { OptionalResponsiveValue } from '../../css/atoms/sprinkles.css';
+import {
+ alignYToFlexAlign,
+ type AlignY,
+ type Align,
+ alignToFlexAlign,
+} from '../../utils/align';
+import { type RequiredResponsiveValue, responsiveGap } from './Spread.css';
+
+export interface SpreadProps {
+ children: ReactNodeNoStrings;
+ space: RequiredResponsiveValue;
+ direction?: 'horizontal' | 'vertical';
+ align?: OptionalResponsiveValue;
+ alignY?: OptionalResponsiveValue;
+}
+
+export const Spread = ({
+ children,
+ space,
+ direction = 'horizontal',
+ align,
+ alignY,
+}: SpreadProps) => {
+ const isVertical = direction === 'vertical';
+ const isHorizontal = !isVertical;
+ let alignItems: BoxProps['alignItems'];
+
+ if (align && isVertical) {
+ alignItems = alignToFlexAlign(align);
+ } else if (alignY && isHorizontal) {
+ alignItems = alignYToFlexAlign(alignY);
+ }
+
+ return (
+
+ {children}
+
+ );
+};
diff --git a/packages/braid-design-system/src/lib/components/index.ts b/packages/braid-design-system/src/lib/components/index.ts
index a37bd22d9b2..5a4ec85fc49 100644
--- a/packages/braid-design-system/src/lib/components/index.ts
+++ b/packages/braid-design-system/src/lib/components/index.ts
@@ -65,6 +65,7 @@ export { RadioGroup } from './RadioGroup/RadioGroup';
export { RadioItem } from './RadioGroup/RadioItem';
export { Rating } from './Rating/Rating';
export { Secondary } from './Secondary/Secondary';
+export { Spread } from './Spread/Spread';
export { Stack } from './Stack/Stack';
export { Step } from './Stepper/Step';
export { Stepper } from './Stepper/Stepper';
diff --git a/packages/braid-design-system/src/lib/playroom/components.ts b/packages/braid-design-system/src/lib/playroom/components.ts
index 6090f24cfa5..acb43b6dd41 100644
--- a/packages/braid-design-system/src/lib/playroom/components.ts
+++ b/packages/braid-design-system/src/lib/playroom/components.ts
@@ -35,6 +35,7 @@ export { PasswordField } from '../components/PasswordField/PasswordField.playroo
export { Radio } from '../components/Radio/Radio.playroom';
export { RadioGroup } from '../components/RadioGroup/RadioGroup.playroom';
export { Rating } from '../components/Rating/Rating.playroom';
+export { Spread } from '../components/Spread/Spread.playroom';
export { Stack } from '../components/Stack/Stack.playroom';
export { TabsProvider, Tabs, Tab } from '../components/Tabs/Tabs.playroom';
export { Tag } from '../components/Tag/Tag.playroom';
diff --git a/packages/braid-design-system/src/lib/playroom/snippets.ts b/packages/braid-design-system/src/lib/playroom/snippets.ts
index 86267feb933..c1a4012c071 100644
--- a/packages/braid-design-system/src/lib/playroom/snippets.ts
+++ b/packages/braid-design-system/src/lib/playroom/snippets.ts
@@ -31,6 +31,7 @@ import { snippets as PasswordField } from './snippets/PasswordField';
import { snippets as RadioGroup } from './snippets/RadioGroup';
import { snippets as Rating } from './snippets/Rating';
import { snippets as Secondary } from './snippets/Secondary';
+import { snippets as Spread } from './snippets/Spread';
import { snippets as Stack } from './snippets/Stack';
import { snippets as Stepper } from './snippets/Stepper';
import { snippets as Strong } from './snippets/Strong';
@@ -79,6 +80,7 @@ export default Object.entries({
RadioGroup,
Rating,
Secondary,
+ Spread,
Stack,
Stepper,
Strong,
diff --git a/packages/generate-component-docs/src/__snapshots__/contract.test.ts.snap b/packages/generate-component-docs/src/__snapshots__/contract.test.ts.snap
index db512efeab1..1c1a4f05a04 100644
--- a/packages/generate-component-docs/src/__snapshots__/contract.test.ts.snap
+++ b/packages/generate-component-docs/src/__snapshots__/contract.test.ts.snap
@@ -7485,6 +7485,42 @@ exports[`Secondary 1`] = `
}
`;
+exports[`Spread 1`] = `
+{
+ exportType: component,
+ props: {
+ align?:
+ | "center"
+ | "left"
+ | "right"
+ | Partial>
+ | ResponsiveArray<1 | 2 | 3 | 4, Align | null>
+ alignY?:
+ | "bottom"
+ | "center"
+ | "top"
+ | Partial>
+ | ResponsiveArray<1 | 2 | 3 | 4, AlignY | null>
+ children: ReactNodeNoStrings
+ direction?:
+ | "horizontal"
+ | "vertical"
+ space:
+ | "gutter"
+ | "large"
+ | "medium"
+ | "none"
+ | "small"
+ | "xlarge"
+ | "xsmall"
+ | "xxlarge"
+ | "xxsmall"
+ | "xxxlarge"
+ | RequiredConditionalObject<"mobile", "tablet" | "desktop" | "wide", Space>
+},
+}
+`;
+
exports[`Stack 1`] = `
{
exportType: component,
diff --git a/site/src/App/DocNavigation/DocReleases.tsx b/site/src/App/DocNavigation/DocReleases.tsx
index ceb4e739ba4..7a0616f0c47 100644
--- a/site/src/App/DocNavigation/DocReleases.tsx
+++ b/site/src/App/DocNavigation/DocReleases.tsx
@@ -6,8 +6,7 @@ import {
Badge,
TextLink,
Text,
- Column,
- Columns,
+ Spread,
List,
} from 'braid-src/lib/components';
import { LinkableHeading } from '@braid-design-system/docs-ui';
@@ -59,21 +58,17 @@ export const DocReleases = () => {
paddingTop={index > 0 ? 'medium' : undefined}
>
-
-
- {`v${version}`}
-
+
+ {`v${version}`}
{historyItem.time ? (
-
-
- {historyItem.time}
-
-
+
+ {historyItem.time}
+
) : null}
-
+
{historyItem.changesets.map((change, changeIndex) => (
diff --git a/site/src/App/routes/examples/job-summary/job-summary.tsx b/site/src/App/routes/examples/job-summary/job-summary.tsx
index a7025af90aa..82cbfe2b7d7 100644
--- a/site/src/App/routes/examples/job-summary/job-summary.tsx
+++ b/site/src/App/routes/examples/job-summary/job-summary.tsx
@@ -6,8 +6,6 @@ import {
Divider,
Card,
Stack,
- Columns,
- Column,
Badge,
IconTag,
Rating,
@@ -18,6 +16,7 @@ import {
TextLink,
List,
ButtonIcon,
+ Spread,
} from 'braid-src/lib/components';
import { TextStack } from '../../../TextStack/TextStack';
import { Placeholder } from 'braid-src/lib/playroom/components';
@@ -55,51 +54,47 @@ const page: Page = {
-
-
-
-
- New
- Product Designer
-
- Braid Design Pty Ltd
-
-
-
-
-
- }
- label="Save job"
- id="save-preview"
- />
-
-
+
+
+
+ New
+ Product Designer
+
+ Braid Design Pty Ltd
+
+
+
+ }
+ label="Save job"
+ id="save-preview"
+ />
+
- }>
+ }>
Melbourne
- }>
+ }>
Information Technology
- }>
+ }>
150k+
Long description of card details providing more information.
-
+
2d ago
- How do I build this example for myself?
+ How do I build this example for myself?
Designs like this are rarely built top-to-bottom in a single pass.
@@ -135,7 +130,7 @@ const page: Page = {
}
>
- Product Designer
+ Product Designer
Braid Design Pty Ltd
Melbourne
Information Technology
@@ -161,8 +156,8 @@ const page: Page = {
}
>
-
- Product Designer
+
+ Product Designer
Braid Design Pty Ltd
Melbourne
Information Technology
@@ -190,9 +185,9 @@ const page: Page = {
}
>
-
+
- Product Designer
+ Product Designer
Braid Design Pty Ltd
@@ -225,29 +220,23 @@ const page: Page = {
}
>
-
+
- Product Designer
- Braid Design Pty Ltd
+ Product Designer
+ Braid Design Pty Ltd
-
- Melbourne
-
-
- Information Technology
-
-
- 150k+
-
+ Melbourne
+ Information Technology
+ 150k+
Long description of card details providing more information.
-
+
2d ago
@@ -266,20 +255,20 @@ const page: Page = {
}
>
-
+
- Product Designer
- Braid Design Pty Ltd
+ Product Designer
+ Braid Design Pty Ltd
-
- }>
+
+ }>
Melbourne
- }>
+ }>
Information Technology
- }>
+ }>
150k+
@@ -288,7 +277,7 @@ const page: Page = {
Long description of card details providing more information.
-
+
2d ago
@@ -307,21 +296,21 @@ const page: Page = {
}
>
-
+
New
- Product Designer
- Braid Design Pty Ltd
+ Product Designer
+ Braid Design Pty Ltd
-
- }>
+
+ }>
Melbourne
- }>
+ }>
Information Technology
- }>
+ }>
150k+
@@ -330,7 +319,7 @@ const page: Page = {
Long description of card details providing more information.
-
+
2d ago
@@ -356,24 +345,24 @@ const page: Page = {
}
>
-
+
New
- Product Designer
-
- Braid Design Pty Ltd
+ Product Designer
+
+ Braid Design Pty Ltd
-
- }>
+
+ }>
Melbourne
- }>
+ }>
Information Technology
- }>
+ }>
150k+
@@ -382,7 +371,7 @@ const page: Page = {
Long description of card details providing more information.
-
+
2d ago
@@ -396,8 +385,8 @@ const page: Page = {
Sometimes adding new features can necessitate changing the
layout. First, we’ll use a{' '}
- Columns{' '}
- component to break up our card into two columns.
+ Spread component
+ to separate our content and action.
NOTE: To make this easier to follow, we’ve replaced the
@@ -407,170 +396,101 @@ const page: Page = {
}
>
-
-
-
-
-
-
-
-
+
+
+
+
- In the second column we’ll use a{' '}
+ For the save action we’ll use a{' '}
ButtonIcon with
an{' '}
- IconBookmark{' '}
- as the save action. By default, `Columns` are of equal width. In
- this design however, the second column should only be as wide as
- the save action itself. This can be controlled by setting the
- `Column` to have a “width” of “content”.
+ IconBookmark.
+ We can now replace our “Save action” Placeholder with
+ the ButtonIcon.
}
>
-
-
-
-
-
- }
- label="Save job"
- id="save-7a"
- />
-
-
+
+
+ }
+ label="Save job"
+ id="save-7a"
+ />
+
- Now that we’ve adjusted the layout, let’s reinstate
- our job content in the main column.
+ Now that we’ve added the action, let’s reinstate our
+ content by replacing the “Job content” Placeholder.
}
>
-
-
-
-
- New
- Product Designer
-
- Braid Design Pty Ltd
-
-
-
-
-
- }>
- Melbourne
-
- }>
- Information Technology
-
- }>
- 150k+
-
-
-
-
- Long description of card details providing more information.
-
+
+
+
+ New
+ Product Designer
+
+ Braid Design Pty Ltd
+
+
+
-
- 2d ago
+
+ }>
+ Melbourne
+
+ }>
+ Information Technology
+
+ }>
+ 150k+
-
-
- }
- label="Save job"
- id="save-7b"
- />
-
-
-
-
-
-
- Now that we have all our elements in place we can polish until
- we are happy. Adjusting white space between elements, or even
- responsively, to achieve the desired goal.
-
-
- In this case, we might loosen up the metadata section by
- increasing the space to “small”.
-
-
- }
- >
-
-
-
-
-
- New
- Product Designer
-
- Braid Design Pty Ltd
-
-
-
-
-
- }
- label="Save job"
- id="save-8"
- />
-
-
-
-
- }>
- Melbourne
-
- }>
- Information Technology
+
+ Long description of card details providing more information.
- }>
- 150k+
+
+
+ 2d ago
-
- Long description of card details providing more information.
-
-
- 2d ago
-
-
+ }
+ label="Save job"
+ id="save-7b"
+ />
+
+
+
+ Now that we have all our elements in place we can polish until we are
+ happy. Adjusting white space between elements, or even responsively,
+ to achieve the desired goal.
+
- Next steps
+ Next steps
diff --git a/site/src/App/routes/foundations/layout/layout.tsx b/site/src/App/routes/foundations/layout/layout.tsx
index 88df00e38b4..a4fc7b90e30 100644
--- a/site/src/App/routes/foundations/layout/layout.tsx
+++ b/site/src/App/routes/foundations/layout/layout.tsx
@@ -23,6 +23,7 @@ import {
Bleed,
PageBlock,
Page,
+ Spread,
} from 'braid-src/lib/components';
import { TextStack } from '../../../TextStack/TextStack';
import Code from '../../../Code/Code';
@@ -116,6 +117,9 @@ const page: DocsPage = {
Columns
+
+ Spread
+
Tiles
@@ -540,40 +544,30 @@ const page: DocsPage = {
as the content within it.
- For example, if you wanted a card with a left-aligned{' '}
- Heading and a
- right-aligned{' '}
- OverflowMenu:
+ For example, if you wanted a column to be as large as its illustration
+ followed by a second column that filled the space:
{source(
-
-
-
- Card heading
-
-
-
-
-
-
-
-
- Card content
-
+
+
+
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ Suspendisse dignissim dapibus elit, vel egestas felis pharetra
+ non. Cras malesuada, massa nec ultricies efficitur, lectus
+ ante consequat magna, a porttitor massa ex ut quam.
+
+
+
,
)}
@@ -645,6 +639,75 @@ const page: DocsPage = {
+ Spread
+
+ If you’d like to spread components to opposite ends of a container while
+ maintaining a minimum amount of space in between them, Braid provides
+ the Spread component.
+
+
+
+ An example might be a card with a left-aligned{' '}
+ Heading and a
+ right-aligned{' '}
+ OverflowMenu:
+
+
+
+ {source(
+
+
+ Heading
+
+
+
+
+
+ ,
+ )}
+
+
+
+ By default, components will be spread horizontally but you can change
+ the direction to vertical by providing the{' '}
+ direction prop.
+
+
+
+ This is useful when aligning content vertically across containers while
+ maintaining predicatable spacing — particularly when wrapping text comes
+ into play.
+
+
+
+ {source(
+
+
+
+
+ Minim aliqua nulla id excepteur labore amet do dolore.
+
+ Duis
+
+
+
+
+ Minim aliqua nulla id.
+ Duis
+
+
+
+
+ Minim aliqua nulla id excepteur labore.
+ Duis
+
+
+ ,
+ )}
+
+
+
+
Tiles
If you’d like to render a grid of components with equal spacing between
diff --git a/site/src/App/routes/gallery/Gallery.tsx b/site/src/App/routes/gallery/Gallery.tsx
index 5a4a1242efd..bee903a30b6 100644
--- a/site/src/App/routes/gallery/Gallery.tsx
+++ b/site/src/App/routes/gallery/Gallery.tsx
@@ -40,6 +40,7 @@ import {
Secondary,
IconCopy,
ButtonIcon,
+ Spread,
} from 'braid-src/lib/components';
// TODO: COLORMODE RELEASE
// Use public import
@@ -158,26 +159,22 @@ const RenderExample = ({ id, example, isIcon }: RenderExampleProps) => {
const { code, value } = useSourceFromExample(id, example);
const CopyCodeButton = () => (
-
-
- {label ? (
-
- {label}
-
- ) : null}
-
+
+ {label ? (
+
+ {label}
+
+ ) : null}
{code ? (
-
- copy(formatSnippet(code))}
- successLabel="Copied!"
- >
- Copy code
-
-
+ copy(formatSnippet(code))}
+ successLabel="Copied!"
+ >
+ Copy code
+
) : null}
-
+
);
const children = [