@cnamts/synapse 0.0.0-alpha.0 → 0.0.3-alpha
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/README.md +72 -2
- package/dist/design-system-v3.d.ts +234 -2
- package/dist/design-system-v3.js +1413 -4404
- package/dist/design-system-v3.umd.cjs +1 -2
- package/dist/style.css +1 -1
- package/package.json +37 -36
- package/src/components/Alert/Alert.vue +8 -8
- package/src/components/CollapsibleList/CollapsibleList.mdx +47 -0
- package/src/components/CollapsibleList/CollapsibleList.stories.ts +52 -0
- package/src/components/CollapsibleList/CollapsibleList.vue +157 -0
- package/src/components/CollapsibleList/tests/CollapsibleList.spec.ts +60 -0
- package/src/components/CollapsibleList/types.d.ts +5 -0
- package/src/components/Customs/CustomInputSelect/CustomInputSelect.mdx +42 -0
- package/src/components/Customs/CustomInputSelect/CustomInputSelect.stories.ts +154 -0
- package/src/components/Customs/CustomInputSelect/CustomInputSelect.vue +185 -0
- package/src/components/Customs/CustomInputSelect/tests/CustomInputSelect.spec.ts +216 -0
- package/src/components/Customs/CustomSelect/CustomSelect.mdx +47 -0
- package/src/components/Customs/CustomSelect/CustomSelect.stories.ts +182 -0
- package/src/components/Customs/CustomSelect/CustomSelect.vue +188 -0
- package/src/components/Customs/CustomSelect/tests/CustomSelect.spec.ts +236 -0
- package/src/components/FooterBar/A11yCompliance.ts +9 -0
- package/src/components/FooterBar/FooterBar.mdx +115 -0
- package/src/components/FooterBar/FooterBar.stories.ts +632 -0
- package/src/components/FooterBar/FooterBar.vue +330 -0
- package/src/components/FooterBar/config.ts +20 -0
- package/src/components/FooterBar/defaultSocialMediaLinks.ts +21 -0
- package/src/components/FooterBar/locales.ts +16 -0
- package/src/components/FooterBar/tests/FooterBar.spec.ts +167 -0
- package/src/components/FooterBar/tests/FooterBarConfig.spec.ts +36 -0
- package/src/components/FooterBar/tests/__snapshots__/FooterBar.spec.ts.snap +27 -0
- package/src/components/FooterBar/types.d.ts +10 -0
- package/src/components/FranceConnectBtn/FranceConnectBtn.vue +2 -2
- package/src/components/HeaderBar/HeaderBar.mdx +137 -0
- package/src/components/HeaderBar/HeaderBar.stories.ts +159 -0
- package/src/components/HeaderBar/HeaderBar.vue +238 -0
- package/src/components/HeaderBar/HeaderComplexMenu/HeaderComplexMenu.stories.ts +272 -0
- package/src/components/HeaderBar/HeaderComplexMenu/HeaderComplexMenu.vue +205 -0
- package/src/components/HeaderBar/HeaderComplexMenu/HeaderMenuItem/HeaderMenuItem.stories.ts +49 -0
- package/src/components/HeaderBar/HeaderComplexMenu/HeaderMenuItem/HeaderMenuItem.vue +51 -0
- package/src/components/HeaderBar/HeaderComplexMenu/HeaderMenuItem/tests/HeaderMenuItem.spec.ts +16 -0
- package/src/components/HeaderBar/HeaderComplexMenu/HeaderMenuItem/tests/__snapshots__/HeaderMenuItem.spec.ts.snap +3 -0
- package/src/components/HeaderBar/HeaderComplexMenu/HeaderMenuSection/HeaderMenuSection.stories.ts +56 -0
- package/src/components/HeaderBar/HeaderComplexMenu/HeaderMenuSection/HeaderMenuSection.vue +51 -0
- package/src/components/HeaderBar/HeaderComplexMenu/HeaderMenuSection/tests/HeaderMenuSection.spec.ts +33 -0
- package/src/components/HeaderBar/HeaderComplexMenu/HeaderSubMenu/HeaderSubMenu.stories.ts +137 -0
- package/src/components/HeaderBar/HeaderComplexMenu/HeaderSubMenu/HeaderSubMenu.vue +180 -0
- package/src/components/HeaderBar/HeaderComplexMenu/HeaderSubMenu/tests/HeaderSubMenu.spec.ts +63 -0
- package/src/components/HeaderBar/HeaderComplexMenu/conts.ts +1 -0
- package/src/components/HeaderBar/HeaderComplexMenu/locals.ts +4 -0
- package/src/components/HeaderBar/HeaderComplexMenu/tests/HeaderComplexMenu.spec.ts +129 -0
- package/src/components/HeaderBar/HeaderComplexMenu/tests/__snapshots__/HeaderComplexMenu.spec.ts.snap +18 -0
- package/src/components/HeaderBar/HeaderComplexMenu/tests/useHandleSubMenus.spec.ts +158 -0
- package/src/components/HeaderBar/HeaderComplexMenu/useHandleSubMenus.ts +49 -0
- package/src/components/HeaderBar/HeaderLogo/HeaderLogo.vue +106 -0
- package/src/components/HeaderBar/HeaderLogo/locales.ts +3 -0
- package/src/components/HeaderBar/HeaderLogo/logos/Logo-mobile.vue +117 -0
- package/src/components/HeaderBar/HeaderLogo/logos/Logo.vue +279 -0
- package/src/components/HeaderBar/HeaderLogo/tests/HeaderLogo.spec.ts +71 -0
- package/src/components/HeaderBar/HeaderMenuBtn/HeaderMenuBtn.vue +88 -0
- package/src/components/HeaderBar/HeaderMenuBtn/locals.ts +4 -0
- package/src/components/HeaderBar/consts.scss +7 -0
- package/src/components/HeaderBar/consts.ts +2 -0
- package/src/components/HeaderBar/locales.ts +3 -0
- package/src/components/HeaderBar/tests/HeaderBar.spec.ts +210 -0
- package/src/components/HeaderBar/tests/__snapshots__/HeaderBar.spec.ts.snap +50 -0
- package/src/components/HeaderBar/tests/useHeaderResponsiveMode.spec.ts +26 -0
- package/src/components/HeaderBar/tests/useScrollDirection.spec.ts +34 -0
- package/src/components/HeaderBar/useHeaderResponsiveMode.ts +25 -0
- package/src/components/HeaderBar/useScrollDirection.ts +26 -0
- package/src/components/LangBtn/LangBtn.mdx +2 -1
- package/src/components/LangBtn/LangBtn.vue +3 -3
- package/src/components/Logo/Logo.mdx +26 -0
- package/src/components/Logo/Logo.stories.ts +217 -0
- package/src/components/Logo/Logo.vue +397 -0
- package/src/components/Logo/LogoSize.ts +7 -0
- package/src/components/Logo/locales.ts +6 -0
- package/src/components/Logo/logoDimensionsMapping.ts +16 -0
- package/src/components/Logo/tests/Logo.spec.ts +75 -0
- package/src/components/Logo/types.d.ts +8 -0
- package/src/components/NotificationBar/NotificationBar.vue +5 -7
- package/src/components/PageContainer/PageContainer.vue +0 -1
- package/src/components/SocialMediaLinks/DefaultSocialMediaLinks.ts +21 -0
- package/src/components/SocialMediaLinks/SocialMediaLinks.mdx +15 -0
- package/src/components/SocialMediaLinks/SocialMediaLinks.stories.ts +72 -0
- package/src/components/SocialMediaLinks/SocialMediaLinks.vue +92 -0
- package/src/components/SocialMediaLinks/locales.ts +3 -0
- package/src/components/SocialMediaLinks/tests/DefaultSocialMediaLinks.spec.ts +21 -0
- package/src/components/SocialMediaLinks/tests/SocialMediaLinks.spec.ts +89 -0
- package/src/components/SocialMediaLinks/tests/__snapshots__/SocialMediaLinks.spec.ts.snap +24 -0
- package/src/components/SocialMediaLinks/types.d.ts +5 -0
- package/src/components/index.ts +6 -0
- package/src/directives/clickOutside.ts +24 -0
- package/src/temp/TestDTComponent.vue +6 -10
- package/src/temp/gridsTests.vue +0 -4
- package/src/utils/propValidator/index.ts +20 -0
- package/src/utils/propValidator/tests/propValidator.spec.ts +40 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { PropType } from 'vue'
|
|
3
|
+
import { locales } from './locales'
|
|
4
|
+
import type { SocialMediaLink } from './types'
|
|
5
|
+
|
|
6
|
+
const props = defineProps({
|
|
7
|
+
links: {
|
|
8
|
+
type: Array as PropType<SocialMediaLink[]>,
|
|
9
|
+
default: null,
|
|
10
|
+
},
|
|
11
|
+
})
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<template>
|
|
15
|
+
<div class="d-flex flex-column">
|
|
16
|
+
<span class="vd-social-media-links-label text-subtitle-2 text--primary">
|
|
17
|
+
{{ locales.followUs }}
|
|
18
|
+
</span>
|
|
19
|
+
|
|
20
|
+
<ul class="d-flex max-width-none">
|
|
21
|
+
<li
|
|
22
|
+
v-for="(social, index) in props.links"
|
|
23
|
+
:key="index"
|
|
24
|
+
>
|
|
25
|
+
<VBtn
|
|
26
|
+
:id="`social-btn-${index}`"
|
|
27
|
+
:href="social.href"
|
|
28
|
+
target="_blank"
|
|
29
|
+
rel="noopener noreferrer"
|
|
30
|
+
:icon="true"
|
|
31
|
+
:aria-label="`Lien vers ${social.name}`"
|
|
32
|
+
variant="text"
|
|
33
|
+
>
|
|
34
|
+
<VIcon
|
|
35
|
+
size="30px"
|
|
36
|
+
class="vd-social-media-links-icon"
|
|
37
|
+
>
|
|
38
|
+
{{ social.icon }}
|
|
39
|
+
</VIcon>
|
|
40
|
+
</VBtn>
|
|
41
|
+
</li>
|
|
42
|
+
</ul>
|
|
43
|
+
</div>
|
|
44
|
+
</template>
|
|
45
|
+
|
|
46
|
+
<style lang="scss" scoped>
|
|
47
|
+
@use '@/assets/tokens.scss';
|
|
48
|
+
|
|
49
|
+
.vd-social-media-links {
|
|
50
|
+
display: flex;
|
|
51
|
+
flex-direction: column;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
li {
|
|
55
|
+
list-style: none;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.vd-social-media-links-label.text--primary {
|
|
59
|
+
color: tokens.$blue-base;
|
|
60
|
+
font-weight: 600;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.v-theme--dark .vd-social-media-links-label.text--primary {
|
|
64
|
+
color: white;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.vd-social-media-links-icon {
|
|
68
|
+
color: tokens.$grey-base;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.v-btn--icon {
|
|
72
|
+
width: calc(var(--v-btn-height) + 5px);
|
|
73
|
+
height: calc(var(--v-btn-height) + 5px);
|
|
74
|
+
border: 0;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.v-theme--dark .v-btn--variant-text:hover :deep() {
|
|
78
|
+
background: rgba(white, 0.1);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@media (min-width: 768px) {
|
|
82
|
+
.vd-social-media-links-label {
|
|
83
|
+
text-align: right;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@media (max-width: 767px) {
|
|
88
|
+
.vd-social-media-links-label {
|
|
89
|
+
text-align: left;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
</style>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { defaultSocialMediaLinks } from '../DefaultSocialMediaLinks'
|
|
2
|
+
import { describe, it, expect } from 'vitest'
|
|
3
|
+
import { mdiLinkedin, mdiTwitter } from '@mdi/js'
|
|
4
|
+
|
|
5
|
+
describe('defaultSocialMediaLinks', () => {
|
|
6
|
+
it('contains the correct number of links', () => {
|
|
7
|
+
expect(defaultSocialMediaLinks.length).toBe(3)
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
it('contains the correct LinkedIn link', () => {
|
|
11
|
+
const linkedinLink = defaultSocialMediaLinks.find(link => link.href === 'https://www.linkedin.com/company/assurance-maladie/')
|
|
12
|
+
expect(linkedinLink).toBeDefined()
|
|
13
|
+
expect(linkedinLink?.icon).toBe(mdiLinkedin)
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
it('contains the correct Twitter link', () => {
|
|
17
|
+
const twitterLink = defaultSocialMediaLinks.find(link => link.href === 'https://twitter.com/Assur_Maladie')
|
|
18
|
+
expect(twitterLink).toBeDefined()
|
|
19
|
+
expect(twitterLink?.icon).toBe(mdiTwitter)
|
|
20
|
+
})
|
|
21
|
+
})
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { mount, VueWrapper } from '@vue/test-utils'
|
|
2
|
+
import SocialMediaLinks from '../SocialMediaLinks.vue'
|
|
3
|
+
import { describe, it, expect, afterEach } from 'vitest'
|
|
4
|
+
import { createVuetify } from 'vuetify'
|
|
5
|
+
import * as components from 'vuetify/components'
|
|
6
|
+
import * as directives from 'vuetify/directives'
|
|
7
|
+
|
|
8
|
+
const vuetify = createVuetify({
|
|
9
|
+
components,
|
|
10
|
+
directives,
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
describe('SocialMediaLinks.vue', () => {
|
|
14
|
+
let wrapper: VueWrapper
|
|
15
|
+
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
if (wrapper) {
|
|
18
|
+
wrapper.unmount()
|
|
19
|
+
}
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('renders correctly with default props', () => {
|
|
23
|
+
wrapper = mount(SocialMediaLinks, {
|
|
24
|
+
global: {
|
|
25
|
+
plugins: [vuetify],
|
|
26
|
+
},
|
|
27
|
+
props: {
|
|
28
|
+
links: undefined,
|
|
29
|
+
},
|
|
30
|
+
})
|
|
31
|
+
expect(wrapper.html()).toMatchSnapshot()
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('renders correctly with provided links', () => {
|
|
35
|
+
const links = [
|
|
36
|
+
{ href: 'https://twitter.com', name: 'Twitter', icon: 'mdi-twitter' },
|
|
37
|
+
{ href: 'https://facebook.com', name: 'Facebook', icon: 'mdi-facebook' },
|
|
38
|
+
]
|
|
39
|
+
wrapper = mount(SocialMediaLinks, {
|
|
40
|
+
global: {
|
|
41
|
+
plugins: [vuetify],
|
|
42
|
+
},
|
|
43
|
+
props: {
|
|
44
|
+
links,
|
|
45
|
+
},
|
|
46
|
+
})
|
|
47
|
+
expect(wrapper.html()).toMatchSnapshot()
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('renders the correct number of social media links', () => {
|
|
51
|
+
const links = [
|
|
52
|
+
{ href: 'https://twitter.com', name: 'Twitter', icon: 'mdi-twitter' },
|
|
53
|
+
{ href: 'https://facebook.com', name: 'Facebook', icon: 'mdi-facebook' },
|
|
54
|
+
]
|
|
55
|
+
wrapper = mount(SocialMediaLinks, {
|
|
56
|
+
global: {
|
|
57
|
+
plugins: [vuetify],
|
|
58
|
+
},
|
|
59
|
+
props: {
|
|
60
|
+
links,
|
|
61
|
+
},
|
|
62
|
+
})
|
|
63
|
+
expect(wrapper.findAll('li').length).toBe(links.length)
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('renders no links when links prop is empty array', () => {
|
|
67
|
+
wrapper = mount(SocialMediaLinks, {
|
|
68
|
+
global: {
|
|
69
|
+
plugins: [vuetify],
|
|
70
|
+
},
|
|
71
|
+
props: {
|
|
72
|
+
links: [],
|
|
73
|
+
},
|
|
74
|
+
})
|
|
75
|
+
expect(wrapper.findAll('li').length).toBe(0)
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('renders no links when links prop is null', () => {
|
|
79
|
+
wrapper = mount(SocialMediaLinks, {
|
|
80
|
+
global: {
|
|
81
|
+
plugins: [vuetify],
|
|
82
|
+
},
|
|
83
|
+
props: {
|
|
84
|
+
links: undefined,
|
|
85
|
+
},
|
|
86
|
+
})
|
|
87
|
+
expect(wrapper.findAll('li').length).toBe(0)
|
|
88
|
+
})
|
|
89
|
+
})
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`SocialMediaLinks.vue > renders correctly with default props 1`] = `
|
|
4
|
+
"<div data-v-9d3df26f="" class="d-flex flex-column"><span data-v-9d3df26f="" class="vd-social-media-links-label text-subtitle-2 text--primary">Suivez-nous :</span>
|
|
5
|
+
<ul data-v-9d3df26f="" class="d-flex max-width-none"></ul>
|
|
6
|
+
</div>"
|
|
7
|
+
`;
|
|
8
|
+
|
|
9
|
+
exports[`SocialMediaLinks.vue > renders correctly with provided links 1`] = `
|
|
10
|
+
"<div data-v-9d3df26f="" class="d-flex flex-column"><span data-v-9d3df26f="" class="vd-social-media-links-label text-subtitle-2 text--primary">Suivez-nous :</span>
|
|
11
|
+
<ul data-v-9d3df26f="" class="d-flex max-width-none">
|
|
12
|
+
<li data-v-9d3df26f=""><a data-v-9d3df26f="" class="v-btn v-btn--icon v-theme--light v-btn--density-default v-btn--size-default v-btn--variant-text" href="https://twitter.com" id="social-btn-0" target="_blank" rel="noopener noreferrer" aria-label="Lien vers Twitter"><span class="v-btn__overlay"></span><span class="v-btn__underlay"></span>
|
|
13
|
+
<!----><span class="v-btn__content" data-no-activator=""><i data-v-9d3df26f="" class="mdi-twitter mdi v-icon notranslate v-theme--light vd-social-media-links-icon" style="font-size: 30px; height: 30px; width: 30px;" aria-hidden="true"></i></span>
|
|
14
|
+
<!---->
|
|
15
|
+
<!---->
|
|
16
|
+
</a></li>
|
|
17
|
+
<li data-v-9d3df26f=""><a data-v-9d3df26f="" class="v-btn v-btn--icon v-theme--light v-btn--density-default v-btn--size-default v-btn--variant-text" href="https://facebook.com" id="social-btn-1" target="_blank" rel="noopener noreferrer" aria-label="Lien vers Facebook"><span class="v-btn__overlay"></span><span class="v-btn__underlay"></span>
|
|
18
|
+
<!----><span class="v-btn__content" data-no-activator=""><i data-v-9d3df26f="" class="mdi-facebook mdi v-icon notranslate v-theme--light vd-social-media-links-icon" style="font-size: 30px; height: 30px; width: 30px;" aria-hidden="true"></i></span>
|
|
19
|
+
<!---->
|
|
20
|
+
<!---->
|
|
21
|
+
</a></li>
|
|
22
|
+
</ul>
|
|
23
|
+
</div>"
|
|
24
|
+
`;
|
package/src/components/index.ts
CHANGED
|
@@ -3,6 +3,12 @@ export { default as Alert } from './Alert/Alert.vue'
|
|
|
3
3
|
export { default as CopyBtn } from './CopyBtn/CopyBtn.vue'
|
|
4
4
|
export { default as SkipLink } from './SkipLink/SkipLink.vue'
|
|
5
5
|
export { default as BackToTopBtn } from './BackToTopBtn/BackToTopBtn.vue'
|
|
6
|
+
export { default as BackBtn } from './BackBtn/BackBtn.vue'
|
|
7
|
+
export { default as DownloadBtn } from './DownloadBtn/DownloadBtn.vue'
|
|
6
8
|
export { default as FranceConnectBtn } from './FranceConnectBtn/FranceConnectBtn.vue'
|
|
7
9
|
export { default as NotificationBar } from './NotificationBar/NotificationBar.vue'
|
|
8
10
|
export { default as LangBtn } from './LangBtn/LangBtn.vue'
|
|
11
|
+
export { default as Logo } from './Logo/Logo.vue'
|
|
12
|
+
export { default as CollapsibleList } from './CollapsibleList/CollapsibleList.vue'
|
|
13
|
+
export { default as SocialMediaLinks } from './SocialMediaLinks/SocialMediaLinks.vue'
|
|
14
|
+
export { default as FooterBar } from './FooterBar/FooterBar.vue'
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { createApp } from 'vue'
|
|
2
|
+
|
|
3
|
+
const app = createApp({})
|
|
4
|
+
|
|
5
|
+
// Click Outside Directive
|
|
6
|
+
app.directive('click-outside', {
|
|
7
|
+
beforeMount(el, binding) {
|
|
8
|
+
el.clickOutsideEvent = function (event: Event) {
|
|
9
|
+
// Check if the click is outside the element
|
|
10
|
+
if (!(el === event.target || el.contains(event.target))) {
|
|
11
|
+
// If so, call the method provided in the binding
|
|
12
|
+
binding.value(event)
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
// Attach the event listener
|
|
16
|
+
document.addEventListener('click', el.clickOutsideEvent)
|
|
17
|
+
},
|
|
18
|
+
unmounted(el) {
|
|
19
|
+
// Clean up the event listener
|
|
20
|
+
document.removeEventListener('click', el.clickOutsideEvent)
|
|
21
|
+
},
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
app.mount('#app')
|
|
@@ -74,20 +74,16 @@
|
|
|
74
74
|
</template>
|
|
75
75
|
|
|
76
76
|
<style lang="scss" scoped>
|
|
77
|
-
|
|
78
|
-
@import '../assets/tokens';
|
|
79
|
-
========
|
|
80
|
-
@import '../../../assets/tokens';
|
|
81
|
-
>>>>>>>> 82f4bcd (chore(deps): update dependency vue to v3.5.2 (#66)):src/components/Temp/TestDesignTokensComponent/TestDTComponent.vue
|
|
77
|
+
@use '@/assets/tokens.scss';
|
|
82
78
|
|
|
83
79
|
h1 {
|
|
84
|
-
color:
|
|
80
|
+
color: tokens.$orange-base;
|
|
85
81
|
}
|
|
86
82
|
|
|
87
83
|
button {
|
|
88
|
-
background-color:
|
|
89
|
-
color:
|
|
90
|
-
border-radius:
|
|
91
|
-
//padding:
|
|
84
|
+
background-color: tokens.$blue-base;
|
|
85
|
+
color: tokens.$white-base;
|
|
86
|
+
border-radius: tokens.$radius-rounded;
|
|
87
|
+
//padding: tokens.$padding-10 tokens.$padding-4;
|
|
92
88
|
}
|
|
93
89
|
</style>
|
package/src/temp/gridsTests.vue
CHANGED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Validate a prop against a set of values */
|
|
2
|
+
export function propValidator(
|
|
3
|
+
propName: string,
|
|
4
|
+
acceptedValues: string[],
|
|
5
|
+
value: string,
|
|
6
|
+
): boolean {
|
|
7
|
+
const stringValues = acceptedValues.join('|')
|
|
8
|
+
const formattedValues = `(${stringValues})`
|
|
9
|
+
const valuesRegexp = new RegExp(`^${formattedValues}$`)
|
|
10
|
+
|
|
11
|
+
const isValid = value.match(valuesRegexp) !== null
|
|
12
|
+
|
|
13
|
+
if (!isValid) {
|
|
14
|
+
console.error(
|
|
15
|
+
`Invalid value for the \`${propName}\` prop. Received: "${value}", expected one of: [${acceptedValues.join(', ')}].`,
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return true
|
|
20
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {
|
|
2
|
+
describe,
|
|
3
|
+
it,
|
|
4
|
+
expect,
|
|
5
|
+
afterEach,
|
|
6
|
+
vi,
|
|
7
|
+
beforeEach,
|
|
8
|
+
} from 'vitest'
|
|
9
|
+
import { propValidator } from '../index'
|
|
10
|
+
|
|
11
|
+
const PROP_NAME = 'test'
|
|
12
|
+
const ACCEPTED_VALUES = ['value1', 'value2']
|
|
13
|
+
|
|
14
|
+
describe('propValidator', () => {
|
|
15
|
+
let consoleErrorSpy: unknown
|
|
16
|
+
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
consoleErrorSpy = vi
|
|
19
|
+
.spyOn(console, 'error')
|
|
20
|
+
.mockImplementation(() => {})
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('does not log anything if the prop is valid', () => {
|
|
24
|
+
const result = propValidator(PROP_NAME, ACCEPTED_VALUES, 'value1')
|
|
25
|
+
|
|
26
|
+
expect(result).toBeTruthy()
|
|
27
|
+
expect(consoleErrorSpy).not.toHaveBeenCalled()
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it('logs an error if the prop is not valid', () => {
|
|
31
|
+
const result = propValidator(PROP_NAME, ACCEPTED_VALUES, 'wrongValue')
|
|
32
|
+
|
|
33
|
+
expect(result).toBeTruthy()
|
|
34
|
+
expect(consoleErrorSpy).toHaveBeenCalled()
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
afterEach(() => {
|
|
38
|
+
vi.restoreAllMocks()
|
|
39
|
+
})
|
|
40
|
+
})
|