diff --git a/packages/element-plus/index.ts b/packages/element-plus/index.ts
index a4593edc8e..b0f2e7432d 100644
--- a/packages/element-plus/index.ts
+++ b/packages/element-plus/index.ts
@@ -12,6 +12,7 @@ import ElBreadcrumb from '@element-plus/breadcrumb'
import ElIcon from '@element-plus/icon'
import ElLink from '@element-plus/link'
import ElRate from '@element-plus/rate'
+import ElSwitch from '@element-plus/switch'
export {
ElAvatar,
@@ -27,6 +28,7 @@ export {
ElIcon,
ElLink,
ElRate,
+ ElSwitch,
}
export default function install(app: App): void {
@@ -43,4 +45,5 @@ export default function install(app: App): void {
ElIcon(app)
ElLink(app)
ElRate(app)
+ ElSwitch(app)
}
diff --git a/packages/element-plus/package.json b/packages/element-plus/package.json
index 1146667154..6991972887 100644
--- a/packages/element-plus/package.json
+++ b/packages/element-plus/package.json
@@ -26,6 +26,9 @@
"@element-plus/progress": "^0.0.0",
"@element-plus/tag": "^0.0.0",
"@element-plus/time-line": "^0.0.0",
- "@element-plus/rate": "^0.0.0"
+ "@element-plus/rate": "^0.0.0",
+ "@element-plus/breadcrumb": "^0.0.0",
+ "@element-plus/icon": "^0.0.0",
+ "@element-plus/switch": "^0.0.0"
}
}
diff --git a/packages/switch/__tests__/switch.spec.ts b/packages/switch/__tests__/switch.spec.ts
new file mode 100644
index 0000000000..fbea1055f4
--- /dev/null
+++ b/packages/switch/__tests__/switch.spec.ts
@@ -0,0 +1,231 @@
+import { mount } from '@vue/test-utils'
+import Switch from '../src/index.vue'
+
+describe('Switch.vue', () => {
+
+ test('create', () => {
+ const wrapper = mount(Switch, {
+ props: {
+ activeText: 'on',
+ inactiveText: 'off',
+ activeColor: '#0f0',
+ inactiveColor: '#f00',
+ width: 100,
+ },
+ })
+ const vm = wrapper.vm
+ const coreEl = vm.$el.querySelector('.el-switch__core')
+ expect(coreEl.style.backgroundColor).toEqual('rgb(255, 0, 0)')
+ expect(coreEl.style.width).toEqual('100px')
+ const leftLabelWrapper = wrapper.find('.el-switch__label--left span')
+ expect(leftLabelWrapper.text()).toEqual('off')
+ })
+
+ test('switch with icons', () => {
+ const wrapper = mount(Switch, {
+ props: {
+ activeIconClass: 'el-icon-check',
+ inactiveIconClass: 'el-icon-close',
+ },
+ })
+
+ const iconWrapper = wrapper.find('.el-switch__label--left i')
+ expect(iconWrapper.classes('el-icon-close')).toBe(true)
+ })
+
+ test('value correctly update', async () => {
+ const wrapper = mount({
+ components: {
+ 'el-switch': Switch,
+ },
+ template: `
+
+
+
+
+ `,
+ data() {
+ return {
+ value: true,
+ }
+ },
+ })
+ const vm = wrapper.vm
+ const coreEl = vm.$el.querySelector('.el-switch__core')
+ expect(coreEl.style.backgroundColor).toEqual('rgb(0, 255, 0)')
+ const coreWrapper = wrapper.find('.el-switch__core')
+ await coreWrapper.trigger('click')
+ expect(coreEl.style.backgroundColor).toEqual('rgb(255, 0, 0)')
+ expect(vm.value).toEqual(false)
+ await coreWrapper.trigger('click')
+ expect(vm.value).toEqual(true)
+ })
+
+ test('change event', async () => {
+ const wrapper = mount({
+ components: {
+ 'el-switch': Switch,
+ },
+ template: `
+
+
+
+
+ `,
+ methods: {
+ handleChange(val) {
+ this.target = val
+ },
+ },
+ data() {
+ return {
+ target: 1,
+ value: true,
+ }
+ },
+ })
+ const vm = wrapper.vm
+
+ expect(vm.target).toEqual(1)
+ const coreWrapper = wrapper.find('.el-switch__core')
+ await coreWrapper.trigger('click')
+ const switchWrapper = wrapper.findComponent(Switch)
+ expect(switchWrapper.emitted()['update:modelValue']).toBeTruthy()
+ expect(vm.target).toEqual(false)
+ })
+
+ test('disabled switch should not respond to user click', async () => {
+ const wrapper = mount({
+ components: {
+ 'el-switch': Switch,
+ },
+ template: `
+
+
+
+ `,
+ data() {
+ return {
+ value: true,
+ }
+ },
+ })
+ const vm = wrapper.vm
+
+ expect(vm.value).toEqual(true)
+ const coreWrapper = wrapper.find('.el-switch__core')
+ await coreWrapper.trigger('click')
+ expect(vm.value).toEqual(true)
+ })
+
+ test('expand switch value', async () => {
+ const wrapper = mount({
+ components: {
+ 'el-switch': Switch,
+ },
+ template: `
+
+
+
+ `,
+ data() {
+ return {
+ value: '100',
+ onValue: '100',
+ offValue: '0',
+ }
+ },
+ })
+ const vm = wrapper.vm
+
+ const coreWrapper = wrapper.find('.el-switch__core')
+ await coreWrapper.trigger('click')
+ expect(vm.value).toEqual('0')
+ await coreWrapper.trigger('click')
+ expect(vm.value).toEqual('100')
+ })
+
+ test('value is the single source of truth', async () => {
+ const wrapper = mount({
+ components: {
+ 'el-switch': Switch,
+ },
+ template: `
+
+
+
+ `,
+ })
+ const vm = wrapper.vm
+ const coreWrapper = wrapper.find('.el-switch__core')
+ const switchWrapper = wrapper.findComponent(Switch)
+ const switchVm = switchWrapper.vm
+ const inputEl = vm.$el.querySelector('input')
+
+ expect(switchVm.checked).toBe(true)
+ expect(switchWrapper.classes('is-checked')).toEqual(true)
+ expect(inputEl.checked).toEqual(true)
+ await coreWrapper.trigger('click')
+ expect(switchVm.checked).toBe(true)
+ expect(switchWrapper.classes('is-checked')).toEqual(true)
+ expect(inputEl.checked).toEqual(true)
+ })
+
+ test('model-value is the single source of truth', async () => {
+ const wrapper = mount({
+ components: {
+ 'el-switch': Switch,
+ },
+ template: `
+
+
+
+ `,
+ })
+ const vm = wrapper.vm
+ const coreWrapper = wrapper.find('.el-switch__core')
+ const switchWrapper = wrapper.findComponent(Switch)
+ const switchVm = switchWrapper.vm
+ const inputEl = vm.$el.querySelector('input')
+
+ expect(switchVm.checked).toBe(true)
+ expect(switchWrapper.classes('is-checked')).toEqual(true)
+ expect(inputEl.checked).toEqual(true)
+ await coreWrapper.trigger('click')
+ expect(switchVm.checked).toBe(true)
+ expect(switchWrapper.classes('is-checked')).toEqual(true)
+ expect(inputEl.checked).toEqual(true)
+ })
+
+ test('sets checkbox value', async () => {
+ const wrapper = mount({
+ components: {
+ 'el-switch': Switch,
+ },
+ template: `
+
+
+
+ `,
+ data() {
+ return {
+ value: false,
+ }
+ },
+ })
+ const vm = wrapper.vm
+ const inputEl = vm.$el.querySelector('input')
+
+ vm.value = true
+ await vm.$nextTick()
+ expect(inputEl.checked).toEqual(true)
+ vm.value = false
+ await vm.$nextTick()
+ expect(inputEl.checked).toEqual(false)
+ })
+})
diff --git a/packages/switch/doc/basic.vue b/packages/switch/doc/basic.vue
new file mode 100644
index 0000000000..8628f878a7
--- /dev/null
+++ b/packages/switch/doc/basic.vue
@@ -0,0 +1,28 @@
+
+
+
+ use v-model
+
+
+
+ use :value
+
+
+
+ use :model-value
+
+
+
+
+
+
+
diff --git a/packages/switch/doc/index.stories.ts b/packages/switch/doc/index.stories.ts
new file mode 100644
index 0000000000..40b8c46e67
--- /dev/null
+++ b/packages/switch/doc/index.stories.ts
@@ -0,0 +1,6 @@
+export { default as BasicUsage } from './basic.vue'
+
+export default {
+ title: 'Switch',
+}
+
diff --git a/packages/switch/index.ts b/packages/switch/index.ts
new file mode 100644
index 0000000000..d95865f1c6
--- /dev/null
+++ b/packages/switch/index.ts
@@ -0,0 +1,5 @@
+import { App } from 'vue'
+import Switch from './src/index.vue'
+export default (app: App): void => {
+ app.component(Switch.name, Switch)
+}
diff --git a/packages/switch/package.json b/packages/switch/package.json
new file mode 100644
index 0000000000..30df452a02
--- /dev/null
+++ b/packages/switch/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "@element-plus/switch",
+ "version": "0.0.0",
+ "main": "dist/index.js",
+ "license": "MIT",
+ "peerDependencies": {
+ "vue": "^3.0.0-rc.1"
+ },
+ "devDependencies": {
+ "@vue/test-utils": "^2.0.0-beta.0"
+ }
+}
diff --git a/packages/switch/src/index.vue b/packages/switch/src/index.vue
new file mode 100644
index 0000000000..53d2ad8ce5
--- /dev/null
+++ b/packages/switch/src/index.vue
@@ -0,0 +1,224 @@
+
+
+
+
+
+ {{ inactiveText }}
+
+
+
+
+
+ {{ activeText }}
+
+
+
+
+
+