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 + + + First + Second + + +``` + +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 - - - - Menu Item - - - + + + Heading + + Menu Item + + 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{' '} - - - - )} - > - {}}> - Item 1 - - {}}> - Item 2 - - {}}> - Item 3 - - - - - - - {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{' '} + + + + )} + > + {}}> + Item 1 + + {}}> + Item 2 + + {}}> + Item 3 + + + + {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); - }} - > - {}}> - Item 1 - - {}}> - Item 2 - - {}}> - Item 3 - - - - - - - {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); + }} + > + {}}> + Item 1 + + {}}> + Item 2 + + {}}> + Item 3 + + + + + {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 + + First + Second + + , + ), + }, + { + 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 - - - - { - /* */ - }} - > - First - - { - /* */ - }} - > - Second - - - - - 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 + + First + Second + + + , + )} + + + + 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 = [