Merge branch 'button' into 'main'
Button See merge request cellule-financiere-pmo/design-system/visua-vue!1
This commit is contained in:
commit
772bf1418f
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -30,3 +30,4 @@ coverage
|
||||||
*.tsbuildinfo
|
*.tsbuildinfo
|
||||||
|
|
||||||
.npmrc
|
.npmrc
|
||||||
|
template
|
||||||
|
|
|
@ -10,6 +10,11 @@ cache:
|
||||||
- node_modules/
|
- node_modules/
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
|
- echo "@cellule-financiere-pmo:registry=https://gitlab.com/api/v4/projects/71595796/packages/npm/" > .npmrc
|
||||||
|
- echo "//gitlab.com/api/v4/projects/71595796/packages/npm/:username=${NPM_DEPLOY_USER}" >> .npmrc
|
||||||
|
- echo "//gitlab.com/api/v4/projects/71595796/packages/npm/:_password=$(echo -n ${NPM_DEPLOY_TOKEN} | base64)" >> .npmrc
|
||||||
|
- echo "//gitlab.com/api/v4/projects/71595796/packages/npm/:email=ci@example.com" >> .npmrc
|
||||||
|
- echo "//gitlab.com/api/v4/projects/71595796/packages/npm/:always-auth=true" >> .npmrc
|
||||||
- npm ci
|
- npm ci
|
||||||
|
|
||||||
unit-tests:
|
unit-tests:
|
||||||
|
@ -21,14 +26,11 @@ unit-tests:
|
||||||
- coverage/
|
- coverage/
|
||||||
expire_in: 1 month
|
expire_in: 1 month
|
||||||
only:
|
only:
|
||||||
- branches
|
|
||||||
- merge_requests
|
- merge_requests
|
||||||
|
|
||||||
publish-npm:
|
publish-npm:
|
||||||
stage: deploy
|
stage: deploy
|
||||||
script:
|
script:
|
||||||
- echo "@cellule-financiere-pmo:registry=https://${CI_SERVER_HOST}/api/v4/projects/${CI_PROJECT_ID}/packages/npm/" > .npmrc
|
|
||||||
- echo "//${CI_SERVER_HOST}/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=${CI_JOB_TOKEN}" >> .npmrc
|
|
||||||
- npm publish
|
- npm publish
|
||||||
only:
|
only:
|
||||||
- tags
|
- tags
|
1101
package-lock.json
generated
1101
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
@ -13,7 +13,8 @@
|
||||||
"test:unit": "vitest run --coverage"
|
"test:unit": "vitest run --coverage"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cellule-financiere-pmo/visua": "^1.1.0",
|
"@cellule-financiere-pmo/visua": "1.1.3",
|
||||||
|
"jsdom": "^26.1.0",
|
||||||
"primevue": "^4.3.6",
|
"primevue": "^4.3.6",
|
||||||
"vite-plugin-inspect": "^11.3.0",
|
"vite-plugin-inspect": "^11.3.0",
|
||||||
"vue": "^3.5.17"
|
"vue": "^3.5.17"
|
||||||
|
@ -22,6 +23,7 @@
|
||||||
"@tsconfig/node22": "^22.0.2",
|
"@tsconfig/node22": "^22.0.2",
|
||||||
"@types/node": "^22.15.32",
|
"@types/node": "^22.15.32",
|
||||||
"@vitejs/plugin-vue": "^6.0.0",
|
"@vitejs/plugin-vue": "^6.0.0",
|
||||||
|
"@vitest/coverage-v8": "^3.2.4",
|
||||||
"@vue/eslint-config-typescript": "^14.5.1",
|
"@vue/eslint-config-typescript": "^14.5.1",
|
||||||
"@vue/test-utils": "^2.4.6",
|
"@vue/test-utils": "^2.4.6",
|
||||||
"@vue/tsconfig": "^0.7.0",
|
"@vue/tsconfig": "^0.7.0",
|
||||||
|
@ -32,6 +34,7 @@
|
||||||
"typescript": "~5.8.0",
|
"typescript": "~5.8.0",
|
||||||
"vite": "^7.0.0",
|
"vite": "^7.0.0",
|
||||||
"vite-plugin-vue-devtools": "^7.7.7",
|
"vite-plugin-vue-devtools": "^7.7.7",
|
||||||
|
"vitest": "^3.2.4",
|
||||||
"vue-tsc": "^2.2.10"
|
"vue-tsc": "^2.2.10"
|
||||||
},
|
},
|
||||||
"description": "**Current version: v0.0.0**",
|
"description": "**Current version: v0.0.0**",
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import VButtonView from '../template/VButtonView.vue'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VButtonView/>
|
||||||
|
</template>
|
|
@ -1,6 +1,7 @@
|
||||||
/* Adding styles */
|
/* Adding styles */
|
||||||
@import '../../../node_modules/@cellule-financiere-pmo/visua/output/variables.css';
|
@import '@visua/variables.css';
|
||||||
@import './global.css';
|
@import './style/global.css';
|
||||||
|
@import './style/primevue-configuration.css';
|
||||||
|
|
||||||
/* Basic setup */
|
/* Basic setup */
|
||||||
html {
|
html {
|
1
src/assets/main.css
Normal file
1
src/assets/main.css
Normal file
|
@ -0,0 +1 @@
|
||||||
|
@import './base.css';
|
1
src/assets/style/primevue-configuration.css
Normal file
1
src/assets/style/primevue-configuration.css
Normal file
|
@ -0,0 +1 @@
|
||||||
|
@import './primevue-style/button.css';
|
67
src/assets/style/primevue-style/button.css
Normal file
67
src/assets/style/primevue-style/button.css
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
:root{
|
||||||
|
/* global style */
|
||||||
|
--p-button-border-radius: 0px;
|
||||||
|
--p-button-gap: 0.5rem;
|
||||||
|
--p-button-label-font-weight: var(--text-body-MD-standard-text-Regular-weight);
|
||||||
|
/* size: normal */
|
||||||
|
--p-button-padding-x: 1rem;
|
||||||
|
--p-button-padding-y: 0.5rem;
|
||||||
|
--p-button-icon-only-width: 2.5rem;
|
||||||
|
/* size: small */
|
||||||
|
--p-button-sm-padding-x: 0.75rem;
|
||||||
|
--p-button-sm-padding-y: 0.25rem;
|
||||||
|
--p-button-sm-font-size: var(--text-body-SM-detail-text-Regular-size);
|
||||||
|
--p-button-sm-icon-only-width: 2rem;
|
||||||
|
/* size: large */
|
||||||
|
--p-button-lg-padding-x: 1.5rem;
|
||||||
|
--p-button-lg-padding-y: 0.625rem;
|
||||||
|
--p-button-lg-font-size: var(--text-body-LG-article-text-Medium-size);
|
||||||
|
--p-button-lg-icon-only-width: 3rem;
|
||||||
|
/* variant: primary or default */
|
||||||
|
--p-button-primary-background: var(--background-action-high-blue-france);
|
||||||
|
--p-button-primary-hover-background: var(--background-action-high-blue-france-hover);
|
||||||
|
--p-button-primary-active-background: var(--background-action-high-blue-france-active);
|
||||||
|
--p-button-primary-border-color: transparent;
|
||||||
|
--p-button-primary-hover-border-color: transparent;
|
||||||
|
--p-button-primary-active-border-color: transparent;
|
||||||
|
--p-button-primary-color: var(--text-inverted-blue-france);
|
||||||
|
--p-button-primary-hover-color: var(--text-inverted-blue-france);
|
||||||
|
--p-button-primary-active-color: var(--text-inverted-blue-france);
|
||||||
|
/* variant: secondary */
|
||||||
|
--p-button-secondary-background: var(--background-transparent);
|
||||||
|
--p-button-secondary-hover-background: var(--background-transparent-hover);
|
||||||
|
--p-button-secondary-active-background: var(--background-transparent-active);
|
||||||
|
--p-button-secondary-border-color: var(--border-action-high-blue-france);
|
||||||
|
--p-button-secondary-hover-border-color: var(--border-action-high-blue-france);
|
||||||
|
--p-button-secondary-active-border-color: var(--border-action-high-blue-france);
|
||||||
|
--p-button-outlined-secondary-hover-background: var(--background-transparent-hover);
|
||||||
|
--p-button-outlined-secondary-active-background: var(--background-transparent-active);
|
||||||
|
--p-button-outlined-secondary-border-color: var(--border-action-high-blue-france);
|
||||||
|
--p-button-outlined-secondary-color: var(--text-action-high-blue-france);
|
||||||
|
/* variant: tertiary */
|
||||||
|
--p-button-outlined-primary-hover-background: var(--background-transparent-hover);
|
||||||
|
--p-button-outlined-primary-active-background: var(--background-transparent-active);
|
||||||
|
--p-button-outlined-primary-border-color: var(--border-default-grey);
|
||||||
|
--p-button-outlined-primary-color: var(--text-action-high-blue-france);
|
||||||
|
/* variant: no-outline */
|
||||||
|
--p-button-text-primary-hover-background: var(--background-transparent-hover);
|
||||||
|
--p-button-text-primary-active-background: var(--background-transparent-active);
|
||||||
|
--p-button-text-primary-color: var(--text-action-high-blue-france);
|
||||||
|
/* variant: danger */
|
||||||
|
--p-button-danger-background: var(--primary-color-425-red-marianne-default);
|
||||||
|
--p-button-danger-hover-background: var(--primary-color-425-red-marianne-hover);
|
||||||
|
--p-button-danger-active-background: var(--primary-color-425-red-marianne-active);
|
||||||
|
--p-button-danger-border-color: transparent;
|
||||||
|
--p-button-danger-hover-border-color: transparent;
|
||||||
|
--p-button-danger-active-border-color: transparent;
|
||||||
|
--p-button-danger-color: var(--text-inverted-blue-france);
|
||||||
|
--p-button-danger-hover-color: var(--text-inverted-blue-france);
|
||||||
|
--p-button-danger-active-color: var(--text-inverted-blue-france);
|
||||||
|
/* focus */
|
||||||
|
--p-button-focus-ring-width: var(--focus-width);
|
||||||
|
--p-button-focus-ring-style: var(--focus-style);
|
||||||
|
--p-button-focus-ring-offset: var(--focus-offset);
|
||||||
|
--p-button-primary-focus-ring-color: var(--focus-color);
|
||||||
|
--p-button-secondary-focus-ring-color: var(--focus-color);
|
||||||
|
--p-button-danger-focus-ring-color: var(--focus-color);
|
||||||
|
}
|
74
src/components/button/IVButton.type.ts
Normal file
74
src/components/button/IVButton.type.ts
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
import type { ButtonHTMLAttributes } from "vue"
|
||||||
|
/**
|
||||||
|
* Interface representing the properties of a single button component.
|
||||||
|
*/
|
||||||
|
export default interface IVButton {
|
||||||
|
/** Whether the button is disabled */
|
||||||
|
disabled?: boolean;
|
||||||
|
|
||||||
|
/** Text label displayed on the button */
|
||||||
|
label?: string;
|
||||||
|
|
||||||
|
/** Applies the secondary button style */
|
||||||
|
secondary?: boolean;
|
||||||
|
|
||||||
|
/** Applies the tertiary button style */
|
||||||
|
tertiary?: boolean;
|
||||||
|
|
||||||
|
/** Displays the icon on the right side of the button */
|
||||||
|
iconRight?: boolean;
|
||||||
|
|
||||||
|
/** Displays only the icon without any label */
|
||||||
|
iconOnly?: boolean;
|
||||||
|
|
||||||
|
/** Removes the default outline style */
|
||||||
|
noOutline?: boolean;
|
||||||
|
|
||||||
|
/** Applies a danger style to the button */
|
||||||
|
danger?: boolean;
|
||||||
|
|
||||||
|
/** Size of the button */
|
||||||
|
size?: 'sm' | 'small' | 'lg' | 'large' | 'md' | 'medium' | '' | undefined;
|
||||||
|
|
||||||
|
/** Name of the icon to display */
|
||||||
|
icon?: string;
|
||||||
|
|
||||||
|
/** Click event handler */
|
||||||
|
onClick?: ($event: MouseEvent) => void;
|
||||||
|
|
||||||
|
/** Tooltip or accessibility title for the button (required) */
|
||||||
|
title: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface representing a group of buttons with layout and style options.
|
||||||
|
*/
|
||||||
|
export default interface IVButtonGroup {
|
||||||
|
/**
|
||||||
|
* Array of buttons to display in the group.
|
||||||
|
* Each button can include standard HTML button attributes.
|
||||||
|
*/
|
||||||
|
buttons?: (IVButton & ButtonHTMLAttributes)[];
|
||||||
|
|
||||||
|
/** Reverses the order of the buttons */
|
||||||
|
reverse?: boolean;
|
||||||
|
|
||||||
|
/** Makes all buttons in the group the same width */
|
||||||
|
equisized?: boolean;
|
||||||
|
|
||||||
|
/** Aligns icons to the right for all buttons */
|
||||||
|
iconRight?: boolean;
|
||||||
|
|
||||||
|
/** Alignment of the button group */
|
||||||
|
align?: 'right' | 'center' | '' | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controls when the layout should switch to inline.
|
||||||
|
* Can be based on screen size or always/never.
|
||||||
|
*/
|
||||||
|
inlineLayoutWhen?: 'always' | 'never' | 'sm' | 'small' | 'lg' | 'large' | 'md' | 'medium' | '' | true | undefined;
|
||||||
|
|
||||||
|
/** Size of all buttons in the group */
|
||||||
|
size?: 'sm' | 'small' | 'lg' | 'large' | 'md' | 'medium' | '' | undefined;
|
||||||
|
}
|
||||||
|
|
120
src/components/button/VButton.vue
Normal file
120
src/components/button/VButton.vue
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import Button from 'primevue/button';
|
||||||
|
import type IVButton from './IVButton.type';
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import styles from '@visua/typography.module.css';
|
||||||
|
|
||||||
|
// Props configuration with default values
|
||||||
|
const props = withDefaults(defineProps<IVButton>(), {
|
||||||
|
disabled: false,
|
||||||
|
label: undefined,
|
||||||
|
secondary: false,
|
||||||
|
tertiary: false,
|
||||||
|
iconRight: false,
|
||||||
|
iconOnly: false,
|
||||||
|
noOutline: false,
|
||||||
|
danger: false,
|
||||||
|
size: 'md',
|
||||||
|
icon: '',
|
||||||
|
onClick: () => undefined,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Button size class computed
|
||||||
|
const size = computed(() => {
|
||||||
|
if (['sm', 'small'].includes(props.size)) return 'small';
|
||||||
|
else if (['md', 'medium', '', undefined].includes(props.size)) return undefined;
|
||||||
|
else if (['lg', 'large'].includes(props.size)) return 'large';
|
||||||
|
else return undefined;
|
||||||
|
})
|
||||||
|
|
||||||
|
// Icon position computed
|
||||||
|
const iconPos = computed<string>(() => {
|
||||||
|
return props.iconRight ? 'right': 'left'
|
||||||
|
})
|
||||||
|
|
||||||
|
// Button variant computed
|
||||||
|
const variant = computed(() => {
|
||||||
|
if(props.noOutline) return 'text';
|
||||||
|
else if (props.secondary || props.tertiary) return 'outlined';
|
||||||
|
else return undefined;
|
||||||
|
})
|
||||||
|
|
||||||
|
// Button severity computed
|
||||||
|
const severity = computed(() => {
|
||||||
|
if(props.secondary) return 'secondary';
|
||||||
|
else if(props.danger) return 'danger';
|
||||||
|
else return undefined
|
||||||
|
});
|
||||||
|
|
||||||
|
// Button font computed
|
||||||
|
const font = computed(() => {
|
||||||
|
switch (size.value) {
|
||||||
|
case 'large': return styles['text-body-LG-article-text-Regular'];
|
||||||
|
case 'small': return styles['text-body-SM-detail-text-Regular'];
|
||||||
|
default: return styles['text-body-MD-standard-text-Regular'];
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Button
|
||||||
|
:label="props.iconOnly ? undefined : props.label"
|
||||||
|
:variant="variant"
|
||||||
|
:severity="severity"
|
||||||
|
:icon="props.icon"
|
||||||
|
:size="size"
|
||||||
|
:class="['p-button', font]"
|
||||||
|
v-bind="$attrs"
|
||||||
|
:disabled="props.disabled"
|
||||||
|
:aria-disabled="props.disabled"
|
||||||
|
:icon-pos="iconPos"
|
||||||
|
:onclick="props.onClick"
|
||||||
|
:title="props.title"
|
||||||
|
role="button"
|
||||||
|
:aria-label="props.label"
|
||||||
|
>
|
||||||
|
</Button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* disable state */
|
||||||
|
.p-button:disabled{
|
||||||
|
/* variant: primary or default */
|
||||||
|
--p-button-primary-background: var(--background-disabled-grey);
|
||||||
|
--p-button-primary-hover-background: var(--background-disabled-grey);
|
||||||
|
--p-button-primary-active-background: var(--background-disabled-grey);
|
||||||
|
--p-button-primary-color: var(--text-disabled-grey);
|
||||||
|
--p-button-primary-hover-color: var(--text-disabled-grey);
|
||||||
|
--p-button-primary-active-color: var(--text-disabled-grey);
|
||||||
|
/* variant: danger */
|
||||||
|
--p-button-danger-background: var(--background-disabled-grey);
|
||||||
|
--p-button-danger-hover-background: var(--background-disabled-grey);
|
||||||
|
--p-button-danger-active-background: var(--background-disabled-grey);
|
||||||
|
--p-button-danger-color: var(--text-disabled-grey);
|
||||||
|
--p-button-danger-hover-color: var(--text-disabled-grey);
|
||||||
|
--p-button-danger-active-color: var(--text-disabled-grey);
|
||||||
|
/* variant: secondary and tertiary */
|
||||||
|
--p-button-secondary-background: var(--background-transparent);
|
||||||
|
--p-button-secondary-hover-background: var(--background-transparent);
|
||||||
|
--p-button-secondary-active-background: var(--background-transparent);
|
||||||
|
--p-button-secondary-border-color: var(--border-disabled-grey);
|
||||||
|
--p-button-secondary-hover-border-color: var(--border-disabled-grey);
|
||||||
|
--p-button-secondary-active-border-color: var(--border-disabled-grey);
|
||||||
|
|
||||||
|
--p-button-outlined-primary-hover-background: var(--background-transparent);
|
||||||
|
--p-button-outlined-primary-active-background: var(--background-transparent);
|
||||||
|
--p-button-outlined-primary-border-color: var(--border-disabled-grey);
|
||||||
|
--p-button-outlined-primary-color: var(--text-disabled-grey);
|
||||||
|
--p-button-outlined-secondary-hover-background: var(--background-transparent);
|
||||||
|
--p-button-outlined-secondary-active-background: var(--background-transparent);
|
||||||
|
--p-button-outlined-secondary-border-color: var(--border-disabled-grey);
|
||||||
|
--p-button-outlined-secondary-color: var(--text-disabled-grey);
|
||||||
|
/* variant: no-outline */
|
||||||
|
--p-button-text-primary-hover-background: var(--background-transparent);
|
||||||
|
--p-button-text-primary-active-background: var(--background-transparent);
|
||||||
|
--p-button-text-primary-color: var(--text-disabled-grey);
|
||||||
|
-webkit-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,6 +1,10 @@
|
||||||
import './assets/main.css'
|
import './assets/main.css'
|
||||||
|
|
||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
|
import primeVue from 'primevue/config'
|
||||||
|
|
||||||
createApp(App).mount('#app')
|
const app = createApp(App)
|
||||||
|
|
||||||
|
app.use(primeVue)
|
||||||
|
|
||||||
|
app.mount('#app')
|
||||||
|
|
212
test/VButton.spec.ts
Normal file
212
test/VButton.spec.ts
Normal file
|
@ -0,0 +1,212 @@
|
||||||
|
import { mount } from '@vue/test-utils'
|
||||||
|
import VButton from '@/components/button/VButton.vue'
|
||||||
|
import {test, expect, describe, vi} from 'vitest'
|
||||||
|
|
||||||
|
describe('VButton', () => {
|
||||||
|
test('Displays button label', () => {
|
||||||
|
const wrapper = mount(VButton, {
|
||||||
|
props: {
|
||||||
|
label: 'button label',
|
||||||
|
title: 'button'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// Check that the props label has gone through
|
||||||
|
expect(wrapper.props('label')).toBe('button label')
|
||||||
|
// Checks that the rendering contains the expected value
|
||||||
|
expect(wrapper.text()).toContain('button label')
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Displays only icon button when iconOnly props is set', () => {
|
||||||
|
const wrapper = mount(VButton, {
|
||||||
|
props: {
|
||||||
|
icon: 'ri-settings-4-line',
|
||||||
|
iconOnly: true,
|
||||||
|
label: 'label',
|
||||||
|
title: 'button'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const button = wrapper.find('button')
|
||||||
|
// check the rendering doesn't contain any button label
|
||||||
|
expect(button.text()).toBe('')
|
||||||
|
// Check the icon is present
|
||||||
|
const icon = button.find('.p-button-icon')
|
||||||
|
expect(icon.exists()).toBe(true)
|
||||||
|
expect(icon.classes()).toContain('ri-settings-4-line')
|
||||||
|
// check that the aria-label attribute is correctly defined
|
||||||
|
expect(button.attributes('aria-label')).toBe('label')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('Displays label and button icon when both are set', () => {
|
||||||
|
const wrapper = mount(VButton, {
|
||||||
|
props: {
|
||||||
|
title: 'button',
|
||||||
|
label: 'label',
|
||||||
|
icon: 'ri-settings-4-line'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const button = wrapper.find('button')
|
||||||
|
// check the rendering contains button label value
|
||||||
|
expect(button.text()).toBe('label')
|
||||||
|
// Check the icon is present
|
||||||
|
const icon = button.find('.p-button-icon')
|
||||||
|
expect(icon.exists()).toBe(true)
|
||||||
|
expect(icon.classes()).toContain('ri-settings-4-line')
|
||||||
|
// check if the button icon is shown on left by default
|
||||||
|
expect(icon.classes()).toContain('p-button-icon-left')
|
||||||
|
// check that the aria-label attribute is correctly defined
|
||||||
|
expect(button.attributes('aria-label')).toBe('label')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('Displays button icon on right when iconRight props is set', () => {
|
||||||
|
const wrapper = mount(VButton, {
|
||||||
|
props: {
|
||||||
|
title: 'button',
|
||||||
|
label: 'label',
|
||||||
|
icon: 'ri-settings-4-line',
|
||||||
|
iconRight: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const button = wrapper.find('button')
|
||||||
|
// Check if button icon is on right
|
||||||
|
const iconRight = button.find('.p-button-icon-right')
|
||||||
|
expect(iconRight.exists()).toBe(true)
|
||||||
|
expect(iconRight.classes()).not.toContain('p-button-icon-left')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('Disabled button', async () => {
|
||||||
|
const onClick = vi.fn()
|
||||||
|
const wrapper = mount(VButton, {
|
||||||
|
props: {
|
||||||
|
title: 'button',
|
||||||
|
label: 'label',
|
||||||
|
disabled: true,
|
||||||
|
onClick,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const button = wrapper.find('button')
|
||||||
|
await button.trigger('click')
|
||||||
|
// check disabled props is set
|
||||||
|
expect(button.attributes('disabled')).toBeDefined()
|
||||||
|
// check aria-disabled atribute is set
|
||||||
|
expect(button.attributes('aria-disabled')).toBe('true')
|
||||||
|
// check that the onClck function hasn't been called
|
||||||
|
expect(onClick).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('small button', () => {
|
||||||
|
const wrapper = mount(VButton, {
|
||||||
|
props: {
|
||||||
|
title: 'button',
|
||||||
|
label: 'label',
|
||||||
|
size: 'sm'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const button = wrapper.find('button')
|
||||||
|
expect(button.classes()).toContain('p-button-sm')
|
||||||
|
expect(button.classes()).not.toContain('p-button-lg')
|
||||||
|
expect(button.classes().some(c => c.includes('text-body-SM'))).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('large button', () => {
|
||||||
|
const wrapper = mount(VButton, {
|
||||||
|
props: {
|
||||||
|
title: 'button',
|
||||||
|
label: 'label',
|
||||||
|
size: 'lg'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const button = wrapper.find('button')
|
||||||
|
expect(button.classes()).toContain('p-button-lg')
|
||||||
|
expect(button.classes()).not.toContain('p-button-sm')
|
||||||
|
expect(button.classes().some(c => c.includes('text-body-LG'))).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('medium button', () => {
|
||||||
|
const wrapper = mount(VButton, {
|
||||||
|
props: {
|
||||||
|
title: 'button',
|
||||||
|
label: 'label',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const button = wrapper.find('button')
|
||||||
|
expect(button.classes()).not.toContain('p-button-lg')
|
||||||
|
expect(button.classes()).not.toContain('p-button-sm')
|
||||||
|
expect(button.classes().some(c => c.includes('text-body-MD'))).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('primary button', () => {
|
||||||
|
const wrapper = mount(VButton, {
|
||||||
|
props: {
|
||||||
|
title: 'button',
|
||||||
|
label: 'label',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const button = wrapper.find('button')
|
||||||
|
expect(button.classes()).not.toContain('p-button-secondary')
|
||||||
|
expect(button.classes()).not.toContain('p-button-outlined')
|
||||||
|
expect(button.classes()).not.toContain('p-button-text')
|
||||||
|
expect(button.classes()).not.toContain('p-button-danger')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('secondary button', () => {
|
||||||
|
const wrapper = mount(VButton, {
|
||||||
|
props: {
|
||||||
|
title: 'button',
|
||||||
|
label: 'label',
|
||||||
|
secondary: true,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const button = wrapper.find('button')
|
||||||
|
expect(button.classes()).toContain('p-button-secondary')
|
||||||
|
expect(button.classes()).toContain('p-button-outlined')
|
||||||
|
expect(button.classes()).not.toContain('p-button-text')
|
||||||
|
expect(button.classes()).not.toContain('p-button-danger')
|
||||||
|
expect(button.attributes('data-p-severity')).toBe('secondary')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('tertiary button', () => {
|
||||||
|
const wrapper = mount(VButton, {
|
||||||
|
props: {
|
||||||
|
title: 'button',
|
||||||
|
label: 'label',
|
||||||
|
tertiary: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const button = wrapper.find('button')
|
||||||
|
expect(button.classes()).not.toContain('p-button-secondary')
|
||||||
|
expect(button.classes()).toContain('p-button-outlined')
|
||||||
|
expect(button.classes()).not.toContain('p-button-text')
|
||||||
|
expect(button.classes()).not.toContain('p-button-danger')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('no outlined button', () => {
|
||||||
|
const wrapper = mount(VButton, {
|
||||||
|
props: {
|
||||||
|
title: 'button',
|
||||||
|
label: 'label',
|
||||||
|
noOutline: true,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const button = wrapper.find('button')
|
||||||
|
expect(button.classes()).not.toContain('p-button-secondary')
|
||||||
|
expect(button.classes()).not.toContain('p-button-outlined')
|
||||||
|
expect(button.classes()).toContain('p-button-text')
|
||||||
|
expect(button.classes()).not.toContain('p-button-danger')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('danger variant button', () => {
|
||||||
|
const wrapper = mount(VButton, {
|
||||||
|
props: {
|
||||||
|
title: 'button',
|
||||||
|
label: 'label',
|
||||||
|
danger: true,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const button = wrapper.find('button')
|
||||||
|
expect(button.classes()).not.toContain('p-button-secondary')
|
||||||
|
expect(button.classes()).not.toContain('p-button-outlined')
|
||||||
|
expect(button.classes()).not.toContain('p-button-text')
|
||||||
|
expect(button.classes()).toContain('p-button-danger')
|
||||||
|
expect(button.attributes('data-p-severity')).toBe('danger')
|
||||||
|
})
|
||||||
|
})
|
|
@ -1,12 +1,13 @@
|
||||||
{
|
{
|
||||||
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
||||||
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
|
"include": ["env.d.ts", "src/**/*", "src/**/*.vue", "test/VButton.spec.ts"],
|
||||||
"exclude": ["src/**/__tests__/*"],
|
"exclude": ["src/**/__tests__/*"],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||||
|
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./src/*"]
|
"@/*": ["./src/*"],
|
||||||
|
"@visua/*": ["./node_modules/@cellule-financiere-pmo/visua/output/*"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,5 +7,8 @@
|
||||||
{
|
{
|
||||||
"path": "./tsconfig.app.json"
|
"path": "./tsconfig.app.json"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"compilerOptions": {
|
||||||
|
"types": ["vitest"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { fileURLToPath, URL } from 'node:url'
|
import { fileURLToPath, URL } from 'node:url'
|
||||||
|
import { defineConfig } from 'vitest/config'
|
||||||
import { defineConfig } from 'vite'
|
|
||||||
import vue from '@vitejs/plugin-vue'
|
import vue from '@vitejs/plugin-vue'
|
||||||
import vueDevTools from 'vite-plugin-vue-devtools'
|
import vueDevTools from 'vite-plugin-vue-devtools'
|
||||||
|
import path from 'path'
|
||||||
|
|
||||||
// https://vite.dev/config/
|
// https://vite.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
@ -12,7 +12,13 @@ export default defineConfig({
|
||||||
],
|
],
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'@': fileURLToPath(new URL('./src', import.meta.url))
|
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
||||||
|
'@visua': path.resolve(__dirname, './node_modules/@cellule-financiere-pmo/visua/output')
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
test: {
|
||||||
|
globals: true,
|
||||||
|
environment: 'jsdom',
|
||||||
|
include: ['test/**/*.spec.ts'],
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue
Block a user