Skip to content

Commit a2cb1db

Browse files
feat(react-recipes): Adding MediaObject recipe and Example template (#26594)
* adding media object recipe and Example template * adding requested changes * adding Template prefix to Example template
1 parent 306fe5e commit a2cb1db

File tree

5 files changed

+469
-0
lines changed

5 files changed

+469
-0
lines changed
Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
import LinkTo from '@storybook/addon-links/react';
2+
import { Meta } from '@storybook/addon-docs';
3+
import { TextPositionVariations, TextAlignmentVariations, FlexSkeleton, IconMediaObject } from './code-snippets';
4+
import { Example } from '../../templates';
5+
6+
<Meta title="Concepts/Recipes/Media Object" />
7+
8+
---
9+
10+
# Media Object recipe
11+
12+
### **Overview**
13+
14+
A Media Object, is a pattern commonly used to display media content and a description of that content.
15+
A typical example of this patter is displaying an Avatar of a person (the media content) next to their name (the description). Fluent UI's <LinkTo kind="components-persona--default">Persona</LinkTo> is an example of this pattern.
16+
17+
This recipe focuses on other uses of this patterns and will show you how to create a Media Object to display images, icons or any other media content you want to add.
18+
19+
### **Ingredients**
20+
21+
- <LinkTo kind="concepts-developer-icons-icons--page">@fluentui/react-icons</LinkTo>
22+
- <LinkTo kind="components-image--default">@fluentui/react-image</LinkTo>
23+
- <LinkTo kind="components-text--default">@fluentui/react-text</LinkTo>
24+
25+
> **\*\*Note:\*\*** This recipe is meant to provide a way to use custom media. If you want to use
26+
> `Avatar` or `PresenceBadge` as media, please refer to our <LinkTo kind="components-persona--default">Persona component</LinkTo>.
27+
28+
## **Steps**
29+
30+
There are two ways to build a Media Object, you can use a grid layout or a flex layout. We will cover both in this
31+
recipe. There are upsides and downsides to both, but the main difference is that grid layout uses less DOM than the
32+
flex option.
33+
34+
### **Flex Layout**
35+
36+
The main idea behind the flex layout is to have a container and two children, as shown below. The parent div will
37+
contain the media and another div (text div) that will contain the text content.
38+
39+
<TemplateExample centered>
40+
<FlexSkeleton />
41+
</TemplateExample>
42+
43+
To achieve this layout, we will follow these steps:
44+
45+
#### **Step 1: Creating our parent and text container styles.**
46+
47+
As seen above, we will first need to create our parent div and our text containers. These containers will need to have
48+
the `display: flex` css property and a `row` direction for the parent and a `column` direction for the text container, as shown in the `makeStyles` call below:
49+
50+
```jsx
51+
const useStyles = makeStyles({
52+
parent: {
53+
display: 'flex',
54+
flexDirection: 'row',
55+
},
56+
textContainer: {
57+
display: 'flex',
58+
flexDirection: 'column',
59+
},
60+
});
61+
```
62+
63+
#### **Step 2: Putting everything together.**
64+
65+
After we have our styles, we just have to put our styles to work! Since we are using flex box we don't need to worry about dynamically placing items. Do take into account that using this approach will be heavier on the DOM than the grid approach.
66+
67+
```jsx
68+
import { Text, makeStyles } from '@fluentui/react-components';
69+
70+
// Our makeStyles call from above
71+
72+
const MediaObject: React.FC<{ text?: string }> = ({ children, text }) => {
73+
const styles = useStyles();
74+
75+
return (
76+
<div className={styles.parent}>
77+
{children}
78+
<div className={styles.textContainer}>
79+
<Text>{text}</Text>
80+
</div>
81+
</div>
82+
);
83+
};
84+
```
85+
86+
After these steps you should be able to build something like the example below.
87+
88+
<TemplateExample centered>
89+
<IconMediaObject />
90+
</TemplateExample>
91+
92+
### **Grid Layout**
93+
94+
When using a grid for Media Object, we only need a parent div and we can pass the items directly into it.
95+
As you can tell, the grid layout has one less layer of DOM compared to the flex layout. This is especially important
96+
when the component is going to be used repeatedly in a list or the media or/and text have many layers themselves.
97+
98+
To get started, we will follow these steps:
99+
100+
#### **Step 1: Creating our grid.**
101+
102+
To get the initial layout, we need to add these css properties to our parent div:
103+
104+
- `display: grid`: This will create our grid layout and allow us to use the grid properties.
105+
- `grid-auto-flow: column`: This will make the grid flow as a column and allow our media to be on the left and our text on the right.
106+
107+
Resulting in a `makeStyles` call like this:
108+
109+
```jsx
110+
const useStyles = makeStyles({
111+
parent: {
112+
display: 'grid',
113+
gridAutoFlow: 'column',
114+
},
115+
});
116+
```
117+
118+
#### **Step 2: Adding our media styles.**
119+
120+
Our next step is to add our media styles. Unlike the flex layout, we will need to add some css properties to our media because we are using `grid-auto-flow: column`. To make our media take all the rows on the left, we will need to make our media span the number of rows the text will take. If we have 4 lines of text, we will need to add `grid-row-start: span 4`. While this could be done dynamically using line names, this is the simplest way to achieve a media object with grid. This will give us the following `makeStyles` call:
121+
122+
```jsx
123+
const useStyles = makeStyles({
124+
// parent styles
125+
media: {
126+
gridRowStart: 'span 4',
127+
},
128+
});
129+
```
130+
131+
#### **Step 3: Putting everything together.**
132+
133+
After these steps we should be able to add our media and text, and get the desired layout shown above. We should have a component that looks like this:
134+
135+
```jsx
136+
import { Text, makeStyles } from '@fluentui/react-components';
137+
138+
// Our makeStyles call from above
139+
140+
const MediaObject: React.FC<{ text?: string }> = ({ children, text }) => {
141+
const styles = useStyles();
142+
143+
return (
144+
<div className={styles.parent}>
145+
<div className={styles.media}>{children}</div>
146+
<Text className={styles.text}>{text}</Text>
147+
</div>
148+
);
149+
};
150+
```
151+
152+
#### **Step 3 (_optional_): Dynamically place media and text.**
153+
154+
If you want to dynamically place your media and text, you can use `grid-template-columns` to achieve this. For the basic layout, we need to add the css property `grid-template-columns: max-content [middle] auto`. This will create two columns and a line name called middle. The max-content column will be the media which will help only use the space needed for the media and the auto column will be the text so we can wrap it when there is not enough space in our container. This will give us the following `makeStyles` call:
155+
156+
```jsx
157+
const useStyles = makeStyles({
158+
parent: {
159+
display: 'grid',
160+
gridTemplateColumns: 'max-content [middle] auto',
161+
},
162+
});
163+
```
164+
165+
#### **Step 4 (_optional_): Let your media and text know where to start and end.**
166+
167+
Now that we have our template columns, we need to let our text know where to start and our media where to end. The media must end at the middle line and the text must start at the middle line. This has the pro of not having to know how many rows of text we will have, but the downside is that we have to let the media and text know where to start or end. We should a `makeStyles` call like this:
168+
169+
```jsx
170+
const useStyles = makeStyles({
171+
// parent styles
172+
media: {
173+
gridColumnEnd: 'middle',
174+
},
175+
text: {
176+
gridColumnStart: 'middle',
177+
},
178+
});
179+
```
180+
181+
#### **Step 5 (_optional_): Putting everything together.**
182+
183+
After our styles are ready to be used, we can put everything together and get the desired layout shown above. We should have a component that looks like this:
184+
185+
```jsx
186+
import { Text, makeStyles } from '@fluentui/react-components';
187+
188+
// Our makeStyles call from above
189+
190+
const MediaObject: React.FC<{ text?: string }> = ({ children, text }) => {
191+
const styles = useStyles();
192+
193+
return (
194+
<div className={styles.parent}>
195+
<div className={styles.media}>{children}</div>
196+
<Text className={styles.text}>{text}</Text>
197+
</div>
198+
);
199+
};
200+
```
201+
202+
## **Variants**
203+
204+
There are a few common variants that you might want to use when building a Media Object. These are some of them:
205+
206+
- ### **Text Alignment Variations**
207+
208+
There are text alignment variations that might be useful when building an application. These can be ones below where the
209+
first one is after the media, the second one is below, and the last one is before.
210+
211+
<TemplateExample centered>
212+
<TextPositionVariations />
213+
</TemplateExample>
214+
215+
- ### **Text Vertical Alignment Variations**
216+
217+
There are also vertical alignment variations, these include start and center as seen below.
218+
219+
<TemplateExample centered>
220+
<TextAlignmentVariations />
221+
</TemplateExample>
222+
223+
## **Best practices**
224+
225+
- The higher up the text line, the more important it is. You should not apply higher weights to the lines underneath.
226+
- When using `grid-template-columns` make sure the DOM makes sense and not differ from how the grid is placing them. Do
227+
not have your DOM be `<media> <text>` when the rendered result looks like `<text> <media>`.

0 commit comments

Comments
 (0)