Skip to content

[AXA.fr] [Espace Client] [Organisme] Evolutions du composant Modal #824 #1184

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Jul 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
e647f33
feat(apollo): added useHasScroll hook
May 12, 2025
06e381d
feat(apollo,look&feel): évolution du composant modal
May 12, 2025
0b6a9a7
feat(apollo,look&feel): ajout des tests du composant modal
May 12, 2025
c114fcb
feat(apollo): ajout des stories du composant modal
May 12, 2025
e51169a
feat(look&feel): suppression du code du composant modal et réexportat…
May 12, 2025
ad633ba
feat(look&feel): encapsulation des stories du composant modal dans so…
May 12, 2025
5c22b88
style(apollo,look&feel): defined overlay color in modal lf css
Jun 4, 2025
c51b61c
revert "feat(look&feel): suppression du code du composant modal et ré…
Jun 12, 2025
2dd7e37
feat(look&feel): mention du composant en deprecated et suggestion d'u…
Jun 12, 2025
6eb228a
feat(apollo,look&feel): retours pr
Jun 18, 2025
8e126ea
revert "feat(look&feel): encapsulation des stories du composant modal…
Jun 18, 2025
c3bfadd
feat(look&feel): ajout des stories de la modal venant d'apollo
Jun 18, 2025
5dbdfd0
style(apollo,look&feel): modification du préfixe af-modal* par af-apo…
Jun 18, 2025
f03e0be
style(apollo,look&feel): retour sur la config legacy de color-functio…
Jun 19, 2025
58e833a
feat(look&feel): retour pr story
Jun 19, 2025
fa257a1
test(apollo): corrected failing build
Jun 19, 2025
b9ed4cd
feat(apollo): fixed errors in modal stories
Jun 23, 2025
20be8c1
feat(look&feel): fixed errors in modal stories and importing modal fr…
Jun 23, 2025
d143f1d
test(apollo): fixed modal test
Jun 23, 2025
67cfe29
feat(apollo,look&feel): retour pr sur les stories et tests
Jun 25, 2025
8360317
feat(apollo,look&feel): reduction du temps de transition de la modal
Jun 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 134 additions & 0 deletions apps/apollo-stories/src/components/Modal/Modal.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import { Canvas, Controls, Meta } from "@storybook/addon-docs";
import * as ModalStories from "./Modal.stories.tsx";
import * as ModalCoreStories from "./ModalCore.stories.tsx";

<Meta of={ModalStories} name="Docs" />

# Modal

1. [ModalCore](#modalcore)
2. [Modal](#modal)

The ModalCore is the component to use if you want to fully configure your modal.

With the `ModalCoreHeader` you can configure the header of the modal.

With the `ModalCoreBody` you can configure the body of the modal.

And with the `ModalCoreFooter` you can configure the footer of the modal.

You need to pass a `ref` to the `Modal` component in order to call the `showModal` function when you want to open the modal and the `close` function for closing it.

## ModalCore

Example of usage of ModalCore component :

```tsx
import { useRef } from "react";

export const YourComponent = () => {
const ref = useRef<HTMLDialogElement>(null);

return (
<>
<ButtonClient onClick={() => ref.current?.showModal()}>
Open the modal
</ButtonClient>

<ModalCore
onCancel={() => {}}
onClose={() => {}}
onSubmit={() => {}}
title="Modal title"
ref={ref}
>
<ModalCoreHeader
headingProps={{
children: "Modal title",
}}
iconProps={{ src: iconSrc }}
onClose={() => {}}
/>
<ModalCoreBody>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse
consectetur urna a tellus semper, id elementum ligula fermentum. In
semper quis mi eu commodo. Vivamus in metus eros. Sed ut pellentesque
purus. Maecenas congue ornare massa quis porttitor. Nullam ut diam
dapibus, consequat libero eget, faucibus nibh. Etiam imperdiet metus
at nulla fermentum semper. In ipsum urna, tempus vel lorem vel,
venenatis malesuada dui. Cras massa ipsum, accumsan et scelerisque ut,
vulputate at elit.
</ModalCoreBody>
<ModalCoreFooter
primaryButtonProps={{
children: "Valider",
}}
secondaryButtonProps={{
children: "Annuler",
}}
/>
</ModalCore>
</>
);
};
```

<Canvas of={ModalCoreStories.ModalCore} />

<Controls of={ModalCoreStories.ModalCore} />

## Modal

Example of usage of Modal component :

```tsx
import { useRef } from "react";

export const YourComponent = () => {
const ref = useRef<HTMLDialogElement>(null);

return (
<>
<button type="button" onClick={() => ref.current?.showModal()}>
Open modal
</button>

<Modal
ref={ref}
headingProps={{
firstSubtitle: "Modal subtitle",
}}
icon={iconSrc}
iconProps={{
variant: "primary",
}}
onCancel={() => {}}
onClose={() => {}}
primaryButtonProps={{
children: "Submit",
onClick: () => {},
}}
secondaryButtonProps={{
children: "Cancel",
onClick: () => {},
}}
title="Modal title"
>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
occaecat cupidatat non proident, sunt in culpa qui officia deserunt
mollit anim id est laborum. Curabitur pretium tincidunt lacus. Nulla
gravida orci a odio. Nullam varius, turpis et commodo pharetra, est eros
bibendum elit, nec luctus magna felis sollicitudin mauris
</Modal>
</>
);
};
```

<Canvas of={ModalStories.Playground} />

<Controls of={ModalStories.Playground} />
112 changes: 112 additions & 0 deletions apps/apollo-stories/src/components/Modal/Modal.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import "./Modal.story.scss";

import { Button, Modal } from "@axa-fr/design-system-apollo-react";
import bank from "@material-symbols/svg-700/rounded/account_balance.svg";
import { action } from "@storybook/addon-actions";
import type { Meta, StoryObj } from "@storybook/react";
import { fn } from "@storybook/test";
import { ComponentPropsWithRef, useLayoutEffect, useRef } from "react";

const meta: Meta<typeof Modal> = {
title: "Components/Modal",
component: Modal,
parameters: {
layout: "fullscreen",
viewport: { defaultViewport: "desktop" },
},
args: {
onClose: fn(),
onCancel: fn(),
},
};
export default meta;

type ModalStory = StoryObj<ComponentPropsWithRef<typeof Modal>>;

export const ModalContent: ModalStory = {
name: "Modal",
decorators: [
(Story, { args: { open, ...args } }) => {
const modalRef = useRef<HTMLDialogElement>(null);

useLayoutEffect(() => {
if (open) {
modalRef.current?.showModal();
return;
}

modalRef.current?.close();
}, [open]);

return <Story args={{ ...args, ref: modalRef }} />;
},
],
args: {
open: true,
title: "Modal title",
headingProps: {
firstSubtitle: "Modal subtitle",
},
icon: bank,
iconProps: { variant: "primary" },
children:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Curabitur pretium tincidunt lacus. Nulla gravida orci a odio. Nullam varius, turpis et commodo pharetra, est eros bibendum elit, nec luctus magna felis sollicitudin mauris",
secondaryButtonProps: {
children: "Cancel",
onClick: action("[Cancel] onClick"),
},
primaryButtonProps: {
children: "Submit",
onClick: action("[Submit] onClick"),
},
},
};

export const Playground: ModalStory = {
decorators: [
(Story, { args: { secondaryButtonProps = {}, ...args } }) => {
const ref = useRef<HTMLDialogElement>(null);

const onClose = () => {
args.onClose?.();
ref.current?.close();
};

const onClickSecondaryButton: React.MouseEventHandler<
HTMLButtonElement
> = (e) => {
secondaryButtonProps.onClick?.(e);
ref.current?.close();
};

return (
<>
<div className="button-wrapper">
<Button onClick={() => ref.current?.showModal()}>
Open the Modal
</Button>
</div>
<Story
args={{
...args,
ref,
onClose,
secondaryButtonProps: {
...secondaryButtonProps,
onClick: onClickSecondaryButton,
},
}}
/>
</>
);
},
],
args: { ...ModalContent.args, open: undefined },
};

export const MobilePlayground: ModalStory = {
...Playground,
parameters: {
viewport: { defaultViewport: "mobile1" },
},
};
7 changes: 7 additions & 0 deletions apps/apollo-stories/src/components/Modal/Modal.story.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.paragraph {
margin: 0;
}

.button-wrapper {
padding: 1rem;
}
108 changes: 108 additions & 0 deletions apps/apollo-stories/src/components/Modal/ModalCore.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import "./Modal.story.scss";

import {
Button,
ModalCoreBody,
ModalCore as ModalCoreComponent,
ModalCoreFooter,
ModalCoreHeader,
} from "@axa-fr/design-system-apollo-react";
import bank from "@material-symbols/svg-700/rounded/account_balance.svg";
import type { Meta, StoryObj } from "@storybook/react";
import { fn } from "@storybook/test";
import { useRef } from "react";

const meta: Meta<typeof ModalCoreComponent> = {
title: "Components/Modal/ModalCore",
component: ModalCoreComponent,
parameters: {
layout: "fullscreen",
},
args: {
onSubmit: fn(),
onCancel: fn(),
onClose: fn(),
},
};
export default meta;

type TModalCoreStory = StoryObj<typeof meta>;

export const ModalCore: TModalCoreStory = {
decorators: [
(Story, { args }) => {
const ref = useRef<HTMLDialogElement>(null);
const onClose = () => {
ref.current?.close();
args.onClose?.();
};
const children = (
<>
<ModalCoreHeader
headingProps={{ children: args.title }}
iconProps={{ src: bank }}
onClose={onClose as VoidFunction}
/>
<ModalCoreBody>{args.children}</ModalCoreBody>
<ModalCoreFooter
primaryButtonProps={{ children: "Valider" }}
secondaryButtonProps={{ children: "Annuler" }}
/>
</>
);

return (
<>
<div style={{ padding: 8 }}>
<Button onClick={() => ref.current?.showModal()}>
Open the modal
</Button>
</div>
<Story args={{ ...{ ...args, ref, onClose, children } }} />
</>
);
},
],
args: {
open: false,
title: "Modal title",
children: (
<>
<p className="paragraph">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse
consectetur urna a tellus semper, id elementum ligula fermentum. In
semper quis mi eu commodo. Vivamus in metus eros. Sed ut pellentesque
purus. Maecenas congue ornare massa quis porttitor. Nullam ut diam
dapibus, consequat libero eget, faucibus nibh. Etiam imperdiet metus
at nulla fermentum semper. In ipsum urna, tempus vel lorem vel,
venenatis malesuada dui. Cras massa ipsum, accumsan et scelerisque ut,
vulputate at elit.
</p>

<p className="paragraph">
Donec non quam neque. Nullam fermentum erat in sem fermentum euismod.
Phasellus sollicitudin condimentum diam ut euismod. Duis nec bibendum
metus. Ut convallis tincidunt risus. Nam vel ultricies augue. Donec
malesuada dolor et ligula egestas, sit amet ultrices libero bibendum.
Phasellus varius pulvinar lectus, a ultrices risus tempus ut. Aliquam
faucibus tortor lorem, et mattis dolor efficitur quis. Pellentesque
ipsum nunc, finibus nec velit eget, sodales lobortis leo.
</p>
<p className="paragraph">
Pellentesque venenatis est quis aliquam tristique. In tincidunt orci
ac ipsum vulputate, quis mattis orci commodo. Pellentesque at
hendrerit felis, pulvinar porttitor lorem. Sed vulputate quis diam sit
amet ultricies. Cras non nisl pharetra, ornare lectus sed, fringilla
turpis. Cras molestie velit in enim pretium, id vestibulum est luctus.
Ut mattis consequat magna, ac scelerisque massa consequat in. Proin
euismod pulvinar congue. Donec dapibus lorem tellus, dapibus dignissim
elit condimentum non. Donec luctus nulla a turpis mattis, vehicula
posuere quam convallis. Nullam gravida ante rutrum purus efficitur
hendrerit. Aenean magna tortor, cursus at ligula vel, aliquet iaculis
arcu. Praesent varius, purus eget interdum tempor, magna nisi pretium
neque, pharetra viverra leo neque at est.
</p>
</>
),
},
};
Loading