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 1 commit
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'

Check warning on line 1 in src/components/swiper/demos/demo8.tsx

View workflow job for this annotation

GitHub Actions / check

'useState' is defined but never used
import { Space, Swiper, Button } from 'antd-mobile'

Check warning on line 2 in src/components/swiper/demos/demo8.tsx

View workflow job for this annotation

GitHub Actions / check

'Space' is defined but never used

Check warning on line 2 in src/components/swiper/demos/demo8.tsx

View workflow job for this annotation

GitHub Actions / check

'Button' is defined but never used
import { DemoBlock, DemoDescription } from 'demos'

Check warning on line 3 in src/components/swiper/demos/demo8.tsx

View workflow job for this annotation

GitHub Actions / check

'DemoDescription' is defined but never used

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='基础用法'>
<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>
</>
)
}
5 changes: 5 additions & 0 deletions src/components/swiper/index.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ When you use a vertical Swiper, be sure to set its height through the `--height`

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

### rtl support
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

写个demo 就够了,不必再起一行说明吧~

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

好的,我把这里精简一下


The RTL (right-to-left) mode is only effective when the direction attribute is set to `horizontal`. <code src="./demos/demo8.tsx"></code>

## Swiper

### Props
Expand All @@ -56,6 +60,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
5 changes: 5 additions & 0 deletions src/components/swiper/index.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@

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

### rtl 支持

rtl 模式仅在 direction 属性为`horizontal`时生效 <code src="./demos/demo8.tsx"></code>

## Swiper

### 属性
Expand All @@ -54,6 +58,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
43 changes: 32 additions & 11 deletions src/components/swiper/swiper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
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 @@
stuckAtBoundary: true,
rubberband: true,
stopPropagation: [] as PropagationEvent[],
docDirection: 'ltr',
}

let currentUid: undefined | {}
Expand All @@ -85,6 +87,9 @@
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 @@

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 @@
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 @@
)

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,17 +255,23 @@
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)

Check warning on line 267 in src/components/swiper/swiper.tsx

View check run for this annotation

Codecov / codecov/patch

src/components/swiper/swiper.tsx#L267

Added line #L267 was not covered by tests
: swipeTo(Math.round(position.get() / 100) + 1)
}

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

Check warning on line 273 in src/components/swiper/swiper.tsx

View check run for this annotation

Codecov / codecov/patch

src/components/swiper/swiper.tsx#L273

Added line #L273 was not covered by tests
: swipeTo(Math.round(position.get() / 100) - 1)
}

useImperativeHandle(ref, () => ({
Expand Down Expand Up @@ -300,15 +317,19 @@
})}
style={{
[isVertical ? 'y' : 'x']: position.to(position => {
let finalPosition = -position + index * 100
let finalPosition = isRtl
? -position - index * 100

Check warning on line 321 in src/components/swiper/swiper.tsx

View check run for this annotation

Codecov / codecov/patch

src/components/swiper/swiper.tsx#L321

Added line #L321 was not covered by tests
: -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 +367,7 @@
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 +390,7 @@
classPrefix,
`${classPrefix}-${props.direction}`
)}
style={style}
style={{ ...style, direction: props.docDirection }}
>
<div
ref={trackRef}
Expand Down
Loading
Loading