diff --git a/site/mobile/mobile.config.js b/site/mobile/mobile.config.js index 03039a05..d8fcfdec 100644 --- a/site/mobile/mobile.config.js +++ b/site/mobile/mobile.config.js @@ -63,7 +63,7 @@ export default { { title: 'Slider 滑动选择器', name: 'slider', - component: () => import('tdesign-mobile-react/slider/_example/index.jsx'), + component: () => import('tdesign-mobile-react/slider/_example/index.tsx'), }, { title: 'Radio 单选框', diff --git a/src/slider/Handle.tsx b/src/slider/Handle.tsx deleted file mode 100644 index 70bd0c94..00000000 --- a/src/slider/Handle.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { useDrag } from "@use-gesture/react"; -import React, { FC, RefObject, useRef } from "react"; -import useConfig from "../_util/useConfig"; - -interface HandleProps { - value: number; - min: number; - max: number; - disabled: boolean; - onDrag: (value: number, first: boolean, last: boolean) => void; - barRef: RefObject; -} - -const Handle: FC = (props) => { - const { value, min, max, disabled, onDrag, barRef } = props; - - const { classPrefix } = useConfig(); - const name = `${classPrefix}-slider`; - - const preValue = useRef(0); - - const bind = useDrag( - ({ first, last, xy, initial }) => { - - if (disabled) return; - if (first) { - preValue.current = value; - } - const x = xy[0] - initial[0]; - const sliderOffsetWidth = barRef.current?.offsetWidth; - if (!sliderOffsetWidth) return; - const diff = (x / Math.ceil(sliderOffsetWidth)) * (max - min); - onDrag(preValue.current + diff, first, last); - }, - { - axis: "x", - pointer: { touch: true }, - } - ); - - return ( -
- ); -}; - -Handle.displayName = 'Handle' - -export default Handle; diff --git a/src/slider/Marks.tsx b/src/slider/Marks.tsx deleted file mode 100644 index 905c0128..00000000 --- a/src/slider/Marks.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import isArray from 'lodash/isArray'; -import React, { FC } from 'react'; -import cls from 'classnames'; -import useConfig from '../_util/useConfig'; -import { SliderMarks } from './type'; - -interface MarkProps { - range: boolean; - value?: [number, number]; - marks?: Array | SliderMarks; -} - -const defaultProps = { - range: false, -}; - -const Marks: FC = (props) => { - const { range, value, marks } = props; - - const { classPrefix } = useConfig(); - const name = `${classPrefix}-slider`; - - // 渲染单个刻度 - const renderMark = (item, index, renderIndex = false) => { - const textClass = cls({ - [`${name}__mark-text`]: true, - [`${classPrefix}-is-active`]: value[1] > index, - }); - - return ( -
- {item} -
- ); - }; - - if (range || (marks && isArray(marks))) { - return
{value.map((item, index) => renderMark(item, index))}
; - } - if (marks && !isArray(marks)) { - return
{Object.keys(marks).map((key) => renderMark(marks[key], key, true))}
; - } - - return null; -}; - -Marks.defaultProps = defaultProps; -Marks.displayName = 'Marks'; - -export default Marks; diff --git a/src/slider/Slider.tsx b/src/slider/Slider.tsx index 5bfdd698..517e6616 100644 --- a/src/slider/Slider.tsx +++ b/src/slider/Slider.tsx @@ -1,223 +1,406 @@ -import React, { FC, useCallback, useMemo, useRef } from 'react'; -import classnames from 'classnames'; -import identity from 'lodash/identity'; -import isArray from 'lodash/isArray'; -import useConfig from '../_util/useConfig'; -import nearest from '../_util/nearest'; +import React, { FC, useEffect, useRef, useState } from 'react'; +import type { MouseEvent, TouchEvent } from 'react'; +import classNames from 'classnames'; +import isFunction from 'lodash/isFunction'; +import cloneDeep from 'lodash/cloneDeep'; +import { usePrefixClass } from '../hooks/useClass'; +import useDefaultProps from '../hooks/useDefaultProps'; import useDefault from '../_util/useDefault'; -import withNativeProps, { NativeProps } from '../_util/withNativeProps'; -import Handle from './Handle'; -import Marks from './Marks'; +import { StyledProps } from '../common'; import { SliderValue, TdSliderProps } from './type'; +import { sliderDefaultProps } from './defaultProps'; +import { trimSingleValue, trimValue } from './utils'; +import { BLOCK_SIZE, BORDER_WIDTH } from './constants'; -const defaultProps = { - disabled: false, - max: 100, - min: 0, - range: false, - step: 1, - label: true, - showExtremeValue: false, - onChange: identity, - onDragstart: identity, - onDragend: identity, -}; - -export interface SliderProps extends TdSliderProps, NativeProps {} +export interface SliderProps extends TdSliderProps, StyledProps {} const Slider: FC = (props) => { - const { classPrefix } = useConfig(); - const name = `${classPrefix}-slider`; - const { + className, + style, disabled, max, min, range, step, + theme, value, defaultValue, marks, showExtremeValue, label, onChange, - onDragstart, - onDragend, - } = props; + } = useDefaultProps(props, sliderDefaultProps); - const barRef = useRef(null); - const handleRef = useRef(null); - const firstValueRef = useRef<[number, number]>(); - const dragLockRef = useRef(false); + const [scaleArray, setScaleArray] = useState([]); + const [scaleTextArray, setScaleTextArray] = useState([]); + const [isScale, setIsScale] = useState(false); + const [maxRange, setMaxRange] = useState(0); + const [dotTopValue, setDotTopValue] = useState([0, 0]); + const [lineLeft, setLineLeft] = useState(); + const [lineRight, setLineRight] = useState(0); + const [lineBarWidth, setLineBarWidth] = useState(0); + const rootRef = useRef(null); + const leftDotRef = useRef(null); + const rightDotRef = useRef(null); + const sliderLineRef = useRef(null); + const initialLeft = useRef(0); + const initialRight = useRef(0); + const [innerValue, setInnerValue] = useDefault(value, defaultValue, onChange); + const scope = Number(max) - Number(min); - const [rawValue, setRawValue] = useDefault( - value, - defaultValue || (range ? [min, min] : min), - onChange, + const rootClassName = usePrefixClass('slider'); + + const containerClassName = classNames( + rootClassName, + { + [`${rootClassName}--top`]: label || scaleTextArray.length, + [`${rootClassName}--disabled`]: disabled, + [`${rootClassName}--range`]: range, + }, + className, ); + const sliderLineClassName = classNames(`${rootClassName}__bar`, `${rootClassName}__bar--${theme}`, { + [`${rootClassName}__bar--disabled`]: disabled, + [`${rootClassName}__bar--marks`]: isScale && theme === 'capsule', + }); + const sliderMaxTextClassName = classNames(`${rootClassName}__value`, `${rootClassName}__value--max`); - // 排序 - const sortValue = useCallback((val: [number, number]): [number, number] => val.sort((a, b) => a - b), []); + useEffect(() => { + if (theme) { + getInitialStyle(theme); + } + }, [theme]); - // 统一单/双游标滑块value结构 - const convertValue = useCallback( - (value: SliderValue): [number, number] => (range ? value : [min, value]) as [number, number], - [min, range], - ); + useEffect(() => { + function setSingleBarWidth(value: number) { + const halfBlock = theme === 'capsule' ? BLOCK_SIZE / 2 : 0; + const percentage = (Number(value) - min) / scope; + setLineBarWidth(percentage * maxRange + halfBlock); + } - const reverseValue = useCallback((value: [number, number]): SliderValue => (range ? value : value[1]), [range]); + function setLineStyle(left: number, right: number) { + const parseNumber = (v: any) => parseInt(v, 10); + const halfBlock = theme === 'capsule' ? BLOCK_SIZE / 2 : 0; + const [a, b] = innerValue as Array; - // 计算要显示的点 - const pointList = useMemo(() => { - if (marks) { - return isArray(marks) - ? marks.sort((a, b) => a - b) - : Object.keys(marks) - .map(parseFloat) - .sort((a, b) => a - b); + setDotTopValue([a, b]); + + if (left + right <= maxRange) { + setLineLeft(parseNumber(left + halfBlock)); + setLineRight(parseNumber(right + halfBlock)); + } else { + setLineLeft(parseNumber(maxRange + halfBlock - right)); + setLineRight(parseNumber(maxRange - left + halfBlock * 1.5)); + } } - const points: number[] = []; - for (let i = min; i <= max; i += step) { - points.push(i); + + if (!range) { + setSingleBarWidth(innerValue as number); + return; + } + const left = (maxRange * (innerValue[0] - min)) / scope; + const right = (maxRange * (max - innerValue[1])) / scope; + setLineStyle(left, right); + }, [innerValue, max, maxRange, min, range, scope, theme]); + + useEffect(() => { + function handleMask(marks: any) { + const calcPos = (arr: number[]) => { + const margin = theme === 'capsule' ? BLOCK_SIZE / 2 : 0; + return arr.map((item) => ({ + val: item, + left: Math.round(((item - min) / scope) * maxRange) + margin, + })); + }; + if (marks?.length && Array.isArray(marks)) { + setIsScale(true); + setScaleArray(calcPos(marks)); + setScaleTextArray([]); + } + + if (Object.prototype.toString.call(marks) === '[object Object]') { + const scaleArray = Object.keys(marks).map((item) => Number(item)); + const scaleTextArray = scaleArray.map((item) => marks[item]); + setIsScale(scaleArray.length > 0); + setScaleArray(calcPos(scaleArray)); + setScaleTextArray(scaleTextArray); + } } - return points; - }, [marks, max, min, step]); - const sliderValue = useMemo(() => sortValue(convertValue(rawValue)), [rawValue, convertValue, sortValue]); + if (marks) { + handleMask(marks); + } + }, [marks, maxRange, min, scope, theme]); - const trackSize = `${(100 * (sliderValue[1] - sliderValue[0])) / (max - min)}%`; + function getInitialStyle(theme: 'default' | 'capsule') { + const line = sliderLineRef.current?.getBoundingClientRect() as DOMRect; + const halfBlock = Number(BLOCK_SIZE) / 2; + const maxRange = line.right - line.left; - const trackStart = `${(100 * (sliderValue[0] - min)) / (max - min)}%`; + setMaxRange(theme === 'capsule' ? maxRange - BLOCK_SIZE - BORDER_WIDTH : maxRange); + initialLeft.current = line.left; + initialRight.current = line.right; + if (theme === 'capsule') { + initialLeft.current -= halfBlock; + initialRight.current -= halfBlock; + } + } - const getValueByPosition = (position: number) => { - let newPosition = position; - if (position < min) { - newPosition = min; - } else if (position > max) { - newPosition = max; + const getValue = (label: any, value: any) => { + const REGEXP = /[$][{value}]{7}/; + if (isFunction(label)) { + return label(value); + } + if (label) { + return value; } + if (REGEXP.test(label)) { + return label.replace(REGEXP, value); + } + }; - let value = min; + const convertPosToValue = (posValue: number, isLeft = true) => + isLeft ? (posValue / maxRange) * scope + min : max - (posValue / maxRange) * scope; - // 如果有显示刻度点,就移动到刻度点上 - if (pointList?.length) { - value = nearest({ - items: pointList, - target: newPosition, - }); - } else { - const lengthPerStep = 100 / ((max - min) / step); - const steps = Math.round(newPosition / lengthPerStep); - value = lengthPerStep * steps * (max - min) * 0.01 + min; + const getPrecision = () => { + const precisions = [min, max, step].map((item) => { + const decimalArr = `${item}`.split('.'); + return decimalArr[1] ? decimalArr[1].length : 0; + }); + return Math.max.apply(null, precisions); + }; + + const calcByStep = (value: number): number => { + const precision = getPrecision(); + if (step < 0 || step > scope) { + return Number(parseFloat(`${value}`).toFixed(precision)); } - return value; + const closestStep = trimSingleValue(Math.round(value / step) * step, min, max); + + return Number(parseFloat(`${closestStep}`).toFixed(precision)); }; - // 更新滑块value - const updateSliderValue = (value: [number, number]) => { - const next = sortValue(value); - const current = sliderValue; - if (next[0] === current[0] && next[1] === current[1]) return; - setRawValue(reverseValue(next)); + const changeValue = (value: SliderValue) => { + setInnerValue(trimValue(value, { min, max, range })); }; - const handleClick = (e) => { - if (!dragLockRef.current) return; - if (disabled) return; + const handleRangeClick = (e: MouseEvent) => { + e.stopPropagation(); + if (disabled) { + return; + } + const halfBlock = props.theme === 'capsule' ? Number(BLOCK_SIZE) / 2 : 0; + const currentLeft = e.clientX - initialLeft.current; + if (currentLeft < 0 || currentLeft > maxRange + Number(BLOCK_SIZE)) { + return; + } + + const leftDotValue = leftDotRef.current?.getBoundingClientRect() as DOMRect; + const rightDotValue = rightDotRef.current?.getBoundingClientRect() as DOMRect; + // 点击处-halfblock 与 leftDot左侧的距离(绝对值) + const distanceLeft = Math.abs(e.clientX - leftDotValue.left - halfBlock); + // 点击处-halfblock 与 rightDot左侧的距离(绝对值) + const distanceRight = Math.abs(rightDotValue.left - e.clientX + halfBlock); + // 哪个绝对值小就移动哪个Dot + const isMoveLeft = distanceLeft < distanceRight; + + if (isMoveLeft) { + // 当前leftdot中心 + 左侧偏移量 = 目标左侧中心距离 + const left = e.clientX - initialLeft.current; + const leftValue = convertPosToValue(left); + changeValue([calcByStep(leftValue), innerValue?.[1]]); + } else { + const right = -(e.clientX - initialRight.current); + const rightValue = convertPosToValue(right, false); + changeValue([innerValue?.[0], calcByStep(rightValue)]); + } + }; + const handleSingleClick = (e: MouseEvent) => { e.stopPropagation(); + if (disabled) { + return; + } + if (!sliderLineRef.current) { + return; + } + const currentLeft = e.clientX - initialLeft.current; + const value = convertPosToValue(currentLeft); + changeValue(calcByStep(value)); + }; - const bar = barRef.current; - if (!bar) return; + const onTouchMoveLeft = (e: TouchEvent) => { + if (disabled) { + return; + } + const { pageX } = e?.changedTouches?.[0] || {}; + const currentLeft = pageX - initialLeft.current; + const newData = cloneDeep(innerValue as number[]); + const leftValue = convertPosToValue(currentLeft); + newData[0] = calcByStep(leftValue); + changeValue(newData); + }; + + const onTouchMoveRight = (e: TouchEvent) => { + if (disabled) { + return; + } + const { pageX } = e?.changedTouches?.[0] || {}; + const currentRight = -(pageX - initialRight.current); + const newData = cloneDeep(innerValue as number[]); + const rightValue = convertPosToValue(currentRight, false); + newData[1] = calcByStep(rightValue); + changeValue(newData); + }; - const sliderOffsetLeft = bar.getBoundingClientRect().left; - const position = ((e.clientX - sliderOffsetLeft) / Math.ceil(bar.offsetWidth)) * (max - min) + min; + const onSingleDotMove = (e: TouchEvent) => { + if (disabled) { + return; + } + const { pageX } = e.changedTouches?.[0] || {}; + const value = convertPosToValue(pageX - initialLeft.current); + changeValue(calcByStep(value)); + }; - const targetValue = getValueByPosition(position); - let next: [number, number]; + const renderMinText = () => { + if (!showExtremeValue) { + return null; + } + const textClassName = classNames({ + [`${rootClassName}__value`]: !range, + [`${rootClassName}__value--min`]: !range, + [`${rootClassName}__range-extreme`]: range, + [`${rootClassName}__range-extreme--min`]: range, + }); if (range) { - if (Math.abs(targetValue - sliderValue[0]) > Math.abs(targetValue - sliderValue[1])) { - next = [sliderValue[0], targetValue]; - } else { - next = [targetValue, sliderValue[1]]; - } - } else { - next = [min, targetValue]; + return {min}; } + return {label ? getValue(label, min) : min}; + }; - updateSliderValue(next); + const renderMaxText = () => { + if (!showExtremeValue) { + return null; + } + if (range) { + return {max}; + } + return {label ? getValue(label, max) : max}; }; - // 游标滑块 - const renderHandle = (index: number) => ( - { - if (first) { - dragLockRef.current = true; - firstValueRef.current = sliderValue; - onDragstart(); - } - const val = getValueByPosition(position); - const firstValue = firstValueRef.current; - if (!firstValue) return; - const next = [...firstValue] as [number, number]; - next[index] = val; - updateSliderValue(next); - if (last) { - onDragend(); - window.setTimeout(() => { - dragLockRef.current = false; - }, 100); - } - }} - /> - ); + const renderScale = () => { + if (!isScale) { + return null; + } + return scaleArray.map((item, index) => ( +
= item.val) || + (range && dotTopValue[1] >= item.val && item.val >= dotTopValue[0]), + [`${rootClassName}__scale-item--disabled`]: disabled, + [`${rootClassName}__scale-item--hidden`]: + ((index === 0 || index === scaleArray.length - 1) && theme === 'capsule') || innerValue === item.val, + }, + )} + > + {scaleTextArray.length ? ( +
+ {scaleTextArray[index]} +
+ ) : null} +
+ )); + }; - return withNativeProps( - props, + const renderLineRange = () => (
- {showExtremeValue &&
{min}
}
+ {label ? ( +
+ {getValue(label, dotTopValue[0]) || dotTopValue[0]} +
+ ) : null} +
+
+
- {/* 总长度 */} -
- {/* 滑块长度 */} -
- {/* 双游标滑块操作 */} - {range && renderHandle(0)} - {/* 单游标滑块操作 */} - {renderHandle(1)} - {/* 刻度内容 */} - + {props.label && ( +
+ {getValue(props.label, dotTopValue[1]) || dotTopValue[1]} +
+ )} +
+
+
+ ); + + const renderLineSingle = () => ( +
+
+ {label ? ( +
+ {getValue(label, value) || innerValue} +
+ ) : null} +
+
+
+ ); + + return ( +
+ {renderMinText()} +
+ {renderScale()} + {range ? renderLineRange() : renderLineSingle()}
- {!range && label &&
{sliderValue[1]}
} - {showExtremeValue &&
{max}
} -
, + {renderMaxText()} +
); }; -Slider.defaultProps = defaultProps; Slider.displayName = 'Slider'; export default Slider; diff --git a/src/slider/_example/base.jsx b/src/slider/_example/base.jsx deleted file mode 100644 index 3396ce05..00000000 --- a/src/slider/_example/base.jsx +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import { Slider } from 'tdesign-mobile-react'; - -export default function BaseDemo() { - const onChange = (value) => { - console.log(`change to ${value}`); - }; - return ; -} diff --git a/src/slider/_example/base.tsx b/src/slider/_example/base.tsx new file mode 100644 index 00000000..13b1bfbf --- /dev/null +++ b/src/slider/_example/base.tsx @@ -0,0 +1,10 @@ +import React from 'react'; +import { Slider } from 'tdesign-mobile-react'; + +export default function BaseDemo() { + return ( +
+ +
+ ); +} diff --git a/src/slider/_example/capsule.tsx b/src/slider/_example/capsule.tsx new file mode 100644 index 00000000..1da1a7c8 --- /dev/null +++ b/src/slider/_example/capsule.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { Slider } from 'tdesign-mobile-react'; + +export default function CapsuleDemo() { + const marks = { + 0: '0', + 20: '20', + 40: '40', + 60: '60', + 80: '80', + 100: '100', + }; + return ( + <> +
+ +
+
+ +
+
+ {/* eslint-disable-next-line no-template-curly-in-string */} + +
+
+ +
+
+ +
+ + ); +} diff --git a/src/slider/_example/disable.jsx b/src/slider/_example/disable.jsx deleted file mode 100644 index 884cfe2d..00000000 --- a/src/slider/_example/disable.jsx +++ /dev/null @@ -1,6 +0,0 @@ -import React from 'react'; -import { Slider } from 'tdesign-mobile-react'; - -export default function DisableDemo() { - return ; -} diff --git a/src/slider/_example/disabled.tsx b/src/slider/_example/disabled.tsx new file mode 100644 index 00000000..6fd365d2 --- /dev/null +++ b/src/slider/_example/disabled.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { Slider } from 'tdesign-mobile-react'; + +export default function DisabledDemo() { + const marks = { + 0: '0', + 20: '20', + 40: '40', + 60: '60', + 80: '80', + 100: '100', + }; + return ( + <> +
+ +
+ {/*
+ +
*/} +
+ +
+ + ); +} diff --git a/src/slider/_example/index.jsx b/src/slider/_example/index.jsx deleted file mode 100644 index a0f84c16..00000000 --- a/src/slider/_example/index.jsx +++ /dev/null @@ -1,60 +0,0 @@ -import React from 'react'; -import TDemoBlock from '../../../site/mobile/components/DemoBlock'; -import TDemoHeader from '../../../site/mobile/components/DemoHeader'; -import './style/index.less'; - -import BaseDemo from './base'; -import ValueDemo from './value'; -import UnZeroDemo from './unZero'; -import MarkDemo from './mark'; -import RangDemo from './range'; -import DisableDemo from './disable'; -import TitleDemo from './title'; - -export default function Base() { - return ( -
- - -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
-
- ); -} diff --git a/src/slider/_example/index.tsx b/src/slider/_example/index.tsx new file mode 100644 index 00000000..7583875d --- /dev/null +++ b/src/slider/_example/index.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import TDemoHeader from '../../../site/mobile/components/DemoHeader'; +import TDemoBlock from '../../../site/mobile/components/DemoBlock'; +import BaseDemo from './base'; +import RangDemo from './range'; +import LabelDemo from './label'; +import StepDemo from './step'; +import DisabledDemo from './disabled'; +import CapsuleDemo from './capsule'; +import './style/index.less'; + +export default function Base() { + return ( +
+ + + + + + + + + + + + + + + + + + + +
+ ); +} diff --git a/src/slider/_example/label.tsx b/src/slider/_example/label.tsx new file mode 100644 index 00000000..9e1add45 --- /dev/null +++ b/src/slider/_example/label.tsx @@ -0,0 +1,24 @@ +import React, { useState } from 'react'; +import { Slider } from 'tdesign-mobile-react'; +import type { SliderValue } from 'tdesign-mobile-react'; + +export default function LabelDemo() { + const [value, setValue] = useState(10); + + const onChange = (value: number) => { + setValue(value); + }; + + const handleLabel = (value: SliderValue) => value; + + return ( + <> +
+ +
+
+ +
+ + ); +} diff --git a/src/slider/_example/mark.jsx b/src/slider/_example/mark.jsx deleted file mode 100644 index 7b8fec39..00000000 --- a/src/slider/_example/mark.jsx +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; -import { Slider } from 'tdesign-mobile-react'; - -const marks = { - 0: '小', - 50: '中', - 100: '大', -}; - -export default function MarkDemo() { - return ; -} diff --git a/src/slider/_example/range.jsx b/src/slider/_example/range.jsx deleted file mode 100644 index 72d66446..00000000 --- a/src/slider/_example/range.jsx +++ /dev/null @@ -1,6 +0,0 @@ -import React from 'react'; -import { Slider } from 'tdesign-mobile-react'; - -export default function RangDemo() { - return ; -} diff --git a/src/slider/_example/range.tsx b/src/slider/_example/range.tsx new file mode 100644 index 00000000..e8eba620 --- /dev/null +++ b/src/slider/_example/range.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import { Slider } from 'tdesign-mobile-react'; + +export default function RangDemo() { + const onChange = (value: number | number[]) => { + console.log(`change to ${value}`); + }; + return ( +
+ +
+ ); +} diff --git a/src/slider/_example/step.tsx b/src/slider/_example/step.tsx new file mode 100644 index 00000000..af403085 --- /dev/null +++ b/src/slider/_example/step.tsx @@ -0,0 +1,36 @@ +import React, { useState } from 'react'; +import { Slider } from 'tdesign-mobile-react'; + +export default function StepDemo() { + const [value, setValue] = useState(6.5); + const marksRange = { + 5: '5', + 6: '6', + 7: '7', + 8: '8', + 9: '9', + 10: '10', + }; + const marks = { + 0: '0', + 20: '20', + 40: '40', + 60: '60', + 80: '80', + 100: '100', + }; + + const onChange = (value: number) => { + setValue(value); + }; + return ( + <> +
+ +
+
+ +
+ + ); +} diff --git a/src/slider/_example/style/index.less b/src/slider/_example/style/index.less index cc83738d..6fc4c146 100644 --- a/src/slider/_example/style/index.less +++ b/src/slider/_example/style/index.less @@ -1,21 +1,23 @@ -.tdesign-mobile-demo { - background-color: #ffffff; - padding-bottom: 62px; - .tdesign-demo-block-wrap { - padding: 0 16px 8px; - min-height: 48px; - display: flex; - - &__title { - width: 30%; - } +.wrapper { + &-base, + &-disabled, + &-label, + &-capsule { + background: var(--bg-color-demo, #fff); + padding: 18px 0; + } - &-flex { - display: flex; - } + &-capsule { + padding: 16px 0; + } - &__slider { - width: 70%; - } + &-capsule, + &-disabled, + &-label { + margin-top: 16px; } } + +.tdesign-mobile-demo { + background: #f6f6f6; +} diff --git a/src/slider/_example/title.jsx b/src/slider/_example/title.jsx deleted file mode 100644 index 82a8aa5c..00000000 --- a/src/slider/_example/title.jsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; -import { Slider } from 'tdesign-mobile-react'; - -export default function TitleDemo() { - return ( - <> -
选择器标题
-
- -
- - ); -} diff --git a/src/slider/_example/unZero.jsx b/src/slider/_example/unZero.jsx deleted file mode 100644 index f8abb2d6..00000000 --- a/src/slider/_example/unZero.jsx +++ /dev/null @@ -1,6 +0,0 @@ -import React from 'react'; -import { Slider } from 'tdesign-mobile-react'; - -export default function UnZeroDemo() { - return ; -} diff --git a/src/slider/_example/value.jsx b/src/slider/_example/value.jsx deleted file mode 100644 index 031f39b3..00000000 --- a/src/slider/_example/value.jsx +++ /dev/null @@ -1,11 +0,0 @@ -import React, { useState } from 'react'; -import { Slider } from 'tdesign-mobile-react'; - -export default function ValueDemo() { - const [value, setValue] = useState(50); - const onChange = (value) => { - setValue(value); - }; - - return ; -} diff --git a/src/slider/constants.ts b/src/slider/constants.ts new file mode 100644 index 00000000..6aeeea5c --- /dev/null +++ b/src/slider/constants.ts @@ -0,0 +1,3 @@ +export const BLOCK_SIZE = 20; + +export const BORDER_WIDTH = 6; diff --git a/src/slider/defaultProps.ts b/src/slider/defaultProps.ts new file mode 100644 index 00000000..b2eb076f --- /dev/null +++ b/src/slider/defaultProps.ts @@ -0,0 +1,17 @@ +/** + * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC + * */ + +import { TdSliderProps } from './type'; + +export const sliderDefaultProps: TdSliderProps = { + disabled: undefined, + label: false, + max: 100, + min: 0, + range: false, + showExtremeValue: false, + step: 1, + theme: 'default', + defaultValue: 0, +}; diff --git a/src/slider/index.tsx b/src/slider/index.tsx index 3e3c8ea2..64eca5d3 100644 --- a/src/slider/index.tsx +++ b/src/slider/index.tsx @@ -1,8 +1,8 @@ import _Slider from './Slider'; +import './style/index.js'; -import './style'; +export type { SliderProps } from './Slider'; +export * from './type'; export const Slider = _Slider; - export default Slider; - diff --git a/src/slider/slider.en-US.md b/src/slider/slider.en-US.md new file mode 100644 index 00000000..b0f57db3 --- /dev/null +++ b/src/slider/slider.en-US.md @@ -0,0 +1,24 @@ +:: BASE_DOC :: + +## API + +### Slider Props + +name | type | default | description | required +-- | -- | -- | -- | -- +className | String | - | className of component | N +style | Object | - | CSS(Cascading Style Sheets),Typescript:`React.CSSProperties` | N +disabled | Boolean | undefined | \- | N +label | TNode | false | Typescript:`string \| boolean \| TNode<{ value: SliderValue; position?: 'start' \| 'end' }>`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +marks | Object / Array | - | Typescript:`Array \| SliderMarks` `interface SliderMarks { [mark: number]: string \| TNode<{ value: number }> }`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts)。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/slider/type.ts) | N +max | Number | 100 | \- | N +min | Number | 0 | \- | N +range | Boolean | false | \- | N +showExtremeValue | Boolean | false | \- | N +step | Number | 1 | \- | N +theme | String | default | options: default/capsule | N +value | Number / Array | 0 | Typescript:`SliderValue` `type SliderValue = number \| Array`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/slider/type.ts) | N +defaultValue | Number / Array | 0 | uncontrolled property。Typescript:`SliderValue` `type SliderValue = number \| Array`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/slider/type.ts) | N +onChange | Function | | Typescript:`(value: SliderValue) => void`
| N +onDragend | Function | | Typescript:`(value: SliderValue, e: TouchEvent) => void`
| N +onDragstart | Function | | Typescript:`(e: TouchEvent) => void`
| N diff --git a/src/slider/slider.md b/src/slider/slider.md index 7ea4b0cf..580ec966 100644 --- a/src/slider/slider.md +++ b/src/slider/slider.md @@ -1,22 +1,24 @@ :: BASE_DOC :: ## API + ### Slider Props -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- className | String | - | 类名 | N style | Object | - | 样式,TS 类型:`React.CSSProperties` | N -disabled | Boolean | false | 是否禁用组件 | N -label | TNode | true | 滑块当前值文本。
值为 true 显示默认文案;值为 false 不显示滑块当前值文本;
值为 `value` 则表示组件会根据占位符渲染文案;
值类型为函数时,参数 `value` 标识滑块值,参数 `position=start` 表示范围滑块的起始值,参数 `position=end` 表示范围滑块的终点值。TS 类型:`string | boolean | TNode<{ value: SliderValue; position?: 'start' | 'end' }>`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N -marks | Object / Array | - | 刻度标记,示例:[0, 10, 40, 200] 或者 `{ 10: (val) => val + '%', 50: (h) => }`。TS 类型:`Array | SliderMarks` `interface SliderMarks { [mark: number]: string | TNode<{ value: number }> }`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts)。[详细类型定义](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/slider/type.ts) | N +disabled | Boolean | undefined | 是否禁用组件 | N +label | TNode | false | 滑块当前值文本。
值为 true 显示默认文案;值为 false 不显示滑块当前值文本;
值为 `${value}%` 则表示组件会根据占位符渲染文案;
值类型为函数时,参数 `value` 标识滑块值,参数 `position=start` 表示范围滑块的起始值,参数 `position=end` 表示范围滑块的终点值。TS 类型:`string \| boolean \| TNode<{ value: SliderValue; position?: 'start' \| 'end' }>`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +marks | Object / Array | - | 刻度标记,示例:[0, 10, 40, 200] 或者 `{ 10: (val) => val + '%', 50: (h) => }`。TS 类型:`Array \| SliderMarks` `interface SliderMarks { [mark: number]: string \| TNode<{ value: number }> }`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts)。[详细类型定义](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/slider/type.ts) | N max | Number | 100 | 滑块范围最大值 | N min | Number | 0 | 滑块范围最小值 | N range | Boolean | false | 双游标滑块 | N showExtremeValue | Boolean | false | 是否边界值 | N step | Number | 1 | 步长 | N -value | Number / Array | - | 滑块值。TS 类型:`SliderValue` `type SliderValue = number | Array`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/slider/type.ts) | N -defaultValue | Number / Array | - | 滑块值。非受控属性。TS 类型:`SliderValue` `type SliderValue = number | Array`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/slider/type.ts) | N +theme | String | default | 滑块风格。可选项:default/capsule | N +value | Number / Array | 0 | 滑块值。TS 类型:`SliderValue` `type SliderValue = number \| Array`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/slider/type.ts) | N +defaultValue | Number / Array | 0 | 滑块值。非受控属性。TS 类型:`SliderValue` `type SliderValue = number \| Array`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/slider/type.ts) | N onChange | Function | | TS 类型:`(value: SliderValue) => void`
滑块值变化时触发 | N -onDragend | Function | | TS 类型:`() => void`
结束拖动时触发 | N -onDragstart | Function | | TS 类型:`() => void`
开始拖动时触发 | N +onDragend | Function | | TS 类型:`(value: SliderValue, e: TouchEvent) => void`
结束拖动时触发 | N +onDragstart | Function | | TS 类型:`(e: TouchEvent) => void`
开始拖动时触发 | N diff --git a/src/slider/style/index.js b/src/slider/style/index.js index ec130ce3..586efd57 100644 --- a/src/slider/style/index.js +++ b/src/slider/style/index.js @@ -1 +1 @@ -import '../../_common/style/mobile/components/slider/_index.less'; +import '../../_common/style/mobile/components/slider/v2/_index.less'; diff --git a/src/slider/type.ts b/src/slider/type.ts index 3d8ef4d6..17a810ef 100644 --- a/src/slider/type.ts +++ b/src/slider/type.ts @@ -5,16 +5,16 @@ * */ import { TNode } from '../common'; +import { TouchEvent } from 'react'; export interface TdSliderProps { /** * 是否禁用组件 - * @default false */ disabled?: boolean; /** * 滑块当前值文本。
值为 true 显示默认文案;值为 false 不显示滑块当前值文本;
值为 `${value}%` 则表示组件会根据占位符渲染文案;
值类型为函数时,参数 `value` 标识滑块值,参数 `position=start` 表示范围滑块的起始值,参数 `position=end` 表示范围滑块的终点值 - * @default true + * @default false */ label?: string | boolean | TNode<{ value: SliderValue; position?: 'start' | 'end' }>; /** @@ -46,12 +46,19 @@ export interface TdSliderProps { * @default 1 */ step?: number; + /** + * 滑块风格 + * @default default + */ + theme?: 'default' | 'capsule'; /** * 滑块值 + * @default 0 */ value?: SliderValue; /** * 滑块值,非受控属性 + * @default 0 */ defaultValue?: SliderValue; /** @@ -61,13 +68,15 @@ export interface TdSliderProps { /** * 结束拖动时触发 */ - onDragend?: () => void; + onDragend?: (value: SliderValue, e: TouchEvent) => void; /** * 开始拖动时触发 */ - onDragstart?: () => void; + onDragstart?: (e: TouchEvent) => void; } -export interface SliderMarks { [mark: number]: string | TNode<{ value: number }> }; +export interface SliderMarks { + [mark: number]: string | TNode<{ value: number }>; +} export type SliderValue = number | Array; diff --git a/src/slider/utils/index.ts b/src/slider/utils/index.ts new file mode 100644 index 00000000..b66e194c --- /dev/null +++ b/src/slider/utils/index.ts @@ -0,0 +1,38 @@ +/** + * 处理单个number的超限和异常 + * @param {any} value + * @param {number} min + * @param {number} max + * @return {number} + */ +export const trimSingleValue = (value: any, min: number, max: number): number => { + if (value < min) { + return min; + } + + if (value > max) { + return max; + } + + return value; +}; + +/** + * 处理超限和异常value + * @param value + * @param props + * @returns + */ +export const trimValue = (value: number | number[], props: any): number | number[] => { + const { min, max, range } = props; + + if (range) { + if (Array.isArray(value)) { + const newValue = value.map((cur) => trimSingleValue(cur, min, max)); + return newValue[0] <= newValue[1] ? value : [value[1], value[0]]; + } + return [min, max]; + } + + return trimSingleValue(value, min, max); +}; diff --git a/test/snap/__snapshots__/csr.test.jsx.snap b/test/snap/__snapshots__/csr.test.jsx.snap index 8571e9fa..400d9c55 100644 --- a/test/snap/__snapshots__/csr.test.jsx.snap +++ b/test/snap/__snapshots__/csr.test.jsx.snap @@ -25441,27 +25441,23 @@ exports[`csr snapshot test > csr test src/loading/_example/index.tsx 1`] = ` class="slider-wrap" >
-
-
-
-
- 5 + class="t-slider__line t-slider__line--default t-slider__line--single" + style="width: 0px;" + > +
+
+
+
@@ -25688,27 +25684,23 @@ exports[`csr snapshot test > csr test src/loading/_example/speed.tsx 1`] = ` class="slider-wrap" >
-
-
-
-
- 5 + class="t-slider__line t-slider__line--default t-slider__line--single" + style="width: 0px;" + > +
+
+
+
@@ -38476,179 +38468,1741 @@ exports[`csr snapshot test > csr test src/skeleton/_example/grid.tsx 1`] = `
`; -exports[`csr snapshot test > csr test src/skeleton/_example/image-group.tsx 1`] = ` +exports[`csr snapshot test > csr test src/skeleton/_example/image-group.tsx 1`] = ` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`; + +exports[`csr snapshot test > csr test src/skeleton/_example/theme.tsx 1`] = ` +
+
+
+ 头像骨架屏 +
+
+
+
+
+
+
+
+
+
+
+ 图片骨架屏 +
+
+
+
+
+
+
+
+
+
+
+ 文本骨架屏 +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 段落骨架屏 +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`; + +exports[`csr snapshot test > csr test src/slider/_example/base.tsx 1`] = ` +
+
+
+
+
+
+
+
+
+
+
+
+
+`; + +exports[`csr snapshot test > csr test src/slider/_example/capsule.tsx 1`] = ` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 40 +
+
+
+
+
+ 60 +
+
+
+
+
+
+
+
+
+
+
+
+ 0 +
+
+
+
+ 20 +
+
+
+
+ 40 +
+
+
+
+ 60 +
+
+
+
+ 80 +
+
+
+
+ 100 +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0 +
+
+
+
+ 20 +
+
+
+
+ 40 +
+
+
+
+ 60 +
+
+
+
+ 80 +
+
+
+
+ 100 +
+
+
+
+
+
+
+
+
+
+
+
+
+
+`; + +exports[`csr snapshot test > csr test src/slider/_example/disabled.tsx 1`] = ` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0 +
+
+
+
+ 20 +
+
+
+
+ 40 +
+
+
+
+ 60 +
+
+
+
+ 80 +
+
+
+
+ 100 +
+
+
+
+
+
+
+
+
+
+
+
+
+
+`; + +exports[`csr snapshot test > csr test src/slider/_example/index.tsx 1`] = ` +
+
+
+

+ Slider 滑动选择器 +

+

+ 用于选择横轴上的数值、区间、档位 +

+
+
+
+

+ 01 类型 +

+

+ 单游标滑块 +

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ 双游标滑块 +

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ 带数值单游标/双游标滑块 +

+
+
+
+
+
+
+
+
+ 10 +
+
+
+
+
+
+
+
+
+ + 0 + +
+
+
+
+ 20 +
+
+
+
+
+ 60 +
+
+
+
+
+ + 100 + +
+
+
+
+
+
+

+ 带刻度单游标/双游标滑块 +

+
+
+
+
+
+
+
+ 5 +
+
+
+
+ 6 +
+
+
+
+ 7 +
+
+
+
+ 8 +
+
+
+
+ 9 +
+
+
+
+ 10 +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0 +
+
+
+
+ 20 +
+
+
+
+ 40 +
+
+
+
+ 60 +
+
+
+
+ 80 +
+
+
+
+ 100 +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ 02 组件状态 +

+

+ 滑块禁用状态 +

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0 +
+
+
+
+ 20 +
+
+
+
+ 40 +
+
+
+
+ 60 +
+
+
+
+ 80 +
+
+
+
+ 100 +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ 03 特殊样式 +

+

+ 胶囊型滑块 +

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 40 +
+
+
+
+
+ 60 +
+
+
+
+
+
+
+
+
+
+
+
+ 0 +
+
+
+
+ 20 +
+
+
+
+ 40 +
+
+
+
+ 60 +
+
+
+
+ 80 +
+
+
+
+ 100 +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0 +
+
+
+
+ 20 +
+
+
+
+ 40 +
+
+
+
+ 60 +
+
+
+
+ 80 +
+
+
+
+ 100 +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`; + +exports[`csr snapshot test > csr test src/slider/_example/label.tsx 1`] = `
-
-
-
-
-
-
-
+
+ class="t-slider__line t-slider__line--default t-slider__line--single" + style="width: 0px;" + > +
+
+ 10 +
+
+
+
-
-
+
+
+ -
-
+ 0 +
+ class="t-slider__line t-slider__line--default" + style="right: 0px; left: 0px;" + > +
+
+ 20 +
+
+
+
+
+ 60 +
+
+
+
-
-
-
+ 100 +
`; -exports[`csr snapshot test > csr test src/skeleton/_example/theme.tsx 1`] = ` +exports[`csr snapshot test > csr test src/slider/_example/range.tsx 1`] = `
-
-
- 头像骨架屏 -
+
-
+
+ class="t-slider__dot t-slider__dot--left" + > +
+
+
+
+
-
-
- 图片骨架屏 -
+
+`; + +exports[`csr snapshot test > csr test src/slider/_example/step.tsx 1`] = ` +
+
-
+
+ class="t-slider__scale-desc t-slider__scale-desc--default" + > + 5 +
-
-
-
-
-
- 文本骨架屏 -
-
-
+ class="t-slider__scale-desc t-slider__scale-desc--default" + > + 6 +
+
+
+ class="t-slider__scale-desc t-slider__scale-desc--default" + > + 7 +
+ class="t-slider__scale-desc t-slider__scale-desc--default" + > + 8 +
+
+
+
+ 9 +
+
+
+
+ 10 +
+
+
+
+
+
-
-
- 段落骨架屏 -
+
-
+
+ class="t-slider__scale-desc t-slider__scale-desc--default" + > + 0 +
+ class="t-slider__scale-desc t-slider__scale-desc--default" + > + 20 +
+ class="t-slider__scale-desc t-slider__scale-desc--default" + > + 40 +
+ class="t-slider__scale-desc t-slider__scale-desc--default" + > + 60 +
+
+
+
+ 80 +
+
+
+
+ 100 +
+
+
+
+
+
+
+
+
@@ -51948,7 +53502,7 @@ exports[`ssr snapshot test > ssr test src/loading/_example/fullscreen.tsx 1`] = exports[`ssr snapshot test > ssr test src/loading/_example/horz.tsx 1`] = `"
加载中...
加载中...
"`; -exports[`ssr snapshot test > ssr test src/loading/_example/index.tsx 1`] = `"

Loading 加载

用于表示页面或操作的加载状态,给予用户反馈的同时减缓等待的焦虑感,由一个或一组反馈动效组成。

01 类型

纯图标

图标加文字横向

加载中...
加载中...

图标加文字竖向

加载中
加载中...

纯文字

加载中...

02 组件尺寸

大尺寸
加载中...
中尺寸
加载中...
小尺寸
加载中...

03 加载速度

加载速度调整

加载中...
5
"`; +exports[`ssr snapshot test > ssr test src/loading/_example/index.tsx 1`] = `"

Loading 加载

用于表示页面或操作的加载状态,给予用户反馈的同时减缓等待的焦虑感,由一个或一组反馈动效组成。

01 类型

纯图标

图标加文字横向

加载中...
加载中...

图标加文字竖向

加载中
加载中...

纯文字

加载中...

02 组件尺寸

大尺寸
加载中...
中尺寸
加载中...
小尺寸
加载中...

03 加载速度

加载速度调整

加载中...
"`; exports[`ssr snapshot test > ssr test src/loading/_example/pure-text.tsx 1`] = `"
加载中...
"`; @@ -51956,7 +53510,7 @@ exports[`ssr snapshot test > ssr test src/loading/_example/service.tsx 1`] = `"< exports[`ssr snapshot test > ssr test src/loading/_example/size.tsx 1`] = `"
大尺寸
加载中...
中尺寸
加载中...
小尺寸
加载中...
"`; -exports[`ssr snapshot test > ssr test src/loading/_example/speed.tsx 1`] = `"
加载中...
5
"`; +exports[`ssr snapshot test > ssr test src/loading/_example/speed.tsx 1`] = `"
加载中...
"`; exports[`ssr snapshot test > ssr test src/loading/_example/vert.tsx 1`] = `"
加载中
加载中...
"`; @@ -52062,6 +53616,20 @@ exports[`ssr snapshot test > ssr test src/skeleton/_example/image-group.tsx 1`] exports[`ssr snapshot test > ssr test src/skeleton/_example/theme.tsx 1`] = `"
头像骨架屏
图片骨架屏
文本骨架屏
段落骨架屏
"`; +exports[`ssr snapshot test > ssr test src/slider/_example/base.tsx 1`] = `"
"`; + +exports[`ssr snapshot test > ssr test src/slider/_example/capsule.tsx 1`] = `"
0
0
"`; + +exports[`ssr snapshot test > ssr test src/slider/_example/disabled.tsx 1`] = `"
"`; + +exports[`ssr snapshot test > ssr test src/slider/_example/index.tsx 1`] = `"

Slider 滑动选择器

用于选择横轴上的数值、区间、档位

01 类型

单游标滑块

双游标滑块

带数值单游标/双游标滑块

10
0
0
0
100

带刻度单游标/双游标滑块

02 组件状态

滑块禁用状态

03 特殊样式

胶囊型滑块

0
0
"`; + +exports[`ssr snapshot test > ssr test src/slider/_example/label.tsx 1`] = `"
10
0
0
0
100
"`; + +exports[`ssr snapshot test > ssr test src/slider/_example/range.tsx 1`] = `"
"`; + +exports[`ssr snapshot test > ssr test src/slider/_example/step.tsx 1`] = `"
"`; + exports[`ssr snapshot test > ssr test src/stepper/_example/base.tsx 1`] = `"
"`; exports[`ssr snapshot test > ssr test src/stepper/_example/index.tsx 1`] = `"

Stepper 步进器

用于数量的增减

01 类型

基础步进器

02 组件状态

最大最小状态

禁用状态

02 组件样式

步进器样式

步进器尺寸

"`; diff --git a/test/snap/__snapshots__/ssr.test.jsx.snap b/test/snap/__snapshots__/ssr.test.jsx.snap index d2d2c00d..b3964200 100644 --- a/test/snap/__snapshots__/ssr.test.jsx.snap +++ b/test/snap/__snapshots__/ssr.test.jsx.snap @@ -204,7 +204,7 @@ exports[`ssr snapshot test > ssr test src/loading/_example/fullscreen.tsx 1`] = exports[`ssr snapshot test > ssr test src/loading/_example/horz.tsx 1`] = `"
加载中...
加载中...
"`; -exports[`ssr snapshot test > ssr test src/loading/_example/index.tsx 1`] = `"

Loading 加载

用于表示页面或操作的加载状态,给予用户反馈的同时减缓等待的焦虑感,由一个或一组反馈动效组成。

01 类型

纯图标

图标加文字横向

加载中...
加载中...

图标加文字竖向

加载中
加载中...

纯文字

加载中...

02 组件尺寸

大尺寸
加载中...
中尺寸
加载中...
小尺寸
加载中...

03 加载速度

加载速度调整

加载中...
5
"`; +exports[`ssr snapshot test > ssr test src/loading/_example/index.tsx 1`] = `"

Loading 加载

用于表示页面或操作的加载状态,给予用户反馈的同时减缓等待的焦虑感,由一个或一组反馈动效组成。

01 类型

纯图标

图标加文字横向

加载中...
加载中...

图标加文字竖向

加载中
加载中...

纯文字

加载中...

02 组件尺寸

大尺寸
加载中...
中尺寸
加载中...
小尺寸
加载中...

03 加载速度

加载速度调整

加载中...
"`; exports[`ssr snapshot test > ssr test src/loading/_example/pure-text.tsx 1`] = `"
加载中...
"`; @@ -212,7 +212,7 @@ exports[`ssr snapshot test > ssr test src/loading/_example/service.tsx 1`] = `"< exports[`ssr snapshot test > ssr test src/loading/_example/size.tsx 1`] = `"
大尺寸
加载中...
中尺寸
加载中...
小尺寸
加载中...
"`; -exports[`ssr snapshot test > ssr test src/loading/_example/speed.tsx 1`] = `"
加载中...
5
"`; +exports[`ssr snapshot test > ssr test src/loading/_example/speed.tsx 1`] = `"
加载中...
"`; exports[`ssr snapshot test > ssr test src/loading/_example/vert.tsx 1`] = `"
加载中
加载中...
"`; @@ -318,6 +318,20 @@ exports[`ssr snapshot test > ssr test src/skeleton/_example/image-group.tsx 1`] exports[`ssr snapshot test > ssr test src/skeleton/_example/theme.tsx 1`] = `"
头像骨架屏
图片骨架屏
文本骨架屏
段落骨架屏
"`; +exports[`ssr snapshot test > ssr test src/slider/_example/base.tsx 1`] = `"
"`; + +exports[`ssr snapshot test > ssr test src/slider/_example/capsule.tsx 1`] = `"
0
0
"`; + +exports[`ssr snapshot test > ssr test src/slider/_example/disabled.tsx 1`] = `"
"`; + +exports[`ssr snapshot test > ssr test src/slider/_example/index.tsx 1`] = `"

Slider 滑动选择器

用于选择横轴上的数值、区间、档位

01 类型

单游标滑块

双游标滑块

带数值单游标/双游标滑块

10
0
0
0
100

带刻度单游标/双游标滑块

02 组件状态

滑块禁用状态

03 特殊样式

胶囊型滑块

0
0
"`; + +exports[`ssr snapshot test > ssr test src/slider/_example/label.tsx 1`] = `"
10
0
0
0
100
"`; + +exports[`ssr snapshot test > ssr test src/slider/_example/range.tsx 1`] = `"
"`; + +exports[`ssr snapshot test > ssr test src/slider/_example/step.tsx 1`] = `"
"`; + exports[`ssr snapshot test > ssr test src/stepper/_example/base.tsx 1`] = `"
"`; exports[`ssr snapshot test > ssr test src/stepper/_example/index.tsx 1`] = `"

Stepper 步进器

用于数量的增减

01 类型

基础步进器

02 组件状态

最大最小状态

禁用状态

02 组件样式

步进器样式

步进器尺寸

"`;