Skip to content

Commit

Permalink
[5.2.0-rc.1]feat: refactor Slider
Browse files Browse the repository at this point in the history
  • Loading branch information
1uokun committed Jul 8, 2024
1 parent 9bfc8c5 commit f0283cc
Show file tree
Hide file tree
Showing 12 changed files with 689 additions and 172 deletions.
30 changes: 30 additions & 0 deletions components/slider/PropsType.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { ReactNode } from 'react'
import React from 'react'
import { StyleProp, ViewStyle } from 'react-native'
import { SliderStyle } from './style'

export type SliderMarks = {
[key: number]: React.ReactNode
}

export type SliderValue = number | [number, number]

export type SliderProps = {
min?: number
max?: number
value?: SliderValue
defaultValue?: SliderValue
step?: number
marks?: SliderMarks
ticks?: boolean
disabled?: boolean
range?: boolean
icon?: ReactNode
// TODO-luokun
// popover?: boolean | ((value: number) => ReactNode)
// residentPopover?: boolean
onChange?: (value: SliderValue) => void
onAfterChange?: (value: SliderValue) => void
style?: StyleProp<ViewStyle>
styles?: Partial<SliderStyle>
}
138 changes: 53 additions & 85 deletions components/slider/demo/basic.tsx
Original file line number Diff line number Diff line change
@@ -1,93 +1,61 @@
import React from 'react'
import { Text, View } from 'react-native'
import { Slider } from '../../'

export default class BasicSliderExample extends React.Component<any, any> {
constructor(props: any) {
super(props)
this.state = {
changingValue: 0.25,
changedValue: 0.15,
minMaxValue: 0,
slideCompletionCount: 0,
}
}

handleChange = (value: any) => {
this.setState({
changingValue: value,
})
}

onAfterChange = (value: any) => {
this.setState({
changedValue: value,
})
import { ScrollView } from 'react-native'

import { List, Slider, Toast } from '../../'

export default function StepperExample() {
const marks = {
0: 0,
20: 20,
40: 40,
60: 60,
80: 80,
100: 100,
}

minMaxChange = (value: any) => {
this.setState({
minMaxValue: value,
})
const toastValue = (value: number | [number, number]) => {
let text = ''
if (typeof value === 'number') {
text = `${value}`
} else {
text = `[${value.join(',')}]`
}
Toast.show({ content: `当前选中值为:${text}`, position: 'top' })
}

render() {
return (
<View>
<View>
<Text>Default settings</Text>
<Slider />
</View>

<View style={{ marginTop: 20 }}>
<Text>Initial value: 0.5</Text>
<Slider defaultValue={0.5} />
</View>

<View style={{ marginTop: 20 }}>
<Text>min: 0, max: 1, current Value: {this.state.minMaxValue}</Text>
return (
<ScrollView>
<List renderHeader={'基础用法'}>
<List.Item>
<Slider onAfterChange={toastValue} />
</List.Item>
</List>
<List renderHeader={'显示刻度(ticks)并指定步距(step)'}>
<List.Item>
<Slider ticks step={10} defaultValue={40} />
</List.Item>
</List>
<List renderHeader={'传入刻度标记(marks)'}>
<List.Item>
<Slider marks={marks} ticks step={20} />
</List.Item>
</List>
<List renderHeader={'最大(max)/最小值(min)'}>
<List.Item>
<Slider
min={0}
max={1}
onAfterChange={(value: any) => this.minMaxChange(value)}
step={100}
min={100}
max={1000}
ticks
onAfterChange={toastValue}
/>
</View>

<View style={{ marginTop: 20 }}>
<Text>step: 0.25</Text>
<Slider step={0.25} value={0.25} />
</View>

<View style={{ marginTop: 20 }}>
<Text>disabled</Text>
<Slider disabled defaultValue={0.25} />
</View>

<View style={{ marginTop: 20 }}>
<Text>onChange value: {this.state.changingValue}</Text>
<Slider
defaultValue={0.25}
onChange={(value: any) => this.handleChange(value)}
/>
</View>

<View style={{ marginTop: 20 }}>
<Text>onAfterChange value: {this.state.changedValue}</Text>
<Slider
defaultValue={0.15}
onAfterChange={(value: any) => this.onAfterChange(value)}
/>
</View>

<View style={{ marginTop: 20 }}>
<Text>custom color: </Text>
<Slider
defaultValue={0.15}
minimumTrackTintColor="red"
maximumTrackTintColor="blue"
/>
</View>
</View>
)
}
</List.Item>
</List>
<List renderHeader={'双滑块(range)'}>
<List.Item>
<Slider marks={marks} ticks range defaultValue={[60, 40]} />
</List.Item>
</List>
</ScrollView>
)
}
26 changes: 14 additions & 12 deletions components/slider/index.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,17 @@ A Slider component for selecting particular value in range, eg: controls the dis

## API

Properties | Descrition | Type | Default
-----------|------------|------|--------
| min | Number | 0 | The minimum value the slider can slide to. |
| max | Number | 100 | The maximum value the slider can slide to. |
| step | Number or null | 1 | The granularity the slider can step through values. Must greater than 0, and be divided by (max - min) . When `marks` no null, `step` can be `null`. |
| value | Number | | The value of slider. |
| defaultValue | Number | 0 | The default value of slider. |
| disabled | Boolean | false | If true, the slider will not be interactable. |
| onChange | Function | Noop | Callback function that is called when the user changes the slider's value. |
| onAfterChange | Function | Noop | Fired when `ontouchend` is fired. |
| maximumTrackTintColor (`iOS`) | String | `#108ee9` | The color used for the track to the right of the button. Overrides the default blue gradient image on iOS. |
| minimumTrackTintColor (iOS) | String | `#ddd` | The color used for the track to the left of the button. Overrides the default blue gradient image on iOS. |
| Properties | Description | Type | Default |
| --- | --- | --- | --- |
| defaultValue | Default value | `number \| [number, number]` | `range ? [0, 0] : 0` |
| disabled | Whether disabled | `boolean` | `false` |
| icon | The icon of slider | `ReactNode` | - |
| marks | Tick marks | `{ [key: number]: React.ReactNode }` | - |
| max | Max value | `number` | `100` |
| min | Min value | `number` | `0` |
| onAfterChange | Consistent with the trigger timing of `touchend`, pass the current value as a parameter | `(value: number \| [number, number]) => void` | - |
| onChange | Triggered when the slider is dragged, and the current dragged value is passed in as a parameter | `(value: number \| [number, number]) => void` | - |
| range | Whether it is a double sliders | `boolean` | `false` |
| step | Step distance, the value must be greater than `0`, and `(max-min)` can be divisible by `step`. When `marks` is not null, the configuration of `step` is invalid | `number` | `1` |
| ticks | Whether to display the scale | `boolean` | `false` |
| value | Current value | `number \| [number, number]` | - |
66 changes: 3 additions & 63 deletions components/slider/index.tsx
Original file line number Diff line number Diff line change
@@ -1,65 +1,5 @@
import React from 'react'
import { View } from 'react-native'
import Slider from '@react-native-community/slider'
import { WithTheme } from '../style'
import { Slider } from './slider'

export interface SliderProps {
maximumTrackTintColor?: string
minimumTrackTintColor?: string
onChange?: (value?: number) => void
onAfterChange?: (value?: number) => void
defaultValue?: number
tipFormatter?: (value?: string) => React.ReactNode
value?: number
min?: number
max?: number
step?: number
disabled?: boolean
}
export type { SliderProps, SliderValue } from './PropsType'

export default class SliderAntm extends React.Component<SliderProps, any> {
static defaultProps = {
onChange() {},
onAfterChange() {},
defaultValue: 0,
disabled: false,
}

render() {
const {
defaultValue,
value,
min,
max,
step,
disabled,
onChange,
onAfterChange,
maximumTrackTintColor,
minimumTrackTintColor,
} = this.props
return (
<WithTheme>
{(_, theme) => (
<View>
<Slider
value={defaultValue || value}
minimumValue={min}
maximumValue={max}
step={step}
minimumTrackTintColor={
minimumTrackTintColor || theme.brand_primary
}
maximumTrackTintColor={
maximumTrackTintColor || theme.border_color_base
}
disabled={disabled}
onValueChange={onChange}
onSlidingComplete={onAfterChange}
/>
</View>
)}
</WithTheme>
)
}
}
export default Slider
26 changes: 14 additions & 12 deletions components/slider/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,17 @@ subtitle: 滑动输入条

## API

属性 | 说明 | 类型 | 默认值
----|-----|------|------
| min | Number | 0 | 最小值 |
| max | Number | 100 | 最大值 |
| step | Number or null | 1 | 步长,取值必须大于 0,并且可被 (max - min) 整除。当 `marks` 不为空对象时,可以设置 `step``null`,此时 Slider 的可选值仅有 marks 标出来的部分 |
| value | Number | | 设置当前取值。 |
| defaultValue | Number | 0 | 设置初始取值。|
| disabled | Boolean | false | 值为 `true` 时,滑块为禁用状态 |
| onChange | Function | Noop | 当 Slider 的值发生改变时,会触发 onChange 事件,并把改变后的值作为参数传入 |
| maximumTrackTintColor(`iOS`) | String | `#108ee9`(RN) | 底部背景色 |
| minimumTrackTintColor(`iOS`) | String | `#ddd` (RN) | 当前选中部分的颜色 |
| onAfterChange | Function | Noop |`ontouchend` 触发时机一致,把当前值作为参数传入 |
| 属性 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| defaultValue | 默认值 | `number \| [number, number]` | `range ? [0, 0] : 0` |
| disabled | 是否禁用 | `boolean` | `false` |
| icon | 滑块的图标 | `ReactNode` | - |
| marks | 刻度标记 | `{ [key: number]: React.ReactNode }` | - |
| max | 最大值 | `number` | `100` |
| min | 最小值 | `number` | `0` |
| onAfterChange |`touchend` 触发时机一致,把当前值作为参数传入 | `(value: number \| [number, number]) => void` | - |
| onChange | 拖拽滑块时触发,并把当前拖拽的值作为参数传入 | `(value: number \| [number, number]) => void` | - |
| range | 是否为双滑块 | `boolean` | `false` |
| step | 步距,取值必须大于 `0`,并且 `(max - min)` 可被 `step` 整除。当 `marks` 不为空对象时,`step` 的配置失效 | `number` | `1` |
| ticks | 是否显示刻度 | `boolean` | `false` |
| value | 当前值 | `number \| [number, number]` | - |
59 changes: 59 additions & 0 deletions components/slider/marks.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import type { FC, ReactNode } from 'react'
import React from 'react'
import { View } from 'react-native'
import AntmView from '../view'
import { SliderStyle } from './style'

export type SliderMarks = {
[key: number]: ReactNode
}

type MarksProps = {
marks: SliderMarks
max: number
min: number
upperBound: number
lowerBound: number
styles: Partial<SliderStyle>
}

const Marks: FC<MarksProps> = ({
marks,
upperBound,
lowerBound,
max,
min,
styles,
}) => {
const marksKeys = Object.keys(marks)

const range = max - min
const elements = marksKeys
.map(parseFloat)
.sort((a, b) => a - b)
.filter((point) => point >= min && point <= max)
.map((point) => {
const markPoint = marks[point]
if (!markPoint && markPoint !== 0) {
return null
}

const isActive = point <= upperBound && point >= lowerBound

const style = {
left: `${((point - min) / range) * 100}%`,
}
return (
<View style={[{ position: 'absolute' }, style]} key={point}>
<AntmView
style={[styles.markText, isActive && styles.markTextActive]}>
{markPoint}
</AntmView>
</View>
)
})

return <View style={styles.mark}>{elements}</View>
}

export default Marks
Loading

0 comments on commit f0283cc

Please sign in to comment.