Skip to content

Commit d8b4d5e

Browse files
River component updates (#1231)
1 parent e4e935c commit d8b4d5e

File tree

108 files changed

+1979
-106
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

108 files changed

+1979
-106
lines changed

.changeset/wide-seed-sky.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
---
2+
'@primer/react-brand': minor
3+
'@primer/brand-primitives': minor
4+
---
5+
6+
Updates to `River` component
7+
8+
#### New Features
9+
10+
- **New `River` prop**: `variant`. This prop controls the layout and appearance of the River component. Two variants are available: `default` and `gridline`.
11+
12+
The `default` variant is the pre-existing `River` configuration and remains the default value.
13+
14+
The `gridline` variant adds lateral padding and borders for use within bordered grid layouts.
15+
16+
```jsx
17+
<River variant="gridline" />
18+
```
19+
20+
- **New `River.Visual` prop**: `imageBackgroundColor`. Set to `'subtle'` to create a full-bleed container with a background color and the image/video centered inside with padding.
21+
22+
```jsx
23+
<River variant="gridline">
24+
<River.Visual imageBackgroundColor="subtle">
25+
<img src="..." alt="..." />
26+
</River.Visual>
27+
<River.Content>...</River.Content>
28+
</River>
29+
```
30+
31+
- **New `River.Content` prop**: `align`. Controls vertical alignment of content within its container. Values: `'center'` (default), `'block-end'`.
32+
33+
- **`EyebrowText` support**: `River.Content` now accepts `EyebrowText` as a child for adding small, uppercase labels above the heading.
34+
35+
```jsx
36+
<River.Content>
37+
<EyebrowText>Feature</EyebrowText>
38+
<Heading>Title</Heading>
39+
<Text>Description</Text>
40+
</River.Content>
41+
```
42+
43+
- **New `RiverBreakout` prop**: `variant`. This prop controls the layout and appearance of the RiverBreakout component. Two variants are available: `default` and `gridline`.
44+
45+
The `gridline` variant adds horizontal border lines, lateral spacing, and supports vertical dividers for the trailing component on tablet+ viewports.
46+
47+
```jsx
48+
<RiverBreakout variant="gridline">
49+
<RiverBreakout.A11yHeading>Title</RiverBreakout.A11yHeading>
50+
<RiverBreakout.Visual>
51+
<img src="..." alt="..." />
52+
</RiverBreakout.Visual>
53+
<RiverBreakout.Content trailingComponent={Timeline} trailingComponentDivider>
54+
<Text>Description</Text>
55+
</RiverBreakout.Content>
56+
</RiverBreakout>
57+
```
58+
59+
- **`RiverBreakout` padded background support**: `RiverBreakout.Visual` now supports `imageBackgroundColor="subtle"` to display the visual with a padded background container that bleeds to the gridline borders.

apps/next-docs/content/components/River/react.mdx

Lines changed: 79 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ storybook: '/brand/storybook/?path=/story/components-river--default'
1111
---
1212

1313
import {Label} from '@primer/react'
14-
import {RiverAlignProp, RiverImageTextRatio} from './react'
14+
import {RiverAlignProp, RiverImageTextRatio, RiverVariantProp} from './react'
1515

1616
```js
1717
import {River, RiverBreakout} from '@primer/react-brand'
@@ -22,7 +22,7 @@ import {River, RiverBreakout} from '@primer/react-brand'
2222
### Default
2323

2424
```jsx live
25-
<Stack>
25+
<Stack style={{width: '100%'}}>
2626
<River>
2727
<River.Visual>
2828
<img src="/images/placeholder.png" alt="placeholder, blank area with a gray background color" />
@@ -66,10 +66,71 @@ import {River, RiverBreakout} from '@primer/react-brand'
6666
</Stack>
6767
```
6868

69+
### GridLine variant
70+
71+
The `gridline` variant adds lateral padding to the River component, making it suitable for use within bordered grid layouts.
72+
73+
```jsx live
74+
<Stack style={{width: '100%'}}>
75+
<River variant="gridline">
76+
<River.Visual>
77+
<img src="/images/placeholder.png" alt="placeholder, blank area with a gray background color" />
78+
</River.Visual>
79+
<River.Content>
80+
<Heading>GridLine variant</Heading>
81+
<Text>Use the gridline variant when the River needs lateral spacing to align with bordered grid layouts.</Text>
82+
<Link href="#">Call to action</Link>
83+
</River.Content>
84+
</River>
85+
<River variant="gridline" align="end">
86+
<River.Visual>
87+
<img src="/images/placeholder.png" alt="placeholder, blank area with a gray background color" />
88+
</River.Visual>
89+
<River.Content>
90+
<Heading>GridLine variant</Heading>
91+
<Text>The variant works with all alignment options.</Text>
92+
<Link href="#">Call to action</Link>
93+
</River.Content>
94+
</River>
95+
</Stack>
96+
```
97+
98+
### Visual with background
99+
100+
Use the `imageBackgroundColor` prop on `River.Visual` to create a full-bleed container with a background color and the image/video centered inside with padding. This is intended for use with the `gridline` variant.
101+
102+
```jsx live
103+
<Stack style={{width: '100%'}}>
104+
<River variant="gridline">
105+
<River.Visual imageBackgroundColor="subtle">
106+
<img src="/images/placeholder.png" alt="placeholder, blank area with a gray background color" />
107+
</River.Visual>
108+
<River.Content>
109+
<Heading>Visual with background</Heading>
110+
<Text>
111+
The imageBackgroundColor prop creates a full-bleed container with a subtle background, centering the media with
112+
padding around it.
113+
</Text>
114+
<Link href="#">Call to action</Link>
115+
</River.Content>
116+
</River>
117+
<River variant="gridline" align="end">
118+
<River.Visual imageBackgroundColor="subtle">
119+
<img src="/images/placeholder.png" alt="placeholder, blank area with a gray background color" />
120+
</River.Visual>
121+
<River.Content>
122+
<Heading>Visual with background (end)</Heading>
123+
<Text>The imageBackgroundColor prop works with all alignment options.</Text>
124+
<Link href="#">Call to action</Link>
125+
</River.Content>
126+
</River>
127+
</Stack>
128+
```
129+
69130
### Image to text ratio
70131

71132
```jsx live
72-
<Stack>
133+
<Stack style={{width: '100%'}}>
73134
{/* 50/50 (default) example */}
74135
<River>
75136
<River.Visual>
@@ -98,7 +159,7 @@ import {River, RiverBreakout} from '@primer/react-brand'
98159
### Video
99160

100161
```jsx live
101-
<River imageTextRatio="60:40">
162+
<River style={{width: '100%'}} imageTextRatio="60:40">
102163
<River.Visual hasShadow={false}>
103164
<video
104165
loop
@@ -130,7 +191,7 @@ import {River, RiverBreakout} from '@primer/react-brand'
130191
### Alternative heading levels
131192

132193
```jsx live
133-
<River imageTextRatio="60:40">
194+
<River style={{width: '100%'}} imageTextRatio="60:40">
134195
<River.Visual>
135196
<img src="/images/placeholder.png" alt="placeholder with a gray background color" />
136197
</River.Visual>
@@ -144,7 +205,7 @@ import {River, RiverBreakout} from '@primer/react-brand'
144205
### Duotone
145206

146207
```jsx live
147-
<River>
208+
<River style={{width: '100%'}}>
148209
<River.Visual>
149210
<img src="/images/placeholder.png" alt="placeholder, blank area with a gray background color" />
150211
</River.Visual>
@@ -161,7 +222,7 @@ import {River, RiverBreakout} from '@primer/react-brand'
161222
### River breakout
162223

163224
```jsx live
164-
<RiverBreakout>
225+
<RiverBreakout style={{width: '100%'}}>
165226
<RiverBreakout.A11yHeading>Accelerate workflows</RiverBreakout.A11yHeading>
166227
<RiverBreakout.Visual>
167228
<img src="/images/placeholder.png" alt="placeholder, blank area with a gray background color" />
@@ -195,21 +256,23 @@ import {River, RiverBreakout} from '@primer/react-brand'
195256
| :--------------- | :----------------------------- | :---------------------: | :---------------------------------------------------------------------------------------------------------- |
196257
| `align` | `'start'`, `'end'`, `'center'` | <RiverAlignProp /> | Alignment of text content relative to the Visual position |
197258
| `imageTextRatio` | `'50:50'`, `'60:40'` | <RiverImageTextRatio /> | The aspect ratio applied to the image in relation to the adjacent text. Affects overall layout proportions. |
259+
| `variant` | `'default'`, `'gridline'` | <RiverVariantProp /> | Visual variant. Use `gridline` to add lateral padding for bordered grid layouts. |
198260
| `className` | `string` | | Sets a custom class on the root element |
199261
| `id` | `string` | | Sets a custom id |
200262
| `ref` | `React.RefObject` | | Forward a Ref to the underlying DOM node |
201263

202264
### River.Visual and RiverBreakout.Visual <Label>Required</Label>
203265

204-
| Name | Type | Default | Description |
205-
| :---------- | :---------------- | :-----: | :-------------------------------------------------------------------------------------------------------------------------------------------- |
206-
| `fillMedia` | `boolean` | true | Automatically styles images and video to fill and fit the width of the parent. Disable this setting if you have bespoke styling requirements. |
207-
| `children` | `ReactElement` | | Bring your own component (BYOC) `img` or `ReactElement` (E.g. Next.js `Image` component) |
208-
| `hasShadow` | `boolean` | `false` | Shadow applied to the `children`. Set be `false` when the child node has a transparent background. |
209-
| `className` | `string` | | Sets a custom class on the root element |
210-
| `id` | `string` | | Sets a custom id |
211-
| `ref` | `React.RefObject` | | Forward a Ref to the underlying DOM node |
212-
| `rounded` | `boolean` | `true` | Toggle visually rounded corners. Enabled by default. |
266+
| Name | Type | Default | Description |
267+
| :--------------------- | :---------------------- | :-----: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
268+
| `fillMedia` | `boolean` | true | Automatically styles images and video to fill and fit the width of the parent. Disable this setting if you have bespoke styling requirements. |
269+
| `children` | `ReactElement` | | Bring your own component (BYOC) `img` or `ReactElement` (E.g. Next.js `Image` component) |
270+
| `imageBackgroundColor` | `'default'`, `'subtle'` | | Applies a background color with padding around the media. Use `'subtle'` to create a full-bleed container with the image/video centered inside. Intended for use with `gridline` variant. |
271+
| `hasShadow` | `boolean` | `false` | Shadow applied to the `children`. Set be `false` when the child node has a transparent background. |
272+
| `className` | `string` | | Sets a custom class on the root element |
273+
| `id` | `string` | | Sets a custom id |
274+
| `ref` | `React.RefObject` | | Forward a Ref to the underlying DOM node |
275+
| `rounded` | `boolean` | `true` | Toggle visually rounded corners. Enabled by default. |
213276

214277
### River.Content and RiverBreakout.Content <Label>Required</Label>
215278

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
'use client'
22

3-
import {defaultRiverImageTextRatio, defaultRiverAlign} from '../../../../../packages/react/src/river/River'
3+
import {
4+
defaultRiverImageTextRatio,
5+
defaultRiverAlign,
6+
defaultRiverVariant,
7+
} from '../../../../../packages/react/src/river/River'
48

59
export const RiverAlignProp = () => defaultRiverAlign
610
export const RiverImageTextRatio = () => defaultRiverImageTextRatio
11+
export const RiverVariantProp = () => defaultRiverVariant

packages/design-tokens/src/tokens/functional/components/river/river.json

Lines changed: 75 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,10 @@
22
"River": {
33
"spacing": {
44
"inner": {
5-
"value": "var(--base-size-24)",
5+
"value": "var(--base-size-40)",
66
"responsive": {
7-
"768px": {
8-
"value": "var(--base-size-36)"
9-
},
107
"1280px": {
11-
"value": "var(--base-size-48)"
8+
"value": "var(--base-size-24)"
129
}
1310
}
1411
},
@@ -23,14 +20,36 @@
2320
}
2421
}
2522
},
26-
"outer": {
23+
"outerBlock": {
2724
"value": "var(--base-size-36)",
2825
"responsive": {
2926
"1280px": {
3027
"value": "var(--base-size-48)"
3128
}
3229
}
3330
}
31+
},
32+
"variant": {
33+
"gridline": {
34+
"spacing": {
35+
"outerBlock": {
36+
"value": "var(--base-size-40)",
37+
"responsive": {
38+
"1280px": {
39+
"value": "var(--base-size-64)"
40+
}
41+
}
42+
},
43+
"outerInline": {
44+
"value": "var(--base-size-20)",
45+
"responsive": {
46+
"1280px": {
47+
"value": "var(--base-size-64)"
48+
}
49+
}
50+
}
51+
}
52+
}
3453
}
3554
},
3655
"RiverBreakout": {
@@ -46,6 +65,56 @@
4665
}
4766
}
4867
}
68+
},
69+
"variant": {
70+
"gridline": {
71+
"spacing": {
72+
"outerBlock": {
73+
"value": "var(--base-size-36)",
74+
"responsive": {
75+
"768px": {
76+
"value": "var(--base-size-40)"
77+
},
78+
"1280px": {
79+
"value": "var(--base-size-64)"
80+
}
81+
}
82+
},
83+
"outerBlockEnd": {
84+
"value": "var(--base-size-40)",
85+
"responsive": {
86+
"768px": {
87+
"value": "var(--base-size-48)"
88+
},
89+
"1280px": {
90+
"value": "var(--base-size-80)"
91+
}
92+
}
93+
},
94+
"outerInline": {
95+
"value": "var(--base-size-20)",
96+
"responsive": {
97+
"768px": {
98+
"value": "var(--base-size-36)"
99+
},
100+
"1280px": {
101+
"value": "var(--base-size-64)"
102+
}
103+
}
104+
},
105+
"contentGap": {
106+
"value": "var(--base-size-16)",
107+
"responsive": {
108+
"768px": {
109+
"value": "var(--base-size-20)"
110+
},
111+
"1280px": {
112+
"value": "var(--base-size-24)"
113+
}
114+
}
115+
}
116+
}
117+
}
49118
}
50119
}
51120
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.EyebrowText {
2+
text-transform: uppercase;
3+
letter-spacing: var(--brand-text-letterSpacing-100);
4+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
declare const styles: {
2+
readonly "EyebrowText": string;
3+
};
4+
export = styles;
5+
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import type {Meta, StoryObj} from '@storybook/react'
2+
import React from 'react'
3+
import {EyebrowText} from '.'
4+
5+
const meta = {
6+
title: 'Components/EyebrowText',
7+
component: EyebrowText,
8+
args: {
9+
children: 'Eyebrow text',
10+
},
11+
argTypes: {
12+
children: {
13+
name: 'children',
14+
description: 'EyebrowText content.',
15+
type: {name: 'string', required: true},
16+
control: {
17+
type: 'text',
18+
},
19+
},
20+
},
21+
} satisfies Meta<typeof EyebrowText>
22+
23+
export default meta
24+
type Story = StoryObj<typeof EyebrowText>
25+
26+
export const Default: Story = {
27+
render: () => <EyebrowText>Default</EyebrowText>,
28+
}
29+
30+
export const Playground: Story = {
31+
render: args => <EyebrowText {...args} />,
32+
}

0 commit comments

Comments
 (0)