@ouestfrance/sipa-bms-ui 8.17.0 → 8.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/navigation/BmsTabs.vue.d.ts +6 -1
- package/dist/components/navigation/UiTab.vue.d.ts +5 -4
- package/dist/components/navigation/UiTabs.vue.d.ts +21 -0
- package/dist/helpers/tab.helper.d.ts +2 -0
- package/dist/models/tab.model.d.ts +5 -0
- package/dist/sipa-bms-ui.css +22 -15
- package/dist/sipa-bms-ui.es.js +275 -198
- package/dist/sipa-bms-ui.es.js.map +1 -1
- package/dist/sipa-bms-ui.umd.js +282 -205
- package/dist/sipa-bms-ui.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/components/layout/BmsFloatingWindow.vue +1 -0
- package/src/components/navigation/BmsTabs.stories.js +58 -4
- package/src/components/navigation/BmsTabs.vue +53 -33
- package/src/components/navigation/UiTab.stories.js +5 -5
- package/src/components/navigation/UiTab.vue +15 -20
- package/src/components/navigation/UiTabs.stories.js +34 -0
- package/src/components/navigation/UiTabs.vue +76 -0
- package/src/helpers/tab.helper.ts +3 -0
- package/src/models/tab.model.ts +6 -0
package/package.json
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import BmsTabs from '@/components/navigation/BmsTabs.vue';
|
|
2
|
+
import { vueRouter } from 'storybook-vue3-router';
|
|
2
3
|
|
|
3
4
|
export default {
|
|
4
5
|
title: 'Composants/navigation/Tabs',
|
|
@@ -6,6 +7,21 @@ export default {
|
|
|
6
7
|
argTypes: {
|
|
7
8
|
items: {},
|
|
8
9
|
},
|
|
10
|
+
decorators: [
|
|
11
|
+
vueRouter([
|
|
12
|
+
{
|
|
13
|
+
name: 'titi',
|
|
14
|
+
path: '/titi',
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
path: '/',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: 'toto',
|
|
21
|
+
path: '/toto',
|
|
22
|
+
},
|
|
23
|
+
]),
|
|
24
|
+
],
|
|
9
25
|
};
|
|
10
26
|
|
|
11
27
|
const Template = (args) => ({
|
|
@@ -20,11 +36,49 @@ const Template = (args) => ({
|
|
|
20
36
|
`,
|
|
21
37
|
});
|
|
22
38
|
|
|
23
|
-
export const
|
|
24
|
-
|
|
39
|
+
export const Default = Template.bind({});
|
|
40
|
+
Default.args = {
|
|
41
|
+
title: 'Title',
|
|
42
|
+
tabs: [{ name: 'Titi', id: 'titi' }, { name: 'Toto' }],
|
|
43
|
+
};
|
|
44
|
+
export const WithSelectedTabId = Template.bind({});
|
|
45
|
+
WithSelectedTabId.args = {
|
|
46
|
+
title: 'Title',
|
|
47
|
+
initialTabId: 'Toto',
|
|
48
|
+
tabs: [
|
|
49
|
+
{ name: 'Titi', id: 'titi' },
|
|
50
|
+
{ name: 'Tata' },
|
|
51
|
+
{ name: 'Toto' },
|
|
52
|
+
{ name: 'Tutu' },
|
|
53
|
+
],
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const WithRouterEngine = Template.bind({});
|
|
57
|
+
WithRouterEngine.args = {
|
|
58
|
+
title: 'Title',
|
|
59
|
+
initialTabId: 'titi',
|
|
60
|
+
tabs: [
|
|
61
|
+
{ name: 'Titi', routeName: 'titi', id: 'titi' },
|
|
62
|
+
{ name: 'Toto', routePath: '/toto' },
|
|
63
|
+
],
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const WithError = Template.bind({});
|
|
67
|
+
WithError.args = {
|
|
68
|
+
title: 'Title',
|
|
69
|
+
initialTabId: 'titi',
|
|
70
|
+
tabs: [
|
|
71
|
+
{ name: 'Titi', routeName: 'titi', id: 'titi' },
|
|
72
|
+
{ name: 'Toto', routePath: '/toto', error: true },
|
|
73
|
+
],
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export const WithDisabled = Template.bind({});
|
|
77
|
+
WithDisabled.args = {
|
|
25
78
|
title: 'Title',
|
|
79
|
+
initialTabId: 'titi',
|
|
26
80
|
tabs: [
|
|
27
|
-
{ name: 'Titi',
|
|
28
|
-
{ name: 'Toto', routePath: 'toto' },
|
|
81
|
+
{ name: 'Titi', routeName: 'titi', id: 'titi' },
|
|
82
|
+
{ name: 'Toto', routePath: '/toto', disabled: true },
|
|
29
83
|
],
|
|
30
84
|
};
|
|
@@ -1,46 +1,66 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
:
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
2
|
+
<UiTabs
|
|
3
|
+
:title="title"
|
|
4
|
+
:tabs="tabs"
|
|
5
|
+
:initial-tab-id="selectedTabId"
|
|
6
|
+
@click="$emits('click', $event)"
|
|
7
|
+
>
|
|
8
|
+
<template v-if="needRouterEngine" #router="{ tab }">
|
|
9
|
+
<router-link class="tab" :to="getTabTarget(tab)">{{
|
|
10
|
+
tab.name
|
|
11
|
+
}}</router-link>
|
|
12
|
+
</template>
|
|
13
|
+
</UiTabs>
|
|
13
14
|
</template>
|
|
14
15
|
|
|
15
16
|
<script setup lang="ts">
|
|
16
|
-
import { useRouter } from 'vue-router';
|
|
17
17
|
import { Tab } from '@/models/tab.model';
|
|
18
|
-
import
|
|
18
|
+
import UiTabs from './UiTabs.vue';
|
|
19
|
+
import { computed, ComputedRef, onMounted, ref, watch } from 'vue';
|
|
20
|
+
import { RouteLocation, useRouter } from 'vue-router';
|
|
21
|
+
import { getTabId } from '@/helpers/tab.helper';
|
|
19
22
|
|
|
20
23
|
const { currentRoute } = useRouter();
|
|
21
24
|
|
|
22
|
-
defineProps<{
|
|
23
|
-
|
|
25
|
+
const props = defineProps<{
|
|
26
|
+
title: string;
|
|
27
|
+
tabs: Tab[];
|
|
28
|
+
initialTabId?: string;
|
|
29
|
+
}>();
|
|
24
30
|
|
|
25
|
-
|
|
26
|
-
.
|
|
27
|
-
|
|
28
|
-
align-items: center;
|
|
29
|
-
border-bottom: 1px solid var(--bms-grey-25);
|
|
30
|
-
box-sizing: border-box;
|
|
31
|
+
const getTabTarget = (tab: Tab) => {
|
|
32
|
+
return tab.routePath ? { path: tab.routePath } : { name: tab.routeName };
|
|
33
|
+
};
|
|
31
34
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
const $emits = defineEmits<{
|
|
36
|
+
(e: 'click', tab: Tab): void;
|
|
37
|
+
}>();
|
|
35
38
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
const needRouterEngine = computed(() => {
|
|
40
|
+
return (
|
|
41
|
+
!!props.tabs &&
|
|
42
|
+
!!props.tabs[0] &&
|
|
43
|
+
!!(props.tabs[0].routePath || props.tabs[0].routeName)
|
|
44
|
+
);
|
|
45
|
+
});
|
|
40
46
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
const selectedTabId: ComputedRef<string | null> = computed(() => {
|
|
48
|
+
if (needRouterEngine.value) {
|
|
49
|
+
const selectedTab =
|
|
50
|
+
props.tabs.find((t) => isTabSelected(t, currentRoute.value)) || null;
|
|
51
|
+
return selectedTab ? getTabId(selectedTab) : null;
|
|
52
|
+
} else if (props.initialTabId) {
|
|
53
|
+
return props.initialTabId;
|
|
54
|
+
} else {
|
|
55
|
+
return null;
|
|
44
56
|
}
|
|
45
|
-
}
|
|
46
|
-
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const isTabSelected = (tab: Tab, currentRoute: RouteLocation) =>
|
|
60
|
+
tab.routePath
|
|
61
|
+
? currentRoute.path.includes(tab.routePath)
|
|
62
|
+
: tab.routeName
|
|
63
|
+
? !!currentRoute.name &&
|
|
64
|
+
(currentRoute.name as string).includes(tab.routeName)
|
|
65
|
+
: false;
|
|
66
|
+
</script>
|
|
@@ -30,31 +30,31 @@ const Template = (args) => ({
|
|
|
30
30
|
|
|
31
31
|
export const Default = Template.bind({});
|
|
32
32
|
Default.args = {
|
|
33
|
-
|
|
33
|
+
selectedTabId: 'toto',
|
|
34
34
|
tab: { name: 'Titi', routePath: 'titi' },
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
export const Active = Template.bind({});
|
|
38
38
|
Active.args = {
|
|
39
|
-
|
|
39
|
+
selectedTabId: 'Titi',
|
|
40
40
|
tab: { name: 'Titi', routePath: 'titi' },
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
export const Disabled = Template.bind({});
|
|
44
44
|
Disabled.args = {
|
|
45
|
-
|
|
45
|
+
selectedTabId: 'toto',
|
|
46
46
|
tab: { name: 'Titi', routePath: 'titi', disabled: true },
|
|
47
47
|
};
|
|
48
48
|
|
|
49
49
|
export const Error = Template.bind({});
|
|
50
50
|
Error.args = {
|
|
51
|
-
|
|
51
|
+
selectedTabId: 'toto',
|
|
52
52
|
tab: { name: 'Titi', routePath: 'titi', error: true },
|
|
53
53
|
};
|
|
54
54
|
|
|
55
55
|
export const Hover = Template.bind({});
|
|
56
56
|
Hover.args = {
|
|
57
|
-
|
|
57
|
+
selectedTabId: 'toto',
|
|
58
58
|
tab: { name: 'Titi', routePath: 'titi' },
|
|
59
59
|
};
|
|
60
60
|
Hover.play = async ({ canvasElement }) => {
|
|
@@ -1,40 +1,30 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
:to="tabTarget"
|
|
2
|
+
<span
|
|
4
3
|
data-testid="tab"
|
|
5
4
|
class="tab"
|
|
6
5
|
:class="{ active: isTabSelected, error: tab.error, disabled: tab.disabled }"
|
|
7
6
|
>
|
|
8
|
-
<slot>{{ tab.name }}</slot>
|
|
9
|
-
</
|
|
7
|
+
<slot name="router" :tab="tab">{{ tab.name }}</slot>
|
|
8
|
+
</span>
|
|
10
9
|
</template>
|
|
11
10
|
|
|
12
11
|
<script lang="ts" setup>
|
|
13
12
|
import { Tab } from '@/models/tab.model';
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
13
|
+
import { computed, ComputedRef } from 'vue';
|
|
14
|
+
import { getTabId } from '@/helpers/tab.helper';
|
|
16
15
|
|
|
17
16
|
const props = withDefaults(
|
|
18
17
|
defineProps<{
|
|
19
|
-
|
|
18
|
+
selectedTabId: string | null;
|
|
20
19
|
tab: Tab;
|
|
21
20
|
}>(),
|
|
22
21
|
{},
|
|
23
22
|
);
|
|
24
23
|
|
|
25
|
-
const
|
|
26
|
-
props.tab.routePath
|
|
27
|
-
? props.currentRoute.path.includes(props.tab.routePath)
|
|
28
|
-
: props.tab.routeName
|
|
29
|
-
? !!props.currentRoute.name &&
|
|
30
|
-
(props.currentRoute.name as string).includes(props.tab.routeName)
|
|
31
|
-
: false,
|
|
32
|
-
);
|
|
24
|
+
const tabId = computed(() => getTabId(props.tab));
|
|
33
25
|
|
|
34
|
-
const
|
|
35
|
-
props.
|
|
36
|
-
? { path: props.tab.routePath }
|
|
37
|
-
: { name: props.tab.routeName },
|
|
26
|
+
const isTabSelected: ComputedRef<boolean> = computed(
|
|
27
|
+
() => (tabId.value && tabId.value === props.selectedTabId) || false,
|
|
38
28
|
);
|
|
39
29
|
</script>
|
|
40
30
|
|
|
@@ -47,10 +37,15 @@ const tabTarget: ComputedRef<RouteLocationRaw> = computed(() =>
|
|
|
47
37
|
text-decoration: none;
|
|
48
38
|
border-bottom: 4px solid var(--tab-border-color);
|
|
49
39
|
padding: 0 8px 16px 8px;
|
|
50
|
-
|
|
40
|
+
cursor: pointer;
|
|
41
|
+
:deep(a) {
|
|
42
|
+
color: var(--tab-color);
|
|
43
|
+
text-decoration: none;
|
|
44
|
+
}
|
|
51
45
|
&:hover,
|
|
52
46
|
&__hover {
|
|
53
47
|
--tab-border-color: var(--bms-main-50);
|
|
48
|
+
text-decoration: none;
|
|
54
49
|
}
|
|
55
50
|
|
|
56
51
|
&.active {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import UiTabs from '@/components/navigation/UiTabs.vue';
|
|
2
|
+
import template from '@/documentation/template_field_dependency.mdx';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
parameters: {
|
|
6
|
+
docs: {
|
|
7
|
+
page: template,
|
|
8
|
+
},
|
|
9
|
+
},
|
|
10
|
+
title: 'Composants/navigation/UiTabs',
|
|
11
|
+
component: UiTabs,
|
|
12
|
+
argTypes: {
|
|
13
|
+
items: {},
|
|
14
|
+
},
|
|
15
|
+
tags: ['technical'],
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const Template = (args) => ({
|
|
19
|
+
components: {
|
|
20
|
+
UiTabs,
|
|
21
|
+
},
|
|
22
|
+
setup() {
|
|
23
|
+
return { args };
|
|
24
|
+
},
|
|
25
|
+
template: `
|
|
26
|
+
<UiTabs v-bind="args" />
|
|
27
|
+
`,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
export const Primary = Template.bind({});
|
|
31
|
+
Primary.args = {
|
|
32
|
+
title: 'Title',
|
|
33
|
+
tabs: [{ name: 'Titi', id: 'titi' }, { name: 'Toto' }],
|
|
34
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="tabs-header">
|
|
3
|
+
<div class="tabs-title">
|
|
4
|
+
<h3>{{ title }}</h3>
|
|
5
|
+
</div>
|
|
6
|
+
<UiTab
|
|
7
|
+
v-for="tab in tabs"
|
|
8
|
+
:key="getTabId(tab)"
|
|
9
|
+
:selectedTabId="selectedTabId"
|
|
10
|
+
:tab="tab"
|
|
11
|
+
@click="onTabClick(tab)"
|
|
12
|
+
>
|
|
13
|
+
<template #router="{ tab }"><slot name="router" :tab="tab" /></template>
|
|
14
|
+
</UiTab>
|
|
15
|
+
</div>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<script setup lang="ts">
|
|
19
|
+
import { Tab } from '@/models/tab.model';
|
|
20
|
+
import UiTab from './UiTab.vue';
|
|
21
|
+
import { computed, ComputedRef, onMounted, ref, watch } from 'vue';
|
|
22
|
+
import { getTabId } from '@/helpers/tab.helper';
|
|
23
|
+
|
|
24
|
+
const props = defineProps<{
|
|
25
|
+
title: string;
|
|
26
|
+
tabs: Tab[];
|
|
27
|
+
initialTabId?: string | null;
|
|
28
|
+
}>();
|
|
29
|
+
|
|
30
|
+
const selectedTabId = ref<string | null>(null);
|
|
31
|
+
|
|
32
|
+
onMounted(() => {
|
|
33
|
+
selectedTabId.value = props.initialTabId || null;
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
watch(
|
|
37
|
+
() => props.initialTabId,
|
|
38
|
+
() => {
|
|
39
|
+
selectedTabId.value = props.initialTabId || null;
|
|
40
|
+
},
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const $emits = defineEmits<{
|
|
44
|
+
(e: 'click', value: any): void;
|
|
45
|
+
}>();
|
|
46
|
+
|
|
47
|
+
const onTabClick = (tab: Tab) => {
|
|
48
|
+
if (getTabId(tab) !== selectedTabId.value) {
|
|
49
|
+
$emits('click', tab);
|
|
50
|
+
selectedTabId.value = getTabId(tab);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<style lang="scss" scoped>
|
|
56
|
+
.tabs-header {
|
|
57
|
+
display: flex;
|
|
58
|
+
align-items: center;
|
|
59
|
+
border-bottom: 1px solid var(--bms-grey-25);
|
|
60
|
+
box-sizing: border-box;
|
|
61
|
+
|
|
62
|
+
.tabs-title {
|
|
63
|
+
margin-right: auto;
|
|
64
|
+
margin-bottom: 16px;
|
|
65
|
+
|
|
66
|
+
h3 {
|
|
67
|
+
margin: 0;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
span {
|
|
72
|
+
position: relative;
|
|
73
|
+
top: 1px;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
</style>
|
package/src/models/tab.model.ts
CHANGED