Skip to content

Commit 355a5fc

Browse files
IcetCodejd-solanki
andauthored
feat(switch): added on-value and off-value props (#136)
Co-authored-by: jd-solanki <jdsolanki0001@gmail.com>
1 parent 815cbaa commit 355a5fc

File tree

5 files changed

+90
-8
lines changed

5 files changed

+90
-8
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<script lang="ts" setup>
2+
import { ref } from 'vue'
3+
4+
const status = ref('enabled')
5+
const onValue = ref('enabled')
6+
const offValue = ref('disabled')
7+
</script>
8+
9+
<template>
10+
<div class="grid-row">
11+
<ASwitch
12+
v-model="status"
13+
:on-value="onValue"
14+
:off-value="offValue"
15+
/>
16+
<span>Status: "{{ status }}"</span>
17+
</div>
18+
</template>

docs/guide/components/switch.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,17 @@ Use `on-icon` & `off-icon` prop to render icons inside switch dot.
5656

5757
::::
5858

59+
<!-- Custom model values -->
60+
::::card Custom model values
61+
62+
You can use `on-value` and `off-value` props to set custom `v-model` value.
63+
64+
:::code DemoSwitchCustomModelValue
65+
<<< @/components/demos/switch/DemoSwitchCustomModelValue.vue{13,14}
66+
:::
67+
68+
::::
69+
5970
<!-- 👉 Sizing -->
6071
::::card Sizing
6172

packages/anu-vue/src/components/switch/ASwitch.vue

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script lang="ts" setup>
22
import { defu } from 'defu'
3-
import type { ExtractPropTypes, PropType } from 'vue'
3+
import type { ExtractPropTypes } from 'vue'
44
import { color as colorProp, disabled as disabledProp } from '@/composables/useProps'
55
66
const props = defineProps({
@@ -20,7 +20,23 @@ const props = defineProps({
2020
* Bind v-model value
2121
*/
2222
modelValue: {
23-
type: [Boolean, Array, Set] as PropType<any[] | Set<any> | boolean>,
23+
type: [Boolean, Number, String],
24+
default: true,
25+
},
26+
27+
/**
28+
* Switch value when in on state
29+
*/
30+
onValue: {
31+
type: [Boolean, Number, String],
32+
default: true,
33+
},
34+
35+
/**
36+
* Switch value when in off state
37+
*/
38+
offValue: {
39+
type: [Boolean, Number, String],
2440
default: false,
2541
},
2642
@@ -39,7 +55,6 @@ const props = defineProps({
3955
*/
4056
disabled: disabledProp,
4157
})
42-
4358
const emit = defineEmits<{
4459
(e: 'update:modelValue', value: (ExtractPropTypes<typeof props>)['modelValue']): void
4560
}>()
@@ -50,11 +65,17 @@ defineOptions({
5065
5166
const attrs = useAttrs()
5267
68+
const isChecked = computed(() => props.modelValue === props.onValue)
69+
70+
const handleChange = () => {
71+
const val = isChecked.value ? props.offValue : props.onValue
72+
emit('update:modelValue', val)
73+
}
74+
5375
const elementId = `a-switch-${attrs.id || attrs.value}-${Math.random().toString(36).slice(2, 7)}`
54-
const data = useVModel(props, 'modelValue', emit)
5576
5677
const dotPosition = computed(() => {
57-
if (!data.value)
78+
if (!isChecked.value)
5879
return { transform: 'translateX(0)' }
5980
else return { transform: 'translateX(calc(var(--a-switch-track-size) - 100% - (var(--a-switch-thumb-margin) *2 )))' }
6081
})
@@ -74,10 +95,10 @@ const dotPosition = computed(() => {
7495

7596
<input
7697
:id="elementId"
77-
v-model="data"
7898
class="hidden"
7999
role="switch"
80100
type="checkbox"
101+
@change="handleChange"
81102
>
82103

83104
<!-- 👉 Label -->
@@ -89,7 +110,7 @@ const dotPosition = computed(() => {
89110
<!-- min width should be double the dot size -->
90111
<div
91112
class="a-switch-toggle flex rounded-inherit min-w-$a-switch-track-size"
92-
:class="data
113+
:class="isChecked
93114
? `bg-${props.color}`
94115
: 'bg-[hsl(var(--a-switch-default-color))]'"
95116
>
@@ -100,7 +121,7 @@ const dotPosition = computed(() => {
100121
<div
101122
class="a-switch-icon color-$a-switch-icon-color"
102123
:class="[
103-
data
124+
isChecked
104125
? `${props.onIcon} text-${props.color}`
105126
: props.offIcon,
106127
]"
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { mount } from '@vue/test-utils'
2+
import { describe, expect, it } from 'vitest'
3+
import { ref } from 'vue'
4+
import { ASwitch } from '../src/components'
5+
6+
describe('Testing ASwitch', () => {
7+
it('expand switch value', async () => {
8+
const modelValue = ref('100')
9+
const onValue = ref('100')
10+
const offValue = ref('0')
11+
12+
const wrapper = mount(() => (
13+
<ASwitch
14+
v-model={modelValue.value}
15+
onValue={onValue.value}
16+
offValue={offValue.value}
17+
/>
18+
), {
19+
// trigger click on a label have an issue
20+
// https://github.com/vuejs/vue-test-utils/issues/760
21+
attachTo: document.body,
22+
})
23+
24+
const coreWrapper = wrapper.find('.a-switch')
25+
await coreWrapper.trigger('click')
26+
expect(modelValue.value).toBe('0')
27+
await wrapper.trigger('click')
28+
expect(modelValue.value).toBe('100')
29+
})
30+
})

packages/anu-vue/vite.config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import vue from '@vitejs/plugin-vue'
44
import AutoImport from 'unplugin-auto-import/vite'
55
import VueMacros from 'unplugin-vue-macros/vite'
66
import { defineConfig } from 'vitest/config'
7+
import vueJsx from '@vitejs/plugin-vue-jsx'
78

89
const externals = [
910
'vue',
@@ -44,6 +45,7 @@ export default defineConfig({
4445
vue: vue(),
4546
},
4647
}),
48+
vueJsx(),
4749
AutoImport({
4850
imports: ['vue', '@vueuse/core'],
4951
}),

0 commit comments

Comments
 (0)