Skip to content

Commit 937a690

Browse files
committed
refactor(tabs): ♻️ modernise DsfrTabContent avec defineSlots et story CSF3
## Pourquoi les changements ont été faits : - Moderniser le composant DsfrTabContent pour utiliser les dernières conventions Vue 3 - Améliorer la documentation des slots disponibles pour les développeurs - Convertir la story Storybook au format CSF3 moderne pour une meilleure maintenabilité ## Quelles modifications ont été apportées : - Ajout de defineSlots avec documentation du slot par défaut - Conversion de la story ContenuDOnglet au format CSF3 avec Meta/StoryObj - Remplacement de data() par setup() utilisant ref pour selectedTabIndex - Utilisation de ref pour gérer l'état réactif de l'onglet sélectionné - Conservation de toute la logique de transition et d'injection existante
1 parent 527ece5 commit 937a690

File tree

2 files changed

+61
-28
lines changed

2 files changed

+61
-28
lines changed
Lines changed: 54 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
import type { Meta, StoryObj } from '@storybook/vue3'
2+
3+
import { ref } from 'vue'
4+
15
import DsfrTabContent from './DsfrTabContent.vue'
26
import DsfrTabs from './DsfrTabs.vue'
37

4-
export default {
8+
const meta = {
59
component: DsfrTabContent,
610
title: 'Composants/DsfrTabs',
711
argTypes: {
@@ -15,30 +19,47 @@ export default {
1519
description:
1620
'Props de et `DsfrTabContent`: Identifiant du titre de l’onglet ̛ ; doit être identique à la props `panel-id` du `DsfrTabContent` correspondant - **Obligatoire**',
1721
},
18-
selected: {
19-
control: 'boolean',
22+
selectedTabIndex: {
23+
control: 'number',
2024
description:
21-
'Indique si cet onglet est celui sélectionné (`true`) ou non (`false`, défaut)',
25+
'Index de l’onglet sélectionné (0 pour le premier onglet)',
26+
table: {
27+
category: 'Props du parent (DsfrTabs)',
28+
},
2229
},
23-
asc: {
24-
control: 'boolean',
25-
description:
26-
'Indique si l’onglet suivant à afficher est à droite (`true`, ascendant) ou à gauche (`false`)',
30+
tabListName: {
31+
control: 'text',
32+
description: 'Nom de la liste d’onglet (utilisée dans le aria-label de la liste `<ul>`)',
33+
table: {
34+
category: 'Props du parent (DsfrTabs)',
35+
},
36+
},
37+
tabTitles: {
38+
control: 'object',
39+
description: 'Titres des onglets',
40+
table: {
41+
category: 'Props du parent (DsfrTabs)',
42+
},
2743
},
2844
},
29-
}
45+
} satisfies Meta<typeof DsfrTabContent>
3046

31-
export const ContenuDOnglet = (args) => ({
32-
components: {
33-
DsfrTabs,
34-
DsfrTabContent,
35-
},
47+
export default meta
3648

37-
data () {
38-
return args
39-
},
49+
type Story = StoryObj<typeof meta>
50+
51+
export const ContenuDOnglet: Story = {
52+
render: (args) => ({
53+
components: {
54+
DsfrTabs,
55+
DsfrTabContent,
56+
},
4057

41-
template: `
58+
setup () {
59+
return args
60+
},
61+
62+
template: `
4263
<DsfrTabs
4364
v-model="selectedTabIndex"
4465
:tab-list-name="tabListName"
@@ -52,13 +73,19 @@ export const ContenuDOnglet = (args) => ({
5273
</DsfrTabContent>
5374
</DsfrTabs>
5475
`,
55-
})
56-
ContenuDOnglet.args = {
57-
panelId: 'tab-content-0',
58-
tabId: 'tab-0',
59-
selectedTabIndex: 0,
60-
tabListName: 'Liste d’onglet',
61-
tabTitles: [
62-
{ title: 'Titre 1', icon: 'ri-checkbox-circle-line', tabId: 'tab-0', panelId: 'tab-content-0' },
63-
],
76+
}),
77+
args: {
78+
panelId: 'tab-content-0',
79+
selectedTabIndex: 0,
80+
tabId: 'tab-0',
81+
tabListName: 'Liste d\'onglet',
82+
tabTitles: [
83+
{
84+
title: 'Titre 1',
85+
icon: 'ri-checkbox-circle-line',
86+
tabId: 'tab-0',
87+
panelId: 'tab-content-0',
88+
},
89+
],
90+
},
6491
}

src/components/DsfrTabs/DsfrTabContent.vue

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ export type DsfrTabContentProps = {
99
}
1010
const props = defineProps<DsfrTabContentProps>()
1111
12+
defineSlots<{
13+
/**
14+
* Slot par défaut pour le contenu de l’onglet. Sera dans `<div class="fr-tabs__panel">`
15+
*/
16+
default?: () => any
17+
}>()
18+
1219
const values = { true: '100%', false: '-100%' }
1320
const useTab = inject(registerTabKey)!
1421
const { isVisible, asc } = useTab(toRef(() => props.tabId))
@@ -34,7 +41,6 @@ const translateValueTo = computed(() => values[String(!asc?.value)])
3441
:aria-labelledby="tabId"
3542
:tabindex="isVisible ? 0 : -1"
3643
>
37-
<!-- @slot Slot par défaut pour le contenu de l’onglet. Sera dans `<div class="fr-tabs__panel">` -->
3844
<slot />
3945
</div>
4046
</Transition>

0 commit comments

Comments
 (0)