From af4dcdfc0428c16cd6b062a1f907f1a870f9863b Mon Sep 17 00:00:00 2001 From: kevin Date: Wed, 11 Mar 2026 15:48:59 +0100 Subject: [PATCH 1/4] feat : ajout composant select checkbox --- .../pages/composant/selectCheckbox.vue | 149 ++++++++ app/components/malio/SelectCheckbox.test.ts | 75 ++++ app/components/malio/SelectCheckbox.vue | 349 ++++++++++++++++++ 3 files changed, 573 insertions(+) create mode 100644 .playground/pages/composant/selectCheckbox.vue create mode 100644 app/components/malio/SelectCheckbox.test.ts create mode 100644 app/components/malio/SelectCheckbox.vue diff --git a/.playground/pages/composant/selectCheckbox.vue b/.playground/pages/composant/selectCheckbox.vue new file mode 100644 index 0000000..8652f26 --- /dev/null +++ b/.playground/pages/composant/selectCheckbox.vue @@ -0,0 +1,149 @@ + + + diff --git a/app/components/malio/SelectCheckbox.test.ts b/app/components/malio/SelectCheckbox.test.ts new file mode 100644 index 0000000..9ea4e7b --- /dev/null +++ b/app/components/malio/SelectCheckbox.test.ts @@ -0,0 +1,75 @@ +import {describe, expect, it} from 'vitest' +import {mount} from '@vue/test-utils' +import type {DefineComponent} from 'vue' +import SelectCheckbox from './SelectCheckbox.vue' + +type Option = { + label: string + value: string | number +} + +type SelectCheckboxProps = { + modelValue: Array + options?: Option[] + emptyOptionLabel?: string + label?: string + hint?: string + error?: string + success?: string + minWidth?: string + maxWidth?: string + textField?: string + textValue?: string + textLabel?: string + rounded?: string + disabled?: boolean +} + +const SelectCheckboxForTest = SelectCheckbox as DefineComponent + +const options: Option[] = [ + {label: 'France', value: 'fr'}, + {label: 'Belgique', value: 'be'}, + {label: 'Canada', value: 'ca'}, +] + +describe('MalioSelectCheckbox', () => { + it('renders checkbox inputs for options', async () => { + const wrapper = mount(SelectCheckboxForTest, { + props: {modelValue: [], options}, + }) + + await wrapper.get('button').trigger('click') + + const checkboxes = wrapper.findAll('input[type="checkbox"]') + expect(checkboxes).toHaveLength(options.length) + }) + + it('emits an array with the toggled option value', async () => { + const wrapper = mount(SelectCheckboxForTest, { + props: {modelValue: ['fr'], options}, + }) + + await wrapper.get('button').trigger('click') + const checkboxInputs = wrapper.findAll('input[type="checkbox"]') + await checkboxInputs[1].setValue(true) + + expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([['fr', 'be']]) + }) + + it('shows the selected count over the total count in the trigger', () => { + const wrapper = mount(SelectCheckboxForTest, { + props: {modelValue: ['fr', 'ca'], options}, + }) + + expect(wrapper.text()).toContain('2/3') + }) + + it('shows 0 over the total count when nothing is selected', () => { + const wrapper = mount(SelectCheckboxForTest, { + props: {modelValue: [], options}, + }) + + expect(wrapper.text()).toContain('0/3') + }) +}) diff --git a/app/components/malio/SelectCheckbox.vue b/app/components/malio/SelectCheckbox.vue new file mode 100644 index 0000000..0e1fdea --- /dev/null +++ b/app/components/malio/SelectCheckbox.vue @@ -0,0 +1,349 @@ + + + + + -- 2.39.5 From c96eafdb23ead6c537b515498cf3cfe4db139a02 Mon Sep 17 00:00:00 2001 From: kevin Date: Thu, 12 Mar 2026 15:31:29 +0100 Subject: [PATCH 2/4] feat : ajout composant select checkbox --- app/components/malio/SelectCheckbox.vue | 39 ++++++++++++++++++------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/app/components/malio/SelectCheckbox.vue b/app/components/malio/SelectCheckbox.vue index 0e1fdea..37e87e7 100644 --- a/app/components/malio/SelectCheckbox.vue +++ b/app/components/malio/SelectCheckbox.vue @@ -25,7 +25,7 @@ ? openDirection === 'down' ? 'rounded-b-none !border-2 !border-m-primary !border-b-0' : 'rounded-t-none !border-2 !border-m-primary !border-t-0' - : isOptionSelected + : isOptionSelected ? 'border-black' : 'border-m-muted', disabled ? 'cursor-not-allowed border-m-muted text-black/60' : 'cursor-pointer', @@ -44,7 +44,7 @@ v-if="label" class="floating-label pointer-events-none absolute left-3 inline-block origin-left transition-transform duration-150 font-medium" :class="[ - isOpen ? 'top-2 z-30' : 'top-1/2 -translate-y-1/2', + shouldFloatLabel ? 'top-2 z-30' : 'top-1/2 -translate-y-1/2', hasError ? 'text-m-error' : hasSuccess @@ -61,7 +61,22 @@ {{ label }} +
+ + {{ option.label }} + +
+ - +
+

Avec tag

+ +
+
+

Avec tag + label

+ +

Avec label

>([]) const labelValue = ref>([]) +const labelValue1 = ref>([]) const selectedValue = ref>(['fr']) const hintValue = ref>([]) const errorValue = ref>([]) diff --git a/app/components/malio/SelectCheckbox.test.ts b/app/components/malio/SelectCheckbox.test.ts index 9ea4e7b..0092f16 100644 --- a/app/components/malio/SelectCheckbox.test.ts +++ b/app/components/malio/SelectCheckbox.test.ts @@ -22,6 +22,7 @@ type SelectCheckboxProps = { textValue?: string textLabel?: string rounded?: string + displayTag?: boolean disabled?: boolean } @@ -72,4 +73,23 @@ describe('MalioSelectCheckbox', () => { expect(wrapper.text()).toContain('0/3') }) + + it('hides the summary when displayTag is enabled and options are selected', () => { + const wrapper = mount(SelectCheckboxForTest, { + props: {modelValue: ['fr', 'ca'], options, displayTag: true}, + }) + + expect(wrapper.text()).not.toContain('2/3') + expect(wrapper.text()).toContain('France') + expect(wrapper.text()).toContain('Canada') + }) + + it('hides the summary when displayTag is enabled and nothing is selected', () => { + const wrapper = mount(SelectCheckboxForTest, { + props: {modelValue: [], options, displayTag: true, emptyOptionLabel: 'Aucune selection'}, + }) + + expect(wrapper.text()).not.toContain('0/3') + expect(wrapper.text()).toContain('Aucune selection') + }) }) diff --git a/app/components/malio/SelectCheckbox.vue b/app/components/malio/SelectCheckbox.vue index 37e87e7..7778882 100644 --- a/app/components/malio/SelectCheckbox.vue +++ b/app/components/malio/SelectCheckbox.vue @@ -63,20 +63,32 @@
- {{ option.label }} + {{ option.label }}
+ {{ emptyOptionLabel }} + + +