Skip to content

Commit

Permalink
feat: add DsfrDataTableV2 and DsfrTabsV2.vue
Browse files Browse the repository at this point in the history
  • Loading branch information
iNeoO committed Oct 2, 2024
1 parent 51a88c8 commit 0bd8da6
Show file tree
Hide file tree
Showing 5 changed files with 447 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .talismanrc
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,14 @@ fileignoreconfig:
checksum: e064a2ee73c2ecb4da219f78c7458302383d264330cc7bf645239519f906f64f
- filename: packages/shared/src/components/Chat.vue
checksum: f2dbbf72bf098c7abd2c3aee230d220f5a5a106952883c0e116eb49f4f9d4db7
- filename: packages/shared/src/components/DsfrTabsV2.vue
checksum: 960c18a7ad76a91c74e5535240ae6ac4f87bb8aff10155096cd35afe5609cff8
- filename: packages/shared/src/components/PasswordInput.vue
checksum: af4fe62dc455e943fcfacaa6ee0495e1ab20f9ed2094ad70c457b7a27ab46759
- filename: packages/shared/src/components/Table/DsfrDataTableV2.vue
checksum: 234f0db9a3e3dd4fbff644f2f597f87e4ab0ed08847b14f128482ea6b0aa7732
- filename: packages/shared/src/type.ts
checksum: 8c75e8784ded25a61d6e14cd682bfe67e4ecdde5a6582fb83035fcae39a87b98
- filename: pg/scripts/01-init.sql
checksum: 20dd5b8d36b1b0517fe185d30003af7866ef5678eed4e7571a6d9797ec3b2a46
- filename: pg/scripts/02/02-1-geo-init.sql
Expand Down
175 changes: 175 additions & 0 deletions packages/shared/src/components/DsfrTabsV2.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
<script lang="ts" setup>
import { onMounted, onUnmounted, ref, computed } from "vue";
const props = defineProps<{
tabs: {
label: string;
tabPanelId: string;
tabId: string;
}[];
modelValue: number;
}>();
const emits = defineEmits<{
"update:modelValue": [number];
}>();
const activeTab = computed({
get() {
return props.modelValue;
},
set(value) {
emits("update:modelValue", value);
},
});
const tabsStyle = ref({ "--tabs-height": "100px" });
const $el = ref<HTMLElement | null>(null);
const tablist = ref<HTMLUListElement | null>(null);
const renderTabs = () => {
if (activeTab.value < 0) {
return;
}
if (!tablist.value || !tablist.value.offsetHeight) {
return;
}
const tablistHeight = tablist.value.offsetHeight;
const selectedTab = $el.value?.querySelector(".fr-tabs__panel");
if (!selectedTab || !(selectedTab as HTMLElement).offsetHeight) {
return;
}
const selectedTabHeight = (selectedTab as HTMLElement).offsetHeight;
tabsStyle.value["--tabs-height"] = `${tablistHeight + selectedTabHeight}px`;
};
const animationDirection = ref("right");
const selectTab = (index: number) => {
unobservePanel();
animationDirection.value = activeTab.value > index ? "left" : "right";
activeTab.value = index;
};
const selectPrevious = () => {
unobservePanel();
const newIndex =
activeTab.value === 0 ? props.tabs.length - 1 : activeTab.value - 1;
animationDirection.value = "left";
activeTab.value = newIndex;
};
const selectNext = () => {
unobservePanel();
const newIndex =
activeTab.value === props.tabs.length - 1 ? 0 : activeTab.value + 1;
animationDirection.value = "right";
activeTab.value = newIndex;
};
const selectFirst = () => {
unobservePanel();
animationDirection.value = "left";
activeTab.value = 0;
};
const selectLast = () => {
unobservePanel();
animationDirection.value = "right";
activeTab.value = props.tabs.length - 1;
};
const observePanel = () => {
const panel = $el.value?.querySelector(".fr-tabs__panel");
if (panel) {
resizeObserver.value?.observe(panel);
}
};
const unobservePanel = () => {
const panel = $el.value?.querySelector(".fr-tabs__panel");
if (panel) {
resizeObserver.value?.unobserve(panel);
}
};
const resizeObserver = ref<ResizeObserver | null>(null);
onMounted(() => {
if (window.ResizeObserver) {
resizeObserver.value = new window.ResizeObserver(() => {
renderTabs();
});
}
observePanel();
});
onUnmounted(() => {
unobservePanel();
});
const animationEnd = () => {
renderTabs();
observePanel();
};
</script>

<template>
<div ref="$el" class="fr-tabs" :style="tabsStyle">
<ul
ref="tablist"
class="fr-tabs__list"
role="tablist"
aria-label="[A modifier | nom du système d'onglet]"
>
<dsfr-tab-item
v-for="(tab, index) in tabs"
:key="tab.tabId"
:label="tab.label"
:tab-id="tab.tabId"
:tab-panel-id="tab.tabPanelId"
:selected="activeTab === index"
@click="selectTab(index)"
@next="selectNext()"
@previous="selectPrevious()"
@first="selectFirst()"
@last="selectLast()"
/>
</ul>
<transition
:name="`translate-fade-${animationDirection}`"
mode="out-in"
@after-leave="animationEnd"
>
<slot />
</transition>
</div>
</template>

<style scoped>
.translate-fade-right-enter-active,
.translate-fade-right-leave-active {
transition: all 0.25s ease-out;
}
.translate-fade-right-enter-from {
opacity: 0;
transform: translateX(100%);
}
.translate-fade-right-leave-to {
opacity: 0;
transform: translateX(-100%);
}
.translate-fade-left-enter-active,
.translate-fade-left-leave-active {
transition: all 0.25s ease-out;
}
.translate-fade-left-enter-from {
opacity: 0;
transform: translateX(-100%);
}
.translate-fade-left-leave-to {
opacity: 0;
transform: translateX(100%);
}
</style>
Loading

0 comments on commit 0bd8da6

Please sign in to comment.