Skip to content

Commit

Permalink
fix(comp:cascader): the cloned node should have a unique key (#940)
Browse files Browse the repository at this point in the history
  • Loading branch information
danranVm committed Jun 7, 2022
1 parent 7161d96 commit 45ece7b
Show file tree
Hide file tree
Showing 14 changed files with 74 additions and 107 deletions.
1 change: 1 addition & 0 deletions packages/cdk/drag-drop/demo/Basic.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const { position } = useDraggable(elementRef, { onStart, onMove, onEnd })
cursor: move;
user-select: none;
padding: 8px;
background-color: #fff;
border: 1px solid #c3c3c3;
box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.2);
}
Expand Down
4 changes: 2 additions & 2 deletions packages/components/carousel/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ export type {
CarouselInstance,
CarouselComponent,
CarouselPublicProps as CarouselProps,
DotPlacement,
DotTrigger,
CarouselDotPlacement,
CarouselDotTrigger,
} from './src/types'
18 changes: 10 additions & 8 deletions packages/components/carousel/src/Carousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,16 +98,18 @@ export default defineComponent({

return () => {
const prefixCls = mergedPrefixCls.value
const startVNode = cloneVNode(children.value[length.value - 1])
const endVNode = cloneVNode(children.value[0])
const slides = [startVNode, ...children.value, endVNode].map(slideItem => (
<div class={itemClass.value} style={slideItemStyle.value}>
const startVNode = children.value[length.value - 1]
const endVNode = children.value[0]
const clonedStartNode = cloneVNode(startVNode, { key: `${String(startVNode.key)}-start-cloned-key` })
const clonedEndNode = cloneVNode(endVNode, { key: `${String(endVNode.key)}-end-cloned-key` })
const slides = [clonedStartNode, ...children.value, clonedEndNode].map(slideItem => (
<div key={slideItem.key!} class={itemClass.value} style={slideItemStyle.value}>
{slideItem}
</div>
))
const prevArrow = slots.arrow ? slots.arrow({ type: 'prev' }) : <IxIcon name="left-circle" />
const nextArrow = slots.arrow ? slots.arrow({ type: 'next' }) : <IxIcon name="right-circle" />
const dots = Array.from({ length: length.value }).map((_, index: number) => {
const dots = children.value.map((node, index: number) => {
const isActive = index + 1 === activeIndex.value
const itemClass = {
[`${prefixCls}-dot-item`]: true,
Expand All @@ -119,7 +121,7 @@ export default defineComponent({
<button class={`${prefixCls}-dot-item-default`}></button>
)
return (
<li class={itemClass} onClick={() => onClick(index)} onMouseenter={() => onMouseenter(index)}>
<li key={node.key!} class={itemClass} onClick={() => onClick(index)} onMouseenter={() => onMouseenter(index)}>
{children}
</li>
)
Expand All @@ -132,10 +134,10 @@ export default defineComponent({
</div>
{showArrow.value && (
<>
<div class={`${prefixCls}-arrow ${prefixCls}-arrow-prev`} onClick={prev}>
<div key="__arrow-prev" class={`${prefixCls}-arrow ${prefixCls}-arrow-prev`} onClick={prev}>
{prevArrow}
</div>
<div class={`${prefixCls}-arrow ${prefixCls}-arrow-next`} onClick={next}>
<div key="__arrow-next" class={`${prefixCls}-arrow ${prefixCls}-arrow-next`} onClick={next}>
{nextArrow}
</div>
</>
Expand Down
17 changes: 10 additions & 7 deletions packages/components/carousel/src/composables/useAutoplay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,25 @@ import { ComputedRef, onBeforeUnmount, watch } from 'vue'
export const useAutoplay = (autoplayTime: ComputedRef<number>, next: () => void): void => {
let timer: number | null = null

const cleanup = () => {
if (timer !== null) {
clearInterval(timer)
timer = null
}
}

watch(
autoplayTime,
(newVal: number) => {
timer && window.clearInterval(timer)
cleanup()
if (newVal) {
timer = window.setInterval(() => {
timer = setInterval(() => {
next()
}, newVal)
}
},
{ immediate: true },
)

onBeforeUnmount(() => {
if (timer !== null) {
window.clearInterval(timer)
}
})
onBeforeUnmount(cleanup)
}
10 changes: 6 additions & 4 deletions packages/components/carousel/src/composables/useWalk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
* found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE
*/

import type { CarouselProps } from '../types'

import { ComputedRef, nextTick, watch } from 'vue'
import { type ComputedRef, nextTick, watch } from 'vue'

import { callEmit, useState } from '@idux/cdk/utils'

interface WalkContext {
import { type CarouselProps } from '../types'

export interface WalkContext {
goTo(slideIndex: number): void
next(): void
prev(): void
Expand All @@ -23,6 +23,8 @@ export const useWalk = (length: ComputedRef<number>, props: CarouselProps): Walk
const [activeIndex, setActiveIndex] = useState(1)
let running = false

watch(length, () => goTo(0))

watch(activeIndex, (newVal: number, oldVal: number) => {
if (newVal >= 1 && newVal <= length.value) {
callEmit(props.onChange, newVal, oldVal)
Expand Down
29 changes: 12 additions & 17 deletions packages/components/carousel/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,21 @@
* 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'

import { IxPropTypes } from '@idux/cdk/utils'

export type DotPlacement = 'top' | 'start' | 'bottom' | 'end' | 'none'
const dotPlacement: DotPlacement[] = ['top', 'start', 'bottom', 'end', 'none']

export type DotTrigger = 'click' | 'hover'
const dotTrigger: DotTrigger[] = ['click', 'hover']
import type { ExtractInnerPropTypes, ExtractPublicPropTypes, MaybeArray } from '@idux/cdk/utils'
import type { DefineComponent, HTMLAttributes, PropType } from 'vue'

export const carouselProps = {
autoplayTime: IxPropTypes.number,
dotPlacement: IxPropTypes.oneOf<DotPlacement>(dotPlacement),
showArrow: IxPropTypes.bool,
trigger: IxPropTypes.oneOf<DotTrigger>(dotTrigger),
onChange: IxPropTypes.emit<(prevIndex: number, nextIndex: number) => void>(),
}
autoplayTime: { type: Number, default: undefined },
dotPlacement: { type: String as PropType<CarouselDotPlacement>, default: undefined },
showArrow: { type: Boolean, default: undefined },
trigger: { type: String as PropType<CarouselDotTrigger>, default: undefined },
onChange: [Function, Array] as PropType<MaybeArray<(prevIndex: number, nextIndex: number) => void>>,
} as const

export interface CarouselBindings {
next: () => void
prev: () => void
goTo: (slideIndex: number) => void
goTo: (index: number) => void
}

export type CarouselProps = ExtractInnerPropTypes<typeof carouselProps>
Expand All @@ -37,3 +29,6 @@ export type CarouselComponent = DefineComponent<
CarouselBindings
>
export type CarouselInstance = InstanceType<DefineComponent<CarouselProps, CarouselBindings>>

export type CarouselDotPlacement = 'top' | 'start' | 'bottom' | 'end' | 'none'
export type CarouselDotTrigger = 'click' | 'hover'
6 changes: 3 additions & 3 deletions packages/components/config/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import type { AlertType } from '@idux/components/alert'
import type { AvatarShape, AvatarSize } from '@idux/components/avatar'
import type { ButtonSize } from '@idux/components/button'
import type { CardSize } from '@idux/components/card'
import type { DotPlacement, DotTrigger } from '@idux/components/carousel'
import type { CarouselDotPlacement, CarouselDotTrigger } from '@idux/components/carousel'
import type { CascaderData } from '@idux/components/cascader'
import type { DatePickerType } from '@idux/components/date-picker/src/types'
import type { FormLabelAlign, FormLayout, FormSize } from '@idux/components/form'
Expand Down Expand Up @@ -141,9 +141,9 @@ export interface CardConfig {

export interface CarouselConfig {
autoplayTime: number
dotPlacement: DotPlacement
dotPlacement: CarouselDotPlacement
showArrow: boolean
trigger: DotTrigger
trigger: CarouselDotTrigger
}

export interface CascaderConfig {
Expand Down
2 changes: 2 additions & 0 deletions packages/components/modal/demo/Footer.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ order: 4

## zh

通过设置 `cancelText`,`cancelButton`,`okText`,`okText` 来自定义了页脚的按钮。
通过设置 `footer` 来自定义了页脚的按钮。

## en

Via setting `cancelText`,`cancelButton`,`okText`,`okText` to customized footer button bar.
Via setting `footer` to customized footer button bar.
30 changes: 24 additions & 6 deletions packages/components/modal/demo/Footer.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<template>
<IxSpace>
<IxButton @click="visible = !visible">Change visible</IxButton>
<IxButton mode="primary" @click="openModal">Open modal</IxButton>
<IxButton @click="openModal1">Open modal</IxButton>
<IxButton @click="openModal2">Open modal</IxButton>
<IxButton mode="primary" @click="visible = !visible">Change visible</IxButton>
</IxSpace>
<IxModal v-model:visible="visible" type="confirm" title="Customize footer via slot">
<template #footer="{ cancel, ok }">
Expand All @@ -17,12 +18,27 @@ import { h, ref } from 'vue'
import { useModal } from '@idux/components/modal'
const visible = ref(false)
const { confirm } = useModal()
const openModal = () => {
const cancelText = 'No'
const cancelButton = { mode: 'dashed' } as const
const okText = 'Yes'
const okButton = { mode: 'dashed', danger: true } as const
const openModal1 = () => {
confirm({
title: 'Customize footer via props',
content: h('p', 'Some contents...'),
cancelText,
cancelButton,
okText,
okButton,
})
}
const openModal2 = () => {
const modalRef = confirm({
title: 'Customize footer via options',
title: 'Customize footer via footer',
content: h('p', 'Some contents...'),
footer: [
{
Expand All @@ -37,4 +53,6 @@ const openModal = () => {
],
})
}
const visible = ref(false)
</script>
14 changes: 0 additions & 14 deletions packages/components/modal/demo/FooterButtons.md

This file was deleted.

42 changes: 0 additions & 42 deletions packages/components/modal/demo/FooterButtons.vue

This file was deleted.

4 changes: 2 additions & 2 deletions packages/components/modal/demo/PositionWidth.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ order: 6

## zh

通过设置 `centered` 或类似 `style.top` 的样式来自定义对话框的位置
通过设置 `centered` 或者 `offset` 的自定义对话框的位置

通过设置 `width` 自定义对话框的的宽度。

## en

You can use `centered`, `style.top` or other styles to set position of modal dialog.
You can use `centered` or `offset` to set position of modal dialog.

You can use `width` to set width of modal dialog.
2 changes: 1 addition & 1 deletion packages/components/modal/demo/PositionWidth.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<IxButton @click="visible = !visible">Change visible</IxButton>
<IxButton mode="primary" @click="openModal">Open modal</IxButton>
</IxSpace>
<IxModal v-model:visible="visible" header="This is title" :style="{ top: '200px' }" :width="400">
<IxModal v-model:visible="visible" header="This is title" :centered="false" :offset="800" :width="400">
<p>Some contents...</p>
</IxModal>
</template>
Expand Down
2 changes: 1 addition & 1 deletion scripts/gulp/site/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export function initSite(): void {
const filterComponentName = [
'_private',
'config',
// 'drag-drop', // 暂时不对外提供
'drag-drop', // 暂时不对外提供
'locales',
'node_modules',
'style',
Expand Down

0 comments on commit 45ece7b

Please sign in to comment.