Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(swiper): support RTL mode #6450

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions src/components/swiper/demos/demo8.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import React, { useState } from 'react'
import { Space, Swiper, Button } from 'antd-mobile'
import { DemoBlock, DemoDescription } from 'demos'

import styles from './demo1.less'

const colors = ['#ace0ff', '#bcffbd', '#e4fabd', '#ffcfac']

const items = colors.map((color, index) => (
<Swiper.Item key={index}>
<div className={styles.content} style={{ background: color }}>
{index + 1}
</div>
</Swiper.Item>
))

export default () => {
return (
<>
<DemoBlock title='rtl 基础用法'>
<Swiper docDirection={'rtl'}>{items}</Swiper>
</DemoBlock>
<DemoBlock title='循环'>
<Swiper
loop
autoplay
onIndexChange={i => {
console.log(i, 'onIndexChange1')
}}
docDirection={'rtl'}
>
{items}
</Swiper>
</DemoBlock>
<DemoBlock title='卡在边界'>
<Swiper
trackOffset={10}
slideSize={80}
style={{
'--border-radius': '8px',
}}
defaultIndex={0}
docDirection={'rtl'}
>
{items}
</Swiper>
</DemoBlock>

<DemoBlock title='居中展示'>
<Swiper
slideSize={80}
trackOffset={10}
stuckAtBoundary={false}
docDirection={'rtl'}
>
{items}
</Swiper>
</DemoBlock>

<DemoBlock title='循环居中展示'>
<Swiper
slideSize={70}
trackOffset={15}
loop
stuckAtBoundary={false}
docDirection={'rtl'}
>
{items}
</Swiper>
</DemoBlock>
</>
)
}
3 changes: 3 additions & 0 deletions src/components/swiper/index.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ When you use a vertical Swiper, be sure to set its height through the `--height`

<code src="./demos/demo7.tsx" debug></code>

<code src="./demos/demo8.tsx"></code>

## Swiper

### Props
Expand All @@ -56,6 +58,7 @@ When you use a vertical Swiper, be sure to set its height through the `--height`
| stuckAtBoundary | Whether to stuck at boundary in order to prevent white spaces. Only available when `loop` is `false` and `slideWidth` < 100. | `boolean` | `true` |
| trackOffset | The track offset in percentage | `number` | `0` |
| stopPropagation | Stop the propagation of some events. | `PropagationEvent[]` | `[]` | 5.28.0 |
| docDirection | The document layout direction,only effective when the direction is set to `horizontal`. | `'ltr' \| 'rtl'` | `'ltr'` |

```ts
type PropagationEvent = 'mouseup' | 'mousemove' | 'mousedown'
Expand Down
3 changes: 3 additions & 0 deletions src/components/swiper/index.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@

<code src="./demos/demo6.tsx" debug></code> <code src="./demos/demo7.tsx" debug></code>

<code src="./demos/demo8.tsx"></code>

## Swiper

### 属性
Expand All @@ -54,6 +56,7 @@
| stuckAtBoundary | 是否在边界两边卡住,避免出现空白,仅在非 `loop` 模式且 `slideSize` < 100 时生效 | `boolean` | `true` |
| trackOffset | 滑块轨道整体的偏移量百分比 | `number` | `0` |
| stopPropagation | 阻止某些事件的冒泡 | `PropagationEvent[]` | `[]` | 5.28.0 |
| docDirection | 文档排版方向,仅在 direction 为`horizontal`是生效 | `'ltr' \| 'rtl'` | `'ltr'` |

```ts
type PropagationEvent = 'mouseup' | 'mousemove' | 'mousedown'
Expand Down
47 changes: 35 additions & 12 deletions src/components/swiper/swiper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export type SwiperProps = {
rubberband?: boolean
stopPropagation?: PropagationEvent[]
children?: ReactElement | ReactElement[]
docDirection?: 'ltr' | 'rtl'
} & NativeProps<'--height' | '--width' | '--border-radius' | '--track-padding'>

const defaultProps = {
Expand All @@ -71,6 +72,7 @@ const defaultProps = {
stuckAtBoundary: true,
rubberband: true,
stopPropagation: [] as PropagationEvent[],
docDirection: 'ltr',
}

let currentUid: undefined | {}
Expand All @@ -85,6 +87,9 @@ export const Swiper = forwardRef<SwiperRef, SwiperProps>(
const slideRatio = props.slideSize / 100
const offsetRatio = props.trackOffset / 100

const isRtl =
props.direction === 'horizontal' && props.docDirection === 'rtl'

const { validChildren, count } = useMemo(() => {
let count = 0
const validChildren = React.Children.map(props.children, child => {
Expand Down Expand Up @@ -140,7 +145,9 @@ export const Swiper = forwardRef<SwiperRef, SwiperProps>(

const [{ position }, api] = useSpring(
() => ({
position: boundIndex(current) * 100,
position: isRtl
? -boundIndex(current) * 100
: boundIndex(current) * 100,
config: { tension: 200, friction: 30 },
onRest: () => {
if (draggingRef.current) return
Expand Down Expand Up @@ -210,8 +217,12 @@ export const Swiper = forwardRef<SwiperRef, SwiperProps>(
bounds: () => {
if (loop) return {}
const slidePixels = getSlidePixels()
const lowerBound = boundIndex(0) * slidePixels
const upperBound = boundIndex(count - 1) * slidePixels
const lowerBound = isRtl
? -boundIndex(count - 1) * slidePixels
: boundIndex(0) * slidePixels
const upperBound = isRtl
? -boundIndex(0) * slidePixels
: boundIndex(count - 1) * slidePixels
return isVertical
? {
top: lowerBound,
Expand All @@ -232,7 +243,7 @@ export const Swiper = forwardRef<SwiperRef, SwiperProps>(
)

function swipeTo(index: number, immediate = false) {
const roundedIndex = Math.round(index)
const roundedIndex = isRtl ? -Math.round(index) : Math.round(index)
const targetIndex = loop
? modulus(roundedIndex, count)
: bound(roundedIndex, 0, count - 1)
Expand All @@ -244,21 +255,29 @@ export const Swiper = forwardRef<SwiperRef, SwiperProps>(
setCurrent(targetIndex)

api.start({
position: (loop ? roundedIndex : boundIndex(roundedIndex)) * 100,
position: isRtl
? -(loop ? roundedIndex : boundIndex(roundedIndex)) * 100
: (loop ? roundedIndex : boundIndex(roundedIndex)) * 100,
immediate,
})
}

function swipeNext() {
swipeTo(Math.round(position.get() / 100) + 1)
isRtl
? swipeTo(Math.round(position.get() / 100) - 1)
: swipeTo(Math.round(position.get() / 100) + 1)
}

function swipePrev() {
swipeTo(Math.round(position.get() / 100) - 1)
isRtl
? swipeTo(Math.round(position.get() / 100) + 1)
: swipeTo(Math.round(position.get() / 100) - 1)
}

useImperativeHandle(ref, () => ({
swipeTo,
swipeTo: index => {
swipeTo(isRtl ? -index : index)
},
swipeNext,
swipePrev,
}))
Expand Down Expand Up @@ -300,15 +319,19 @@ export const Swiper = forwardRef<SwiperRef, SwiperProps>(
})}
style={{
[isVertical ? 'y' : 'x']: position.to(position => {
let finalPosition = -position + index * 100
let finalPosition = isRtl
? -position - index * 100
: -position + index * 100
const totalWidth = count * 100
const flagWidth = totalWidth / 2
finalPosition =
modulus(finalPosition + flagWidth, totalWidth) -
flagWidth
return `${finalPosition}%`
}),
[isVertical ? 'top' : 'left']: `-${index * 100}%`,
[isVertical ? 'top' : `${isRtl ? 'right' : 'left'}`]: `-${
index * 100
}%`,
}}
>
{child}
Expand Down Expand Up @@ -346,7 +369,7 @@ export const Swiper = forwardRef<SwiperRef, SwiperProps>(
const style: CSSProperties &
Record<'--slide-size' | '--track-offset', string> = {
'--slide-size': `${props.slideSize}%`,
'--track-offset': `${props.trackOffset}%`,
'--track-offset': `${isRtl ? -props.trackOffset : props.trackOffset}%`,
}

const dragProps = { ...(props.allowTouchMove ? bind() : {}) }
Expand All @@ -369,7 +392,7 @@ export const Swiper = forwardRef<SwiperRef, SwiperProps>(
classPrefix,
`${classPrefix}-${props.direction}`
)}
style={style}
style={{ ...style, direction: props.docDirection }}
>
<div
ref={trackRef}
Expand Down
Loading