Merge branch 'main' of github.com:TuSimple/naive-ui into main

This commit is contained in:
caoyugang 2021-06-24 21:56:57 +08:00
commit 59fff70fd3
9 changed files with 233 additions and 23 deletions

View File

@ -1,5 +1,15 @@
# CHANGELOG
## Pending
### Feats
- `n-carousel` supports touch operation, closes [#271](https://github.com/TuSimple/naive-ui/issues/271).
### Fixes
- Fix `n-date-picker` `n-provider` pass `date-locale` not work, closes [#250](https://github.com/TuSimple/naive-ui/issues/250).
## 2.14.0 (2021-06-23)
### Breaking Changes

View File

@ -1,5 +1,15 @@
# CHANGELOG
## Pending
### Feats
- `n-carousel` 支持触控操作,关闭 [#271](https://github.com/TuSimple/naive-ui/issues/271)
### Fixes
- 修复 `n-date-picker` `n-provider` 传递 `date-locale` 属性无效,关闭 [#250](https://github.com/TuSimple/naive-ui/issues/250)
## 2.14.0 (2021-06-23)
### Breaking Changes

View File

@ -18,9 +18,7 @@ import style from './styles/index.cssr'
const avatarProps = {
...(useTheme.props as ThemeProps<AvatarTheme>),
size: {
type: [String, Number] as PropType<
number | 'tiny' | 'small' | 'medium' | 'large' | 'huge'
>,
type: [String, Number] as PropType<number | 'small' | 'medium' | 'large'>,
default: 'medium'
},
src: String,

View File

@ -157,19 +157,31 @@ describe('n-button', () => {
})
}
})
const circleReg =
/^(?=.*--width: 34px;)(?=.*--padding: initial;)(?=.*--border-radius: 34px;).*$/im
expect(wrapper.find('button').attributes('style')).toMatch(circleReg)
const circleStyle = [
'--width: 34px;',
'--padding: initial;',
'--border-radius: 34px;'
]
let buttonStyle = wrapper.find('button').attributes('style')
expect(circleStyle.every((i) => buttonStyle.includes(i))).toBe(true)
await wrapper.setProps({ circle: false, round: true })
const roundReg =
/^(?=.*--width: initial;)(?=.*--padding: 0 18px;)(?=.*--border-radius: 34px;).*$/im
expect(wrapper.find('button').attributes('style')).toMatch(roundReg)
const roundStyle = [
'--width: initial;',
'--padding: 0 18px;',
'--border-radius: 34px;'
]
buttonStyle = wrapper.find('button').attributes('style')
expect(roundStyle.every((i) => buttonStyle.includes(i))).toBe(true)
await wrapper.setProps({ circle: false, round: false })
const defaultReg =
/^(?=.*--width: initial;)(?=.*--padding: 0 14px;)(?=.*--border-radius: 3px;).*$/im
expect(wrapper.find('button').attributes('style')).toMatch(defaultReg)
const defaultStyle = [
'--width: initial;',
'--padding: 0 14px;',
'--border-radius: 3px;'
]
buttonStyle = wrapper.find('button').attributes('style')
expect(defaultStyle.every((i) => buttonStyle.includes(i))).toBe(true)
})
it('should work with `ghost` prop', () => {
@ -212,9 +224,13 @@ describe('n-button', () => {
})
expect(wrapper.find('button').classes()).toContain('n-button--color')
const reg =
/^(?=.*--color: #8a2be2;)(?=.*--color-disabled: #8a2be2;)(?=.*--ripple-color: #8a2be2;).*$/im
expect(wrapper.find('button').attributes('style')).toMatch(reg)
const colorStyle = [
'--color: #8a2be2;',
'--color-disabled: #8a2be2;',
'--ripple-color: #8a2be2;'
]
const buttonStyle = wrapper.find('button').attributes('style')
expect(colorStyle.every((i) => buttonStyle.includes(i))).toBe(true)
})
it('should work with `button group`', async () => {

View File

@ -11,6 +11,7 @@ import {
onBeforeUnmount
} from 'vue'
import { indexMap } from 'seemly'
import { on, off } from 'evtd'
import { useConfig, useTheme } from '../../_mixins'
import type { ThemeProps } from '../../_mixins'
import { ExtractPublicPropTypes } from '../../_utils'
@ -36,6 +37,9 @@ export default defineComponent({
const { mergedClsPrefixRef } = useConfig(props)
const currentRef = ref(1)
const lengthRef = { value: 1 }
const touchingRef = ref(false)
const dragOffsetRef = ref(0)
const selfElRef = ref<HTMLDivElement | null>(null)
let timerId: number | null = null
let inTransition = false
// current from 0 to length + 1
@ -84,9 +88,9 @@ export default defineComponent({
const nextCurrent =
current === 0 ? length : current === length + 1 ? 1 : null
if (nextCurrent !== null) {
target.style.transition = 'none'
currentRef.value = nextCurrent
void nextTick(() => {
target.style.transition = 'none'
void target.offsetWidth
target.style.transition = ''
inTransition = false
@ -102,6 +106,57 @@ export default defineComponent({
setCurrent(current)
}
}
let dragStartX = 0
let dragStartTime = 0
let memorizedContainerWidth = 0
function handleTouchstart (e: TouchEvent): void {
if (timerId !== null) {
window.clearInterval(timerId)
}
e.preventDefault()
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
memorizedContainerWidth = selfElRef.value!.offsetWidth
touchingRef.value = true
dragStartTime = Date.now()
dragStartX = e.touches[0].clientX
on('touchmove', document, handleTouchmove)
on('touchend', document, handleTouchend)
on('touchcancel', document, handleTouchend)
}
function handleTouchmove (e: TouchEvent): void {
const dragOffset = e.touches[0].clientX - dragStartX
dragOffsetRef.value =
dragOffset > memorizedContainerWidth
? memorizedContainerWidth
: dragOffset < -memorizedContainerWidth
? -memorizedContainerWidth
: dragOffset
}
function handleTouchend (): void {
if (props.autoplay) resetInterval()
void nextTick(() => {
touchingRef.value = false
})
const { value: selfEl } = selfElRef
if (selfEl) {
const { offsetWidth } = selfEl
const { value: dragOffset } = dragOffsetRef
const duration = Date.now() - dragStartTime
// more than 50% width or faster than 0.4px per ms
if (dragOffset > offsetWidth / 2 || dragOffset / duration > 0.4) {
prev()
} else if (
dragOffset < -offsetWidth / 2 ||
dragOffset / duration < -0.4
) {
next()
}
}
dragOffsetRef.value = 0
off('touchmove', document, handleTouchmove)
off('touchend', document, handleTouchend)
off('touchcancel', document, handleTouchend)
}
function resetInterval (): void {
if (timerId !== null) {
window.clearInterval(timerId)
@ -134,13 +189,17 @@ export default defineComponent({
props
)
return {
selfElRef,
mergedClsPrefix: mergedClsPrefixRef,
current: currentRef,
lengthRef,
touching: touchingRef,
dragOffset: dragOffsetRef,
prev,
next,
setCurrent,
handleKeydown,
handleTouchstart,
handleTransitionEnd,
cssVars: computed(() => {
const {
@ -173,14 +232,17 @@ export default defineComponent({
<div
class={`${mergedClsPrefix}-carousel`}
style={this.cssVars as CSSProperties}
ref="selfElRef"
>
<div
class={`${mergedClsPrefix}-carousel__slides`}
onTouchstart={this.handleTouchstart}
style={{
width: `${total}00%`,
transform: `translate3d(-${
(100 / total) * (current % total)
}%, 0, 0)`
transition: this.touching ? 'none' : '',
transform:
`translate3d(-${(100 / total) * (current % total)}%, 0, 0)` +
(this.touching ? `translateX(${this.dragOffset}px)` : '')
}}
onTransitionend={this.handleTransitionEnd}
role="listbox"

View File

@ -6,7 +6,7 @@
由于尺寸原因Naive UI 并不把 highlight.js 内置。如果你需要使用代码组件,请确保你在使用之前已经设定了 highlight.js。
</n-alert>
下面的代码展示了如何为 Code 设定 hljs。比较推荐的方式是按需引入因为它可以极大减小打包尺寸。
下面的代码展示了如何为 Code 设定 hljs。比较推荐的方式是按需引入因为它可以极大减小打包尺寸。
```html
<template>

View File

@ -333,7 +333,11 @@ export default defineComponent({
if (value === null) {
singleInputValueRef.value = ''
} else {
singleInputValueRef.value = format(value, mergedFormatRef.value)
singleInputValueRef.value = format(
value,
mergedFormatRef.value,
dateFnsOptionsRef.value
)
}
}
function deriveRangeInputState (values: [number, number] | null): void {
@ -341,8 +345,17 @@ export default defineComponent({
rangeStartInputValueRef.value = ''
rangeEndInputValueRef.value = ''
} else {
rangeStartInputValueRef.value = format(values[0], mergedFormatRef.value)
rangeEndInputValueRef.value = format(values[1], mergedFormatRef.value)
const dateFnsOptions = dateFnsOptionsRef.value
rangeStartInputValueRef.value = format(
values[0],
mergedFormatRef.value,
dateFnsOptions
)
rangeEndInputValueRef.value = format(
values[1],
mergedFormatRef.value,
dateFnsOptions
)
}
}
// --- Input deactivate & blur

View File

@ -1,8 +1,64 @@
import { mount } from '@vue/test-utils'
import { nextTick } from '@vue/runtime-core'
import { NEmpty } from '../index'
import commonThemeVars from '../styles/_common'
const descriptionSelector = '.n-empty__description'
describe('n-empty', () => {
it('should work with import on demand', () => {
mount(NEmpty)
})
it('should work with slots', () => {
const wrapper = mount(NEmpty, {
slots: {
default: () => "There's nothing there.",
extra: () => 'There.'
}
})
expect(wrapper.html()).toContain("There's nothing there.")
expect(wrapper.html()).toContain('There.')
expect(wrapper.html()).toMatchSnapshot()
})
it('should render a description', () => {
const description = 'nothing'
const wrapper = mount(NEmpty, {
props: {
description
}
})
expect(wrapper.find(descriptionSelector).text()).toContain(description)
expect(wrapper.html()).toMatchSnapshot()
})
it('should not render a description', async () => {
const wrapper = mount(NEmpty, {
props: {
showDescription: true
}
})
expect(wrapper.find(descriptionSelector).exists()).toBe(true)
await wrapper.setProps({
showDescription: false
})
await nextTick()
expect(wrapper.find(descriptionSelector).exists()).toBe(false)
expect(wrapper.html()).toMatchSnapshot()
})
it('should resize', async () => {
const wrapper = mount(NEmpty)
expect(wrapper.attributes('style')).toContain(
'--icon-size: ' + commonThemeVars.iconSizeMedium
)
await wrapper.setProps({
size: 'small'
})
await nextTick()
expect(wrapper.attributes('style')).toContain(
'--icon-size: ' + commonThemeVars.iconSizeSmall
)
expect(wrapper.html()).toMatchSnapshot()
})
})

View File

@ -0,0 +1,45 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`n-empty should not render a description 1`] = `
"<div class=\\"n-empty\\" style=\\"--icon-size: 40px; --font-size: 14px; --bezier: cubic-bezier(.4, 0, .2, 1); --text-color: rgba(194, 194, 194, 1); --icon-color: rgba(194, 194, 194, 1); --extra-text-color: rgb(51, 54, 57);\\">
<div class=\\"n-empty__icon\\"><i class=\\"n-base-icon\\"><svg viewBox=\\"0 0 28 28\\" fill=\\"none\\" xmlns=\\"http://www.w3.org/2000/svg\\">
<path d=\\"M26 7.5C26 11.0899 23.0899 14 19.5 14C15.9101 14 13 11.0899 13 7.5C13 3.91015 15.9101 1 19.5 1C23.0899 1 26 3.91015 26 7.5ZM16.8536 4.14645C16.6583 3.95118 16.3417 3.95118 16.1464 4.14645C15.9512 4.34171 15.9512 4.65829 16.1464 4.85355L18.7929 7.5L16.1464 10.1464C15.9512 10.3417 15.9512 10.6583 16.1464 10.8536C16.3417 11.0488 16.6583 11.0488 16.8536 10.8536L19.5 8.20711L22.1464 10.8536C22.3417 11.0488 22.6583 11.0488 22.8536 10.8536C23.0488 10.6583 23.0488 10.3417 22.8536 10.1464L20.2071 7.5L22.8536 4.85355C23.0488 4.65829 23.0488 4.34171 22.8536 4.14645C22.6583 3.95118 22.3417 3.95118 22.1464 4.14645L19.5 6.79289L16.8536 4.14645Z\\" fill=\\"currentColor\\"></path>
<path d=\\"M25 22.75V12.5991C24.5572 13.0765 24.053 13.4961 23.5 13.8454V16H17.5L17.3982 16.0068C17.0322 16.0565 16.75 16.3703 16.75 16.75C16.75 18.2688 15.5188 19.5 14 19.5C12.4812 19.5 11.25 18.2688 11.25 16.75L11.2432 16.6482C11.1935 16.2822 10.8797 16 10.5 16H4.5V7.25C4.5 6.2835 5.2835 5.5 6.25 5.5H12.2696C12.4146 4.97463 12.6153 4.47237 12.865 4H6.25C4.45507 4 3 5.45507 3 7.25V22.75C3 24.5449 4.45507 26 6.25 26H21.75C23.5449 26 25 24.5449 25 22.75ZM4.5 22.75V17.5H9.81597L9.85751 17.7041C10.2905 19.5919 11.9808 21 14 21L14.215 20.9947C16.2095 20.8953 17.842 19.4209 18.184 17.5H23.5V22.75C23.5 23.7165 22.7165 24.5 21.75 24.5H6.25C5.2835 24.5 4.5 23.7165 4.5 22.75Z\\" fill=\\"currentColor\\"></path>
</svg></i></div>
<!---->
<!---->
</div>"
`;
exports[`n-empty should render a description 1`] = `
"<div class=\\"n-empty\\" style=\\"--icon-size: 40px; --font-size: 14px; --bezier: cubic-bezier(.4, 0, .2, 1); --text-color: rgba(194, 194, 194, 1); --icon-color: rgba(194, 194, 194, 1); --extra-text-color: rgb(51, 54, 57);\\">
<div class=\\"n-empty__icon\\"><i class=\\"n-base-icon\\"><svg viewBox=\\"0 0 28 28\\" fill=\\"none\\" xmlns=\\"http://www.w3.org/2000/svg\\">
<path d=\\"M26 7.5C26 11.0899 23.0899 14 19.5 14C15.9101 14 13 11.0899 13 7.5C13 3.91015 15.9101 1 19.5 1C23.0899 1 26 3.91015 26 7.5ZM16.8536 4.14645C16.6583 3.95118 16.3417 3.95118 16.1464 4.14645C15.9512 4.34171 15.9512 4.65829 16.1464 4.85355L18.7929 7.5L16.1464 10.1464C15.9512 10.3417 15.9512 10.6583 16.1464 10.8536C16.3417 11.0488 16.6583 11.0488 16.8536 10.8536L19.5 8.20711L22.1464 10.8536C22.3417 11.0488 22.6583 11.0488 22.8536 10.8536C23.0488 10.6583 23.0488 10.3417 22.8536 10.1464L20.2071 7.5L22.8536 4.85355C23.0488 4.65829 23.0488 4.34171 22.8536 4.14645C22.6583 3.95118 22.3417 3.95118 22.1464 4.14645L19.5 6.79289L16.8536 4.14645Z\\" fill=\\"currentColor\\"></path>
<path d=\\"M25 22.75V12.5991C24.5572 13.0765 24.053 13.4961 23.5 13.8454V16H17.5L17.3982 16.0068C17.0322 16.0565 16.75 16.3703 16.75 16.75C16.75 18.2688 15.5188 19.5 14 19.5C12.4812 19.5 11.25 18.2688 11.25 16.75L11.2432 16.6482C11.1935 16.2822 10.8797 16 10.5 16H4.5V7.25C4.5 6.2835 5.2835 5.5 6.25 5.5H12.2696C12.4146 4.97463 12.6153 4.47237 12.865 4H6.25C4.45507 4 3 5.45507 3 7.25V22.75C3 24.5449 4.45507 26 6.25 26H21.75C23.5449 26 25 24.5449 25 22.75ZM4.5 22.75V17.5H9.81597L9.85751 17.7041C10.2905 19.5919 11.9808 21 14 21L14.215 20.9947C16.2095 20.8953 17.842 19.4209 18.184 17.5H23.5V22.75C23.5 23.7165 22.7165 24.5 21.75 24.5H6.25C5.2835 24.5 4.5 23.7165 4.5 22.75Z\\" fill=\\"currentColor\\"></path>
</svg></i></div>
<div class=\\"n-empty__description\\">nothing</div>
<!---->
</div>"
`;
exports[`n-empty should resize 1`] = `
"<div class=\\"n-empty\\" style=\\"--icon-size: 34px; --font-size: 14px; --bezier: cubic-bezier(.4, 0, .2, 1); --text-color: rgba(194, 194, 194, 1); --icon-color: rgba(194, 194, 194, 1); --extra-text-color: rgb(51, 54, 57);\\">
<div class=\\"n-empty__icon\\"><i class=\\"n-base-icon\\"><svg viewBox=\\"0 0 28 28\\" fill=\\"none\\" xmlns=\\"http://www.w3.org/2000/svg\\">
<path d=\\"M26 7.5C26 11.0899 23.0899 14 19.5 14C15.9101 14 13 11.0899 13 7.5C13 3.91015 15.9101 1 19.5 1C23.0899 1 26 3.91015 26 7.5ZM16.8536 4.14645C16.6583 3.95118 16.3417 3.95118 16.1464 4.14645C15.9512 4.34171 15.9512 4.65829 16.1464 4.85355L18.7929 7.5L16.1464 10.1464C15.9512 10.3417 15.9512 10.6583 16.1464 10.8536C16.3417 11.0488 16.6583 11.0488 16.8536 10.8536L19.5 8.20711L22.1464 10.8536C22.3417 11.0488 22.6583 11.0488 22.8536 10.8536C23.0488 10.6583 23.0488 10.3417 22.8536 10.1464L20.2071 7.5L22.8536 4.85355C23.0488 4.65829 23.0488 4.34171 22.8536 4.14645C22.6583 3.95118 22.3417 3.95118 22.1464 4.14645L19.5 6.79289L16.8536 4.14645Z\\" fill=\\"currentColor\\"></path>
<path d=\\"M25 22.75V12.5991C24.5572 13.0765 24.053 13.4961 23.5 13.8454V16H17.5L17.3982 16.0068C17.0322 16.0565 16.75 16.3703 16.75 16.75C16.75 18.2688 15.5188 19.5 14 19.5C12.4812 19.5 11.25 18.2688 11.25 16.75L11.2432 16.6482C11.1935 16.2822 10.8797 16 10.5 16H4.5V7.25C4.5 6.2835 5.2835 5.5 6.25 5.5H12.2696C12.4146 4.97463 12.6153 4.47237 12.865 4H6.25C4.45507 4 3 5.45507 3 7.25V22.75C3 24.5449 4.45507 26 6.25 26H21.75C23.5449 26 25 24.5449 25 22.75ZM4.5 22.75V17.5H9.81597L9.85751 17.7041C10.2905 19.5919 11.9808 21 14 21L14.215 20.9947C16.2095 20.8953 17.842 19.4209 18.184 17.5H23.5V22.75C23.5 23.7165 22.7165 24.5 21.75 24.5H6.25C5.2835 24.5 4.5 23.7165 4.5 22.75Z\\" fill=\\"currentColor\\"></path>
</svg></i></div>
<div class=\\"n-empty__description\\">No Data</div>
<!---->
</div>"
`;
exports[`n-empty should work with slots 1`] = `
"<div class=\\"n-empty\\" style=\\"--icon-size: 40px; --font-size: 14px; --bezier: cubic-bezier(.4, 0, .2, 1); --text-color: rgba(194, 194, 194, 1); --icon-color: rgba(194, 194, 194, 1); --extra-text-color: rgb(51, 54, 57);\\">
<div class=\\"n-empty__icon\\"><i class=\\"n-base-icon\\"><svg viewBox=\\"0 0 28 28\\" fill=\\"none\\" xmlns=\\"http://www.w3.org/2000/svg\\">
<path d=\\"M26 7.5C26 11.0899 23.0899 14 19.5 14C15.9101 14 13 11.0899 13 7.5C13 3.91015 15.9101 1 19.5 1C23.0899 1 26 3.91015 26 7.5ZM16.8536 4.14645C16.6583 3.95118 16.3417 3.95118 16.1464 4.14645C15.9512 4.34171 15.9512 4.65829 16.1464 4.85355L18.7929 7.5L16.1464 10.1464C15.9512 10.3417 15.9512 10.6583 16.1464 10.8536C16.3417 11.0488 16.6583 11.0488 16.8536 10.8536L19.5 8.20711L22.1464 10.8536C22.3417 11.0488 22.6583 11.0488 22.8536 10.8536C23.0488 10.6583 23.0488 10.3417 22.8536 10.1464L20.2071 7.5L22.8536 4.85355C23.0488 4.65829 23.0488 4.34171 22.8536 4.14645C22.6583 3.95118 22.3417 3.95118 22.1464 4.14645L19.5 6.79289L16.8536 4.14645Z\\" fill=\\"currentColor\\"></path>
<path d=\\"M25 22.75V12.5991C24.5572 13.0765 24.053 13.4961 23.5 13.8454V16H17.5L17.3982 16.0068C17.0322 16.0565 16.75 16.3703 16.75 16.75C16.75 18.2688 15.5188 19.5 14 19.5C12.4812 19.5 11.25 18.2688 11.25 16.75L11.2432 16.6482C11.1935 16.2822 10.8797 16 10.5 16H4.5V7.25C4.5 6.2835 5.2835 5.5 6.25 5.5H12.2696C12.4146 4.97463 12.6153 4.47237 12.865 4H6.25C4.45507 4 3 5.45507 3 7.25V22.75C3 24.5449 4.45507 26 6.25 26H21.75C23.5449 26 25 24.5449 25 22.75ZM4.5 22.75V17.5H9.81597L9.85751 17.7041C10.2905 19.5919 11.9808 21 14 21L14.215 20.9947C16.2095 20.8953 17.842 19.4209 18.184 17.5H23.5V22.75C23.5 23.7165 22.7165 24.5 21.75 24.5H6.25C5.2835 24.5 4.5 23.7165 4.5 22.75Z\\" fill=\\"currentColor\\"></path>
</svg></i></div>
<div class=\\"n-empty__description\\">There's nothing there.</div>
<div class=\\"n-empty__extra\\">There.</div>
</div>"
`;