diff --git a/packages/varlet-vue2-ui/src/input/Input.vue b/packages/varlet-vue2-ui/src/input/Input.vue index 3f34421..9d9965a 100644 --- a/packages/varlet-vue2-ui/src/input/Input.vue +++ b/packages/varlet-vue2-ui/src/input/Input.vue @@ -244,7 +244,7 @@ export default defineComponent({ const { disabled, readonly, clearable, getListeners } = this const { onInput, onClear } = getListeners() - if (this.form?.disabled.value || this.form?.readonly.value || disabled || readonly || !clearable) { + if (this.form?.disabled || this.form?.readonly || disabled || readonly || !clearable) { return } @@ -257,7 +257,7 @@ export default defineComponent({ handleClick(e) { const { disabled, getListeners } = this - if (this.form?.disabled.value || disabled) { + if (this.form?.disabled || disabled) { return } diff --git a/packages/varlet-vue2-ui/src/switch/Switch.vue b/packages/varlet-vue2-ui/src/switch/Switch.vue new file mode 100644 index 0000000..fd269ea --- /dev/null +++ b/packages/varlet-vue2-ui/src/switch/Switch.vue @@ -0,0 +1,150 @@ + + + + + diff --git a/packages/varlet-vue2-ui/src/switch/__tests__/__snapshots__/index.spec.js.snap b/packages/varlet-vue2-ui/src/switch/__tests__/__snapshots__/index.spec.js.snap new file mode 100644 index 0000000..3042495 --- /dev/null +++ b/packages/varlet-vue2-ui/src/switch/__tests__/__snapshots__/index.spec.js.snap @@ -0,0 +1,278 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`test switch color and size 1`] = ` +"
+
+
+
+
+ +
+
+
+ + + +
" +`; + +exports[`test switch color and size 2`] = ` +"
+
+
+
+
+ +
+
+
+ + + +
" +`; + +exports[`test switch example 1`] = ` +"
+
基本使用
+
+
+
+
+
+
+ +
+
+
+ + + +
+
+
不可用
+
+
+
+
+
+
+ +
+
+
+ + + +
+
+
+
+
+
+ +
+
+
+ + + +
+
+
自定义颜色
+
+
+
+
+
+
+ +
+
+
+ + + +
+
+
+
+
+
+ +
+
+
+ + + +
+
+
不同大小
+
+
+
+
+
+
+ +
+
+
+ + + +
+
+
+
+
+
+ +
+
+
+ + + +
+
+
+
+
+
+ +
+
+
+ + + +
+
+
加载状态
+
+
+
+
+
+
+
+ +
+
+ + + + + +
+
+
+
+
+ + + +
+
+
+
+
+
+
+ +
+
+ + + + + +
+
+
+
+
+ + + +
+
+
值的校验
+
+
+
+
+
+ +
+
+
+ + + +
+
" +`; + +exports[`test switch loading prop 1`] = ` +"
+
+
+
+
+
+ +
+
+ + + + + +
+
+
+
+
+ + + +
" +`; + +exports[`test switch rules prop 1`] = ` +"
+
+
+
+
+ +
+
+
+ + + +
" +`; + +exports[`test switch rules prop 2`] = ` +"
+
+
+
+
+ +
+
+
+ +
+
错误!
+
+
+
+
" +`; diff --git a/packages/varlet-vue2-ui/src/switch/__tests__/index.spec.js b/packages/varlet-vue2-ui/src/switch/__tests__/index.spec.js new file mode 100644 index 0000000..ee88c8c --- /dev/null +++ b/packages/varlet-vue2-ui/src/switch/__tests__/index.spec.js @@ -0,0 +1,164 @@ +import example from '../example' +import Switch from '..' +import VarSwitch from '../Switch' +import { mount } from '@vue/test-utils' +import Vue from 'vue' +import { delay } from '../../utils/jest' + +test('test switch example', () => { + const wrapper = mount(example) + expect(wrapper.html()).toMatchSnapshot() +}) + +test('test switch plugin', () => { + Vue.use(Switch) + expect(Vue.component(Switch.name)).toBeTruthy() +}) + +test('test switch value props and events', async () => { + const clickFn = jest.fn() + const changeFn = jest.fn() + const template = ` + + ` + + const wrapper = mount({ + components: { + [VarSwitch.name]: VarSwitch, + }, + data() { + return { + value: 2, + } + }, + methods: { + clickFn, + changeFn, + }, + template, + }) + + await delay(0) + + expect(wrapper.find('.var-switch__track').classes()).toContain('var-switch__track-active') + + await wrapper.find('.var-switch-block').trigger('click') + + expect(clickFn).toHaveBeenCalledTimes(1) + expect(changeFn).toHaveBeenCalledTimes(1) + + await delay(0) + + expect(wrapper.vm.value).toBe(1) + expect(wrapper.find('.var-switch__track').classes()).not.toContain('var-switch__track-active') +}) + +test('test switch not available', async () => { + const clickFn = jest.fn() + const changeFn = jest.fn() + const template = ` + + ` + + const wrapper = mount({ + components: { + [VarSwitch.name]: VarSwitch, + }, + data() { + return { + value: true, + disabled: true, + readonly: false, + } + }, + methods: { + clickFn, + changeFn, + }, + template, + }) + + await delay(0) + + expect(wrapper.find('.var-switch__disable')).toBeTruthy() + + await wrapper.find('.var-switch-block').trigger('click') + + expect(clickFn).toHaveBeenCalledTimes(1) + expect(changeFn).toHaveBeenCalledTimes(0) + expect(wrapper.vm.value).toBe(true) + + await wrapper.setData({ + disabled: false, + readonly: true, + }) + + await wrapper.find('.var-switch-block').trigger('click') + expect(clickFn).toHaveBeenCalledTimes(2) + expect(changeFn).toHaveBeenCalledTimes(0) + expect(wrapper.vm.value).toBe(true) +}) + +test('test switch color and size', async () => { + const template = ` + + ` + const wrapper = mount({ + components: { + [VarSwitch.name]: VarSwitch, + }, + data() { + return { + value: true, + } + }, + template, + }) + + await delay(0) + + expect(wrapper.html()).toMatchSnapshot() + + await wrapper.setData({ value: false }) + + await delay(0) + + expect(wrapper.html()).toMatchSnapshot() +}) + +test('test switch loading prop', () => { + const wrapper = mount(VarSwitch, { + propsData: { + loading: true, + modelValue: true, + loadingColor: '#ff9800', + }, + }) + + expect(wrapper.html()).toMatchSnapshot() +}) + +test('test switch rules prop', async () => { + const template = `` + const wrapper = mount({ + components: { + [VarSwitch.name]: VarSwitch, + }, + data() { + return { + value: true, + } + }, + template, + }) + + await delay(0) + + expect(wrapper.html()).toMatchSnapshot() + + await wrapper.find('.var-switch-block').trigger('click') + + await delay(0) + + expect(wrapper.html()).toMatchSnapshot() +}) diff --git a/packages/varlet-vue2-ui/src/switch/docs/en-US.md b/packages/varlet-vue2-ui/src/switch/docs/en-US.md new file mode 100644 index 0000000..cb6f84e --- /dev/null +++ b/packages/varlet-vue2-ui/src/switch/docs/en-US.md @@ -0,0 +1,111 @@ +# Switch + +### Intro + +Switching Selector. + +### Install + +```js +import Vue from 'vue' +import { Switch } from '@varlet/ui' + +Vue.use(Switch) +``` + +### Basic Usage + +```html + +``` + +```javascript +export default { + data() { + return { + value: true + } + } +} +``` + +### Not Available + +```html + + +``` + +### Custom color + +```html + + +``` + +### Size + +Use `size` prop to change size of Switch. + +```html + + + +``` + +### Loading + +```html + + +``` + +### Validate value + +The values are validated by passing in an array of validators,If the validator returns `true`, the validation passes. +Other values are converted to text as a user prompt. + +```html + +``` + +## API + +### Props + +| Prop | Description | Type | Default | +| ----- | -------------- | -------- | ---------- | +| `v-model` | Check status of Switch | _any_ | `false` | +| `active-value` | The value when the switch is turned on | _any_ | `true` | +| `inactive-value` | The value when the switch is turned off | _any_ | `false` | +| `disabled` | Whether to disable switch| _boolean_ | `false` | +| `readonly` | Whether to readonly switch | _boolean_ | `false` | +| `loading` | Whether to show loading icon | _boolean_ | `false` | +| `ripple` | Whether to open ripple | _boolean_ | `true` | +| `color` | Background color when open | _string_ | `#2979ff` | +| `close-color` | Background color when close | _string_ | `#fff` | +| `loading-color` | Color of loading icon | _string_ | `#fff` | +| `size` | Size of switch | _string \| number_ | `20` | +| `rules`| Validation rules | _array_ | - | + +### Events + +| Event | Description | arguments | +| ----- | -------------- | -------- | +| `click` | Emitted when component is clicked | `event: Event` | +| `change` | Emitted when check status changed | `value: any` | + +### Style Variables + +Here are the CSS variables used by the component, Styles can be customized using [StyleProvider](#/en-US/style-provider) + +| Variable | Default | +| --- | --- | +| `--switch-track-background` | `#fff` | +| `--switch-track-active-background` | `var(--color-primary)` | +| `--switch-track-error-background` | `var(--color-danger)` | +| `--switch-ripple-color` | `var(--color-primary)` | +| `--switch-handle-background` | `#fff` | +| `--switch-handle-color` | `#fff` | +| `--switch-handle-active-background` | `var(--color-primary)` | +| `--switch-handle-error-background` | `var(--color-danger)` | diff --git a/packages/varlet-vue2-ui/src/switch/docs/zh-CN.md b/packages/varlet-vue2-ui/src/switch/docs/zh-CN.md new file mode 100644 index 0000000..77be976 --- /dev/null +++ b/packages/varlet-vue2-ui/src/switch/docs/zh-CN.md @@ -0,0 +1,111 @@ +# 开关 + +### 介绍 + +开关选择器。 + +### 引入 + +```js +import Vue from 'vue' +import { Switch } from '@varlet/ui' + +Vue.use(Switch) +``` + +### 基本使用 + +```html + +``` + +```javascript +export default { + data() { + return { + value: true + } + } +} +``` + +### 不可用 + +```html + + +``` + +### 自定义颜色 + +```html + + +``` + +### 不同大小 + +通过 `size` 属性改变 Switch 大小。 + +```html + + + +``` + +### 加载状态 + +```html + + +``` + +### 值的校验 + +通过传入一个校验器数组可以对值进行校验,校验器返回 `true` 则为校验通过。 +以外的值将转换为文本作为用户提示。 + +```html + +``` + +## API + +### 属性 + +| 参数 | 说明 | 类型 | 默认值 | +| ----- | -------------- | -------- | ---------- | +| `v-model` | 开关选中状态 | _any_ | `false` | +| `active-value` | 开关打开时的值 | _any_ | `true` | +| `inactive-value` | 开关关闭时的值 | _any_ | `false` | +| `disabled` | 是否禁用| _boolean_ | `false` | +| `readonly` | 是否只读 | _boolean_ | `false` | +| `loading` | 是否为加载状态 | _boolean_ | `false` | +| `ripple` | 是否启用水波纹 | _boolean_ | `true` | +| `color` | 打开状态下的颜色 | _string_ | `#2979ff` | +| `loading-color` | 加载图标的颜色 | _string_ | `#fff` | +| `close-color` | 关闭状态下的颜色 | _string_ | `#fff` | +| `size` | switch 的大小 | _string \| number_ | `20` | +| `rules`| 校验规则 | _array_ | - | + +### 事件 + +| 事件名 | 说明 | 回调参数 | +| ----- | -------------- | -------- | +| `click` | 点击时触发 | `event: Event` | +| `change` | 开关状态切换时触发 | `value: any` | + +### 样式变量 + +以下为组件使用的 css 变量,可以使用 [StyleProvider 组件](#/zh-CN/style-provider)进行样式定制 + +| 变量名 | 默认值 | +| --- | --- | +| `--switch-track-background` | `#fff` | +| `--switch-track-active-background` | `var(--color-primary)` | +| `--switch-track-error-background` | `var(--color-danger)` | +| `--switch-ripple-color` | `var(--color-primary)` | +| `--switch-handle-background` | `#fff` | +| `--switch-handle-color` | `#fff` | +| `--switch-handle-active-background` | `var(--color-primary)` | +| `--switch-handle-error-background` | `var(--color-danger)` | diff --git a/packages/varlet-vue2-ui/src/switch/example/index.vue b/packages/varlet-vue2-ui/src/switch/example/index.vue new file mode 100644 index 0000000..0fd1269 --- /dev/null +++ b/packages/varlet-vue2-ui/src/switch/example/index.vue @@ -0,0 +1,80 @@ + + + + + diff --git a/packages/varlet-vue2-ui/src/switch/example/locale/en-US.ts b/packages/varlet-vue2-ui/src/switch/example/locale/en-US.ts new file mode 100644 index 0000000..32d356b --- /dev/null +++ b/packages/varlet-vue2-ui/src/switch/example/locale/en-US.ts @@ -0,0 +1,10 @@ +export default { + basicUsage: 'Basic Usage', + customColor: 'Custom Color', + notAvailable: 'Not Available', + size: 'Size', + loading: 'Loading', + validateValue: 'Validate Value', + text: 'Whether to open the switch', + state: 'Error!', +} diff --git a/packages/varlet-vue2-ui/src/switch/example/locale/index.ts b/packages/varlet-vue2-ui/src/switch/example/locale/index.ts new file mode 100644 index 0000000..d2e375e --- /dev/null +++ b/packages/varlet-vue2-ui/src/switch/example/locale/index.ts @@ -0,0 +1,23 @@ +// lib +import _zhCN from '../../../locale/zh-CN' +import _enCN from '../../../locale/en-US' +// mobile example doc +import zhCN from './zh-CN' +import enUS from './en-US' +import { useLocale, add as _add, use as _use } from '../../../locale' + +const { add, use: exampleUse, pack, packs, merge } = useLocale() + +const use = (lang: string) => { + _use(lang) + exampleUse(lang) +} + +export { add, pack, packs, merge, use } + +// lib +_add('zh-CN', _zhCN) +_add('en-US', _enCN) +// mobile example doc +add('zh-CN', zhCN as any) +add('en-US', enUS as any) diff --git a/packages/varlet-vue2-ui/src/switch/example/locale/zh-CN.ts b/packages/varlet-vue2-ui/src/switch/example/locale/zh-CN.ts new file mode 100644 index 0000000..54aaa33 --- /dev/null +++ b/packages/varlet-vue2-ui/src/switch/example/locale/zh-CN.ts @@ -0,0 +1,10 @@ +export default { + basicUsage: '基本使用', + customColor: '自定义颜色', + notAvailable: '不可用', + size: '不同大小', + loading: '加载状态', + validateValue: '值的校验', + text: '是否打开开关', + state: '错误!', +} diff --git a/packages/varlet-vue2-ui/src/switch/index.ts b/packages/varlet-vue2-ui/src/switch/index.ts new file mode 100644 index 0000000..310aaca --- /dev/null +++ b/packages/varlet-vue2-ui/src/switch/index.ts @@ -0,0 +1,10 @@ +import type { VueConstructor } from 'vue' +import Switch from './Switch.vue' + +Switch.install = function (app: VueConstructor) { + app.component(Switch.name, Switch) +} + +export const _SwitchComponent = Switch + +export default Switch diff --git a/packages/varlet-vue2-ui/src/switch/props.ts b/packages/varlet-vue2-ui/src/switch/props.ts new file mode 100644 index 0000000..7779015 --- /dev/null +++ b/packages/varlet-vue2-ui/src/switch/props.ts @@ -0,0 +1,54 @@ +import type { PropType } from 'vue' + +export const props = { + value: { + default: false, + }, + activeValue: { + default: true, + }, + inactiveValue: { + default: false, + }, + disabled: { + type: Boolean, + default: false, + }, + readonly: { + type: Boolean, + default: false, + }, + loading: { + type: Boolean, + default: false, + }, + color: { + type: String, + }, + loadingColor: { + type: String, + }, + closeColor: { + type: String, + }, + size: { + type: [String, Number], + default: 20, + }, + rules: { + type: Array as PropType any>>, + }, + ripple: { + type: Boolean, + default: true, + }, + onClick: { + type: Function as PropType<(event: MouseEvent) => void>, + }, + onChange: { + type: Function as PropType<(value: boolean) => void>, + }, + onInput: { + type: Function as PropType<(value: boolean) => void>, + }, +} diff --git a/packages/varlet-vue2-ui/src/switch/switch.less b/packages/varlet-vue2-ui/src/switch/switch.less new file mode 100644 index 0000000..0a173f8 --- /dev/null +++ b/packages/varlet-vue2-ui/src/switch/switch.less @@ -0,0 +1,80 @@ +@switch-track-background: #fff; +@switch-track-active-background: var(--color-primary); +@switch-track-error-background: var(--color-danger); +@switch-ripple-color: var(--color-primary); +@switch-handle-background: #fff; +@switch-handle-color: #fff; +@switch-handle-active-background: var(--color-primary); +@switch-handle-error-background: var(--color-danger); + +:root { + --switch-track-background: @switch-track-background; + --switch-track-active-background: @switch-track-active-background; + --switch-track-error-background: @switch-track-error-background; + --switch-ripple-color: @switch-ripple-color; + --switch-handle-background: @switch-handle-background; + --switch-handle-color: @switch-handle-color; + --switch-handle-active-background: @switch-handle-active-background; + --switch-handle-error-background: @switch-handle-error-background; +} + +.var-switch { + display: inline-block; + + &-block { + position: relative; + display: flex; + cursor: pointer; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + align-items: center; + justify-content: center; + } + + &__disable { + filter: opacity(0.6); + cursor: not-allowed; + } + + &__track { + background: var(--switch-track-background); + transition: background-color 0.25s; + filter: opacity(0.6); + + &-active { + background-color: var(--switch-track-active-background); + } + + &-error { + background-color: var(--switch-track-error-background) !important; + } + } + + &__ripple { + position: absolute; + display: flex; + align-items: center; + justify-content: center; + color: var(--switch-ripple-color); + border-radius: 50%; + overflow: hidden; + transition: 0.3s var(--cubic-bezier); + } + + &__handle { + border-radius: 50%; + background-color: var(--switch-handle-background); + display: flex; + align-items: center; + justify-content: center; + color: var(--switch-handle-color); + transition: background-color 0.25s; + + &-active { + background-color: var(--switch-handle-active-background); + } + + &-error { + background-color: var(--switch-handle-error-background) !important; + } + } +} diff --git a/packages/varlet-vue2-ui/types/global.d.ts b/packages/varlet-vue2-ui/types/global.d.ts index 7f8c166..6150846 100644 --- a/packages/varlet-vue2-ui/types/global.d.ts +++ b/packages/varlet-vue2-ui/types/global.d.ts @@ -21,6 +21,7 @@ declare module 'vue' { VarRate: typeof import('@varlet-vue2/ui')['_RateComponent'] VarSkeleton: typeof import('@varlet-vue2/ui')['_SkeletonComponent'] VarSnackbar: typeof import('@varlet-vue2/ui')['_SnackbarComponent'] + VarSwitch: typeof import('@varlet-vue2/ui')['_SwitchComponent'] VarSticky: typeof import('@varlet-vue2/ui')['_StickyComponent'] } } diff --git a/packages/varlet-vue2-ui/types/index.d.ts b/packages/varlet-vue2-ui/types/index.d.ts index 657c34a..5de106e 100644 --- a/packages/varlet-vue2-ui/types/index.d.ts +++ b/packages/varlet-vue2-ui/types/index.d.ts @@ -29,5 +29,6 @@ export * from './loading' export * from './menu' export * from './input' export * from './table' +export * from './switch' export * from './varComponent' export * from './varDirective' diff --git a/packages/varlet-vue2-ui/types/switch.d.ts b/packages/varlet-vue2-ui/types/switch.d.ts new file mode 100644 index 0000000..ccb31a5 --- /dev/null +++ b/packages/varlet-vue2-ui/types/switch.d.ts @@ -0,0 +1,25 @@ +import { VarComponent } from './varComponent' + +export interface SwitchProps { + value?: any + activeValue?: any + inactiveValue?: any + disabled?: boolean + readonly?: boolean + loading?: boolean + ripple?: boolean + color?: string + loadingColor?: string + closeColor?: string + size?: string | number + rules?: Array<(value: any) => any> + onClick?: (event: MouseEvent) => void + onChange?: (value: boolean) => void + onInput?: (value: boolean) => void +} + +export class Switch extends VarComponent { + $props: SwitchProps +} + +export class _SwitchComponent extends Switch {}