Skip to content

Commit 7b87b0c

Browse files
fix(DsfrTabs): Fixes #425 - Calc tabs-height CSS property, added Storybook example
1 parent 514c6d9 commit 7b87b0c

File tree

2 files changed

+128
-4
lines changed

2 files changed

+128
-4
lines changed

src/components/DsfrTabs/DsfrTabs.stories.js

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import DsfrTabContent from './DsfrTabContent.vue'
44
import { addIcons } from 'oh-vue-icons'
55

66
import { RiCheckboxCircleLine } from 'oh-vue-icons/icons/ri/index.js'
7+
import DsfrAccordionsGroup from '../DsfrAccordion/DsfrAccordionsGroup.vue'
8+
import DsfrAccordion from '../DsfrAccordion/DsfrAccordion.vue'
79

810
addIcons(RiCheckboxCircleLine)
911

@@ -160,3 +162,96 @@ OngletsComplexes.args = {
160162
selectedTabIndex: 1,
161163
initialSelectedIndex: 1,
162164
}
165+
166+
export const OngletsAvecAccordeon = (args) => ({
167+
components: { DsfrTabs, DsfrTabContent, DsfrAccordionsGroup, DsfrAccordion },
168+
data () {
169+
return {
170+
...args,
171+
asc: true,
172+
}
173+
},
174+
175+
template: `
176+
<DsfrTabs
177+
:tab-list-name="tabListName"
178+
:tab-titles="tabTitles"
179+
:initial-selected-index="initialSelectedIndex"
180+
@select-tab="selectTab"
181+
>
182+
<DsfrTabContent
183+
panel-id="tab-content-0"
184+
tab-id="tab-0"
185+
:selected="selectedTabIndex === 0"
186+
:asc="asc"
187+
>
188+
<DsfrAccordionsGroup>
189+
<li>
190+
<DsfrAccordion
191+
id="accordion-1"
192+
:title="title1"
193+
:expanded-id="expandedId"
194+
@expand="expandedId = $event"
195+
>
196+
Contenu de l’accordéon 1
197+
</DsfrAccordion>
198+
</li>
199+
<li>
200+
<DsfrAccordion
201+
id="accordion-2"
202+
:title="title2"
203+
:expanded-id="expandedId"
204+
@expand="id => expandedId = id"
205+
>
206+
Contenu de l’accordéon 2
207+
</DsfrAccordion>
208+
</li>
209+
<li>
210+
<DsfrAccordion
211+
id="accordion-3"
212+
:title="title3"
213+
:expanded-id="expandedId"
214+
@expand="id => expandedId = id"
215+
>
216+
Contenu de l’accordéon 3
217+
</DsfrAccordion>
218+
</li>
219+
</DsfrAccordionsGroup>
220+
</DsfrTabContent>
221+
222+
<DsfrTabContent
223+
panel-id="tab-content-1"
224+
tab-id="tab-1"
225+
:selected="selectedTabIndex === 1"
226+
:asc="asc"
227+
>
228+
<div>Contenu 2 avec d'autres composants</div>
229+
</DsfrTabContent>
230+
</DsfrTabs>
231+
`,
232+
233+
methods: {
234+
selectTab (idx) {
235+
this.onSelectTab(idx)
236+
this.asc = this.selectedTabIndex < idx
237+
this.selectedTabIndex = idx
238+
},
239+
},
240+
241+
mounted () {
242+
document.body.parentElement.setAttribute('data-fr-theme', this.dark ? 'dark' : 'light')
243+
},
244+
})
245+
OngletsAvecAccordeon.args = {
246+
dark: false,
247+
tabListName,
248+
tabTitles: [
249+
{ title: 'Onglet avec accordéon', icon: 'ri-checkbox-circle-line', tabId: 'tab-0', panelId: 'tab-content-0' },
250+
{ title: 'Titre 2', icon: 'ri-checkbox-circle-line', tabId: 'tab-1', panelId: 'tab-content-1' },
251+
],
252+
selectedTabIndex: 0,
253+
initialSelectedIndex: 0,
254+
title1: 'Un titre d’accordéon 1',
255+
title2: 'Un titre d’accordéon 2',
256+
expandedId: '',
257+
}

src/components/DsfrTabs/DsfrTabs.vue

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ export default defineComponent({
4747
}
4848
},
4949
50+
mounted () {
51+
this.renderTabs()
52+
},
53+
5054
methods: {
5155
isSelected (idx) {
5256
return this.selectedIndex === idx
@@ -63,20 +67,44 @@ export default defineComponent({
6367
this.asc = idx > this.selectedIndex
6468
this.selectedIndex = idx
6569
this.$emit('select-tab', idx)
70+
await this.$nextTick()
71+
this.renderTabs()
6672
},
6773
async selectPrevious () {
6874
const newIndex = this.selectedIndex === 0 ? this.tabTitles.length - 1 : this.selectedIndex - 1
69-
this.selectIndex(newIndex)
75+
await this.selectIndex(newIndex)
7076
},
7177
async selectNext () {
7278
const newIndex = this.selectedIndex === this.tabTitles.length - 1 ? 0 : this.selectedIndex + 1
73-
this.selectIndex(newIndex)
79+
await this.selectIndex(newIndex)
7480
},
7581
async selectFirst () {
76-
this.selectIndex(0)
82+
await this.selectIndex(0)
7783
},
7884
async selectLast () {
79-
this.selectIndex(this.tabTitles.length - 1)
85+
await this.selectIndex(this.tabTitles.length - 1)
86+
},
87+
/*
88+
* Need to reimplement tab-height calc
89+
* @see https://github.com/GouvernementFR/dsfr/blob/main/src/component/tab/script/tab/tabs-group.js#L117
90+
*/
91+
renderTabs () {
92+
if (this.selectedIndex < 0) {
93+
return
94+
}
95+
const tablist = this.$refs.tablist
96+
if (!tablist || !tablist.offsetHeight) {
97+
return
98+
}
99+
const tablistHeight = tablist.offsetHeight
100+
// Need to manually select tabs-content in case of manual slot filling
101+
const selectedTab = this.$el.querySelectorAll('.fr-tabs__panel')[this.selectedIndex]
102+
if (!selectedTab || !selectedTab.offsetHeight) {
103+
return
104+
}
105+
const selectedTabHeight = selectedTab.offsetHeight
106+
107+
this.$el.style.setProperty('--tabs-height', (tablistHeight + selectedTabHeight) + 'px')
80108
},
81109
},
82110
})
@@ -85,6 +113,7 @@ export default defineComponent({
85113
<template>
86114
<div class="fr-tabs">
87115
<ul
116+
ref="tablist"
88117
class="fr-tabs__list"
89118
role="tablist"
90119
:aria-label="tabListName"

0 commit comments

Comments
 (0)