diff --git a/packages/varlet-vue2-ui/src/counter/Counter.vue b/packages/varlet-vue2-ui/src/counter/Counter.vue new file mode 100644 index 0000000..2899e21 --- /dev/null +++ b/packages/varlet-vue2-ui/src/counter/Counter.vue @@ -0,0 +1,312 @@ + + + + + diff --git a/packages/varlet-vue2-ui/src/counter/__tests__/__snapshots__/index.spec.js.snap b/packages/varlet-vue2-ui/src/counter/__tests__/__snapshots__/index.spec.js.snap new file mode 100644 index 0000000..b92c379 --- /dev/null +++ b/packages/varlet-vue2-ui/src/counter/__tests__/__snapshots__/index.spec.js.snap @@ -0,0 +1,82 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`test counter example 1`] = ` +"
+
基本使用
+
+
+ + + +
+
设置取值范围
+
+
+ + + +
+
设置步长
+
+
+ + + +
+
保留小数
+
+
+ + + +
+
设置尺寸
+
+
+ + + +
+
禁用
+
+
+ + + +
+
只读
+
+
+ + + +
+
异步变更
+
+
+ + + +
+
字段校验
+
+
+ + + +
+
+
" +`; + +exports[`test counter validation 1`] = ` +"
+
+ +
+
必须大于0
+
+
+
+
" +`; diff --git a/packages/varlet-vue2-ui/src/counter/__tests__/index.spec.js b/packages/varlet-vue2-ui/src/counter/__tests__/index.spec.js new file mode 100644 index 0000000..a8f4a3e --- /dev/null +++ b/packages/varlet-vue2-ui/src/counter/__tests__/index.spec.js @@ -0,0 +1,173 @@ +import example from '../example' +import Counter from '..' +import VarCounter from '../Counter' +import { mount } from '@vue/test-utils' +import Vue from 'vue' +import { delay, trigger } from '../../utils/jest' + +test('test counter example', () => { + const wrapper = mount(example) + expect(wrapper.html()).toMatchSnapshot() + wrapper.destroy() +}) + +test('test counter plugin', () => { + Vue.use(Counter) + expect(Vue.component(Counter.name)).toBeTruthy() +}) + +const Wrapper = { + components: { + [VarCounter.name]: VarCounter, + }, + data: () => ({ + value: 0, + }), + template: ``, +} + +test('test counter increment & decrement', async () => { + const wrapper = mount(Wrapper) + + await wrapper.find('.var-counter__increment-button').trigger('click') + expect(wrapper.vm.value).toBe(1) + await wrapper.find('.var-counter__decrement-button').trigger('click') + expect(wrapper.vm.value).toBe(0) + + wrapper.destroy() +}) + +test('test counter initial value over max', async () => { + const wrapper = mount({ + ...Wrapper, + data: () => ({ + value: 11, + }), + template: ``, + }) + + expect(wrapper.vm.value).toBe(10) + + wrapper.destroy() +}) + +test('test counter initial value less min', async () => { + const wrapper = mount({ + ...Wrapper, + data: () => ({ + value: -1, + }), + template: ``, + }) + + expect(wrapper.vm.value).toBe(0) + + wrapper.destroy() +}) + +test('test counter onChange', async () => { + const onChange = jest.fn() + + const wrapper = mount({ + ...Wrapper, + methods: { + onChange, + }, + template: ``, + }) + + wrapper.find('.var-counter__input').setValue('1') + await wrapper.find('.var-counter__input').trigger('change') + expect(onChange).lastCalledWith(1) + + wrapper.destroy() +}) + +test('test counter press increment', async () => { + const wrapper = mount(Wrapper) + + await trigger(wrapper.find('.var-counter__increment-button'), 'touchstart') + await delay(800) + + const current = wrapper.vm.value + expect(current).toBeGreaterThan(0) + + await trigger(wrapper.find('.var-counter__increment-button'), 'touchend') + await delay(100) + expect(wrapper.vm.value).toBe(current) + + wrapper.destroy() +}) + +test('test counter press decrement', async () => { + const wrapper = mount(Wrapper) + + await trigger(wrapper.find('.var-counter__decrement-button'), 'touchstart') + await delay(750) + + const current = wrapper.vm.value + expect(current).toBeLessThan(0) + + await trigger(wrapper.find('.var-counter__decrement-button'), 'touchend') + await delay(750) + expect(wrapper.vm.value).toBe(current) + + wrapper.destroy() +}) + +test('test counter lazy change', async () => { + const wrapper = mount({ + ...Wrapper, + methods: { + onBeforeChange(value, change) { + const isInc = value > wrapper.vm.value + change(isInc ? value + 1 : value - 1) + }, + }, + template: ``, + }) + + await wrapper.find('.var-counter__increment-button').trigger('click') + expect(wrapper.vm.value).toBe(2) + + await wrapper.find('.var-counter__decrement-button').trigger('click') + expect(wrapper.vm.value).toBe(0) + + wrapper.destroy() +}) + +test('test counter disabled', async () => { + const wrapper = mount({ + ...Wrapper, + template: ``, + }) + + await wrapper.find('.var-counter__increment-button').trigger('click') + expect(wrapper.vm.value).toBe(0) + + await wrapper.find('.var-counter__decrement-button').trigger('click') + expect(wrapper.vm.value).toBe(0) +}) + +test('test counter validation', async () => { + const wrapper = mount({ + ...Wrapper, + template: ``, + }) + + const { counter } = wrapper.vm.$refs + + counter.validate() + await delay(16) + + expect(wrapper.html()).toMatchSnapshot() + expect(wrapper.find('.var-form-details__message').text()).toBe('必须大于0') + + await wrapper.find('.var-counter__increment-button').trigger('click') + await delay(16) + expect(wrapper.find('.var-form-details__message').exists()).toBeFalsy() + + counter.reset() + await delay(16) + expect(wrapper.vm.value).toBe(0) +}) diff --git a/packages/varlet-vue2-ui/src/counter/counter.less b/packages/varlet-vue2-ui/src/counter/counter.less new file mode 100644 index 0000000..f968ff3 --- /dev/null +++ b/packages/varlet-vue2-ui/src/counter/counter.less @@ -0,0 +1,85 @@ +@counter-padding: 0 4px; +@counter-font-color: #fff; +@counter-background: var(--color-primary); +@counter-input-width: 28px; +@counter-input-margin: 0 4px; +@counter-input-font-size: 14px; +@counter-button-size: 28px; +@counter-button-icon-size: 100%; +@counter-disabled-color: var(--color-text-disabled); +@input-error-color: var(--color-danger); + +:root { + --counter-padding: @counter-padding; + --counter-font-color: @counter-font-color; + --counter-background: @counter-background; + --counter-input-width: @counter-input-width; + --counter-input-margin: @counter-input-margin; + --counter-input-font-size: @counter-input-font-size; + --counter-button-size: @counter-button-size; + --counter-button-icon-size: @counter-button-icon-size; + --counter-disabled-color: @counter-disabled-color; + --input-error-color: @input-error-color; +} + +.var-counter { + display: inline-flex; + flex-direction: column; + align-items: flex-start; + + &__controller { + display: flex; + align-items: center; + color: var(--counter-font-color); + border-radius: var(--counter-button-size); + padding: var(--counter-padding); + background: var(--counter-background); + transition: background-color 0.25s; + } + + &__decrement-button[var-counter-cover] { + width: var(--counter-button-size); + height: var(--counter-button-size); + font-size: var(--counter-button-icon-size); + border-radius: 50%; + cursor: pointer; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + } + + &__input { + width: var(--counter-input-width); + font-size: var(--counter-input-font-size); + outline: none; + border: none; + background: transparent; + padding: 0; + text-align: center; + color: var(--counter-font-color); + margin: var(--counter-input-margin); + + &[disabled] { + background: transparent; + } + } + + &__increment-button[var-counter-cover] { + width: var(--counter-button-size); + height: var(--counter-button-size); + font-size: var(--counter-button-icon-size); + border-radius: 50%; + cursor: pointer; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + } + + &--disabled { + background: var(--counter-disabled-color); + } + + &--hidden { + opacity: 0; + } + + &--error { + background: var(--color-danger); + } +} diff --git a/packages/varlet-vue2-ui/src/counter/docs/en-US.md b/packages/varlet-vue2-ui/src/counter/docs/en-US.md new file mode 100644 index 0000000..1312470 --- /dev/null +++ b/packages/varlet-vue2-ui/src/counter/docs/en-US.md @@ -0,0 +1,165 @@ +# Counter + +### Install + +```js +import Vue from 'vue' +import { Counter } from '@varlet-vue2/ui' + +Vue.use(Counter) +``` + +### Basic Usage + +```js +export default { + data: () => ({ + value: 0 + }) +} +``` + +```html + +``` + +### Set the value range + +```html + +``` + +### Set step + +```html + +``` + +### Decimal length + +```html + +``` + +### Set size + +```html + +``` + +### Disabled + +```html + +``` + +### Readonly + +```html + +``` + +### Asynchronous change + +In some scenarios, you may need to wait for the server to return successfully before making changes. +`lazy-change` prevents binding value updates on the component itself. +Register `before-change` events for manual updates. + +```html + +``` + +```js +export default { + data: () => ({ + value: 0 + }), + methods: { + handleBeforeChange(value, change) { + setTimeout(() => change(value), 500) + } + } +} +``` + +### Validate + +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` | The value of the binding | _string \| number_ | `0` | +| `min` | Minimum value | _string \| number_ | `-` | +| `max` | Maximum value | _string \| number_ | `-` | +| `step` | Step size | _string \| number_ | `-` | +| `decimal-length` | Preserve decimal places | _string \| number_ | `-` | +| `color` | Background color | _string_ | `-` | +| `input-width` | The width of the input box | _string \| number_ | `-` | +| `input-text-size` | The text size of the input box | _string \| number_ | `-` | +| `button-size` | Button size | _string_ | `true` | +| `readonly` | Whether the readonly | _boolean_ | `false` | +| `disabled` | Whether the disabled | _boolean_ | `false` | +| `disable-increment` | Whether to disable increments | _boolean_ | `false` | +| `disable-decrement` | Whether to disable decrements | _boolean_ | `false` | +| `disable-input` | Whether to disable input | _boolean_ | `false` | +| `increment-button` | Whether to display the increment button | _boolean_ | `true` | +| `decrement-button` | Whether to display the decrement button | _boolean_ | `true` | +| `press` | Long press the open button | _boolean_ | `true` | +| `ripple` | Whether to open ripple | _boolean_ | `true` | +| `validate-trigger` | Timing to trigger validation,Optional value is `onInputChange` `onLazyChange` `onIncrement` `onDecrement` | _ValidateTriggers[]_ | `['onIncrement', 'onDecrement', 'onInputChange', 'onLazyChange']` | +| `rules` | The validation rules,Returns `true` to indicate that the validation passed,The remaining values are converted to text as user prompts | _Array<(value: number) => any>_ | `-` | + +### Methods + +| Method | Description | Arguments | Return | +| --- | --- | --- | --- | +| `validate` | Trigger validate | `-` | `valid: Promise` | +| `resetValidation` | Clearing validate messages | `-` | `-` | +| `reset` | Clear the value of the binding(set to `min \|\| 0`)and validate messages | `-` | `-` | + +### Events + +| Event | Description | Arguments | +| --- | --- | --- | +| `before-change` | Triggered before the change (lazy-change mode only) | `value: number`
`change: (value: string \| number) => void` | +| `change` | Triggered on change | `value: number` | +| `increment` | Triggered on increment | `value: number` | +| `decrement` | Triggered on decrement | `value: number` | + + +### Style Variables +Here are the CSS variables used by the component, Styles can be customized using [StyleProvider](#/en-US/style-provider) + +| Variable | Default | +| --- | --- | +| `--counter-padding` | `0 4px` | +| `--counter-font-color` | `#fff` | +| `--counter-background` | `var(--color-primary)` | +| `--counter-input-width` | `28px` | +| `--counter-input-margin` | `0 4px` | +| `--counter-input-font-size` | `14px` | +| `--counter-button-size` | `28px` | +| `--counter-button-icon-size` | `100%` | +| `--counter-disabled-color` | `var(--color-text-disabled)` | +| `--input-error-color` | `var(--color-danger)` | \ No newline at end of file diff --git a/packages/varlet-vue2-ui/src/counter/docs/zh-CN.md b/packages/varlet-vue2-ui/src/counter/docs/zh-CN.md new file mode 100644 index 0000000..6fd745d --- /dev/null +++ b/packages/varlet-vue2-ui/src/counter/docs/zh-CN.md @@ -0,0 +1,165 @@ +# 计数器 + +### 引入 + +```js +import Vue from 'vue' +import { Counter } from '@varlet-vue2/ui' + +Vue.use(Counter) +``` + +### 基本使用 + +```js +export default { + data: () => ({ + value: 0 + }) +} +``` + +```html + +``` + +### 设置取值范围 + +```html + +``` + +### 设置步长 + +```html + +``` + +### 保留小数 + +```html + +``` + +### 设置尺寸 + +```html + +``` + +### 禁用 + +```html + +``` + +### 只读 + +```html + +``` + +### 异步变更 + +在某些场景下需要等待服务器返回成功之后再执行变更。 +设置 `lazy-change` 后会阻止组件本身的绑定值更新操作, +并注册 `before-change` 事件进行手动更新。 + +```html + +``` + +```js +export default { + data: () => ({ + value: 0 + }), + methods: { + handleBeforeChange(value, change) { + setTimeout(() => change(value), 500) + } + } +} +``` + +### 字段校验 + +通过传入一个校验器数组可以对值进行校验,校验器返回 `true` 则为校验通过。 +以外的值将转换为文本作为用户提示。 + +```html + +``` + +## API + +### 属性 + +| 参数 | 说明 | 类型 | 默认值 | +| --- | --- | --- | --- | +| `v-model` | 绑定的值 | _string \| number_ | `0` | +| `min` | 最小值 | _string \| number_ | `-` | +| `max` | 最大值 | _string \| number_ | `-` | +| `step` | 步长 | _string \| number_ | `-` | +| `decimal-length` | 保留小数位数 | _string \| number_ | `-` | +| `color` | 背景颜色 | _string_ | `-` | +| `input-width` | 输入框的宽度 | _string \| number_ | `-` | +| `input-text-size` | 输入框的文字大小 | _string \| number_ | `-` | +| `button-size` | 按钮大小 | _string_ | `true` | +| `readonly` | 是否只读 | _boolean_ | `false` | +| `disabled` | 是否禁用 | _boolean_ | `false` | +| `disable-increment` | 是否禁用增加 | _boolean_ | `false` | +| `disable-decrement` | 是否禁用减少 | _boolean_ | `false` | +| `disable-input` | 是否禁用输入 | _boolean_ | `false` | +| `increment-button` | 是否显示增加按钮 | _boolean_ | `true` | +| `decrement-button` | 是否显示减少按钮 | _boolean_ | `true` | +| `press` | 是否开启按钮长按 | _boolean_ | `true` | +| `ripple` | 是否开启水波纹 | _boolean_ | `true` | +| `validate-trigger` | 触发验证的时机,可选值为 `onInputChange` `onLazyChange` `onIncrement` `onDecrement` | _ValidateTriggers[]_ | `['onIncrement', 'onDecrement', 'onInputChange', 'onLazyChange']` | +| `rules` | 验证规则,返回 `true` 表示验证通过,其余的值则转换为文本作为用户提示 | _Array<(value: number) => any>_ | `-` | + +### 方法 + +| 方法名 | 说明 | 参数 | 返回值 | +| --- | --- | --- | --- | +| `validate` | 触发校验 | `-` | `valid: Promise` | +| `resetValidation` | 清空校验信息 | `-` | `-` | +| `reset` | 清空绑定的值(设置为 `min \|\| 0`)和校验信息 | `-` | `-` | + +### 事件 + +| 事件名 | 说明 | 参数 | +| --- | --- | --- | +| `before-change` | 变更之前(仅限 lazy-change 模式)触发 | `value: number`
`change: (value: string \| number) => void` | +| `change` | 变更时触发 | `value: number` | +| `increment` | 增加时触发 | `value: number` | +| `decrement` | 减少时触发 | `value: number` | + + +### 样式变量 +以下为组件使用的 css 变量,可以使用 [StyleProvider 组件](#/zh-CN/style-provider)进行样式定制 + +| 变量名 | 默认值 | +| --- | --- | +| `--counter-padding` | `0 4px` | +| `--counter-font-color` | `#fff` | +| `--counter-background` | `var(--color-primary)` | +| `--counter-input-width` | `28px` | +| `--counter-input-margin` | `0 4px` | +| `--counter-input-font-size` | `14px` | +| `--counter-button-size` | `28px` | +| `--counter-button-icon-size` | `100%` | +| `--counter-disabled-color` | `var(--color-text-disabled)` | +| `--input-error-color` | `var(--color-danger)` | diff --git a/packages/varlet-vue2-ui/src/counter/example/index.vue b/packages/varlet-vue2-ui/src/counter/example/index.vue new file mode 100644 index 0000000..43ef736 --- /dev/null +++ b/packages/varlet-vue2-ui/src/counter/example/index.vue @@ -0,0 +1,88 @@ + + + + + diff --git a/packages/varlet-vue2-ui/src/counter/example/locale/en-US.ts b/packages/varlet-vue2-ui/src/counter/example/locale/en-US.ts new file mode 100644 index 0000000..ebf22e7 --- /dev/null +++ b/packages/varlet-vue2-ui/src/counter/example/locale/en-US.ts @@ -0,0 +1,12 @@ +export default { + basicUsage: 'Basic Usage', + range: 'Set the value range', + step: 'Set step', + toFixed: 'Decimal length', + disabled: 'Disabled', + readonly: 'Readonly', + lazyChange: 'Asynchronous change', + size: 'Set size', + validate: 'Validate', + validateMessage: 'Please select a value greater than 5', +} diff --git a/packages/varlet-vue2-ui/src/counter/example/locale/index.ts b/packages/varlet-vue2-ui/src/counter/example/locale/index.ts new file mode 100644 index 0000000..d2e375e --- /dev/null +++ b/packages/varlet-vue2-ui/src/counter/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/counter/example/locale/zh-CN.ts b/packages/varlet-vue2-ui/src/counter/example/locale/zh-CN.ts new file mode 100644 index 0000000..078f303 --- /dev/null +++ b/packages/varlet-vue2-ui/src/counter/example/locale/zh-CN.ts @@ -0,0 +1,12 @@ +export default { + basicUsage: '基本使用', + range: '设置取值范围', + step: '设置步长', + toFixed: '保留小数', + disabled: '禁用', + readonly: '只读', + lazyChange: '异步变更', + size: '设置尺寸', + validate: '字段校验', + validateMessage: '请选择大于5的值', +} diff --git a/packages/varlet-vue2-ui/src/counter/index.ts b/packages/varlet-vue2-ui/src/counter/index.ts new file mode 100644 index 0000000..d3bdfad --- /dev/null +++ b/packages/varlet-vue2-ui/src/counter/index.ts @@ -0,0 +1,10 @@ +import type { VueConstructor } from 'vue' +import Counter from './Counter.vue' + +Counter.install = function (app: VueConstructor) { + app.component(Counter.name, Counter) +} + +export const _CounterComponent = Counter + +export default Counter diff --git a/packages/varlet-vue2-ui/src/counter/props.ts b/packages/varlet-vue2-ui/src/counter/props.ts new file mode 100644 index 0000000..09fc45d --- /dev/null +++ b/packages/varlet-vue2-ui/src/counter/props.ts @@ -0,0 +1,82 @@ +import type { PropType } from 'vue' + +export type ValidateTriggers = 'onIncrement' | 'onDecrement' | 'onInputChange' | 'onLazyChange' + +export const props = { + value: { + type: [String, Number], + default: 0, + }, + min: { + type: [String, Number], + }, + max: { + type: [String, Number], + }, + step: { + type: [String, Number], + default: 1, + }, + color: { + type: String, + }, + inputWidth: { + type: [String, Number], + }, + inputTextSize: { + type: [String, Number], + }, + buttonSize: { + type: [String, Number], + }, + decimalLength: { + type: [String, Number], + }, + disabled: { + type: Boolean, + default: false, + }, + readonly: { + type: Boolean, + default: false, + }, + disableIncrement: { + type: Boolean, + default: false, + }, + disableDecrement: { + type: Boolean, + default: false, + }, + disableInput: { + type: Boolean, + default: false, + }, + lazyChange: { + type: Boolean, + default: false, + }, + incrementButton: { + type: Boolean, + default: true, + }, + decrementButton: { + type: Boolean, + default: true, + }, + press: { + type: Boolean, + default: true, + }, + ripple: { + type: Boolean, + default: true, + }, + validateTrigger: { + type: Array as PropType>, + default: () => ['onInputChange', 'onLazyChange', 'onIncrement', 'onDecrement'], + }, + rules: { + type: Array as PropType any>>, + }, +} diff --git a/packages/varlet-vue2-ui/src/input/Input.vue b/packages/varlet-vue2-ui/src/input/Input.vue index 9d9965a..7bdbae6 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 || this.form?.readonly || disabled || readonly || !clearable) { + if (this.formDisabled || this.formReadonly || disabled || readonly || !clearable) { return } @@ -257,7 +257,7 @@ export default defineComponent({ handleClick(e) { const { disabled, getListeners } = this - if (this.form?.disabled || disabled) { + if (this.formDisabled || disabled) { return } diff --git a/packages/varlet-vue2-ui/src/popup/__tests__/__snapshots__/index.spec.js.snap b/packages/varlet-vue2-ui/src/popup/__tests__/__snapshots__/index.spec.js.snap index 7014610..d2127e3 100644 --- a/packages/varlet-vue2-ui/src/popup/__tests__/__snapshots__/index.spec.js.snap +++ b/packages/varlet-vue2-ui/src/popup/__tests__/__snapshots__/index.spec.js.snap @@ -1,12 +1,10 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`test popup show 1`] = ` -" +"
- - - +
" `; diff --git a/packages/varlet-vue2-ui/src/popup/index.ts b/packages/varlet-vue2-ui/src/popup/index.ts index 08bb02e..f73e5aa 100644 --- a/packages/varlet-vue2-ui/src/popup/index.ts +++ b/packages/varlet-vue2-ui/src/popup/index.ts @@ -1,7 +1,7 @@ -import type { App } from 'vue' +import type { VueConstructor } from 'vue' import Popup from './Popup' -Popup.install = function (app: App) { +Popup.install = function (app: VueConstructor) { app.component(Popup.name, Popup) }