Skip to content

Commit

Permalink
feat(comp:button,checkbox,radio): add waveless prop
Browse files Browse the repository at this point in the history
  • Loading branch information
liuzaijiang committed Dec 9, 2022
1 parent f448714 commit 3e79f7f
Show file tree
Hide file tree
Showing 51 changed files with 1,845 additions and 349 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
// Vitest Snapshot v1

exports[`Footer > render work 1`] = `"<div><button class=\\"ix-button ix-button-primary ix-button-md\\" type=\\"button\\"><span>ok</span></button><button class=\\"ix-button ix-button-default ix-button-md\\" type=\\"button\\"><span>cancel</span></button></div>"`;
exports[`Footer > render work 1`] = `
"<div><button class=\\"ix-button ix-button-primary ix-button-md\\" type=\\"button\\"><span>ok</span>
<div aria-hidden=\\"true\\" class=\\"ix-wave\\"></div>
</button><button class=\\"ix-button ix-button-default ix-button-md\\" type=\\"button\\"><span>cancel</span>
<div aria-hidden=\\"true\\" class=\\"ix-wave\\"></div>
</button></div>"
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Vitest Snapshot v1

exports[`Wave > render work 1`] = `"<div aria-hidden=\\"true\\" class=\\"ix-wave\\"></div>"`;
13 changes: 13 additions & 0 deletions packages/components/_private/wave/__tests__/wave.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//import { mount, MountingOptions } from '@vue/test-utils'
import { renderWork } from '@tests'

import Wave from '../src/Wave'
import { WaveProps } from '../src/types'

describe('Wave', () => {
//const WaveMount = (options?: MountingOptions<Partial<WaveProps>>) => mount(Wave, { ...(options as MountingOptions<WaveProps>)})

renderWork<WaveProps>(Wave, {
props: {},
})
})
20 changes: 20 additions & 0 deletions packages/components/_private/wave/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* @license
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE
*/

import type { WaveComponent } from './src/types'

import Wave from './src/Wave'

const ɵWave = Wave as unknown as WaveComponent

export { ɵWave }

export type {
WaveInstance as ɵWaveInstance,
WaveComponent as ɵWaveComponent,
WavePublicProps as ɵWaveProps,
} from './src/types'
57 changes: 57 additions & 0 deletions packages/components/_private/wave/src/Wave.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* @license
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE
*/

import { computed, defineComponent, nextTick, ref } from 'vue'

import { useGlobalConfig } from '@idux/components/config'

import { waveProps } from './types'

export default defineComponent({
name: 'ɵWave',
props: waveProps,
setup(_, { expose }) {
const common = useGlobalConfig('common')
const mergedPrefixCls = computed(() => `${common.prefixCls}-wave`)

const selfRef = ref<HTMLElement>()

const play = () => {
nextTick(() => {
if (selfRef.value && selfRef.value.parentElement && selfRef.value.animate) {
const borderColor = getComputedStyle(selfRef.value.parentElement).borderColor
selfRef.value.animate(
[
{
// from
opacity: 0.6,
boxShadow: `0 0 1px 0 ${borderColor}`,
zIndex: 1,
easing: 'cubic-bezier(0, 0, 0.2, 1)',
},
{
// to
opacity: 0,
zIndex: 0,
boxShadow: `0 0 1px 5px ${borderColor}`,
},
],
600,
)
}
})
}

expose({
play,
})

return () => {
return <div ref={selfRef} aria-hidden class={mergedPrefixCls.value} />
}
},
})
20 changes: 20 additions & 0 deletions packages/components/_private/wave/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* @license
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE
*/

import type { ExtractInnerPropTypes, ExtractPublicPropTypes } from '@idux/cdk/utils'
import type { DefineComponent, HTMLAttributes } from 'vue'

export const waveProps = {} as const

export interface WaveBindings {
play: () => void
}

export type WaveProps = ExtractInnerPropTypes<typeof waveProps>
export type WavePublicProps = ExtractPublicPropTypes<typeof waveProps>
export type WaveComponent = DefineComponent<Omit<HTMLAttributes, keyof WavePublicProps> & WavePublicProps>
export type WaveInstance = InstanceType<DefineComponent<WaveProps, WaveBindings>>
9 changes: 9 additions & 0 deletions packages/components/_private/wave/style/index.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.@{wave-prefix} {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
border-radius: inherit;
pointer-events: none;
}
3 changes: 3 additions & 0 deletions packages/components/_private/wave/style/themes/default.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@import '../../../../style/themes/default.less';
@import './default.variable.less';
@import '../index.less';
2 changes: 2 additions & 0 deletions packages/components/_private/wave/style/themes/default.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// style dependencies
import './default.less'
Empty file.
4 changes: 4 additions & 0 deletions packages/components/_private/wave/style/themes/seer.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@import '../../../../style/themes/seer.less';
@import './seer.variable.less';

@import '../index.less';
2 changes: 2 additions & 0 deletions packages/components/_private/wave/style/themes/seer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// style dependencies
import './seer.less'
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@import './default.variable.less';
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
// Vitest Snapshot v1

exports[`Button > render work 1`] = `"<button class=\\"ix-button ix-button-default ix-button-md\\" type=\\"button\\"></button>"`;
exports[`Button > render work 1`] = `
"<button class=\\"ix-button ix-button-default ix-button-md\\" type=\\"button\\">
<div aria-hidden=\\"true\\" class=\\"ix-wave\\"></div>
</button>"
`;
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,17 @@

exports[`ButtonGroup > render work 1`] = `
"<div class=\\"ix-space ix-space-align-center ix-button-group ix-button-group-compact\\" style=\\"margin-bottom: -0px;\\">
<div class=\\"ix-space-item\\" style=\\"margin-right: 0px; padding-bottom: 0px;\\"><button class=\\"ix-button ix-button-default ix-button-md\\" type=\\"button\\"><span>default</span></button></div>
<div class=\\"ix-space-item\\" style=\\"margin-right: 0px; padding-bottom: 0px;\\"><button class=\\"ix-button ix-button-primary ix-button-md\\" type=\\"button\\"><span>primary</span></button></div>
<div class=\\"ix-space-item\\" style=\\"margin-right: 0px; padding-bottom: 0px;\\"><button class=\\"ix-button ix-button-default ix-button-lg\\" type=\\"button\\"><span>large</span></button></div>
<div class=\\"ix-space-item\\" style=\\"padding-bottom: 0px;\\"><button class=\\"ix-button ix-button-default ix-button-circle ix-button-md\\" type=\\"button\\"><span>circle</span></button></div>
<div class=\\"ix-space-item\\" style=\\"margin-right: 0px; padding-bottom: 0px;\\"><button class=\\"ix-button ix-button-default ix-button-md\\" type=\\"button\\"><span>default</span>
<div aria-hidden=\\"true\\" class=\\"ix-wave\\"></div>
</button></div>
<div class=\\"ix-space-item\\" style=\\"margin-right: 0px; padding-bottom: 0px;\\"><button class=\\"ix-button ix-button-primary ix-button-md\\" type=\\"button\\"><span>primary</span>
<div aria-hidden=\\"true\\" class=\\"ix-wave\\"></div>
</button></div>
<div class=\\"ix-space-item\\" style=\\"margin-right: 0px; padding-bottom: 0px;\\"><button class=\\"ix-button ix-button-default ix-button-lg\\" type=\\"button\\"><span>large</span>
<div aria-hidden=\\"true\\" class=\\"ix-wave\\"></div>
</button></div>
<div class=\\"ix-space-item\\" style=\\"padding-bottom: 0px;\\"><button class=\\"ix-button ix-button-default ix-button-circle ix-button-md\\" type=\\"button\\"><span>circle</span>
<div aria-hidden=\\"true\\" class=\\"ix-wave\\"></div>
</button></div>
</div>"
`;
27 changes: 27 additions & 0 deletions packages/components/button/__tests__/button.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,31 @@ describe('Button', () => {
})
expect(wrapper.text()).toEqual(text)
})

test('waveless work', async () => {
const text = 'Button'
const wrapper = ButtonMount({
slots: {
default: text,
},
})

expect(wrapper.find('.ix-wave').exists()).toBeTruthy()

await wrapper.setProps({ waveless: true })

expect(wrapper.find('.ix-wave').exists()).toBeFalsy()

await wrapper.setProps({ waveless: false, mode: 'text' })

expect(wrapper.find('.ix-wave').exists()).toBeFalsy()

await wrapper.setProps({ mode: 'link' })

expect(wrapper.find('.ix-wave').exists()).toBeFalsy()

await wrapper.setProps({ mode: 'default' })

expect(wrapper.find('.ix-wave').exists()).toBeTruthy()
})
})
2 changes: 1 addition & 1 deletion packages/components/button/demo/Group.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<IxSpace>
<IxButtonGroup>
<IxButtonGroup vertical>
<IxButton>Default</IxButton>
<IxButton icon="setting" shape="square"></IxButton>
</IxButtonGroup>
Expand Down
1 change: 1 addition & 0 deletions packages/components/button/docs/Api.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
| `shape` | 设置按钮形状 | `'square' \| 'circle' \| 'round'` | - | - |- |
| `size` | 设置按钮大小 | `'xl' \| 'lg' \| 'md' \| 'sm' \| 'xs'` | `'md'` || `seer` 主题下默认为 `'sm'` |
| `type` | 原生 `button``type` 属性 | `'button' \| 'submit' \| 'reset'` | `'button'` | - | 参考 [HTML 标准](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-type) |
| `waveless` | 是否关闭按钮点击时波纹动画 | `boolean` | `false` || 不支持`link``text`模式,且存在[浏览器兼容性](https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Animations_API/Keyframe_Formats#%E6%B5%8F%E8%A7%88%E5%99%A8%E5%85%BC%E5%AE%B9%E6%80%A7) |

#### ButtonSlots

Expand Down
13 changes: 12 additions & 1 deletion packages/components/button/src/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
* found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE
*/

import { type VNodeChild, computed, defineComponent, inject, normalizeClass } from 'vue'
import { type VNodeChild, computed, defineComponent, inject, normalizeClass, ref } from 'vue'

import { callEmit } from '@idux/cdk/utils'
import { ɵWave, type ɵWaveInstance } from '@idux/components/_private/wave'
import { useGlobalConfig } from '@idux/components/config'
import { FORM_TOKEN } from '@idux/components/form'
import { IxIcon } from '@idux/components/icon'
Expand All @@ -27,8 +28,13 @@ export default defineComponent({
const groupProps = inject(buttonToken, {} as ButtonGroupProps)
const formContext = inject(FORM_TOKEN, null)

const waveRef = ref<ɵWaveInstance>()

const mode = computed(() => props.mode ?? groupProps.mode ?? 'default')
const size = computed(() => props.size ?? groupProps.size ?? formContext?.size.value ?? config.size)
const mergedWaveless = computed(
() => mode.value === 'text' || mode.value === 'link' || (props.waveless ?? config.waveless),
)

const classes = computed(() => {
const {
Expand Down Expand Up @@ -61,6 +67,10 @@ export default defineComponent({
evt.stopImmediatePropagation()
return
}

if (!mergedWaveless.value && waveRef.value) {
waveRef.value.play()
}
callEmit(props.onClick, evt)
}

Expand Down Expand Up @@ -95,6 +105,7 @@ export default defineComponent({
return (
<button class={classes.value} disabled={disabled || loading} type={type} onClick={handleClick}>
{children}
{!mergedWaveless.value && <ɵWave ref={waveRef} />}
</button>
)
}
Expand Down
1 change: 1 addition & 0 deletions packages/components/button/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const buttonProps = {
size: String as PropType<ButtonSize>,
shape: String as PropType<ButtonShape>,
type: { type: String as PropType<ButtonType>, default: 'button' },
waveless: { type: Boolean, default: undefined },

onClick: [Function, Array] as PropType<(evt: MouseEvent) => void>,
} as const
Expand Down
2 changes: 1 addition & 1 deletion packages/components/button/style/themes/default.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// style dependencies

import '@idux/components/_private/wave/style/themes/default'
import '@idux/components/icon/style/themes/default'

import './default.less'
2 changes: 1 addition & 1 deletion packages/components/button/style/themes/seer.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// style dependencies

import '@idux/components/_private/wave/style/themes/seer'
import '@idux/components/icon/style/themes/seer'

import './seer.less'
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// Vitest Snapshot v1

exports[`Checkbox > render work 1`] = `
"<label class=\\"ix-checkbox\\" role=\\"checkbox\\" aria-checked=\\"false\\"><span class=\\"ix-checkbox-input\\"><input type=\\"checkbox\\" class=\\"ix-checkbox-input-inner\\" aria-hidden=\\"true\\"><span class=\\"ix-checkbox-input-box\\"></span></span>
"<label class=\\"ix-checkbox\\" role=\\"checkbox\\" aria-checked=\\"false\\"><span class=\\"ix-checkbox-input\\"><input type=\\"checkbox\\" class=\\"ix-checkbox-input-inner\\" aria-hidden=\\"true\\"><span class=\\"ix-checkbox-input-box\\"><div aria-hidden=\\"true\\" class=\\"ix-wave\\"></div></span></span>
<!---->
<!---->
<!---->
</label>"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@

exports[`CheckboxGroup > render work 1`] = `
"<div class=\\"ix-space ix-checkbox-group\\" style=\\"margin-bottom: -8px;\\">
<div class=\\"ix-space-item\\" style=\\"margin-right: 8px; padding-bottom: 8px;\\"><label class=\\"ix-checkbox\\" role=\\"checkbox\\" aria-checked=\\"false\\" aria-disabled=\\"false\\"><span class=\\"ix-checkbox-input\\"><input type=\\"checkbox\\" class=\\"ix-checkbox-input-inner\\" aria-hidden=\\"true\\" value=\\"option1\\"><span class=\\"ix-checkbox-input-box\\"></span></span>
<div class=\\"ix-space-item\\" style=\\"margin-right: 8px; padding-bottom: 8px;\\"><label class=\\"ix-checkbox\\" role=\\"checkbox\\" aria-checked=\\"false\\" aria-disabled=\\"false\\"><span class=\\"ix-checkbox-input\\"><input type=\\"checkbox\\" class=\\"ix-checkbox-input-inner\\" aria-hidden=\\"true\\" value=\\"option1\\"><span class=\\"ix-checkbox-input-box\\"><div aria-hidden=\\"true\\" class=\\"ix-wave\\"></div></span></span>
<!---->
<!----><span class=\\"ix-checkbox-label\\">option1</span>
</label></div>
<div class=\\"ix-space-item\\" style=\\"margin-right: 8px; padding-bottom: 8px;\\"><label class=\\"ix-checkbox\\" role=\\"checkbox\\" aria-checked=\\"false\\" aria-disabled=\\"false\\"><span class=\\"ix-checkbox-input\\"><input type=\\"checkbox\\" class=\\"ix-checkbox-input-inner\\" aria-hidden=\\"true\\" value=\\"option2\\"><span class=\\"ix-checkbox-input-box\\"></span></span>
<div class=\\"ix-space-item\\" style=\\"margin-right: 8px; padding-bottom: 8px;\\"><label class=\\"ix-checkbox\\" role=\\"checkbox\\" aria-checked=\\"false\\" aria-disabled=\\"false\\"><span class=\\"ix-checkbox-input\\"><input type=\\"checkbox\\" class=\\"ix-checkbox-input-inner\\" aria-hidden=\\"true\\" value=\\"option2\\"><span class=\\"ix-checkbox-input-box\\"><div aria-hidden=\\"true\\" class=\\"ix-wave\\"></div></span></span>
<!---->
<!----><span class=\\"ix-checkbox-label\\">option2</span>
</label></div>
<div class=\\"ix-space-item\\" style=\\"padding-bottom: 8px;\\"><label class=\\"ix-checkbox\\" role=\\"checkbox\\" aria-checked=\\"false\\" aria-disabled=\\"false\\"><span class=\\"ix-checkbox-input\\"><input type=\\"checkbox\\" class=\\"ix-checkbox-input-inner\\" aria-hidden=\\"true\\" value=\\"option3\\"><span class=\\"ix-checkbox-input-box\\"></span></span>
<div class=\\"ix-space-item\\" style=\\"padding-bottom: 8px;\\"><label class=\\"ix-checkbox\\" role=\\"checkbox\\" aria-checked=\\"false\\" aria-disabled=\\"false\\"><span class=\\"ix-checkbox-input\\"><input type=\\"checkbox\\" class=\\"ix-checkbox-input-inner\\" aria-hidden=\\"true\\" value=\\"option3\\"><span class=\\"ix-checkbox-input-box\\"><div aria-hidden=\\"true\\" class=\\"ix-wave\\"></div></span></span>
<!---->
<!----><span class=\\"ix-checkbox-label\\">option3</span>
</label></div>
</div>"
Expand Down
16 changes: 16 additions & 0 deletions packages/components/checkbox/__tests__/checkbox.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,4 +203,20 @@ describe('Checkbox', () => {

expect(blurFn).toBeCalledTimes(1)
})

test('waveless work', async () => {
const wrapper = CheckboxMount()

expect(wrapper.find('.ix-checkbox-input-box .ix-wave').exists()).toBeTruthy()
expect(wrapper.find('.ix-checkbox-input-tick + .ix-wave').exists()).toBeFalsy()

await wrapper.setProps({ buttoned: true })

expect(wrapper.find('.ix-checkbox-input-box .ix-wave').exists()).toBeFalsy()
expect(wrapper.find('.ix-checkbox-input-tick + .ix-wave').exists()).toBeTruthy()

await wrapper.setProps({ waveless: true })

expect(wrapper.find('.ix-wave').exists()).toBeFalsy()
})
})
1 change: 1 addition & 0 deletions packages/components/checkbox/docs/Api.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
| `value` | 设置勾选框的值,与 `IxCheckboxGroup` 配合使用 | `any`| - | - | 不传时使用 `key` 作为 `value` |
| `size` | 按钮大小 | `'sm' \| 'md' \| 'lg'` | `md` | - |`buttoned``true`时生效 |
| `onChange` | 选中状态发生变化后的回调 | `(newChecked: boolean \| string \| number, oldChecked: boolean \| string \| number) => void`| - | - | - |
| `waveless` | 是否关闭按钮点击时波纹动画 | `boolean` | `false` || 存在[浏览器兼容性](https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Animations_API/Keyframe_Formats#%E6%B5%8F%E8%A7%88%E5%99%A8%E5%85%BC%E5%AE%B9%E6%80%A7) |

#### CheckboxMethods

Expand Down

0 comments on commit 3e79f7f

Please sign in to comment.