Développement réactif et adaptatif
Vous recherchez des conseils pour la conception ? Reportez-vous à la section Conception réactive et adaptative
Terminologie
Les composants Jutro peuvent être :
- **Réactifs **: les composants s'adaptent automatiquement à la taille de l'écran à l'aide de requêtes de média.
- Adaptifs : le composant ne s'ajuste pas à la taille de l'écran et vous devez alors le configurer à l'aide des propriétés des points de rupture. Le rendu du composant varie en fonction de l'appareil.
- **Fixe **: le composant ne s'adapte pas à la taille de l'écran.
Dans Storybook, chaque composant est étiqueté comme réactif, adaptatif ou fixe dans la barre supérieure.
Bien que la plupart des composants soient réactifs sur tous les types d'appareils, certains ne sont parfois pas aussi pratiques à utiliser sur de petits appareils que sur des grands. Nous vous recommandons de configurer ces composants à l'aide de propriétés de point de rupture.
Comment travailler avec des concepteurs
Un concepteur peut vous fournir des conceptions d'application pour différents points de rupture. Interrogez-le sur les comportements attendus, etc., pour vous assurer que vous comprenez bien comment l'utilisateur peut tirer le meilleur parti de l'application.
Voici des conseils généraux pour travailler avec les concepteurs :
- Cherchez à reproduire le même écran sur différents écrans.
- Les concepteurs peuvent utiliser le terme « facteur de forme » pour faire référence à un point d’arrêt spécifique :
phone,phoneWide,tabletoudesktop. Reportez-vous à la section Propriétés des points d’arrêt pour connaître les largeurs exactes. - Utilisez des outils d'« inspection » dans l'application de conception pour connaître l'espacement et les tailles demandés. Veillez à utiliser les variables d'espacement et de dimensionnement Jutro (voir Création de thèmes).
- Montrez votre application à un concepteur dès que possible pour obtenir des commentaires et implémenter davantage de fonctionnalités de manière itérative.
- Obtenez des éclaircissements sur les éléments que vous ne comprenez pas ou sur la façon dont ils doivent fonctionner.
- Utilisez les outils de développement de votre navigateur pour tester la disposition sur différents points d'arrêt.
- Si l'application doit fonctionner sur des téléphones, développez d'abord pour le téléphone et passez ensuite à des tailles plus grandes.
Faisabilité
Examinez les conceptions avec le concepteur et travaillez sur la faisabilité. Ce processus est également appelé « assurance qualité de l'interface utilisateur » (QA UI) :
- Tous les composants sont-ils disponibles ? Il vous est par exemple demandé de fournir un carrousel d'image, mais il ne s'agit pas d'un composant Jutro standard. Cela signifie que vous devrez créer le vôtre.
- Tous les composants fonctionnent-ils comme prévu ? Vous devrez peut-être créer une application de démonstration de faisabilité à ce stade.
- S'il existe des fonctionnalités ou des interactions complexes, vérifiez qu'elles sont autorisées dans Jutro et que leur implémentation est abordable économiquement. Par exemple, le carrousel est-il le meilleur moyen de répondre au cas d'utilisation ? Il faut prévoir une option pour arrêter le défilement des images et éviter ainsi tout mouvement incessant désagréable pour l'utilisateur. Est-il faisable de développer cette fonctionnalité dans le cadre de votre projet ?
Propriétés de point de rupture
Les propriétés de point de rupture sont les suivantes :
| Nom de la propriété | Largeur |
|---|---|
phone | < 580px |
phoneWide (phone in horizontal mode) | 580px to 768px |
tablet | 768px to 1024px |
desktop | > 1024px |
Use these props to override the behavior of your component on different devices.
Override children
For example, you want your action title bar to not include an action when the user is on a mobile device. In that case, you can use the phone prop to override the children of the component.
<ActionTitleBar
phone={{
children: (
<TitleElement>
{/* On a phone, render only a heading */}
<h4>Just a title</h4>
</TitleElement>
),
}}>
{/* On large screens, render an icon with a tooltip and a button */}
<TitleElement>
<h4>Title</h4>
<TooltipIcon {...tooltipIconProps} />
<Button {...buttonProps}>Edit</Button>
</TitleElement>
</ActionTitleBar>
Vous pouvez faire en sorte que la plupart des composants aient un rendu différent sur des périphériques différents en utilisant des propriétés de point d'arrêt.
Remplacer les propriétés
Ces propriétés permettent de modifier les propriétés d'un composant lors du rendu sur un périphérique particulier. Par exemple :
<RadioButtonField
availableValues={[
{
displayName: 'Perform payment on checkout',
},
{
displayName: 'Defer payment to a later date',
},
]}
phone={{
availableValues: [
{
displayName: 'Pay now',
},
{
displayName: 'Pay later',
},
],
}}
/>
Il s’agit d’un exemple très simple d’affichage d’étiquettes différentes pour les cases à cocher sur les petits écrans. Normalement, vous utilisez les messages intl pour afficher le texte d’un composant, mais cet exemple explique comment vous pouvez transmettre une copie de la propriété availableValues et remplacer les éléments qu’elle contient.
Remplacer les styles
La modification des styles pour différents périphériques est un autre exemple :
<Card
className={styles.largeBanner}
phone={{
className: styles.smallBanner,
}}
tablet={{
className: styles.mediumBanner,
}}
/>
Dans cet exemple, nous avons une carte dont le style varie en fonction de la taille de l'appareil.
Le crochet useBreakpoint
useBreakpoint. Les propriétés de point d’arrêt telles que phone, tablet et phoneWide ne sont pas disponibles pour les nouveaux composants prêts à l’emploi.Le crochet useBreakpoint est exporté à partir de @jutro/layout et peut être importé comme import { useBreakpoint } from '@jutro/layout'. Il renvoie un objet avec les propriétés suivantes :
breakpointProps :les propriétés que vous avez transmises dans le composant fusionnées aux valeurs modifiées dans l'une des propriétés suivantes :phone,phoneWide,tabletapplyBreakpoint: une fonction qui prendpropscomme argument et renvoiebreakpointProps. Vous pouvez l’utiliser dans n’importe quel code imbriqué au sein de votre composant dans lequel les crochets ne sont pas autorisés.breakpoint: nom du point d’arrêt actuel. L’un des éléments suivants :phone,phoneWide,tabletoudesktop.
Il existe quatre façons d'utiliser le crochet pour obtenir le résultat escompté.
1. Obtenir des propriétés à partir du crochet pour un point d'arrêt donné
La première façon d'utiliser le crochet consiste à transmettre les propriétés et à appliquer le résultat au composant.
Dans l’exemple suivant, l’objet des propriétés phone est transmis à useBreakpoint. Les propriétés sont ensuite renvoyées en tant que textInputPhoneProps au point d’arrêt phone. Elles sont alors attribuées à TextInput et les propriétés ajoutées précédemment sont remplacées. La propriété label est remplacée, puis les propriétés placeholder et className sont ajoutées lorsque le crochet détecte que le point d’arrêt passe à phone.
const { breakpointProps: textInputPhoneProps } = useBreakpoint({
phone: {
placeholder: 'Phone placeholder',
label: 'Phone label',
className: 'somePhoneClass',
},
});
return (
<TextInput
label="Text input"
{...textInputPhoneProps}
/>
);
2. Obtenir uniquement le statut du point d'arrêt à partir du crochet
La deuxième façon d’utiliser le crochet consiste à obtenir uniquement le statut du point d’arrêt et à l’utiliser pour modifier cette propriété en fonction du point d’arrêt renvoyé. Dans l’exemple suivant, breakpoint est obtenu à partir du crochet et change en fonction de la fenêtre d’affichage. Une valeur différente pour la propriété label peut être attribuée si le point d’arrêt est défini sur phone.
const { breakpoint } = useBreakpoint({});
return (
<TextInput label={breakpoint === 'phone' ? 'Phone label' : 'Text input'} />
);
3. Obtenir le rappel qui renvoie les propriétés des points d'arrêt
La troisième façon d’utiliser le crochet est d’utiliser applyBreakpoint : elle est très similaire à la première option, mais peut être meilleure si différents composants nécessitant de nombreuses instances useBreakPoints se trouvent sur la même page. Dans l’exemple suivant, le rappel qui renvoie les propriétés est obtenu, puis applyBreakpoint est affecté à chaque élément TextInput et des propriétés différentes sont transmises à chaque composant.
const { applyBreakpoint } = useBreakpoint({});
return (
<React.Fragment>
<TextInput
label="Text input"
{...applyBreakpoint({
phone: {
placeholder: 'Phone placeholder',
label: 'Phone label',
className: 'somePhoneClass',
},
})}
/>
<TextInput
label="Text input instance 2"
{...applyBreakpoint({
phone: {
placeholder: 'Another Phone placeholder',
label: 'Another Phone label',
className: 'someOtherPhoneClass',
},
})}
/>
</React.Fragment>
);
4. Tous en même temps
Il est possible d'obtenir les trois éléments renvoyés par useBreakpoint et de les utiliser tous en même temps. Par exemple :
const {
breakpointProps: textInputPhoneProps,
breakpoint,
applyBreakpoint,
} = useBreakpoint({
phone: {
placeholder: 'Phone placeholder',
label: 'Phone label',
className: 'somePhoneClass',
},
});
return (
<React.Fragment>
<TextInput
label="Text input"
{...textInputPhoneProps}
/>
<TextInput
label={breakpoint === 'phone' ? 'Phone label 2' : 'Text input'}
/>
<TextInput
label="Text input"
{...applyBreakpoint({
phone: {
placeholder: 'Phone placeholder 3',
label: 'Phone label 3',
className: 'someOtherPhoneClass',
},
})}
/>
</React.Fragment>
);
Différentes propriétés pour un point d'arrêt
Un cas typique d'utilisation du crochet est lorsque vous voulez transmettre des propriétés personnalisées à un composant en fonction du point d'arrêt. Lorsque vous utilisez le composant, vous procédez comme suit :
<BigBanner
phone={{
message: 'Call us!',
}}
message="Get in touch"
/>
Vous voulez que vos utilisateurs voient le message « Contactez-nous » dans la plupart des cas. Mais, lorsqu’ils sont au téléphone, vous voulez qu’ils voient un message qui dit « Appelez-nous ! ».
Dans le composant fonctionnel, vous utilisez le crochet useBreakpoint et vous transmettez les propriétés en tant qu'argument unique. Vous extrayez ensuite la valeur de la propriété message.
Sur le bureau, elle renvoie « Contactez-nous » et sur le téléphone, elle renvoie « Appelez-nous ! ».
import { useBreakpoint } from '@jutro/layout';
function BigBanner(props) {
const { breakpointProps } = useBreakpoint(props);
return <div>{breakpointProps.message}</div>;
}
Différents styles pour un point d'arrêt
Un autre cas d'utilisation du crochet consiste à appliquer différents styles à un composant en fonction du point d'arrêt actuel.
Vous créez deux classes dans votre module de styles :
.defaultColor {
color: magenta;
}
.phoneColor {
color: blue;
}
Pour utiliser les styles, vous obtenez le point d’arrêt actuel à l’aide du crochet. Ensuite, vous sélectionnez une classe en fonction de la valeur du crochet.
import React from 'react';
import { useBreakpoint } from '@jutro/layout';
import styles from './BigBanner.module.scss';
function BigBanner(props) {
const { breakpoint } = useBreakpoint(props);
const myClass =
breakpoint === 'phone' ? styles.phoneColor : styles.defaultColor;
return <div className={myClass}>Welcome to my banner!</div>;
}
Ou :
import React from 'react';
import cx from 'classnames';
import styles from './BigBanner.module.scss';
import { useBreakpoint } from '@jutro/layout';
function BigBanner(props) {
const { breakpointProps } = useBreakpoint({
...props,
className: cx(props.className, styles.defaultColor),
phone: {
className: cx(props.className, styles.phoneColor),
},
});
const { className } = breakpointProps;
return <div className={className}>{breakpointProps.message}</div>;
}
Contexte BreakpointTracker
Vous pouvez également utiliser BreakpointTrackerContext et BreakpointTracker directement. Vous pouvez les utiliser dans des composants de classe ou à d'autres endroits où l'utilisation de crochets n'est pas possible.
L’application entière est enveloppée dans ce fournisseur de contexte ; vous pouvez donc l’utiliser dans un composant de classe, par exemple dans le bloc render. Vous pouvez également l’utiliser dans des fonctions qui ne sont pas imbriquées dans les composants fonctionnels.
BreakpointTracker.applyBreakpointOverrides renvoie uniquement un objet breakpointProps.
Il prend deux arguments : props et un breakpoint.
Contexte de point d'arrêt dans un composant fonctionnel
import React, { useContext } from 'react';
import { BreakpointTracker, BreakpointTrackerContext } from '@jutro/layout';
function BigBanner(props) {
const breakpoint = useContext(BreakpointTrackerContext);
const someRenderFunction = () => {
const breakpointProps = BreakpointTracker.applyBreakpointOverrides(
props,
breakpoint
);
return (
<pre>
<code>{JSON.stringify(breakpointProps, null, 2)}</code>
</pre>
);
};
return <div>{someRenderFunction()}</div>;
}
Contexte de point d'arrêt dans un composant de classe
import React from 'react';
import { BreakpointTracker, BreakpointTrackerContext } from '@jutro/layout';
class ClassBanner extends React.Component {
static contextType = BreakpointTrackerContext;
render() {
const breakpointProps = BreakpointTracker.applyBreakpointOverrides(
this.props,
this.context
);
return (
<pre>
<code>{JSON.stringify(breakpointProps, null, 2)}</code>
</pre>
);
}
}
export default ClassBanner;
Points d'arrêt dans les tests d'unité
Pour tester les points d’arrêt, vous pouvez vous aider de l’exemple suivant. Il teste le composant BigBanner que nous avons créé dans d’autres sections de cette page.
import React from 'react';
import { render } from '@testing-library/react';
import { BreakpointTrackerContext } from '@jutro/layout';
import { BigBanner } from '../BigBanner';
import styles from '../BigBanner.module.scss';
function renderBigBannerWithBreakpoints(props = {}, breakpoint = 'desktop') {
return render(
<BreakpointTrackerContext.Provider value={breakpoint}>
<BigBanner {...props} />
</BreakpointTrackerContext.Provider>
);
}
describe('BigBanner', () => {
it('renders with default class on desktop', () => {
const { container } = renderBigBannerWithBreakpoints();
expect(container.firstChild).toHaveClass(styles.defaultColor);
});
it('renders with mobile class on phone', () => {
const { container } = renderBigBannerWithBreakpoints({}, 'phone');
expect(container.firstChild).toHaveClass(styles.phoneColor);
});
});