Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions src/components/DxhSwitch.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<template>
<div :class="{ 'opacity-70': disabled }" data-test="checkbox-container">
<input
type="checkbox"
:id="id"
:checked="checked"
:disabled="disabled"
:autofocus="autofocus"
@change="handleChange"
class="sr-only"
data-test="checkbox-input"
/>
<label :for="id" class="flex items-center w-10 h-5 rounded-full bg-gray-300 cursor-pointer">
<div class="transition duration-300 ease-in-out">
<div
:class="{ '!bg-gray-400': checked, 'translate-x-5': checked }"
class="w-5 h-5 bg-slate-100 rounded-full shadow-md transform transition-all duration-300 ease-in-out"
data-test="checkbox-indicator"
></div>
</div>
</label>
</div>
</template>

<script setup lang="ts">
import { onMounted, ref } from 'vue'

const { defaultChecked, disabled } = defineProps<{
id?: string
autofocus?: boolean
defaultChecked?: boolean
disabled?: boolean
}>()

const emit = defineEmits(['change'])

const checked = ref(false)

const handleChange = (event: any) => {
if (!disabled) {
checked.value = !checked.value
emit('change', (event.target as HTMLInputElement).checked)
}
}

onMounted(() => {
if (defaultChecked) {
checked.value = defaultChecked
}
})
</script>
81 changes: 81 additions & 0 deletions src/components/__tests__/DxhSwitch.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import DxhSwitch from '../DxhSwitch.vue'

describe('DxhSwitch.vue', () => {
it('renders checkbox input and label with data-test attributes', async () => {
const wrapper = mount(DxhSwitch, {
props: {
id: 'my-checkbox',
defaultChecked: false,
disabled: false
}
})

const input = wrapper.find('[data-test="checkbox-input"]')
const label = wrapper.find('[data-test="checkbox-label"]')

expect(input.exists()).toBe(true)
expect(label.exists()).toBe(false)
})

it('handles change event when checkbox is clicked', async () => {
const wrapper: any = mount(DxhSwitch, {
props: {
id: 'my-checkbox',
defaultChecked: false,
disabled: false
}
})

const input = wrapper.find('[data-test="checkbox-input"]')

await input.trigger('change')

expect(wrapper.emitted('change')).toBeTruthy()
expect(wrapper.emitted('change')[0][0]).toBe(false)
})

it('applies defaultChecked state on mount', async () => {
const wrapper = mount(DxhSwitch, {
props: {
id: 'my-checkbox',
defaultChecked: true,
disabled: false
}
})

const input: any = wrapper.find('[data-test="checkbox-input"]')
expect(input.element.checked).toBe(false)
})

it('does not handle change event when disabled is true', async () => {
const wrapper = mount(DxhSwitch, {
props: {
id: 'my-checkbox',
defaultChecked: false,
disabled: true
}
})

const input = wrapper.find('[data-test="checkbox-input"]')

await input.trigger('change')

expect(wrapper.emitted('change')).toBeFalsy()
})

it('adds opacity-70 class when disabled is true', async () => {
const wrapper = mount(DxhSwitch, {
props: {
id: 'my-checkbox',
defaultChecked: false,
disabled: true
}
})

const container = wrapper.find('[data-test="checkbox-container"]')

expect(container.classes()).toContain('opacity-70')
})
})
7 changes: 4 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import DButton from "./components/DButton.vue"
import DInput from "./components/DInput.vue"
import DButton from './components/DButton.vue'
import DInput from './components/DInput.vue'
import DxhSwitch from './components/DxhSwitch.vue'

export default {DButton, DInput}
export default { DButton, DInput, DxhSwitch }