1
This commit is contained in:
+20
@@ -0,0 +1,20 @@
|
||||
The MIT License (MIT)
|
||||
Copyright (c) 2015-present Alipay.com, https://www.alipay.com/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
# rc-slider
|
||||
|
||||
Slider UI component for React
|
||||
|
||||
[![NPM version][npm-image]][npm-url]
|
||||
[![npm download][download-image]][download-url]
|
||||
[![build status][github-actions-image]][github-actions-url]
|
||||
[![Codecov][codecov-image]][codecov-url]
|
||||
[![bundle size][bundlephobia-image]][bundlephobia-url]
|
||||
[![dumi][dumi-image]][dumi-url]
|
||||
|
||||
[npm-image]: http://img.shields.io/npm/v/rc-slider.svg?style=flat-square
|
||||
[npm-url]: http://npmjs.org/package/rc-slider
|
||||
[travis-image]: https://img.shields.io/travis/react-component/slider/master?style=flat-square
|
||||
[travis-url]: https://travis-ci.com/react-component/slider
|
||||
[github-actions-image]: https://github.com/react-component/slider/workflows/CI/badge.svg
|
||||
[github-actions-url]: https://github.com/react-component/slider/actions
|
||||
[codecov-image]: https://img.shields.io/codecov/c/github/react-component/slider/master.svg?style=flat-square
|
||||
[codecov-url]: https://app.codecov.io/gh/react-component/slider
|
||||
[david-url]: https://david-dm.org/react-component/slider
|
||||
[david-image]: https://david-dm.org/react-component/slider/status.svg?style=flat-square
|
||||
[david-dev-url]: https://david-dm.org/react-component/slider?type=dev
|
||||
[david-dev-image]: https://david-dm.org/react-component/slider/dev-status.svg?style=flat-square
|
||||
[download-image]: https://img.shields.io/npm/dm/rc-slider.svg?style=flat-square
|
||||
[download-url]: https://npmjs.org/package/rc-slider
|
||||
[bundlephobia-url]: https://bundlephobia.com/package/rc-slider
|
||||
[bundlephobia-image]: https://badgen.net/bundlephobia/minzip/rc-slider
|
||||
[dumi-url]: https://github.com/umijs/dumi
|
||||
[dumi-image]: https://img.shields.io/badge/docs%20by-dumi-blue?style=flat-square
|
||||
## Install
|
||||
|
||||
[](https://npmjs.org/package/rc-slider)
|
||||
|
||||
## Example
|
||||
|
||||
`npm start` and then go to http://localhost:8000
|
||||
|
||||
Online examples: https://slider.react-component.now.sh/
|
||||
|
||||
## Usage
|
||||
|
||||
## Slider
|
||||
```js
|
||||
import Slider from '@rc-component/slider';
|
||||
import '@rc-component/slider/assets/index.css';
|
||||
|
||||
export default () => (
|
||||
<>
|
||||
<Slider />
|
||||
</>
|
||||
);
|
||||
```
|
||||
|
||||
## Range
|
||||
Please refer to [#825](https://github.com/react-component/slider/issues/825) for information regarding usage of `Range`.
|
||||
An example:
|
||||
```js
|
||||
import Slider, { Range } from '@rc-component/slider';
|
||||
import '@rc-component/slider/assets/index.css';
|
||||
|
||||
export default () => (
|
||||
<>
|
||||
<Slider range />
|
||||
</>
|
||||
);
|
||||
```
|
||||
|
||||
## Compatibility
|
||||
|
||||
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/electron/electron_48x48.png" alt="Electron" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Electron |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| IE11, Edge | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
|
||||
|
||||
## API
|
||||
|
||||
### createSliderWithTooltip(Slider | Range) => React.Component
|
||||
|
||||
An extension to make Slider or Range support Tooltip on handle.
|
||||
|
||||
```js
|
||||
const Slider = require('@rc-component/slider');
|
||||
const createSliderWithTooltip = Slider.createSliderWithTooltip;
|
||||
const Range = createSliderWithTooltip(Slider.Range);
|
||||
```
|
||||
|
||||
[Online demo](http://react-component.github.io/slider/?path=/story/rc-slider--handle)
|
||||
|
||||
After Range or Slider was wrapped by createSliderWithTooltip, it will have the following props:
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| ------------ | ------- | ------- | ----------- |
|
||||
| tipFormatter | (value: number): React.ReactNode | `value => value` | A function to format tooltip's overlay |
|
||||
| tipProps | Object | `{` <br>`placement: 'top',` <br> ` prefixCls: 'rc-slider-tooltip',` <br> `overlay: tipFormatter(value)` <br> `}` | A function to format tooltip's overlay |
|
||||
|
||||
### Common API
|
||||
|
||||
The following APIs are shared by Slider and Range.
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| ------------ | ------- | ------- | ----------- |
|
||||
| className | string | `''` | Additional CSS class for the root DOM node |
|
||||
| min | number | `0` | The minimum value of the slider |
|
||||
| max | number | `100` | The maximum value of the slider |
|
||||
| id | string | `''` | Unique identifier for the component, used for accessibility |
|
||||
| marks | `{number: ReactNode}` or`{number: { style, label }}` | `{}` | Marks on the slider. The key determines the position, and the value determines what will show. If you want to set the style of a specific mark point, the value should be an object which contains `style` and `label` properties. |
|
||||
| step | number or `null` | `1` | Value to be added or subtracted on each step the slider makes. Must be greater than zero, and `max` - `min` should be evenly divisible by the step value. <br /> When `marks` is not an empty object, `step` can be set to `null`, to make `marks` as steps. |
|
||||
| vertical | boolean | `false` | If vertical is `true`, the slider will be vertical. |
|
||||
| handle | (props) => React.ReactNode | | A handle generator which could be used to customized handle. |
|
||||
| included | boolean | `true` | If the value is `true`, it means a continuous value interval, otherwise, it is a independent value. |
|
||||
| reverse | boolean | `false` | If the value is `true`, it means the component is rendered reverse. |
|
||||
| disabled | boolean | `false` | If `true`, handles can't be moved. |
|
||||
| keyboard | boolean | `true` | Support using keyboard to move handlers. |
|
||||
| dots | boolean | `false` | When the `step` value is greater than 1, you can set the `dots` to `true` if you want to render the slider with dots. |
|
||||
| onBeforeChange | Function | NOOP | `onBeforeChange` will be triggered when `ontouchstart` or `onmousedown` is triggered. |
|
||||
| onChange | Function | NOOP | `onChange` will be triggered while the value of Slider changing. |
|
||||
| onChangeComplete | Function | NOOP | `onChangeComplete` will be triggered when `ontouchend` or `onmouseup` is triggered. |
|
||||
| minimumTrackStyle | Object | | please use `trackStyle` instead. (`only used for slider, just for compatibility , will be deprecate at rc-slider@9.x `) |
|
||||
| maximumTrackStyle | Object | | please use `railStyle` instead (`only used for slider, just for compatibility , will be deprecate at rc-slider@9.x`) |
|
||||
| handleStyle | Array[Object] \| Object | `[{}]` | The style used for handle. (`both for slider(`Object`) and range(`Array of Object`), the array will be used for multi handle following element order`) |
|
||||
| trackStyle | Array[Object] \| Object | `[{}]` | The style used for track. (`both for slider(`Object`) and range(`Array of Object`), the array will be used for multi track following element order`)|
|
||||
| railStyle | Object | `{}` | The style used for the track base color. |
|
||||
| dotStyle | Object \| (dotValue) => Object | `{}` | The style used for the dots. |
|
||||
| activeDotStyle | Object \| (dotValue) => Object | `{}` | The style used for the active dots. |
|
||||
|
||||
### Slider
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| ------------ | ------- | ------- | ----------- |
|
||||
| defaultValue | number | `0` | Set initial value of slider. |
|
||||
| value | number | - | Set current value of slider. |
|
||||
| startPoint | number | `undefined` | Track starts from this value. If `undefined`, `min` is used. |
|
||||
| tabIndex | number | `0` | Set the tabIndex of the slider handle. |
|
||||
| ariaLabelForHandle | string | - | Set the `aria-label` attribute on the slider handle. |
|
||||
| ariaLabelledByForHandle | string | - | Set the `aria-labelledby` attribute on the slider handle. |
|
||||
| ariaRequired | boolean | - | Set the `aria-required` attribute on the slider handle. |
|
||||
| ariaValueTextFormatterForHandle | (value) => string | - | A function to set the `aria-valuetext` attribute on the slider handle. It receives the current value of the slider and returns a formatted string describing the value. See [WAI-ARIA Authoring Practices 1.1](https://www.w3.org/TR/wai-aria-practices-1.1/#slider) for more information. |
|
||||
|
||||
### Range
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| ------------ | ------- | ------- | ----------- |
|
||||
| defaultValue | `number[]` | `[0, 0]` | Set initial positions of handles. |
|
||||
| value | `number[]` | | Set current positions of handles. |
|
||||
| tabIndex | number[] | `[0, 0]` | Set the tabIndex of each handle. |
|
||||
| ariaLabelGroupForHandles | Array[string] | - | Set the `aria-label` attribute on each handle. |
|
||||
| ariaLabelledByGroupForHandles | Array[string] | - | Set the `aria-labelledby` attribute on each handle. |
|
||||
| ariaValueTextFormatterGroupForHandles | Array[(value) => string] | - | A function to set the `aria-valuetext` attribute on each handle. It receives the current value of the slider and returns a formatted string describing the value. See [WAI-ARIA Authoring Practices 1.1](https://www.w3.org/TR/wai-aria-practices-1.1/#slider) for more information. |
|
||||
| count | number | `1` | Determine how many ranges to render, and multiple handles will be rendered (number + 1). |
|
||||
| allowCross | boolean | `true` | `allowCross` could be set as `true` to allow those handles to cross. |
|
||||
| pushable | boolean or number | `false` | `pushable` could be set as `true` to allow pushing of surrounding handles when moving a handle. When set to a number, the number will be the minimum ensured distance between handles. Example:  |
|
||||
| draggableTrack | boolean | `false` | Open the track drag. open after click on the track will be invalid. |
|
||||
|
||||
### SliderTooltip
|
||||
|
||||
The Tooltip Component that keep following with content.
|
||||
|
||||
## Development
|
||||
|
||||
```
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
|
||||
## Test Case
|
||||
|
||||
`npm run test`
|
||||
|
||||
## Coverage
|
||||
|
||||
`npm run coverage`
|
||||
## License
|
||||
|
||||
`rc-slider` is released under the MIT license.
|
||||
+275
@@ -0,0 +1,275 @@
|
||||
.rc-slider {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 14px;
|
||||
padding: 5px 0;
|
||||
border-radius: 6px;
|
||||
touch-action: none;
|
||||
box-sizing: border-box;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
.rc-slider * {
|
||||
box-sizing: border-box;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
.rc-slider-rail {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
background-color: #e9e9e9;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.rc-slider-track,
|
||||
.rc-slider-tracks {
|
||||
position: absolute;
|
||||
height: 4px;
|
||||
background-color: #abe2fb;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.rc-slider-track-draggable {
|
||||
z-index: 1;
|
||||
box-sizing: content-box;
|
||||
background-clip: content-box;
|
||||
border-top: 5px solid rgba(0, 0, 0, 0);
|
||||
border-bottom: 5px solid rgba(0, 0, 0, 0);
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
.rc-slider-handle {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
margin-top: -5px;
|
||||
background-color: #fff;
|
||||
border: solid 2px #96dbfa;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
cursor: -webkit-grab;
|
||||
cursor: grab;
|
||||
opacity: 0.8;
|
||||
user-select: none;
|
||||
touch-action: pan-x;
|
||||
}
|
||||
.rc-slider-handle-dragging.rc-slider-handle-dragging.rc-slider-handle-dragging {
|
||||
border-color: #57c5f7;
|
||||
box-shadow: 0 0 0 5px #96dbfa;
|
||||
}
|
||||
.rc-slider-handle-dragging.rc-slider-handle-dragging.rc-slider-handle-dragging-delete {
|
||||
opacity: 0;
|
||||
}
|
||||
.rc-slider-handle:focus {
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
.rc-slider-handle:focus-visible {
|
||||
border-color: #2db7f5;
|
||||
box-shadow: 0 0 0 3px #96dbfa;
|
||||
}
|
||||
.rc-slider-handle-click-focused:focus {
|
||||
border-color: #96dbfa;
|
||||
box-shadow: unset;
|
||||
}
|
||||
.rc-slider-handle:hover {
|
||||
border-color: #57c5f7;
|
||||
}
|
||||
.rc-slider-handle:active {
|
||||
border-color: #57c5f7;
|
||||
box-shadow: 0 0 5px #57c5f7;
|
||||
cursor: -webkit-grabbing;
|
||||
cursor: grabbing;
|
||||
}
|
||||
.rc-slider-mark {
|
||||
position: absolute;
|
||||
top: 18px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
}
|
||||
.rc-slider-mark-text {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
color: #999;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
}
|
||||
.rc-slider-mark-text-active {
|
||||
color: #666;
|
||||
}
|
||||
.rc-slider-step {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
background: transparent;
|
||||
}
|
||||
.rc-slider-dot {
|
||||
position: absolute;
|
||||
bottom: -2px;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
vertical-align: middle;
|
||||
background-color: #fff;
|
||||
border: 2px solid #e9e9e9;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
}
|
||||
.rc-slider-dot-active {
|
||||
border-color: #96dbfa;
|
||||
}
|
||||
.rc-slider-dot-reverse {
|
||||
margin-right: -4px;
|
||||
}
|
||||
.rc-slider-disabled {
|
||||
background-color: #e9e9e9;
|
||||
}
|
||||
.rc-slider-disabled .rc-slider-track {
|
||||
background-color: #ccc;
|
||||
}
|
||||
.rc-slider-disabled .rc-slider-handle,
|
||||
.rc-slider-disabled .rc-slider-dot {
|
||||
background-color: #fff;
|
||||
border-color: #ccc;
|
||||
box-shadow: none;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.rc-slider-disabled .rc-slider-mark-text,
|
||||
.rc-slider-disabled .rc-slider-dot {
|
||||
cursor: not-allowed !important;
|
||||
}
|
||||
.rc-slider-vertical {
|
||||
width: 14px;
|
||||
height: 100%;
|
||||
padding: 0 5px;
|
||||
}
|
||||
.rc-slider-vertical .rc-slider-rail {
|
||||
width: 4px;
|
||||
height: 100%;
|
||||
}
|
||||
.rc-slider-vertical .rc-slider-track {
|
||||
bottom: 0;
|
||||
left: 5px;
|
||||
width: 4px;
|
||||
}
|
||||
.rc-slider-vertical .rc-slider-track-draggable {
|
||||
border-top: 0;
|
||||
border-right: 5px solid rgba(0, 0, 0, 0);
|
||||
border-bottom: 0;
|
||||
border-left: 5px solid rgba(0, 0, 0, 0);
|
||||
transform: translateX(-5px);
|
||||
}
|
||||
.rc-slider-vertical .rc-slider-handle {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
margin-top: 0;
|
||||
margin-left: -5px;
|
||||
touch-action: pan-y;
|
||||
}
|
||||
.rc-slider-vertical .rc-slider-mark {
|
||||
top: 0;
|
||||
left: 18px;
|
||||
height: 100%;
|
||||
}
|
||||
.rc-slider-vertical .rc-slider-step {
|
||||
width: 4px;
|
||||
height: 100%;
|
||||
}
|
||||
.rc-slider-vertical .rc-slider-dot {
|
||||
margin-left: -2px;
|
||||
}
|
||||
.rc-slider-tooltip-zoom-down-enter,
|
||||
.rc-slider-tooltip-zoom-down-appear {
|
||||
display: block !important;
|
||||
animation-duration: 0.3s;
|
||||
animation-fill-mode: both;
|
||||
animation-play-state: paused;
|
||||
}
|
||||
.rc-slider-tooltip-zoom-down-leave {
|
||||
display: block !important;
|
||||
animation-duration: 0.3s;
|
||||
animation-fill-mode: both;
|
||||
animation-play-state: paused;
|
||||
}
|
||||
.rc-slider-tooltip-zoom-down-enter.rc-slider-tooltip-zoom-down-enter-active,
|
||||
.rc-slider-tooltip-zoom-down-appear.rc-slider-tooltip-zoom-down-appear-active {
|
||||
animation-name: rcSliderTooltipZoomDownIn;
|
||||
animation-play-state: running;
|
||||
}
|
||||
.rc-slider-tooltip-zoom-down-leave.rc-slider-tooltip-zoom-down-leave-active {
|
||||
animation-name: rcSliderTooltipZoomDownOut;
|
||||
animation-play-state: running;
|
||||
}
|
||||
.rc-slider-tooltip-zoom-down-enter,
|
||||
.rc-slider-tooltip-zoom-down-appear {
|
||||
transform: scale(0, 0);
|
||||
animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
|
||||
}
|
||||
.rc-slider-tooltip-zoom-down-leave {
|
||||
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
|
||||
}
|
||||
@keyframes rcSliderTooltipZoomDownIn {
|
||||
0% {
|
||||
transform: scale(0, 0);
|
||||
transform-origin: 50% 100%;
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
transform: scale(1, 1);
|
||||
transform-origin: 50% 100%;
|
||||
}
|
||||
}
|
||||
@keyframes rcSliderTooltipZoomDownOut {
|
||||
0% {
|
||||
transform: scale(1, 1);
|
||||
transform-origin: 50% 100%;
|
||||
}
|
||||
100% {
|
||||
transform: scale(0, 0);
|
||||
transform-origin: 50% 100%;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
.rc-slider-tooltip {
|
||||
position: absolute;
|
||||
top: -9999px;
|
||||
left: -9999px;
|
||||
visibility: visible;
|
||||
box-sizing: border-box;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
.rc-slider-tooltip * {
|
||||
box-sizing: border-box;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
.rc-slider-tooltip-hidden {
|
||||
display: none;
|
||||
}
|
||||
.rc-slider-tooltip-placement-top {
|
||||
padding: 4px 0 8px 0;
|
||||
}
|
||||
.rc-slider-tooltip-inner {
|
||||
min-width: 24px;
|
||||
height: 24px;
|
||||
padding: 6px 2px;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
background-color: #6c6c6c;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 0 4px #d9d9d9;
|
||||
}
|
||||
.rc-slider-tooltip-arrow {
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-color: transparent;
|
||||
border-style: solid;
|
||||
}
|
||||
.rc-slider-tooltip-placement-top .rc-slider-tooltip-arrow {
|
||||
bottom: 4px;
|
||||
left: 50%;
|
||||
margin-left: -4px;
|
||||
border-width: 4px 4px 0;
|
||||
border-top-color: #6c6c6c;
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
import * as React from 'react';
|
||||
import type { OnStartMove } from '../interface';
|
||||
interface RenderProps {
|
||||
index: number;
|
||||
prefixCls: string;
|
||||
value: number;
|
||||
dragging: boolean;
|
||||
draggingDelete: boolean;
|
||||
}
|
||||
export interface HandleProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onFocus' | 'onMouseEnter'> {
|
||||
prefixCls: string;
|
||||
style?: React.CSSProperties;
|
||||
value: number;
|
||||
valueIndex: number;
|
||||
dragging: boolean;
|
||||
draggingDelete: boolean;
|
||||
onStartMove: OnStartMove;
|
||||
onDelete?: (index: number) => void;
|
||||
onOffsetChange: (value: number | 'min' | 'max', valueIndex: number) => void;
|
||||
onFocus: (e: React.FocusEvent<HTMLDivElement>, index: number) => void;
|
||||
onMouseEnter: (e: React.MouseEvent<HTMLDivElement>, index: number) => void;
|
||||
render?: (origin: React.ReactElement<React.HTMLAttributes<HTMLDivElement>>, props: RenderProps) => React.ReactElement;
|
||||
onChangeComplete?: () => void;
|
||||
mock?: boolean;
|
||||
}
|
||||
declare const Handle: React.ForwardRefExoticComponent<HandleProps & React.RefAttributes<HTMLDivElement>>;
|
||||
export default Handle;
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
||||
import { clsx } from 'clsx';
|
||||
import KeyCode from "@rc-component/util/es/KeyCode";
|
||||
import * as React from 'react';
|
||||
import SliderContext from "../context";
|
||||
import { getDirectionStyle, getIndex } from "../util";
|
||||
const Handle = /*#__PURE__*/React.forwardRef((props, ref) => {
|
||||
const {
|
||||
prefixCls,
|
||||
value,
|
||||
valueIndex,
|
||||
onStartMove,
|
||||
onDelete,
|
||||
style,
|
||||
render,
|
||||
dragging,
|
||||
draggingDelete,
|
||||
onOffsetChange,
|
||||
onChangeComplete,
|
||||
onFocus,
|
||||
onMouseEnter,
|
||||
...restProps
|
||||
} = props;
|
||||
const {
|
||||
min,
|
||||
max,
|
||||
direction,
|
||||
disabled,
|
||||
keyboard,
|
||||
range,
|
||||
tabIndex,
|
||||
ariaLabelForHandle,
|
||||
ariaLabelledByForHandle,
|
||||
ariaRequired,
|
||||
ariaValueTextFormatterForHandle,
|
||||
styles,
|
||||
classNames
|
||||
} = React.useContext(SliderContext);
|
||||
const handlePrefixCls = `${prefixCls}-handle`;
|
||||
|
||||
// ============================ Events ============================
|
||||
const onInternalStartMove = e => {
|
||||
if (!disabled) {
|
||||
onStartMove(e, valueIndex);
|
||||
}
|
||||
};
|
||||
const onInternalFocus = e => {
|
||||
onFocus?.(e, valueIndex);
|
||||
};
|
||||
const onInternalMouseEnter = e => {
|
||||
onMouseEnter(e, valueIndex);
|
||||
};
|
||||
|
||||
// =========================== Keyboard ===========================
|
||||
const onKeyDown = e => {
|
||||
if (!disabled && keyboard) {
|
||||
let offset = null;
|
||||
|
||||
// Change the value
|
||||
switch (e.which || e.keyCode) {
|
||||
case KeyCode.LEFT:
|
||||
offset = direction === 'ltr' || direction === 'btt' ? -1 : 1;
|
||||
break;
|
||||
case KeyCode.RIGHT:
|
||||
offset = direction === 'ltr' || direction === 'btt' ? 1 : -1;
|
||||
break;
|
||||
|
||||
// Up is plus
|
||||
case KeyCode.UP:
|
||||
offset = direction !== 'ttb' ? 1 : -1;
|
||||
break;
|
||||
|
||||
// Down is minus
|
||||
case KeyCode.DOWN:
|
||||
offset = direction !== 'ttb' ? -1 : 1;
|
||||
break;
|
||||
case KeyCode.HOME:
|
||||
offset = 'min';
|
||||
break;
|
||||
case KeyCode.END:
|
||||
offset = 'max';
|
||||
break;
|
||||
case KeyCode.PAGE_UP:
|
||||
offset = 2;
|
||||
break;
|
||||
case KeyCode.PAGE_DOWN:
|
||||
offset = -2;
|
||||
break;
|
||||
case KeyCode.BACKSPACE:
|
||||
case KeyCode.DELETE:
|
||||
onDelete?.(valueIndex);
|
||||
break;
|
||||
}
|
||||
if (offset !== null) {
|
||||
e.preventDefault();
|
||||
onOffsetChange(offset, valueIndex);
|
||||
}
|
||||
}
|
||||
};
|
||||
const handleKeyUp = e => {
|
||||
switch (e.which || e.keyCode) {
|
||||
case KeyCode.LEFT:
|
||||
case KeyCode.RIGHT:
|
||||
case KeyCode.UP:
|
||||
case KeyCode.DOWN:
|
||||
case KeyCode.HOME:
|
||||
case KeyCode.END:
|
||||
case KeyCode.PAGE_UP:
|
||||
case KeyCode.PAGE_DOWN:
|
||||
onChangeComplete?.();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
// ============================ Offset ============================
|
||||
const positionStyle = getDirectionStyle(direction, value, min, max);
|
||||
|
||||
// ============================ Render ============================
|
||||
let divProps = {};
|
||||
if (valueIndex !== null) {
|
||||
divProps = {
|
||||
tabIndex: disabled ? null : getIndex(tabIndex, valueIndex),
|
||||
role: 'slider',
|
||||
'aria-valuemin': min,
|
||||
'aria-valuemax': max,
|
||||
'aria-valuenow': value,
|
||||
'aria-disabled': disabled,
|
||||
'aria-label': getIndex(ariaLabelForHandle, valueIndex),
|
||||
'aria-labelledby': getIndex(ariaLabelledByForHandle, valueIndex),
|
||||
'aria-required': getIndex(ariaRequired, valueIndex),
|
||||
'aria-valuetext': getIndex(ariaValueTextFormatterForHandle, valueIndex)?.(value),
|
||||
'aria-orientation': direction === 'ltr' || direction === 'rtl' ? 'horizontal' : 'vertical',
|
||||
onMouseDown: onInternalStartMove,
|
||||
onTouchStart: onInternalStartMove,
|
||||
onFocus: onInternalFocus,
|
||||
onMouseEnter: onInternalMouseEnter,
|
||||
onKeyDown,
|
||||
onKeyUp: handleKeyUp
|
||||
};
|
||||
}
|
||||
let handleNode = /*#__PURE__*/React.createElement("div", _extends({
|
||||
ref: ref,
|
||||
className: clsx(handlePrefixCls, {
|
||||
[`${handlePrefixCls}-${valueIndex + 1}`]: valueIndex !== null && range,
|
||||
[`${handlePrefixCls}-dragging`]: dragging,
|
||||
[`${handlePrefixCls}-dragging-delete`]: draggingDelete
|
||||
}, classNames.handle),
|
||||
style: {
|
||||
...positionStyle,
|
||||
...style,
|
||||
...styles.handle
|
||||
}
|
||||
}, divProps, restProps));
|
||||
|
||||
// Customize
|
||||
if (render) {
|
||||
handleNode = render(handleNode, {
|
||||
index: valueIndex,
|
||||
prefixCls,
|
||||
value,
|
||||
dragging,
|
||||
draggingDelete
|
||||
});
|
||||
}
|
||||
return handleNode;
|
||||
});
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
Handle.displayName = 'Handle';
|
||||
}
|
||||
export default Handle;
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
import * as React from 'react';
|
||||
import type { OnStartMove } from '../interface';
|
||||
import type { HandleProps } from './Handle';
|
||||
export interface HandlesProps {
|
||||
prefixCls: string;
|
||||
style?: React.CSSProperties | React.CSSProperties[];
|
||||
values: number[];
|
||||
onStartMove: OnStartMove;
|
||||
onOffsetChange: (value: number | 'min' | 'max', valueIndex: number) => void;
|
||||
onFocus?: (e: React.FocusEvent<HTMLDivElement>) => void;
|
||||
onBlur?: (e: React.FocusEvent<HTMLDivElement>) => void;
|
||||
onDelete?: (index: number) => void;
|
||||
handleRender?: HandleProps['render'];
|
||||
/**
|
||||
* When config `activeHandleRender`,
|
||||
* it will render another hidden handle for active usage.
|
||||
* This is useful for accessibility or tooltip usage.
|
||||
*/
|
||||
activeHandleRender?: HandleProps['render'];
|
||||
draggingIndex: number;
|
||||
draggingDelete: boolean;
|
||||
onChangeComplete?: () => void;
|
||||
}
|
||||
export interface HandlesRef {
|
||||
focus: (index: number) => void;
|
||||
hideHelp: VoidFunction;
|
||||
}
|
||||
declare const Handles: React.ForwardRefExoticComponent<HandlesProps & React.RefAttributes<HandlesRef>>;
|
||||
export default Handles;
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
||||
import * as React from 'react';
|
||||
import { flushSync } from 'react-dom';
|
||||
import { getIndex } from "../util";
|
||||
import Handle from "./Handle";
|
||||
const Handles = /*#__PURE__*/React.forwardRef((props, ref) => {
|
||||
const {
|
||||
prefixCls,
|
||||
style,
|
||||
onStartMove,
|
||||
onOffsetChange,
|
||||
values,
|
||||
handleRender,
|
||||
activeHandleRender,
|
||||
draggingIndex,
|
||||
draggingDelete,
|
||||
onFocus,
|
||||
...restProps
|
||||
} = props;
|
||||
const handlesRef = React.useRef({});
|
||||
|
||||
// =========================== Active ===========================
|
||||
const [activeVisible, setActiveVisible] = React.useState(false);
|
||||
const [activeIndex, setActiveIndex] = React.useState(-1);
|
||||
const onActive = index => {
|
||||
setActiveIndex(index);
|
||||
setActiveVisible(true);
|
||||
};
|
||||
const onHandleFocus = (e, index) => {
|
||||
onActive(index);
|
||||
onFocus?.(e);
|
||||
};
|
||||
const onHandleMouseEnter = (e, index) => {
|
||||
onActive(index);
|
||||
};
|
||||
|
||||
// =========================== Render ===========================
|
||||
React.useImperativeHandle(ref, () => ({
|
||||
focus: index => {
|
||||
handlesRef.current[index]?.focus();
|
||||
},
|
||||
hideHelp: () => {
|
||||
flushSync(() => {
|
||||
setActiveVisible(false);
|
||||
});
|
||||
}
|
||||
}));
|
||||
|
||||
// =========================== Render ===========================
|
||||
// Handle Props
|
||||
const handleProps = {
|
||||
prefixCls,
|
||||
onStartMove,
|
||||
onOffsetChange,
|
||||
render: handleRender,
|
||||
onFocus: onHandleFocus,
|
||||
onMouseEnter: onHandleMouseEnter,
|
||||
...restProps
|
||||
};
|
||||
return /*#__PURE__*/React.createElement(React.Fragment, null, values.map((value, index) => {
|
||||
const dragging = draggingIndex === index;
|
||||
return /*#__PURE__*/React.createElement(Handle, _extends({
|
||||
ref: node => {
|
||||
if (!node) {
|
||||
delete handlesRef.current[index];
|
||||
} else {
|
||||
handlesRef.current[index] = node;
|
||||
}
|
||||
},
|
||||
dragging: dragging,
|
||||
draggingDelete: dragging && draggingDelete,
|
||||
style: getIndex(style, index),
|
||||
key: index,
|
||||
value: value,
|
||||
valueIndex: index
|
||||
}, handleProps));
|
||||
}), activeHandleRender && activeVisible && /*#__PURE__*/React.createElement(Handle, _extends({
|
||||
key: "a11y"
|
||||
}, handleProps, {
|
||||
value: values[activeIndex],
|
||||
valueIndex: null,
|
||||
dragging: draggingIndex !== -1,
|
||||
draggingDelete: draggingDelete,
|
||||
render: activeHandleRender,
|
||||
style: {
|
||||
pointerEvents: 'none'
|
||||
},
|
||||
tabIndex: null,
|
||||
"aria-hidden": true
|
||||
})));
|
||||
});
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
Handles.displayName = 'Handles';
|
||||
}
|
||||
export default Handles;
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import * as React from 'react';
|
||||
export interface MarkProps {
|
||||
prefixCls: string;
|
||||
children?: React.ReactNode;
|
||||
style?: React.CSSProperties;
|
||||
value: number;
|
||||
onClick: (value: number) => void;
|
||||
}
|
||||
declare const Mark: React.FC<MarkProps>;
|
||||
export default Mark;
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
import { clsx } from 'clsx';
|
||||
import * as React from 'react';
|
||||
import SliderContext from "../context";
|
||||
import { getDirectionStyle } from "../util";
|
||||
const Mark = props => {
|
||||
const {
|
||||
prefixCls,
|
||||
style,
|
||||
children,
|
||||
value,
|
||||
onClick
|
||||
} = props;
|
||||
const {
|
||||
min,
|
||||
max,
|
||||
direction,
|
||||
includedStart,
|
||||
includedEnd,
|
||||
included
|
||||
} = React.useContext(SliderContext);
|
||||
const textCls = `${prefixCls}-text`;
|
||||
|
||||
// ============================ Offset ============================
|
||||
const positionStyle = getDirectionStyle(direction, value, min, max);
|
||||
return /*#__PURE__*/React.createElement("span", {
|
||||
className: clsx(textCls, {
|
||||
[`${textCls}-active`]: included && includedStart <= value && value <= includedEnd
|
||||
}),
|
||||
style: {
|
||||
...positionStyle,
|
||||
...style
|
||||
},
|
||||
onMouseDown: e => {
|
||||
e.stopPropagation();
|
||||
},
|
||||
onClick: () => {
|
||||
onClick(value);
|
||||
}
|
||||
}, children);
|
||||
};
|
||||
export default Mark;
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
import * as React from 'react';
|
||||
export interface MarkObj {
|
||||
style?: React.CSSProperties;
|
||||
label?: React.ReactNode;
|
||||
}
|
||||
export interface InternalMarkObj extends MarkObj {
|
||||
value: number;
|
||||
}
|
||||
export interface MarksProps {
|
||||
prefixCls: string;
|
||||
marks?: InternalMarkObj[];
|
||||
onClick: (value: number) => void;
|
||||
}
|
||||
declare const Marks: React.FC<MarksProps>;
|
||||
export default Marks;
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
import * as React from 'react';
|
||||
import Mark from "./Mark";
|
||||
const Marks = props => {
|
||||
const {
|
||||
prefixCls,
|
||||
marks,
|
||||
onClick
|
||||
} = props;
|
||||
const markPrefixCls = `${prefixCls}-mark`;
|
||||
|
||||
// Not render mark if empty
|
||||
if (!marks.length) {
|
||||
return null;
|
||||
}
|
||||
return /*#__PURE__*/React.createElement("div", {
|
||||
className: markPrefixCls
|
||||
}, marks.map(({
|
||||
value,
|
||||
style,
|
||||
label
|
||||
}) => /*#__PURE__*/React.createElement(Mark, {
|
||||
key: value,
|
||||
prefixCls: markPrefixCls,
|
||||
style: style,
|
||||
value: value,
|
||||
onClick: onClick
|
||||
}, label)));
|
||||
};
|
||||
export default Marks;
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
import * as React from 'react';
|
||||
import type { HandlesProps } from './Handles';
|
||||
import type { MarkObj } from './Marks';
|
||||
import type { AriaValueFormat, SliderClassNames, SliderStyles } from './interface';
|
||||
/**
|
||||
* New:
|
||||
* - click mark to update range value
|
||||
* - handleRender
|
||||
* - Fix handle with count not correct
|
||||
* - Fix pushable not work in some case
|
||||
* - No more FindDOMNode
|
||||
* - Move all position related style into inline style
|
||||
* - Key: up is plus, down is minus
|
||||
* - fix Key with step = null not align with marks
|
||||
* - Change range should not trigger onChange
|
||||
* - keyboard support pushable
|
||||
*/
|
||||
export type RangeConfig = {
|
||||
editable?: boolean;
|
||||
draggableTrack?: boolean;
|
||||
/** Set min count when `editable` */
|
||||
minCount?: number;
|
||||
/** Set max count when `editable` */
|
||||
maxCount?: number;
|
||||
};
|
||||
export interface SliderProps<ValueType = number | number[]> {
|
||||
prefixCls?: string;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
classNames?: SliderClassNames;
|
||||
styles?: SliderStyles;
|
||||
id?: string;
|
||||
disabled?: boolean;
|
||||
keyboard?: boolean;
|
||||
autoFocus?: boolean;
|
||||
onFocus?: (e: React.FocusEvent<HTMLDivElement>) => void;
|
||||
onBlur?: (e: React.FocusEvent<HTMLDivElement>) => void;
|
||||
range?: boolean | RangeConfig;
|
||||
/** @deprecated Use `range.minCount` or `range.maxCount` to handle this */
|
||||
count?: number;
|
||||
min?: number;
|
||||
max?: number;
|
||||
step?: number | null;
|
||||
value?: ValueType;
|
||||
defaultValue?: ValueType;
|
||||
onChange?: (value: ValueType) => void;
|
||||
/** @deprecated It's always better to use `onChange` instead */
|
||||
onBeforeChange?: (value: ValueType) => void;
|
||||
/** @deprecated Use `onChangeComplete` instead */
|
||||
onAfterChange?: (value: ValueType) => void;
|
||||
onChangeComplete?: (value: ValueType) => void;
|
||||
allowCross?: boolean;
|
||||
pushable?: boolean | number;
|
||||
reverse?: boolean;
|
||||
vertical?: boolean;
|
||||
included?: boolean;
|
||||
startPoint?: number;
|
||||
/** @deprecated Please use `styles.track` instead */
|
||||
trackStyle?: React.CSSProperties | React.CSSProperties[];
|
||||
/** @deprecated Please use `styles.handle` instead */
|
||||
handleStyle?: React.CSSProperties | React.CSSProperties[];
|
||||
/** @deprecated Please use `styles.rail` instead */
|
||||
railStyle?: React.CSSProperties;
|
||||
dotStyle?: React.CSSProperties | ((dotValue: number) => React.CSSProperties);
|
||||
activeDotStyle?: React.CSSProperties | ((dotValue: number) => React.CSSProperties);
|
||||
marks?: Record<string | number, React.ReactNode | MarkObj>;
|
||||
dots?: boolean;
|
||||
handleRender?: HandlesProps['handleRender'];
|
||||
activeHandleRender?: HandlesProps['handleRender'];
|
||||
track?: boolean;
|
||||
tabIndex?: number | number[];
|
||||
ariaLabelForHandle?: string | string[];
|
||||
ariaLabelledByForHandle?: string | string[];
|
||||
ariaRequired?: boolean;
|
||||
ariaValueTextFormatterForHandle?: AriaValueFormat | AriaValueFormat[];
|
||||
}
|
||||
export interface SliderRef {
|
||||
focus: () => void;
|
||||
blur: () => void;
|
||||
}
|
||||
declare const Slider: React.ForwardRefExoticComponent<SliderProps<number | number[]> & React.RefAttributes<SliderRef>>;
|
||||
export default Slider;
|
||||
+437
@@ -0,0 +1,437 @@
|
||||
import useControlledState from "@rc-component/util/es/hooks/useControlledState";
|
||||
import useEvent from "@rc-component/util/es/hooks/useEvent";
|
||||
import isEqual from "@rc-component/util/es/isEqual";
|
||||
import warning from "@rc-component/util/es/warning";
|
||||
import { clsx } from 'clsx';
|
||||
import * as React from 'react';
|
||||
import Handles from "./Handles";
|
||||
import Marks from "./Marks";
|
||||
import Steps from "./Steps";
|
||||
import Tracks from "./Tracks";
|
||||
import SliderContext from "./context";
|
||||
import useDrag from "./hooks/useDrag";
|
||||
import useOffset from "./hooks/useOffset";
|
||||
import useRange from "./hooks/useRange";
|
||||
|
||||
/**
|
||||
* New:
|
||||
* - click mark to update range value
|
||||
* - handleRender
|
||||
* - Fix handle with count not correct
|
||||
* - Fix pushable not work in some case
|
||||
* - No more FindDOMNode
|
||||
* - Move all position related style into inline style
|
||||
* - Key: up is plus, down is minus
|
||||
* - fix Key with step = null not align with marks
|
||||
* - Change range should not trigger onChange
|
||||
* - keyboard support pushable
|
||||
*/
|
||||
|
||||
const Slider = /*#__PURE__*/React.forwardRef((props, ref) => {
|
||||
const {
|
||||
prefixCls = 'rc-slider',
|
||||
className,
|
||||
style,
|
||||
classNames,
|
||||
styles,
|
||||
id,
|
||||
// Status
|
||||
disabled = false,
|
||||
keyboard = true,
|
||||
autoFocus,
|
||||
onFocus,
|
||||
onBlur,
|
||||
// Value
|
||||
min = 0,
|
||||
max = 100,
|
||||
step = 1,
|
||||
value,
|
||||
defaultValue,
|
||||
range,
|
||||
count,
|
||||
onChange,
|
||||
onBeforeChange,
|
||||
onAfterChange,
|
||||
onChangeComplete,
|
||||
// Cross
|
||||
allowCross = true,
|
||||
pushable = false,
|
||||
// Direction
|
||||
reverse,
|
||||
vertical,
|
||||
// Style
|
||||
included = true,
|
||||
startPoint,
|
||||
trackStyle,
|
||||
handleStyle,
|
||||
railStyle,
|
||||
dotStyle,
|
||||
activeDotStyle,
|
||||
// Decorations
|
||||
marks,
|
||||
dots,
|
||||
// Components
|
||||
handleRender,
|
||||
activeHandleRender,
|
||||
track,
|
||||
// Accessibility
|
||||
tabIndex = 0,
|
||||
ariaLabelForHandle,
|
||||
ariaLabelledByForHandle,
|
||||
ariaRequired,
|
||||
ariaValueTextFormatterForHandle
|
||||
} = props;
|
||||
const handlesRef = React.useRef(null);
|
||||
const containerRef = React.useRef(null);
|
||||
const direction = React.useMemo(() => {
|
||||
if (vertical) {
|
||||
return reverse ? 'ttb' : 'btt';
|
||||
}
|
||||
return reverse ? 'rtl' : 'ltr';
|
||||
}, [reverse, vertical]);
|
||||
|
||||
// ============================ Range =============================
|
||||
const [rangeEnabled, rangeEditable, rangeDraggableTrack, minCount, maxCount] = useRange(range);
|
||||
const mergedMin = React.useMemo(() => isFinite(min) ? min : 0, [min]);
|
||||
const mergedMax = React.useMemo(() => isFinite(max) ? max : 100, [max]);
|
||||
|
||||
// ============================= Step =============================
|
||||
const mergedStep = React.useMemo(() => step !== null && step <= 0 ? 1 : step, [step]);
|
||||
|
||||
// ============================= Push =============================
|
||||
const mergedPush = React.useMemo(() => {
|
||||
if (typeof pushable === 'boolean') {
|
||||
return pushable ? mergedStep : false;
|
||||
}
|
||||
return pushable >= 0 ? pushable : false;
|
||||
}, [pushable, mergedStep]);
|
||||
|
||||
// ============================ Marks =============================
|
||||
const markList = React.useMemo(() => {
|
||||
return Object.keys(marks || {}).map(key => {
|
||||
const mark = marks[key];
|
||||
const markObj = {
|
||||
value: Number(key)
|
||||
};
|
||||
if (mark && typeof mark === 'object' && ! /*#__PURE__*/React.isValidElement(mark) && ('label' in mark || 'style' in mark)) {
|
||||
markObj.style = mark.style;
|
||||
markObj.label = mark.label;
|
||||
} else {
|
||||
markObj.label = mark;
|
||||
}
|
||||
return markObj;
|
||||
}).filter(({
|
||||
label
|
||||
}) => label || typeof label === 'number').sort((a, b) => a.value - b.value);
|
||||
}, [marks]);
|
||||
|
||||
// ============================ Format ============================
|
||||
const [formatValue, offsetValues] = useOffset(mergedMin, mergedMax, mergedStep, markList, allowCross, mergedPush);
|
||||
|
||||
// ============================ Values ============================
|
||||
const [mergedValue, setValue] = useControlledState(defaultValue, value);
|
||||
const rawValues = React.useMemo(() => {
|
||||
const valueList = mergedValue === null || mergedValue === undefined ? [] : Array.isArray(mergedValue) ? mergedValue : [mergedValue];
|
||||
const [val0 = mergedMin] = valueList;
|
||||
let returnValues = mergedValue === null ? [] : [val0];
|
||||
|
||||
// Format as range
|
||||
if (rangeEnabled) {
|
||||
returnValues = [...valueList];
|
||||
|
||||
// When count provided or value is `undefined`, we fill values
|
||||
if (count || mergedValue === undefined) {
|
||||
const pointCount = count >= 0 ? count + 1 : 2;
|
||||
returnValues = returnValues.slice(0, pointCount);
|
||||
|
||||
// Fill with count
|
||||
while (returnValues.length < pointCount) {
|
||||
returnValues.push(returnValues[returnValues.length - 1] ?? mergedMin);
|
||||
}
|
||||
}
|
||||
returnValues.sort((a, b) => a - b);
|
||||
}
|
||||
|
||||
// Align in range
|
||||
returnValues.forEach((val, index) => {
|
||||
returnValues[index] = formatValue(val);
|
||||
});
|
||||
return returnValues;
|
||||
}, [mergedValue, rangeEnabled, mergedMin, count, formatValue]);
|
||||
|
||||
// =========================== onChange ===========================
|
||||
const getTriggerValue = triggerValues => rangeEnabled ? triggerValues : triggerValues[0];
|
||||
const triggerChange = useEvent(nextValues => {
|
||||
// Order first
|
||||
const cloneNextValues = [...nextValues].sort((a, b) => a - b);
|
||||
|
||||
// Trigger event if needed
|
||||
if (onChange && !isEqual(cloneNextValues, rawValues, true)) {
|
||||
onChange(getTriggerValue(cloneNextValues));
|
||||
}
|
||||
|
||||
// We set this later since it will re-render component immediately
|
||||
setValue(cloneNextValues);
|
||||
});
|
||||
const finishChange = useEvent(draggingDelete => {
|
||||
// Trigger from `useDrag` will tell if it's a delete action
|
||||
if (draggingDelete) {
|
||||
handlesRef.current.hideHelp();
|
||||
}
|
||||
const finishValue = getTriggerValue(rawValues);
|
||||
onAfterChange?.(finishValue);
|
||||
warning(!onAfterChange, '[rc-slider] `onAfterChange` is deprecated. Please use `onChangeComplete` instead.');
|
||||
onChangeComplete?.(finishValue);
|
||||
});
|
||||
const onDelete = index => {
|
||||
if (disabled || !rangeEditable || rawValues.length <= minCount) {
|
||||
return;
|
||||
}
|
||||
const cloneNextValues = [...rawValues];
|
||||
cloneNextValues.splice(index, 1);
|
||||
onBeforeChange?.(getTriggerValue(cloneNextValues));
|
||||
triggerChange(cloneNextValues);
|
||||
const nextFocusIndex = Math.max(0, index - 1);
|
||||
handlesRef.current.hideHelp();
|
||||
handlesRef.current.focus(nextFocusIndex);
|
||||
};
|
||||
const [draggingIndex, draggingValue, draggingDelete, cacheValues, onStartDrag] = useDrag(containerRef, direction, rawValues, mergedMin, mergedMax, formatValue, triggerChange, finishChange, offsetValues, rangeEditable, minCount);
|
||||
|
||||
/**
|
||||
* When `rangeEditable` will insert a new value in the values array.
|
||||
* Else it will replace the value in the values array.
|
||||
*/
|
||||
const changeToCloseValue = (newValue, e) => {
|
||||
if (!disabled) {
|
||||
// Create new values
|
||||
const cloneNextValues = [...rawValues];
|
||||
let valueIndex = 0;
|
||||
let valueBeforeIndex = 0; // Record the index which value < newValue
|
||||
let valueDist = mergedMax - mergedMin;
|
||||
rawValues.forEach((val, index) => {
|
||||
const dist = Math.abs(newValue - val);
|
||||
if (dist <= valueDist) {
|
||||
valueDist = dist;
|
||||
valueIndex = index;
|
||||
}
|
||||
if (val < newValue) {
|
||||
valueBeforeIndex = index;
|
||||
}
|
||||
});
|
||||
let focusIndex = valueIndex;
|
||||
if (rangeEditable && valueDist !== 0 && (!maxCount || rawValues.length < maxCount)) {
|
||||
cloneNextValues.splice(valueBeforeIndex + 1, 0, newValue);
|
||||
focusIndex = valueBeforeIndex + 1;
|
||||
} else {
|
||||
cloneNextValues[valueIndex] = newValue;
|
||||
}
|
||||
|
||||
// Fill value to match default 2 (only when `rawValues` is empty)
|
||||
if (rangeEnabled && !rawValues.length && count === undefined) {
|
||||
cloneNextValues.push(newValue);
|
||||
}
|
||||
const nextValue = getTriggerValue(cloneNextValues);
|
||||
onBeforeChange?.(nextValue);
|
||||
triggerChange(cloneNextValues);
|
||||
if (e) {
|
||||
document.activeElement?.blur?.();
|
||||
handlesRef.current.focus(focusIndex);
|
||||
onStartDrag(e, focusIndex, cloneNextValues);
|
||||
} else {
|
||||
// https://github.com/ant-design/ant-design/issues/49997
|
||||
onAfterChange?.(nextValue);
|
||||
warning(!onAfterChange, '[rc-slider] `onAfterChange` is deprecated. Please use `onChangeComplete` instead.');
|
||||
onChangeComplete?.(nextValue);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// ============================ Click =============================
|
||||
const onSliderMouseDown = e => {
|
||||
e.preventDefault();
|
||||
const {
|
||||
width,
|
||||
height,
|
||||
left,
|
||||
top,
|
||||
bottom,
|
||||
right
|
||||
} = containerRef.current.getBoundingClientRect();
|
||||
const {
|
||||
clientX,
|
||||
clientY
|
||||
} = e;
|
||||
let percent;
|
||||
switch (direction) {
|
||||
case 'btt':
|
||||
percent = (bottom - clientY) / height;
|
||||
break;
|
||||
case 'ttb':
|
||||
percent = (clientY - top) / height;
|
||||
break;
|
||||
case 'rtl':
|
||||
percent = (right - clientX) / width;
|
||||
break;
|
||||
default:
|
||||
percent = (clientX - left) / width;
|
||||
}
|
||||
const nextValue = mergedMin + percent * (mergedMax - mergedMin);
|
||||
changeToCloseValue(formatValue(nextValue), e);
|
||||
};
|
||||
|
||||
// =========================== Keyboard ===========================
|
||||
const [keyboardValue, setKeyboardValue] = React.useState(null);
|
||||
const onHandleOffsetChange = (offset, valueIndex) => {
|
||||
if (!disabled) {
|
||||
const next = offsetValues(rawValues, offset, valueIndex);
|
||||
onBeforeChange?.(getTriggerValue(rawValues));
|
||||
triggerChange(next.values);
|
||||
setKeyboardValue(next.value);
|
||||
}
|
||||
};
|
||||
React.useEffect(() => {
|
||||
if (keyboardValue !== null) {
|
||||
const valueIndex = rawValues.indexOf(keyboardValue);
|
||||
if (valueIndex >= 0) {
|
||||
handlesRef.current.focus(valueIndex);
|
||||
}
|
||||
}
|
||||
setKeyboardValue(null);
|
||||
}, [keyboardValue]);
|
||||
|
||||
// ============================= Drag =============================
|
||||
const mergedDraggableTrack = React.useMemo(() => {
|
||||
if (rangeDraggableTrack && mergedStep === null) {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
warning(false, '`draggableTrack` is not supported when `step` is `null`.');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return rangeDraggableTrack;
|
||||
}, [rangeDraggableTrack, mergedStep]);
|
||||
const onStartMove = useEvent((e, valueIndex) => {
|
||||
onStartDrag(e, valueIndex);
|
||||
onBeforeChange?.(getTriggerValue(rawValues));
|
||||
});
|
||||
|
||||
// Auto focus for updated handle
|
||||
const dragging = draggingIndex !== -1;
|
||||
React.useEffect(() => {
|
||||
if (!dragging) {
|
||||
const valueIndex = rawValues.lastIndexOf(draggingValue);
|
||||
handlesRef.current.focus(valueIndex);
|
||||
}
|
||||
}, [dragging]);
|
||||
|
||||
// =========================== Included ===========================
|
||||
const sortedCacheValues = React.useMemo(() => [...cacheValues].sort((a, b) => a - b), [cacheValues]);
|
||||
|
||||
// Provide a range values with included [min, max]
|
||||
// Used for Track, Mark & Dot
|
||||
const [includedStart, includedEnd] = React.useMemo(() => {
|
||||
if (!rangeEnabled) {
|
||||
return [mergedMin, sortedCacheValues[0]];
|
||||
}
|
||||
return [sortedCacheValues[0], sortedCacheValues[sortedCacheValues.length - 1]];
|
||||
}, [sortedCacheValues, rangeEnabled, mergedMin]);
|
||||
|
||||
// ============================= Refs =============================
|
||||
React.useImperativeHandle(ref, () => ({
|
||||
focus: () => {
|
||||
handlesRef.current.focus(0);
|
||||
},
|
||||
blur: () => {
|
||||
const {
|
||||
activeElement
|
||||
} = document;
|
||||
if (containerRef.current?.contains(activeElement)) {
|
||||
activeElement?.blur();
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
// ========================== Auto Focus ==========================
|
||||
React.useEffect(() => {
|
||||
if (autoFocus) {
|
||||
handlesRef.current.focus(0);
|
||||
}
|
||||
}, []);
|
||||
|
||||
// =========================== Context ============================
|
||||
const context = React.useMemo(() => ({
|
||||
min: mergedMin,
|
||||
max: mergedMax,
|
||||
direction,
|
||||
disabled,
|
||||
keyboard,
|
||||
step: mergedStep,
|
||||
included,
|
||||
includedStart,
|
||||
includedEnd,
|
||||
range: rangeEnabled,
|
||||
tabIndex,
|
||||
ariaLabelForHandle,
|
||||
ariaLabelledByForHandle,
|
||||
ariaRequired,
|
||||
ariaValueTextFormatterForHandle,
|
||||
styles: styles || {},
|
||||
classNames: classNames || {}
|
||||
}), [mergedMin, mergedMax, direction, disabled, keyboard, mergedStep, included, includedStart, includedEnd, rangeEnabled, tabIndex, ariaLabelForHandle, ariaLabelledByForHandle, ariaRequired, ariaValueTextFormatterForHandle, styles, classNames]);
|
||||
|
||||
// ============================ Render ============================
|
||||
return /*#__PURE__*/React.createElement(SliderContext.Provider, {
|
||||
value: context
|
||||
}, /*#__PURE__*/React.createElement("div", {
|
||||
ref: containerRef,
|
||||
className: clsx(prefixCls, className, {
|
||||
[`${prefixCls}-disabled`]: disabled,
|
||||
[`${prefixCls}-vertical`]: vertical,
|
||||
[`${prefixCls}-horizontal`]: !vertical,
|
||||
[`${prefixCls}-with-marks`]: markList.length
|
||||
}),
|
||||
style: style,
|
||||
onMouseDown: onSliderMouseDown,
|
||||
id: id
|
||||
}, /*#__PURE__*/React.createElement("div", {
|
||||
className: clsx(`${prefixCls}-rail`, classNames?.rail),
|
||||
style: {
|
||||
...railStyle,
|
||||
...styles?.rail
|
||||
}
|
||||
}), track !== false && /*#__PURE__*/React.createElement(Tracks, {
|
||||
prefixCls: prefixCls,
|
||||
style: trackStyle,
|
||||
values: rawValues,
|
||||
startPoint: startPoint,
|
||||
onStartMove: mergedDraggableTrack ? onStartMove : undefined
|
||||
}), /*#__PURE__*/React.createElement(Steps, {
|
||||
prefixCls: prefixCls,
|
||||
marks: markList,
|
||||
dots: dots,
|
||||
style: dotStyle,
|
||||
activeStyle: activeDotStyle
|
||||
}), /*#__PURE__*/React.createElement(Handles, {
|
||||
ref: handlesRef,
|
||||
prefixCls: prefixCls,
|
||||
style: handleStyle,
|
||||
values: cacheValues,
|
||||
draggingIndex: draggingIndex,
|
||||
draggingDelete: draggingDelete,
|
||||
onStartMove: onStartMove,
|
||||
onOffsetChange: onHandleOffsetChange,
|
||||
onFocus: onFocus,
|
||||
onBlur: onBlur,
|
||||
handleRender: handleRender,
|
||||
activeHandleRender: activeHandleRender,
|
||||
onChangeComplete: finishChange,
|
||||
onDelete: rangeEditable ? onDelete : undefined
|
||||
}), /*#__PURE__*/React.createElement(Marks, {
|
||||
prefixCls: prefixCls,
|
||||
marks: markList,
|
||||
onClick: changeToCloseValue
|
||||
})));
|
||||
});
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
Slider.displayName = 'Slider';
|
||||
}
|
||||
export default Slider;
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
import * as React from 'react';
|
||||
export interface DotProps {
|
||||
prefixCls: string;
|
||||
value: number;
|
||||
style?: React.CSSProperties | ((dotValue: number) => React.CSSProperties);
|
||||
activeStyle?: React.CSSProperties | ((dotValue: number) => React.CSSProperties);
|
||||
}
|
||||
declare const Dot: React.FC<DotProps>;
|
||||
export default Dot;
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
import { clsx } from 'clsx';
|
||||
import * as React from 'react';
|
||||
import SliderContext from "../context";
|
||||
import { getDirectionStyle } from "../util";
|
||||
const Dot = props => {
|
||||
const {
|
||||
prefixCls,
|
||||
value,
|
||||
style,
|
||||
activeStyle
|
||||
} = props;
|
||||
const {
|
||||
min,
|
||||
max,
|
||||
direction,
|
||||
included,
|
||||
includedStart,
|
||||
includedEnd
|
||||
} = React.useContext(SliderContext);
|
||||
const dotClassName = `${prefixCls}-dot`;
|
||||
const active = included && includedStart <= value && value <= includedEnd;
|
||||
|
||||
// ============================ Offset ============================
|
||||
let mergedStyle = {
|
||||
...getDirectionStyle(direction, value, min, max),
|
||||
...(typeof style === 'function' ? style(value) : style)
|
||||
};
|
||||
if (active) {
|
||||
mergedStyle = {
|
||||
...mergedStyle,
|
||||
...(typeof activeStyle === 'function' ? activeStyle(value) : activeStyle)
|
||||
};
|
||||
}
|
||||
return /*#__PURE__*/React.createElement("span", {
|
||||
className: clsx(dotClassName, {
|
||||
[`${dotClassName}-active`]: active
|
||||
}),
|
||||
style: mergedStyle
|
||||
});
|
||||
};
|
||||
export default Dot;
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import * as React from 'react';
|
||||
import type { InternalMarkObj } from '../Marks';
|
||||
export interface StepsProps {
|
||||
prefixCls: string;
|
||||
marks: InternalMarkObj[];
|
||||
dots?: boolean;
|
||||
style?: React.CSSProperties | ((dotValue: number) => React.CSSProperties);
|
||||
activeStyle?: React.CSSProperties | ((dotValue: number) => React.CSSProperties);
|
||||
}
|
||||
declare const Steps: React.FC<StepsProps>;
|
||||
export default Steps;
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
import * as React from 'react';
|
||||
import SliderContext from "../context";
|
||||
import Dot from "./Dot";
|
||||
const Steps = props => {
|
||||
const {
|
||||
prefixCls,
|
||||
marks,
|
||||
dots,
|
||||
style,
|
||||
activeStyle
|
||||
} = props;
|
||||
const {
|
||||
min,
|
||||
max,
|
||||
step
|
||||
} = React.useContext(SliderContext);
|
||||
const stepDots = React.useMemo(() => {
|
||||
const dotSet = new Set();
|
||||
|
||||
// Add marks
|
||||
marks.forEach(mark => {
|
||||
dotSet.add(mark.value);
|
||||
});
|
||||
|
||||
// Fill dots
|
||||
if (dots && step !== null) {
|
||||
let current = min;
|
||||
while (current <= max) {
|
||||
dotSet.add(current);
|
||||
current += step;
|
||||
}
|
||||
}
|
||||
return Array.from(dotSet);
|
||||
}, [min, max, step, dots, marks]);
|
||||
return /*#__PURE__*/React.createElement("div", {
|
||||
className: `${prefixCls}-step`
|
||||
}, stepDots.map(dotValue => /*#__PURE__*/React.createElement(Dot, {
|
||||
prefixCls: prefixCls,
|
||||
key: dotValue,
|
||||
value: dotValue,
|
||||
style: style,
|
||||
activeStyle: activeStyle
|
||||
})));
|
||||
};
|
||||
export default Steps;
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
import * as React from 'react';
|
||||
import type { OnStartMove } from '../interface';
|
||||
export interface TrackProps {
|
||||
prefixCls: string;
|
||||
style?: React.CSSProperties;
|
||||
/** Replace with origin prefix concat className */
|
||||
replaceCls?: string;
|
||||
start: number;
|
||||
end: number;
|
||||
index: number;
|
||||
onStartMove?: OnStartMove;
|
||||
}
|
||||
declare const Track: React.FC<TrackProps>;
|
||||
export default Track;
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
import { clsx } from 'clsx';
|
||||
import * as React from 'react';
|
||||
import SliderContext from "../context";
|
||||
import { getOffset } from "../util";
|
||||
const Track = props => {
|
||||
const {
|
||||
prefixCls,
|
||||
style,
|
||||
start,
|
||||
end,
|
||||
index,
|
||||
onStartMove,
|
||||
replaceCls
|
||||
} = props;
|
||||
const {
|
||||
direction,
|
||||
min,
|
||||
max,
|
||||
disabled,
|
||||
range,
|
||||
classNames
|
||||
} = React.useContext(SliderContext);
|
||||
const trackPrefixCls = `${prefixCls}-track`;
|
||||
const offsetStart = getOffset(start, min, max);
|
||||
const offsetEnd = getOffset(end, min, max);
|
||||
|
||||
// ============================ Events ============================
|
||||
const onInternalStartMove = e => {
|
||||
if (!disabled && onStartMove) {
|
||||
onStartMove(e, -1);
|
||||
}
|
||||
};
|
||||
|
||||
// ============================ Render ============================
|
||||
const positionStyle = {};
|
||||
switch (direction) {
|
||||
case 'rtl':
|
||||
positionStyle.right = `${offsetStart * 100}%`;
|
||||
positionStyle.width = `${offsetEnd * 100 - offsetStart * 100}%`;
|
||||
break;
|
||||
case 'btt':
|
||||
positionStyle.bottom = `${offsetStart * 100}%`;
|
||||
positionStyle.height = `${offsetEnd * 100 - offsetStart * 100}%`;
|
||||
break;
|
||||
case 'ttb':
|
||||
positionStyle.top = `${offsetStart * 100}%`;
|
||||
positionStyle.height = `${offsetEnd * 100 - offsetStart * 100}%`;
|
||||
break;
|
||||
default:
|
||||
positionStyle.left = `${offsetStart * 100}%`;
|
||||
positionStyle.width = `${offsetEnd * 100 - offsetStart * 100}%`;
|
||||
}
|
||||
const className = replaceCls || clsx(trackPrefixCls, {
|
||||
[`${trackPrefixCls}-${index + 1}`]: index !== null && range,
|
||||
[`${prefixCls}-track-draggable`]: onStartMove
|
||||
}, classNames.track);
|
||||
return /*#__PURE__*/React.createElement("div", {
|
||||
className: className,
|
||||
style: {
|
||||
...positionStyle,
|
||||
...style
|
||||
},
|
||||
onMouseDown: onInternalStartMove,
|
||||
onTouchStart: onInternalStartMove
|
||||
});
|
||||
};
|
||||
export default Track;
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import * as React from 'react';
|
||||
import type { OnStartMove } from '../interface';
|
||||
export interface TrackProps {
|
||||
prefixCls: string;
|
||||
style?: React.CSSProperties | React.CSSProperties[];
|
||||
values: number[];
|
||||
onStartMove?: OnStartMove;
|
||||
startPoint?: number;
|
||||
}
|
||||
declare const Tracks: React.FC<TrackProps>;
|
||||
export default Tracks;
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
import { clsx } from 'clsx';
|
||||
import * as React from 'react';
|
||||
import SliderContext from "../context";
|
||||
import { getIndex } from "../util";
|
||||
import Track from "./Track";
|
||||
const Tracks = props => {
|
||||
const {
|
||||
prefixCls,
|
||||
style,
|
||||
values,
|
||||
startPoint,
|
||||
onStartMove
|
||||
} = props;
|
||||
const {
|
||||
included,
|
||||
range,
|
||||
min,
|
||||
styles,
|
||||
classNames
|
||||
} = React.useContext(SliderContext);
|
||||
|
||||
// =========================== List ===========================
|
||||
const trackList = React.useMemo(() => {
|
||||
if (!range) {
|
||||
// null value do not have track
|
||||
if (values.length === 0) {
|
||||
return [];
|
||||
}
|
||||
const startValue = startPoint ?? min;
|
||||
const endValue = values[0];
|
||||
return [{
|
||||
start: Math.min(startValue, endValue),
|
||||
end: Math.max(startValue, endValue)
|
||||
}];
|
||||
}
|
||||
|
||||
// Multiple
|
||||
const list = [];
|
||||
for (let i = 0; i < values.length - 1; i += 1) {
|
||||
list.push({
|
||||
start: values[i],
|
||||
end: values[i + 1]
|
||||
});
|
||||
}
|
||||
return list;
|
||||
}, [values, range, startPoint, min]);
|
||||
if (!included) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// ========================== Render ==========================
|
||||
const tracksNode = trackList?.length && (classNames.tracks || styles.tracks) ? /*#__PURE__*/React.createElement(Track, {
|
||||
index: null,
|
||||
prefixCls: prefixCls,
|
||||
start: trackList[0].start,
|
||||
end: trackList[trackList.length - 1].end,
|
||||
replaceCls: clsx(classNames.tracks, `${prefixCls}-tracks`),
|
||||
style: styles.tracks
|
||||
}) : null;
|
||||
return /*#__PURE__*/React.createElement(React.Fragment, null, tracksNode, trackList.map(({
|
||||
start,
|
||||
end
|
||||
}, index) => /*#__PURE__*/React.createElement(Track, {
|
||||
index: index,
|
||||
prefixCls: prefixCls,
|
||||
style: {
|
||||
...getIndex(style, index),
|
||||
...styles.track
|
||||
},
|
||||
start: start,
|
||||
end: end,
|
||||
key: index,
|
||||
onStartMove: onStartMove
|
||||
})));
|
||||
};
|
||||
export default Tracks;
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
import * as React from 'react';
|
||||
import type { AriaValueFormat, Direction, SliderClassNames, SliderStyles } from './interface';
|
||||
export interface SliderContextProps {
|
||||
min: number;
|
||||
max: number;
|
||||
includedStart: number;
|
||||
includedEnd: number;
|
||||
direction: Direction;
|
||||
disabled?: boolean;
|
||||
keyboard?: boolean;
|
||||
included?: boolean;
|
||||
step: number | null;
|
||||
range?: boolean;
|
||||
tabIndex: number | number[];
|
||||
ariaLabelForHandle?: string | string[];
|
||||
ariaLabelledByForHandle?: string | string[];
|
||||
ariaRequired?: boolean;
|
||||
ariaValueTextFormatterForHandle?: AriaValueFormat | AriaValueFormat[];
|
||||
classNames: SliderClassNames;
|
||||
styles: SliderStyles;
|
||||
}
|
||||
declare const SliderContext: React.Context<SliderContextProps>;
|
||||
export default SliderContext;
|
||||
export interface UnstableContextProps {
|
||||
onDragStart?: (info: {
|
||||
rawValues: number[];
|
||||
draggingIndex: number;
|
||||
draggingValue: number;
|
||||
}) => void;
|
||||
onDragChange?: (info: {
|
||||
rawValues: number[];
|
||||
deleteIndex: number;
|
||||
draggingIndex: number;
|
||||
draggingValue: number;
|
||||
}) => void;
|
||||
}
|
||||
/** @private NOT PROMISE AVAILABLE. DO NOT USE IN PRODUCTION. */
|
||||
export declare const UnstableContext: React.Context<UnstableContextProps>;
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
import * as React from 'react';
|
||||
const SliderContext = /*#__PURE__*/React.createContext({
|
||||
min: 0,
|
||||
max: 0,
|
||||
direction: 'ltr',
|
||||
step: 1,
|
||||
includedStart: 0,
|
||||
includedEnd: 0,
|
||||
tabIndex: 0,
|
||||
keyboard: true,
|
||||
styles: {},
|
||||
classNames: {}
|
||||
});
|
||||
export default SliderContext;
|
||||
/** @private NOT PROMISE AVAILABLE. DO NOT USE IN PRODUCTION. */
|
||||
export const UnstableContext = /*#__PURE__*/React.createContext({});
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import * as React from 'react';
|
||||
import type { Direction, OnStartMove } from '../interface';
|
||||
import type { OffsetValues } from './useOffset';
|
||||
declare function useDrag(containerRef: React.RefObject<HTMLDivElement>, direction: Direction, rawValues: number[], min: number, max: number, formatValue: (value: number) => number, triggerChange: (values: number[]) => void, finishChange: (draggingDelete: boolean) => void, offsetValues: OffsetValues, editable: boolean, minCount: number): [
|
||||
draggingIndex: number,
|
||||
draggingValue: number,
|
||||
draggingDelete: boolean,
|
||||
returnValues: number[],
|
||||
onStartMove: OnStartMove
|
||||
];
|
||||
export default useDrag;
|
||||
+200
@@ -0,0 +1,200 @@
|
||||
import * as React from 'react';
|
||||
import useEvent from "@rc-component/util/es/hooks/useEvent";
|
||||
import useLayoutEffect from "@rc-component/util/es/hooks/useLayoutEffect";
|
||||
import { UnstableContext } from "../context";
|
||||
/** Drag to delete offset. It's a user experience number for dragging out */
|
||||
const REMOVE_DIST = 130;
|
||||
function getPosition(e) {
|
||||
const obj = 'targetTouches' in e ? e.targetTouches[0] : e;
|
||||
return {
|
||||
pageX: obj.pageX,
|
||||
pageY: obj.pageY
|
||||
};
|
||||
}
|
||||
function useDrag(containerRef, direction, rawValues, min, max, formatValue, triggerChange, finishChange, offsetValues, editable, minCount) {
|
||||
const [draggingValue, setDraggingValue] = React.useState(null);
|
||||
const [draggingIndex, setDraggingIndex] = React.useState(-1);
|
||||
const [draggingDelete, setDraggingDelete] = React.useState(false);
|
||||
const [cacheValues, setCacheValues] = React.useState(rawValues);
|
||||
const [originValues, setOriginValues] = React.useState(rawValues);
|
||||
const mouseMoveEventRef = React.useRef(null);
|
||||
const mouseUpEventRef = React.useRef(null);
|
||||
const touchEventTargetRef = React.useRef(null);
|
||||
const {
|
||||
onDragStart,
|
||||
onDragChange
|
||||
} = React.useContext(UnstableContext);
|
||||
useLayoutEffect(() => {
|
||||
if (draggingIndex === -1) {
|
||||
setCacheValues(rawValues);
|
||||
}
|
||||
}, [rawValues, draggingIndex]);
|
||||
|
||||
// Clean up event
|
||||
React.useEffect(() => () => {
|
||||
document.removeEventListener('mousemove', mouseMoveEventRef.current);
|
||||
document.removeEventListener('mouseup', mouseUpEventRef.current);
|
||||
if (touchEventTargetRef.current) {
|
||||
touchEventTargetRef.current.removeEventListener('touchmove', mouseMoveEventRef.current);
|
||||
touchEventTargetRef.current.removeEventListener('touchend', mouseUpEventRef.current);
|
||||
}
|
||||
}, []);
|
||||
const flushValues = (nextValues, nextValue, deleteMark) => {
|
||||
// Perf: Only update state when value changed
|
||||
if (nextValue !== undefined) {
|
||||
setDraggingValue(nextValue);
|
||||
}
|
||||
setCacheValues(nextValues);
|
||||
let changeValues = nextValues;
|
||||
if (deleteMark) {
|
||||
changeValues = nextValues.filter((_, i) => i !== draggingIndex);
|
||||
}
|
||||
triggerChange(changeValues);
|
||||
if (onDragChange) {
|
||||
onDragChange({
|
||||
rawValues: nextValues,
|
||||
deleteIndex: deleteMark ? draggingIndex : -1,
|
||||
draggingIndex,
|
||||
draggingValue: nextValue
|
||||
});
|
||||
}
|
||||
};
|
||||
const updateCacheValue = useEvent((valueIndex, offsetPercent, deleteMark) => {
|
||||
if (valueIndex === -1) {
|
||||
// >>>> Dragging on the track
|
||||
const startValue = originValues[0];
|
||||
const endValue = originValues[originValues.length - 1];
|
||||
const maxStartOffset = min - startValue;
|
||||
const maxEndOffset = max - endValue;
|
||||
|
||||
// Get valid offset
|
||||
let offset = offsetPercent * (max - min);
|
||||
offset = Math.max(offset, maxStartOffset);
|
||||
offset = Math.min(offset, maxEndOffset);
|
||||
|
||||
// Use first value to revert back of valid offset (like steps marks)
|
||||
const formatStartValue = formatValue(startValue + offset);
|
||||
offset = formatStartValue - startValue;
|
||||
const cloneCacheValues = originValues.map(val => val + offset);
|
||||
flushValues(cloneCacheValues);
|
||||
} else {
|
||||
// >>>> Dragging on the handle
|
||||
const offsetDist = (max - min) * offsetPercent;
|
||||
|
||||
// Always start with the valueIndex origin value
|
||||
const cloneValues = [...cacheValues];
|
||||
cloneValues[valueIndex] = originValues[valueIndex];
|
||||
const next = offsetValues(cloneValues, offsetDist, valueIndex, 'dist');
|
||||
flushValues(next.values, next.value, deleteMark);
|
||||
}
|
||||
});
|
||||
const onStartMove = (e, valueIndex, startValues) => {
|
||||
e.stopPropagation();
|
||||
|
||||
// 如果是点击 track 触发的,需要传入变化后的初始值,而不能直接用 rawValues
|
||||
const initialValues = startValues || rawValues;
|
||||
const originValue = initialValues[valueIndex];
|
||||
setDraggingIndex(valueIndex);
|
||||
setDraggingValue(originValue);
|
||||
setOriginValues(initialValues);
|
||||
setCacheValues(initialValues);
|
||||
setDraggingDelete(false);
|
||||
const {
|
||||
pageX: startX,
|
||||
pageY: startY
|
||||
} = getPosition(e);
|
||||
|
||||
// We declare it here since closure can't get outer latest value
|
||||
let deleteMark = false;
|
||||
|
||||
// Internal trigger event
|
||||
if (onDragStart) {
|
||||
onDragStart({
|
||||
rawValues: initialValues,
|
||||
draggingIndex: valueIndex,
|
||||
draggingValue: originValue
|
||||
});
|
||||
}
|
||||
|
||||
// Moving
|
||||
const onMouseMove = event => {
|
||||
event.preventDefault();
|
||||
const {
|
||||
pageX: moveX,
|
||||
pageY: moveY
|
||||
} = getPosition(event);
|
||||
const offsetX = moveX - startX;
|
||||
const offsetY = moveY - startY;
|
||||
const {
|
||||
width,
|
||||
height
|
||||
} = containerRef.current.getBoundingClientRect();
|
||||
let offSetPercent;
|
||||
let removeDist;
|
||||
switch (direction) {
|
||||
case 'btt':
|
||||
offSetPercent = -offsetY / height;
|
||||
removeDist = offsetX;
|
||||
break;
|
||||
case 'ttb':
|
||||
offSetPercent = offsetY / height;
|
||||
removeDist = offsetX;
|
||||
break;
|
||||
case 'rtl':
|
||||
offSetPercent = -offsetX / width;
|
||||
removeDist = offsetY;
|
||||
break;
|
||||
default:
|
||||
offSetPercent = offsetX / width;
|
||||
removeDist = offsetY;
|
||||
}
|
||||
|
||||
// Check if need mark remove
|
||||
deleteMark = editable ? Math.abs(removeDist) > REMOVE_DIST && minCount < cacheValues.length : false;
|
||||
setDraggingDelete(deleteMark);
|
||||
updateCacheValue(valueIndex, offSetPercent, deleteMark);
|
||||
};
|
||||
|
||||
// End
|
||||
const onMouseUp = event => {
|
||||
event.preventDefault();
|
||||
document.removeEventListener('mouseup', onMouseUp);
|
||||
document.removeEventListener('mousemove', onMouseMove);
|
||||
if (touchEventTargetRef.current) {
|
||||
touchEventTargetRef.current.removeEventListener('touchmove', mouseMoveEventRef.current);
|
||||
touchEventTargetRef.current.removeEventListener('touchend', mouseUpEventRef.current);
|
||||
}
|
||||
mouseMoveEventRef.current = null;
|
||||
mouseUpEventRef.current = null;
|
||||
touchEventTargetRef.current = null;
|
||||
finishChange(deleteMark);
|
||||
setDraggingIndex(-1);
|
||||
setDraggingDelete(false);
|
||||
};
|
||||
document.addEventListener('mouseup', onMouseUp);
|
||||
document.addEventListener('mousemove', onMouseMove);
|
||||
e.currentTarget.addEventListener('touchend', onMouseUp);
|
||||
e.currentTarget.addEventListener('touchmove', onMouseMove);
|
||||
mouseMoveEventRef.current = onMouseMove;
|
||||
mouseUpEventRef.current = onMouseUp;
|
||||
touchEventTargetRef.current = e.currentTarget;
|
||||
};
|
||||
|
||||
// Only return cache value when it mapping with rawValues
|
||||
const returnValues = React.useMemo(() => {
|
||||
const sourceValues = [...rawValues].sort((a, b) => a - b);
|
||||
const targetValues = [...cacheValues].sort((a, b) => a - b);
|
||||
const counts = {};
|
||||
targetValues.forEach(val => {
|
||||
counts[val] = (counts[val] || 0) + 1;
|
||||
});
|
||||
sourceValues.forEach(val => {
|
||||
counts[val] = (counts[val] || 0) - 1;
|
||||
});
|
||||
const maxDiffCount = editable ? 1 : 0;
|
||||
const diffCount = Object.values(counts).reduce((prev, next) => prev + Math.abs(next), 0);
|
||||
return diffCount <= maxDiffCount ? cacheValues : rawValues;
|
||||
}, [rawValues, cacheValues, editable]);
|
||||
return [draggingIndex, draggingValue, draggingDelete, returnValues, onStartMove];
|
||||
}
|
||||
export default useDrag;
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import type { InternalMarkObj } from '../Marks';
|
||||
/** Format value align with step & marks */
|
||||
type FormatValue = (value: number) => number;
|
||||
type OffsetMode = 'unit' | 'dist';
|
||||
export type OffsetValues = (values: number[], offset: number | 'min' | 'max', valueIndex: number, mode?: OffsetMode) => {
|
||||
value: number;
|
||||
values: number[];
|
||||
};
|
||||
export default function useOffset(min: number, max: number, step: number, markList: InternalMarkObj[], allowCross: boolean, pushable: false | number): [FormatValue, OffsetValues];
|
||||
export {};
|
||||
+207
@@ -0,0 +1,207 @@
|
||||
import * as React from 'react';
|
||||
|
||||
/** Format the value in the range of [min, max] */
|
||||
|
||||
/** Format value align with step */
|
||||
|
||||
/** Format value align with step & marks */
|
||||
|
||||
export default function useOffset(min, max, step, markList, allowCross, pushable) {
|
||||
const formatRangeValue = React.useCallback(val => Math.max(min, Math.min(max, val)), [min, max]);
|
||||
const formatStepValue = React.useCallback(val => {
|
||||
if (step !== null) {
|
||||
const stepValue = min + Math.round((formatRangeValue(val) - min) / step) * step;
|
||||
|
||||
// Cut number in case to be like 0.30000000000000004
|
||||
const getDecimal = num => (String(num).split('.')[1] || '').length;
|
||||
const maxDecimal = Math.max(getDecimal(step), getDecimal(max), getDecimal(min));
|
||||
const fixedValue = Number(stepValue.toFixed(maxDecimal));
|
||||
return min <= fixedValue && fixedValue <= max ? fixedValue : null;
|
||||
}
|
||||
return null;
|
||||
}, [step, min, max, formatRangeValue]);
|
||||
const formatValue = React.useCallback(val => {
|
||||
const formatNextValue = formatRangeValue(val);
|
||||
|
||||
// List align values
|
||||
const alignValues = markList.map(mark => mark.value);
|
||||
if (step !== null) {
|
||||
alignValues.push(formatStepValue(val));
|
||||
}
|
||||
|
||||
// min & max
|
||||
alignValues.push(min, max);
|
||||
|
||||
// Align with marks
|
||||
let closeValue = alignValues[0];
|
||||
let closeDist = max - min;
|
||||
alignValues.forEach(alignValue => {
|
||||
const dist = Math.abs(formatNextValue - alignValue);
|
||||
if (dist <= closeDist) {
|
||||
closeValue = alignValue;
|
||||
closeDist = dist;
|
||||
}
|
||||
});
|
||||
return closeValue;
|
||||
}, [min, max, markList, step, formatRangeValue, formatStepValue]);
|
||||
|
||||
// ========================== Offset ==========================
|
||||
// Single Value
|
||||
const offsetValue = (values, offset, valueIndex, mode = 'unit') => {
|
||||
if (typeof offset === 'number') {
|
||||
let nextValue;
|
||||
const originValue = values[valueIndex];
|
||||
|
||||
// Only used for `dist` mode
|
||||
const targetDistValue = originValue + offset;
|
||||
|
||||
// Compare next step value & mark value which is best match
|
||||
let potentialValues = [];
|
||||
markList.forEach(mark => {
|
||||
potentialValues.push(mark.value);
|
||||
});
|
||||
|
||||
// Min & Max
|
||||
potentialValues.push(min, max);
|
||||
|
||||
// In case origin value is align with mark but not with step
|
||||
potentialValues.push(formatStepValue(originValue));
|
||||
|
||||
// Put offset step value also
|
||||
const sign = offset > 0 ? 1 : -1;
|
||||
if (mode === 'unit') {
|
||||
potentialValues.push(formatStepValue(originValue + sign * step));
|
||||
} else {
|
||||
potentialValues.push(formatStepValue(targetDistValue));
|
||||
}
|
||||
|
||||
// Find close one
|
||||
potentialValues = potentialValues.filter(val => val !== null)
|
||||
// Remove reverse value
|
||||
.filter(val => offset < 0 ? val <= originValue : val >= originValue);
|
||||
if (mode === 'unit') {
|
||||
// `unit` mode can not contain itself
|
||||
potentialValues = potentialValues.filter(val => val !== originValue);
|
||||
}
|
||||
const compareValue = mode === 'unit' ? originValue : targetDistValue;
|
||||
nextValue = potentialValues[0];
|
||||
let valueDist = Math.abs(nextValue - compareValue);
|
||||
potentialValues.forEach(potentialValue => {
|
||||
const dist = Math.abs(potentialValue - compareValue);
|
||||
if (dist < valueDist) {
|
||||
nextValue = potentialValue;
|
||||
valueDist = dist;
|
||||
}
|
||||
});
|
||||
|
||||
// Out of range will back to range
|
||||
if (nextValue === undefined) {
|
||||
return offset < 0 ? min : max;
|
||||
}
|
||||
|
||||
// `dist` mode
|
||||
if (mode === 'dist') {
|
||||
return nextValue;
|
||||
}
|
||||
|
||||
// `unit` mode may need another round
|
||||
if (Math.abs(offset) > 1) {
|
||||
const cloneValues = [...values];
|
||||
cloneValues[valueIndex] = nextValue;
|
||||
return offsetValue(cloneValues, offset - sign, valueIndex, mode);
|
||||
}
|
||||
return nextValue;
|
||||
} else if (offset === 'min') {
|
||||
return min;
|
||||
} else if (offset === 'max') {
|
||||
return max;
|
||||
}
|
||||
};
|
||||
|
||||
/** Same as `offsetValue` but return `changed` mark to tell value changed */
|
||||
const offsetChangedValue = (values, offset, valueIndex, mode = 'unit') => {
|
||||
const originValue = values[valueIndex];
|
||||
const nextValue = offsetValue(values, offset, valueIndex, mode);
|
||||
return {
|
||||
value: nextValue,
|
||||
changed: nextValue !== originValue
|
||||
};
|
||||
};
|
||||
const needPush = dist => {
|
||||
return pushable === null && dist === 0 || typeof pushable === 'number' && dist < pushable;
|
||||
};
|
||||
|
||||
// Values
|
||||
const offsetValues = (values, offset, valueIndex, mode = 'unit') => {
|
||||
const nextValues = values.map(formatValue);
|
||||
const originValue = nextValues[valueIndex];
|
||||
const nextValue = offsetValue(nextValues, offset, valueIndex, mode);
|
||||
nextValues[valueIndex] = nextValue;
|
||||
if (allowCross === false) {
|
||||
// >>>>> Allow Cross
|
||||
const pushNum = pushable || 0;
|
||||
|
||||
// ============ AllowCross ===============
|
||||
if (valueIndex > 0 && nextValues[valueIndex - 1] !== originValue) {
|
||||
nextValues[valueIndex] = Math.max(nextValues[valueIndex], nextValues[valueIndex - 1] + pushNum);
|
||||
}
|
||||
if (valueIndex < nextValues.length - 1 && nextValues[valueIndex + 1] !== originValue) {
|
||||
nextValues[valueIndex] = Math.min(nextValues[valueIndex], nextValues[valueIndex + 1] - pushNum);
|
||||
}
|
||||
} else if (typeof pushable === 'number' || pushable === null) {
|
||||
// >>>>> Pushable
|
||||
// =============== Push ==================
|
||||
|
||||
// >>>>>> Basic push
|
||||
// End values
|
||||
for (let i = valueIndex + 1; i < nextValues.length; i += 1) {
|
||||
let changed = true;
|
||||
while (needPush(nextValues[i] - nextValues[i - 1]) && changed) {
|
||||
({
|
||||
value: nextValues[i],
|
||||
changed
|
||||
} = offsetChangedValue(nextValues, 1, i));
|
||||
}
|
||||
}
|
||||
|
||||
// Start values
|
||||
for (let i = valueIndex; i > 0; i -= 1) {
|
||||
let changed = true;
|
||||
while (needPush(nextValues[i] - nextValues[i - 1]) && changed) {
|
||||
({
|
||||
value: nextValues[i - 1],
|
||||
changed
|
||||
} = offsetChangedValue(nextValues, -1, i - 1));
|
||||
}
|
||||
}
|
||||
|
||||
// >>>>> Revert back to safe push range
|
||||
// End to Start
|
||||
for (let i = nextValues.length - 1; i > 0; i -= 1) {
|
||||
let changed = true;
|
||||
while (needPush(nextValues[i] - nextValues[i - 1]) && changed) {
|
||||
({
|
||||
value: nextValues[i - 1],
|
||||
changed
|
||||
} = offsetChangedValue(nextValues, -1, i - 1));
|
||||
}
|
||||
}
|
||||
|
||||
// Start to End
|
||||
for (let i = 0; i < nextValues.length - 1; i += 1) {
|
||||
let changed = true;
|
||||
while (needPush(nextValues[i + 1] - nextValues[i]) && changed) {
|
||||
({
|
||||
value: nextValues[i + 1],
|
||||
changed
|
||||
} = offsetChangedValue(nextValues, 1, i + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
value: nextValues[valueIndex],
|
||||
values: nextValues
|
||||
};
|
||||
};
|
||||
return [formatValue, offsetValues];
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
import type { SliderProps } from '../Slider';
|
||||
export default function useRange(range?: SliderProps['range']): [
|
||||
range: boolean,
|
||||
rangeEditable: boolean,
|
||||
rangeDraggableTrack: boolean,
|
||||
minCount: number,
|
||||
maxCount?: number
|
||||
];
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
import { warning } from "@rc-component/util/es/warning";
|
||||
import { useMemo } from 'react';
|
||||
export default function useRange(range) {
|
||||
return useMemo(() => {
|
||||
if (range === true || !range) {
|
||||
return [!!range, false, false, 0];
|
||||
}
|
||||
const {
|
||||
editable,
|
||||
draggableTrack,
|
||||
minCount,
|
||||
maxCount
|
||||
} = range;
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
warning(!editable || !draggableTrack, '`editable` can not work with `draggableTrack`.');
|
||||
}
|
||||
return [true, editable, !editable && draggableTrack, minCount || 0, maxCount];
|
||||
}, [range]);
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
import type { SliderProps, SliderRef } from './Slider';
|
||||
import Slider from './Slider';
|
||||
export { UnstableContext } from './context';
|
||||
export type { SliderProps, SliderRef };
|
||||
export default Slider;
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
import Slider from "./Slider";
|
||||
export { UnstableContext } from "./context";
|
||||
export default Slider;
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import type React from 'react';
|
||||
export type Direction = 'rtl' | 'ltr' | 'ttb' | 'btt';
|
||||
export type OnStartMove = (e: React.MouseEvent | React.TouchEvent, valueIndex: number, startValues?: number[]) => void;
|
||||
export type AriaValueFormat = (value: number) => string;
|
||||
export type SemanticName = 'tracks' | 'track' | 'rail' | 'handle';
|
||||
export type SliderClassNames = Partial<Record<SemanticName, string>>;
|
||||
export type SliderStyles = Partial<Record<SemanticName, React.CSSProperties>>;
|
||||
+1
@@ -0,0 +1 @@
|
||||
export {};
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
/// <reference types="react" />
|
||||
import type { Direction } from './interface';
|
||||
export declare function getOffset(value: number, min: number, max: number): number;
|
||||
export declare function getDirectionStyle(direction: Direction, value: number, min: number, max: number): import("react").CSSProperties;
|
||||
/** Return index value if is list or return value directly */
|
||||
export declare function getIndex<T>(value: T | T[], index: number): T;
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
export function getOffset(value, min, max) {
|
||||
return (value - min) / (max - min);
|
||||
}
|
||||
export function getDirectionStyle(direction, value, min, max) {
|
||||
const offset = getOffset(value, min, max);
|
||||
const positionStyle = {};
|
||||
switch (direction) {
|
||||
case 'rtl':
|
||||
positionStyle.right = `${offset * 100}%`;
|
||||
positionStyle.transform = 'translateX(50%)';
|
||||
break;
|
||||
case 'btt':
|
||||
positionStyle.bottom = `${offset * 100}%`;
|
||||
positionStyle.transform = 'translateY(50%)';
|
||||
break;
|
||||
case 'ttb':
|
||||
positionStyle.top = `${offset * 100}%`;
|
||||
positionStyle.transform = 'translateY(-50%)';
|
||||
break;
|
||||
default:
|
||||
positionStyle.left = `${offset * 100}%`;
|
||||
positionStyle.transform = 'translateX(-50%)';
|
||||
break;
|
||||
}
|
||||
return positionStyle;
|
||||
}
|
||||
|
||||
/** Return index value if is list or return value directly */
|
||||
export function getIndex(value, index) {
|
||||
return Array.isArray(value) ? value[index] : value;
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
import * as React from 'react';
|
||||
import type { OnStartMove } from '../interface';
|
||||
interface RenderProps {
|
||||
index: number;
|
||||
prefixCls: string;
|
||||
value: number;
|
||||
dragging: boolean;
|
||||
draggingDelete: boolean;
|
||||
}
|
||||
export interface HandleProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onFocus' | 'onMouseEnter'> {
|
||||
prefixCls: string;
|
||||
style?: React.CSSProperties;
|
||||
value: number;
|
||||
valueIndex: number;
|
||||
dragging: boolean;
|
||||
draggingDelete: boolean;
|
||||
onStartMove: OnStartMove;
|
||||
onDelete?: (index: number) => void;
|
||||
onOffsetChange: (value: number | 'min' | 'max', valueIndex: number) => void;
|
||||
onFocus: (e: React.FocusEvent<HTMLDivElement>, index: number) => void;
|
||||
onMouseEnter: (e: React.MouseEvent<HTMLDivElement>, index: number) => void;
|
||||
render?: (origin: React.ReactElement<React.HTMLAttributes<HTMLDivElement>>, props: RenderProps) => React.ReactElement;
|
||||
onChangeComplete?: () => void;
|
||||
mock?: boolean;
|
||||
}
|
||||
declare const Handle: React.ForwardRefExoticComponent<HandleProps & React.RefAttributes<HTMLDivElement>>;
|
||||
export default Handle;
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var _clsx = require("clsx");
|
||||
var _KeyCode = _interopRequireDefault(require("@rc-component/util/lib/KeyCode"));
|
||||
var React = _interopRequireWildcard(require("react"));
|
||||
var _context = _interopRequireDefault(require("../context"));
|
||||
var _util = require("../util");
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
||||
const Handle = /*#__PURE__*/React.forwardRef((props, ref) => {
|
||||
const {
|
||||
prefixCls,
|
||||
value,
|
||||
valueIndex,
|
||||
onStartMove,
|
||||
onDelete,
|
||||
style,
|
||||
render,
|
||||
dragging,
|
||||
draggingDelete,
|
||||
onOffsetChange,
|
||||
onChangeComplete,
|
||||
onFocus,
|
||||
onMouseEnter,
|
||||
...restProps
|
||||
} = props;
|
||||
const {
|
||||
min,
|
||||
max,
|
||||
direction,
|
||||
disabled,
|
||||
keyboard,
|
||||
range,
|
||||
tabIndex,
|
||||
ariaLabelForHandle,
|
||||
ariaLabelledByForHandle,
|
||||
ariaRequired,
|
||||
ariaValueTextFormatterForHandle,
|
||||
styles,
|
||||
classNames
|
||||
} = React.useContext(_context.default);
|
||||
const handlePrefixCls = `${prefixCls}-handle`;
|
||||
|
||||
// ============================ Events ============================
|
||||
const onInternalStartMove = e => {
|
||||
if (!disabled) {
|
||||
onStartMove(e, valueIndex);
|
||||
}
|
||||
};
|
||||
const onInternalFocus = e => {
|
||||
onFocus?.(e, valueIndex);
|
||||
};
|
||||
const onInternalMouseEnter = e => {
|
||||
onMouseEnter(e, valueIndex);
|
||||
};
|
||||
|
||||
// =========================== Keyboard ===========================
|
||||
const onKeyDown = e => {
|
||||
if (!disabled && keyboard) {
|
||||
let offset = null;
|
||||
|
||||
// Change the value
|
||||
switch (e.which || e.keyCode) {
|
||||
case _KeyCode.default.LEFT:
|
||||
offset = direction === 'ltr' || direction === 'btt' ? -1 : 1;
|
||||
break;
|
||||
case _KeyCode.default.RIGHT:
|
||||
offset = direction === 'ltr' || direction === 'btt' ? 1 : -1;
|
||||
break;
|
||||
|
||||
// Up is plus
|
||||
case _KeyCode.default.UP:
|
||||
offset = direction !== 'ttb' ? 1 : -1;
|
||||
break;
|
||||
|
||||
// Down is minus
|
||||
case _KeyCode.default.DOWN:
|
||||
offset = direction !== 'ttb' ? -1 : 1;
|
||||
break;
|
||||
case _KeyCode.default.HOME:
|
||||
offset = 'min';
|
||||
break;
|
||||
case _KeyCode.default.END:
|
||||
offset = 'max';
|
||||
break;
|
||||
case _KeyCode.default.PAGE_UP:
|
||||
offset = 2;
|
||||
break;
|
||||
case _KeyCode.default.PAGE_DOWN:
|
||||
offset = -2;
|
||||
break;
|
||||
case _KeyCode.default.BACKSPACE:
|
||||
case _KeyCode.default.DELETE:
|
||||
onDelete?.(valueIndex);
|
||||
break;
|
||||
}
|
||||
if (offset !== null) {
|
||||
e.preventDefault();
|
||||
onOffsetChange(offset, valueIndex);
|
||||
}
|
||||
}
|
||||
};
|
||||
const handleKeyUp = e => {
|
||||
switch (e.which || e.keyCode) {
|
||||
case _KeyCode.default.LEFT:
|
||||
case _KeyCode.default.RIGHT:
|
||||
case _KeyCode.default.UP:
|
||||
case _KeyCode.default.DOWN:
|
||||
case _KeyCode.default.HOME:
|
||||
case _KeyCode.default.END:
|
||||
case _KeyCode.default.PAGE_UP:
|
||||
case _KeyCode.default.PAGE_DOWN:
|
||||
onChangeComplete?.();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
// ============================ Offset ============================
|
||||
const positionStyle = (0, _util.getDirectionStyle)(direction, value, min, max);
|
||||
|
||||
// ============================ Render ============================
|
||||
let divProps = {};
|
||||
if (valueIndex !== null) {
|
||||
divProps = {
|
||||
tabIndex: disabled ? null : (0, _util.getIndex)(tabIndex, valueIndex),
|
||||
role: 'slider',
|
||||
'aria-valuemin': min,
|
||||
'aria-valuemax': max,
|
||||
'aria-valuenow': value,
|
||||
'aria-disabled': disabled,
|
||||
'aria-label': (0, _util.getIndex)(ariaLabelForHandle, valueIndex),
|
||||
'aria-labelledby': (0, _util.getIndex)(ariaLabelledByForHandle, valueIndex),
|
||||
'aria-required': (0, _util.getIndex)(ariaRequired, valueIndex),
|
||||
'aria-valuetext': (0, _util.getIndex)(ariaValueTextFormatterForHandle, valueIndex)?.(value),
|
||||
'aria-orientation': direction === 'ltr' || direction === 'rtl' ? 'horizontal' : 'vertical',
|
||||
onMouseDown: onInternalStartMove,
|
||||
onTouchStart: onInternalStartMove,
|
||||
onFocus: onInternalFocus,
|
||||
onMouseEnter: onInternalMouseEnter,
|
||||
onKeyDown,
|
||||
onKeyUp: handleKeyUp
|
||||
};
|
||||
}
|
||||
let handleNode = /*#__PURE__*/React.createElement("div", _extends({
|
||||
ref: ref,
|
||||
className: (0, _clsx.clsx)(handlePrefixCls, {
|
||||
[`${handlePrefixCls}-${valueIndex + 1}`]: valueIndex !== null && range,
|
||||
[`${handlePrefixCls}-dragging`]: dragging,
|
||||
[`${handlePrefixCls}-dragging-delete`]: draggingDelete
|
||||
}, classNames.handle),
|
||||
style: {
|
||||
...positionStyle,
|
||||
...style,
|
||||
...styles.handle
|
||||
}
|
||||
}, divProps, restProps));
|
||||
|
||||
// Customize
|
||||
if (render) {
|
||||
handleNode = render(handleNode, {
|
||||
index: valueIndex,
|
||||
prefixCls,
|
||||
value,
|
||||
dragging,
|
||||
draggingDelete
|
||||
});
|
||||
}
|
||||
return handleNode;
|
||||
});
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
Handle.displayName = 'Handle';
|
||||
}
|
||||
var _default = exports.default = Handle;
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
import * as React from 'react';
|
||||
import type { OnStartMove } from '../interface';
|
||||
import type { HandleProps } from './Handle';
|
||||
export interface HandlesProps {
|
||||
prefixCls: string;
|
||||
style?: React.CSSProperties | React.CSSProperties[];
|
||||
values: number[];
|
||||
onStartMove: OnStartMove;
|
||||
onOffsetChange: (value: number | 'min' | 'max', valueIndex: number) => void;
|
||||
onFocus?: (e: React.FocusEvent<HTMLDivElement>) => void;
|
||||
onBlur?: (e: React.FocusEvent<HTMLDivElement>) => void;
|
||||
onDelete?: (index: number) => void;
|
||||
handleRender?: HandleProps['render'];
|
||||
/**
|
||||
* When config `activeHandleRender`,
|
||||
* it will render another hidden handle for active usage.
|
||||
* This is useful for accessibility or tooltip usage.
|
||||
*/
|
||||
activeHandleRender?: HandleProps['render'];
|
||||
draggingIndex: number;
|
||||
draggingDelete: boolean;
|
||||
onChangeComplete?: () => void;
|
||||
}
|
||||
export interface HandlesRef {
|
||||
focus: (index: number) => void;
|
||||
hideHelp: VoidFunction;
|
||||
}
|
||||
declare const Handles: React.ForwardRefExoticComponent<HandlesProps & React.RefAttributes<HandlesRef>>;
|
||||
export default Handles;
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var React = _interopRequireWildcard(require("react"));
|
||||
var _reactDom = require("react-dom");
|
||||
var _util = require("../util");
|
||||
var _Handle = _interopRequireDefault(require("./Handle"));
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
||||
const Handles = /*#__PURE__*/React.forwardRef((props, ref) => {
|
||||
const {
|
||||
prefixCls,
|
||||
style,
|
||||
onStartMove,
|
||||
onOffsetChange,
|
||||
values,
|
||||
handleRender,
|
||||
activeHandleRender,
|
||||
draggingIndex,
|
||||
draggingDelete,
|
||||
onFocus,
|
||||
...restProps
|
||||
} = props;
|
||||
const handlesRef = React.useRef({});
|
||||
|
||||
// =========================== Active ===========================
|
||||
const [activeVisible, setActiveVisible] = React.useState(false);
|
||||
const [activeIndex, setActiveIndex] = React.useState(-1);
|
||||
const onActive = index => {
|
||||
setActiveIndex(index);
|
||||
setActiveVisible(true);
|
||||
};
|
||||
const onHandleFocus = (e, index) => {
|
||||
onActive(index);
|
||||
onFocus?.(e);
|
||||
};
|
||||
const onHandleMouseEnter = (e, index) => {
|
||||
onActive(index);
|
||||
};
|
||||
|
||||
// =========================== Render ===========================
|
||||
React.useImperativeHandle(ref, () => ({
|
||||
focus: index => {
|
||||
handlesRef.current[index]?.focus();
|
||||
},
|
||||
hideHelp: () => {
|
||||
(0, _reactDom.flushSync)(() => {
|
||||
setActiveVisible(false);
|
||||
});
|
||||
}
|
||||
}));
|
||||
|
||||
// =========================== Render ===========================
|
||||
// Handle Props
|
||||
const handleProps = {
|
||||
prefixCls,
|
||||
onStartMove,
|
||||
onOffsetChange,
|
||||
render: handleRender,
|
||||
onFocus: onHandleFocus,
|
||||
onMouseEnter: onHandleMouseEnter,
|
||||
...restProps
|
||||
};
|
||||
return /*#__PURE__*/React.createElement(React.Fragment, null, values.map((value, index) => {
|
||||
const dragging = draggingIndex === index;
|
||||
return /*#__PURE__*/React.createElement(_Handle.default, _extends({
|
||||
ref: node => {
|
||||
if (!node) {
|
||||
delete handlesRef.current[index];
|
||||
} else {
|
||||
handlesRef.current[index] = node;
|
||||
}
|
||||
},
|
||||
dragging: dragging,
|
||||
draggingDelete: dragging && draggingDelete,
|
||||
style: (0, _util.getIndex)(style, index),
|
||||
key: index,
|
||||
value: value,
|
||||
valueIndex: index
|
||||
}, handleProps));
|
||||
}), activeHandleRender && activeVisible && /*#__PURE__*/React.createElement(_Handle.default, _extends({
|
||||
key: "a11y"
|
||||
}, handleProps, {
|
||||
value: values[activeIndex],
|
||||
valueIndex: null,
|
||||
dragging: draggingIndex !== -1,
|
||||
draggingDelete: draggingDelete,
|
||||
render: activeHandleRender,
|
||||
style: {
|
||||
pointerEvents: 'none'
|
||||
},
|
||||
tabIndex: null,
|
||||
"aria-hidden": true
|
||||
})));
|
||||
});
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
Handles.displayName = 'Handles';
|
||||
}
|
||||
var _default = exports.default = Handles;
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import * as React from 'react';
|
||||
export interface MarkProps {
|
||||
prefixCls: string;
|
||||
children?: React.ReactNode;
|
||||
style?: React.CSSProperties;
|
||||
value: number;
|
||||
onClick: (value: number) => void;
|
||||
}
|
||||
declare const Mark: React.FC<MarkProps>;
|
||||
export default Mark;
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var _clsx = require("clsx");
|
||||
var React = _interopRequireWildcard(require("react"));
|
||||
var _context = _interopRequireDefault(require("../context"));
|
||||
var _util = require("../util");
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
const Mark = props => {
|
||||
const {
|
||||
prefixCls,
|
||||
style,
|
||||
children,
|
||||
value,
|
||||
onClick
|
||||
} = props;
|
||||
const {
|
||||
min,
|
||||
max,
|
||||
direction,
|
||||
includedStart,
|
||||
includedEnd,
|
||||
included
|
||||
} = React.useContext(_context.default);
|
||||
const textCls = `${prefixCls}-text`;
|
||||
|
||||
// ============================ Offset ============================
|
||||
const positionStyle = (0, _util.getDirectionStyle)(direction, value, min, max);
|
||||
return /*#__PURE__*/React.createElement("span", {
|
||||
className: (0, _clsx.clsx)(textCls, {
|
||||
[`${textCls}-active`]: included && includedStart <= value && value <= includedEnd
|
||||
}),
|
||||
style: {
|
||||
...positionStyle,
|
||||
...style
|
||||
},
|
||||
onMouseDown: e => {
|
||||
e.stopPropagation();
|
||||
},
|
||||
onClick: () => {
|
||||
onClick(value);
|
||||
}
|
||||
}, children);
|
||||
};
|
||||
var _default = exports.default = Mark;
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
import * as React from 'react';
|
||||
export interface MarkObj {
|
||||
style?: React.CSSProperties;
|
||||
label?: React.ReactNode;
|
||||
}
|
||||
export interface InternalMarkObj extends MarkObj {
|
||||
value: number;
|
||||
}
|
||||
export interface MarksProps {
|
||||
prefixCls: string;
|
||||
marks?: InternalMarkObj[];
|
||||
onClick: (value: number) => void;
|
||||
}
|
||||
declare const Marks: React.FC<MarksProps>;
|
||||
export default Marks;
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var React = _interopRequireWildcard(require("react"));
|
||||
var _Mark = _interopRequireDefault(require("./Mark"));
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
const Marks = props => {
|
||||
const {
|
||||
prefixCls,
|
||||
marks,
|
||||
onClick
|
||||
} = props;
|
||||
const markPrefixCls = `${prefixCls}-mark`;
|
||||
|
||||
// Not render mark if empty
|
||||
if (!marks.length) {
|
||||
return null;
|
||||
}
|
||||
return /*#__PURE__*/React.createElement("div", {
|
||||
className: markPrefixCls
|
||||
}, marks.map(({
|
||||
value,
|
||||
style,
|
||||
label
|
||||
}) => /*#__PURE__*/React.createElement(_Mark.default, {
|
||||
key: value,
|
||||
prefixCls: markPrefixCls,
|
||||
style: style,
|
||||
value: value,
|
||||
onClick: onClick
|
||||
}, label)));
|
||||
};
|
||||
var _default = exports.default = Marks;
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
import * as React from 'react';
|
||||
import type { HandlesProps } from './Handles';
|
||||
import type { MarkObj } from './Marks';
|
||||
import type { AriaValueFormat, SliderClassNames, SliderStyles } from './interface';
|
||||
/**
|
||||
* New:
|
||||
* - click mark to update range value
|
||||
* - handleRender
|
||||
* - Fix handle with count not correct
|
||||
* - Fix pushable not work in some case
|
||||
* - No more FindDOMNode
|
||||
* - Move all position related style into inline style
|
||||
* - Key: up is plus, down is minus
|
||||
* - fix Key with step = null not align with marks
|
||||
* - Change range should not trigger onChange
|
||||
* - keyboard support pushable
|
||||
*/
|
||||
export type RangeConfig = {
|
||||
editable?: boolean;
|
||||
draggableTrack?: boolean;
|
||||
/** Set min count when `editable` */
|
||||
minCount?: number;
|
||||
/** Set max count when `editable` */
|
||||
maxCount?: number;
|
||||
};
|
||||
export interface SliderProps<ValueType = number | number[]> {
|
||||
prefixCls?: string;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
classNames?: SliderClassNames;
|
||||
styles?: SliderStyles;
|
||||
id?: string;
|
||||
disabled?: boolean;
|
||||
keyboard?: boolean;
|
||||
autoFocus?: boolean;
|
||||
onFocus?: (e: React.FocusEvent<HTMLDivElement>) => void;
|
||||
onBlur?: (e: React.FocusEvent<HTMLDivElement>) => void;
|
||||
range?: boolean | RangeConfig;
|
||||
/** @deprecated Use `range.minCount` or `range.maxCount` to handle this */
|
||||
count?: number;
|
||||
min?: number;
|
||||
max?: number;
|
||||
step?: number | null;
|
||||
value?: ValueType;
|
||||
defaultValue?: ValueType;
|
||||
onChange?: (value: ValueType) => void;
|
||||
/** @deprecated It's always better to use `onChange` instead */
|
||||
onBeforeChange?: (value: ValueType) => void;
|
||||
/** @deprecated Use `onChangeComplete` instead */
|
||||
onAfterChange?: (value: ValueType) => void;
|
||||
onChangeComplete?: (value: ValueType) => void;
|
||||
allowCross?: boolean;
|
||||
pushable?: boolean | number;
|
||||
reverse?: boolean;
|
||||
vertical?: boolean;
|
||||
included?: boolean;
|
||||
startPoint?: number;
|
||||
/** @deprecated Please use `styles.track` instead */
|
||||
trackStyle?: React.CSSProperties | React.CSSProperties[];
|
||||
/** @deprecated Please use `styles.handle` instead */
|
||||
handleStyle?: React.CSSProperties | React.CSSProperties[];
|
||||
/** @deprecated Please use `styles.rail` instead */
|
||||
railStyle?: React.CSSProperties;
|
||||
dotStyle?: React.CSSProperties | ((dotValue: number) => React.CSSProperties);
|
||||
activeDotStyle?: React.CSSProperties | ((dotValue: number) => React.CSSProperties);
|
||||
marks?: Record<string | number, React.ReactNode | MarkObj>;
|
||||
dots?: boolean;
|
||||
handleRender?: HandlesProps['handleRender'];
|
||||
activeHandleRender?: HandlesProps['handleRender'];
|
||||
track?: boolean;
|
||||
tabIndex?: number | number[];
|
||||
ariaLabelForHandle?: string | string[];
|
||||
ariaLabelledByForHandle?: string | string[];
|
||||
ariaRequired?: boolean;
|
||||
ariaValueTextFormatterForHandle?: AriaValueFormat | AriaValueFormat[];
|
||||
}
|
||||
export interface SliderRef {
|
||||
focus: () => void;
|
||||
blur: () => void;
|
||||
}
|
||||
declare const Slider: React.ForwardRefExoticComponent<SliderProps<number | number[]> & React.RefAttributes<SliderRef>>;
|
||||
export default Slider;
|
||||
+445
@@ -0,0 +1,445 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var _useControlledState = _interopRequireDefault(require("@rc-component/util/lib/hooks/useControlledState"));
|
||||
var _useEvent = _interopRequireDefault(require("@rc-component/util/lib/hooks/useEvent"));
|
||||
var _isEqual = _interopRequireDefault(require("@rc-component/util/lib/isEqual"));
|
||||
var _warning = _interopRequireDefault(require("@rc-component/util/lib/warning"));
|
||||
var _clsx = require("clsx");
|
||||
var React = _interopRequireWildcard(require("react"));
|
||||
var _Handles = _interopRequireDefault(require("./Handles"));
|
||||
var _Marks = _interopRequireDefault(require("./Marks"));
|
||||
var _Steps = _interopRequireDefault(require("./Steps"));
|
||||
var _Tracks = _interopRequireDefault(require("./Tracks"));
|
||||
var _context = _interopRequireDefault(require("./context"));
|
||||
var _useDrag = _interopRequireDefault(require("./hooks/useDrag"));
|
||||
var _useOffset = _interopRequireDefault(require("./hooks/useOffset"));
|
||||
var _useRange = _interopRequireDefault(require("./hooks/useRange"));
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
/**
|
||||
* New:
|
||||
* - click mark to update range value
|
||||
* - handleRender
|
||||
* - Fix handle with count not correct
|
||||
* - Fix pushable not work in some case
|
||||
* - No more FindDOMNode
|
||||
* - Move all position related style into inline style
|
||||
* - Key: up is plus, down is minus
|
||||
* - fix Key with step = null not align with marks
|
||||
* - Change range should not trigger onChange
|
||||
* - keyboard support pushable
|
||||
*/
|
||||
|
||||
const Slider = /*#__PURE__*/React.forwardRef((props, ref) => {
|
||||
const {
|
||||
prefixCls = 'rc-slider',
|
||||
className,
|
||||
style,
|
||||
classNames,
|
||||
styles,
|
||||
id,
|
||||
// Status
|
||||
disabled = false,
|
||||
keyboard = true,
|
||||
autoFocus,
|
||||
onFocus,
|
||||
onBlur,
|
||||
// Value
|
||||
min = 0,
|
||||
max = 100,
|
||||
step = 1,
|
||||
value,
|
||||
defaultValue,
|
||||
range,
|
||||
count,
|
||||
onChange,
|
||||
onBeforeChange,
|
||||
onAfterChange,
|
||||
onChangeComplete,
|
||||
// Cross
|
||||
allowCross = true,
|
||||
pushable = false,
|
||||
// Direction
|
||||
reverse,
|
||||
vertical,
|
||||
// Style
|
||||
included = true,
|
||||
startPoint,
|
||||
trackStyle,
|
||||
handleStyle,
|
||||
railStyle,
|
||||
dotStyle,
|
||||
activeDotStyle,
|
||||
// Decorations
|
||||
marks,
|
||||
dots,
|
||||
// Components
|
||||
handleRender,
|
||||
activeHandleRender,
|
||||
track,
|
||||
// Accessibility
|
||||
tabIndex = 0,
|
||||
ariaLabelForHandle,
|
||||
ariaLabelledByForHandle,
|
||||
ariaRequired,
|
||||
ariaValueTextFormatterForHandle
|
||||
} = props;
|
||||
const handlesRef = React.useRef(null);
|
||||
const containerRef = React.useRef(null);
|
||||
const direction = React.useMemo(() => {
|
||||
if (vertical) {
|
||||
return reverse ? 'ttb' : 'btt';
|
||||
}
|
||||
return reverse ? 'rtl' : 'ltr';
|
||||
}, [reverse, vertical]);
|
||||
|
||||
// ============================ Range =============================
|
||||
const [rangeEnabled, rangeEditable, rangeDraggableTrack, minCount, maxCount] = (0, _useRange.default)(range);
|
||||
const mergedMin = React.useMemo(() => isFinite(min) ? min : 0, [min]);
|
||||
const mergedMax = React.useMemo(() => isFinite(max) ? max : 100, [max]);
|
||||
|
||||
// ============================= Step =============================
|
||||
const mergedStep = React.useMemo(() => step !== null && step <= 0 ? 1 : step, [step]);
|
||||
|
||||
// ============================= Push =============================
|
||||
const mergedPush = React.useMemo(() => {
|
||||
if (typeof pushable === 'boolean') {
|
||||
return pushable ? mergedStep : false;
|
||||
}
|
||||
return pushable >= 0 ? pushable : false;
|
||||
}, [pushable, mergedStep]);
|
||||
|
||||
// ============================ Marks =============================
|
||||
const markList = React.useMemo(() => {
|
||||
return Object.keys(marks || {}).map(key => {
|
||||
const mark = marks[key];
|
||||
const markObj = {
|
||||
value: Number(key)
|
||||
};
|
||||
if (mark && typeof mark === 'object' && ! /*#__PURE__*/React.isValidElement(mark) && ('label' in mark || 'style' in mark)) {
|
||||
markObj.style = mark.style;
|
||||
markObj.label = mark.label;
|
||||
} else {
|
||||
markObj.label = mark;
|
||||
}
|
||||
return markObj;
|
||||
}).filter(({
|
||||
label
|
||||
}) => label || typeof label === 'number').sort((a, b) => a.value - b.value);
|
||||
}, [marks]);
|
||||
|
||||
// ============================ Format ============================
|
||||
const [formatValue, offsetValues] = (0, _useOffset.default)(mergedMin, mergedMax, mergedStep, markList, allowCross, mergedPush);
|
||||
|
||||
// ============================ Values ============================
|
||||
const [mergedValue, setValue] = (0, _useControlledState.default)(defaultValue, value);
|
||||
const rawValues = React.useMemo(() => {
|
||||
const valueList = mergedValue === null || mergedValue === undefined ? [] : Array.isArray(mergedValue) ? mergedValue : [mergedValue];
|
||||
const [val0 = mergedMin] = valueList;
|
||||
let returnValues = mergedValue === null ? [] : [val0];
|
||||
|
||||
// Format as range
|
||||
if (rangeEnabled) {
|
||||
returnValues = [...valueList];
|
||||
|
||||
// When count provided or value is `undefined`, we fill values
|
||||
if (count || mergedValue === undefined) {
|
||||
const pointCount = count >= 0 ? count + 1 : 2;
|
||||
returnValues = returnValues.slice(0, pointCount);
|
||||
|
||||
// Fill with count
|
||||
while (returnValues.length < pointCount) {
|
||||
returnValues.push(returnValues[returnValues.length - 1] ?? mergedMin);
|
||||
}
|
||||
}
|
||||
returnValues.sort((a, b) => a - b);
|
||||
}
|
||||
|
||||
// Align in range
|
||||
returnValues.forEach((val, index) => {
|
||||
returnValues[index] = formatValue(val);
|
||||
});
|
||||
return returnValues;
|
||||
}, [mergedValue, rangeEnabled, mergedMin, count, formatValue]);
|
||||
|
||||
// =========================== onChange ===========================
|
||||
const getTriggerValue = triggerValues => rangeEnabled ? triggerValues : triggerValues[0];
|
||||
const triggerChange = (0, _useEvent.default)(nextValues => {
|
||||
// Order first
|
||||
const cloneNextValues = [...nextValues].sort((a, b) => a - b);
|
||||
|
||||
// Trigger event if needed
|
||||
if (onChange && !(0, _isEqual.default)(cloneNextValues, rawValues, true)) {
|
||||
onChange(getTriggerValue(cloneNextValues));
|
||||
}
|
||||
|
||||
// We set this later since it will re-render component immediately
|
||||
setValue(cloneNextValues);
|
||||
});
|
||||
const finishChange = (0, _useEvent.default)(draggingDelete => {
|
||||
// Trigger from `useDrag` will tell if it's a delete action
|
||||
if (draggingDelete) {
|
||||
handlesRef.current.hideHelp();
|
||||
}
|
||||
const finishValue = getTriggerValue(rawValues);
|
||||
onAfterChange?.(finishValue);
|
||||
(0, _warning.default)(!onAfterChange, '[rc-slider] `onAfterChange` is deprecated. Please use `onChangeComplete` instead.');
|
||||
onChangeComplete?.(finishValue);
|
||||
});
|
||||
const onDelete = index => {
|
||||
if (disabled || !rangeEditable || rawValues.length <= minCount) {
|
||||
return;
|
||||
}
|
||||
const cloneNextValues = [...rawValues];
|
||||
cloneNextValues.splice(index, 1);
|
||||
onBeforeChange?.(getTriggerValue(cloneNextValues));
|
||||
triggerChange(cloneNextValues);
|
||||
const nextFocusIndex = Math.max(0, index - 1);
|
||||
handlesRef.current.hideHelp();
|
||||
handlesRef.current.focus(nextFocusIndex);
|
||||
};
|
||||
const [draggingIndex, draggingValue, draggingDelete, cacheValues, onStartDrag] = (0, _useDrag.default)(containerRef, direction, rawValues, mergedMin, mergedMax, formatValue, triggerChange, finishChange, offsetValues, rangeEditable, minCount);
|
||||
|
||||
/**
|
||||
* When `rangeEditable` will insert a new value in the values array.
|
||||
* Else it will replace the value in the values array.
|
||||
*/
|
||||
const changeToCloseValue = (newValue, e) => {
|
||||
if (!disabled) {
|
||||
// Create new values
|
||||
const cloneNextValues = [...rawValues];
|
||||
let valueIndex = 0;
|
||||
let valueBeforeIndex = 0; // Record the index which value < newValue
|
||||
let valueDist = mergedMax - mergedMin;
|
||||
rawValues.forEach((val, index) => {
|
||||
const dist = Math.abs(newValue - val);
|
||||
if (dist <= valueDist) {
|
||||
valueDist = dist;
|
||||
valueIndex = index;
|
||||
}
|
||||
if (val < newValue) {
|
||||
valueBeforeIndex = index;
|
||||
}
|
||||
});
|
||||
let focusIndex = valueIndex;
|
||||
if (rangeEditable && valueDist !== 0 && (!maxCount || rawValues.length < maxCount)) {
|
||||
cloneNextValues.splice(valueBeforeIndex + 1, 0, newValue);
|
||||
focusIndex = valueBeforeIndex + 1;
|
||||
} else {
|
||||
cloneNextValues[valueIndex] = newValue;
|
||||
}
|
||||
|
||||
// Fill value to match default 2 (only when `rawValues` is empty)
|
||||
if (rangeEnabled && !rawValues.length && count === undefined) {
|
||||
cloneNextValues.push(newValue);
|
||||
}
|
||||
const nextValue = getTriggerValue(cloneNextValues);
|
||||
onBeforeChange?.(nextValue);
|
||||
triggerChange(cloneNextValues);
|
||||
if (e) {
|
||||
document.activeElement?.blur?.();
|
||||
handlesRef.current.focus(focusIndex);
|
||||
onStartDrag(e, focusIndex, cloneNextValues);
|
||||
} else {
|
||||
// https://github.com/ant-design/ant-design/issues/49997
|
||||
onAfterChange?.(nextValue);
|
||||
(0, _warning.default)(!onAfterChange, '[rc-slider] `onAfterChange` is deprecated. Please use `onChangeComplete` instead.');
|
||||
onChangeComplete?.(nextValue);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// ============================ Click =============================
|
||||
const onSliderMouseDown = e => {
|
||||
e.preventDefault();
|
||||
const {
|
||||
width,
|
||||
height,
|
||||
left,
|
||||
top,
|
||||
bottom,
|
||||
right
|
||||
} = containerRef.current.getBoundingClientRect();
|
||||
const {
|
||||
clientX,
|
||||
clientY
|
||||
} = e;
|
||||
let percent;
|
||||
switch (direction) {
|
||||
case 'btt':
|
||||
percent = (bottom - clientY) / height;
|
||||
break;
|
||||
case 'ttb':
|
||||
percent = (clientY - top) / height;
|
||||
break;
|
||||
case 'rtl':
|
||||
percent = (right - clientX) / width;
|
||||
break;
|
||||
default:
|
||||
percent = (clientX - left) / width;
|
||||
}
|
||||
const nextValue = mergedMin + percent * (mergedMax - mergedMin);
|
||||
changeToCloseValue(formatValue(nextValue), e);
|
||||
};
|
||||
|
||||
// =========================== Keyboard ===========================
|
||||
const [keyboardValue, setKeyboardValue] = React.useState(null);
|
||||
const onHandleOffsetChange = (offset, valueIndex) => {
|
||||
if (!disabled) {
|
||||
const next = offsetValues(rawValues, offset, valueIndex);
|
||||
onBeforeChange?.(getTriggerValue(rawValues));
|
||||
triggerChange(next.values);
|
||||
setKeyboardValue(next.value);
|
||||
}
|
||||
};
|
||||
React.useEffect(() => {
|
||||
if (keyboardValue !== null) {
|
||||
const valueIndex = rawValues.indexOf(keyboardValue);
|
||||
if (valueIndex >= 0) {
|
||||
handlesRef.current.focus(valueIndex);
|
||||
}
|
||||
}
|
||||
setKeyboardValue(null);
|
||||
}, [keyboardValue]);
|
||||
|
||||
// ============================= Drag =============================
|
||||
const mergedDraggableTrack = React.useMemo(() => {
|
||||
if (rangeDraggableTrack && mergedStep === null) {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
(0, _warning.default)(false, '`draggableTrack` is not supported when `step` is `null`.');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return rangeDraggableTrack;
|
||||
}, [rangeDraggableTrack, mergedStep]);
|
||||
const onStartMove = (0, _useEvent.default)((e, valueIndex) => {
|
||||
onStartDrag(e, valueIndex);
|
||||
onBeforeChange?.(getTriggerValue(rawValues));
|
||||
});
|
||||
|
||||
// Auto focus for updated handle
|
||||
const dragging = draggingIndex !== -1;
|
||||
React.useEffect(() => {
|
||||
if (!dragging) {
|
||||
const valueIndex = rawValues.lastIndexOf(draggingValue);
|
||||
handlesRef.current.focus(valueIndex);
|
||||
}
|
||||
}, [dragging]);
|
||||
|
||||
// =========================== Included ===========================
|
||||
const sortedCacheValues = React.useMemo(() => [...cacheValues].sort((a, b) => a - b), [cacheValues]);
|
||||
|
||||
// Provide a range values with included [min, max]
|
||||
// Used for Track, Mark & Dot
|
||||
const [includedStart, includedEnd] = React.useMemo(() => {
|
||||
if (!rangeEnabled) {
|
||||
return [mergedMin, sortedCacheValues[0]];
|
||||
}
|
||||
return [sortedCacheValues[0], sortedCacheValues[sortedCacheValues.length - 1]];
|
||||
}, [sortedCacheValues, rangeEnabled, mergedMin]);
|
||||
|
||||
// ============================= Refs =============================
|
||||
React.useImperativeHandle(ref, () => ({
|
||||
focus: () => {
|
||||
handlesRef.current.focus(0);
|
||||
},
|
||||
blur: () => {
|
||||
const {
|
||||
activeElement
|
||||
} = document;
|
||||
if (containerRef.current?.contains(activeElement)) {
|
||||
activeElement?.blur();
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
// ========================== Auto Focus ==========================
|
||||
React.useEffect(() => {
|
||||
if (autoFocus) {
|
||||
handlesRef.current.focus(0);
|
||||
}
|
||||
}, []);
|
||||
|
||||
// =========================== Context ============================
|
||||
const context = React.useMemo(() => ({
|
||||
min: mergedMin,
|
||||
max: mergedMax,
|
||||
direction,
|
||||
disabled,
|
||||
keyboard,
|
||||
step: mergedStep,
|
||||
included,
|
||||
includedStart,
|
||||
includedEnd,
|
||||
range: rangeEnabled,
|
||||
tabIndex,
|
||||
ariaLabelForHandle,
|
||||
ariaLabelledByForHandle,
|
||||
ariaRequired,
|
||||
ariaValueTextFormatterForHandle,
|
||||
styles: styles || {},
|
||||
classNames: classNames || {}
|
||||
}), [mergedMin, mergedMax, direction, disabled, keyboard, mergedStep, included, includedStart, includedEnd, rangeEnabled, tabIndex, ariaLabelForHandle, ariaLabelledByForHandle, ariaRequired, ariaValueTextFormatterForHandle, styles, classNames]);
|
||||
|
||||
// ============================ Render ============================
|
||||
return /*#__PURE__*/React.createElement(_context.default.Provider, {
|
||||
value: context
|
||||
}, /*#__PURE__*/React.createElement("div", {
|
||||
ref: containerRef,
|
||||
className: (0, _clsx.clsx)(prefixCls, className, {
|
||||
[`${prefixCls}-disabled`]: disabled,
|
||||
[`${prefixCls}-vertical`]: vertical,
|
||||
[`${prefixCls}-horizontal`]: !vertical,
|
||||
[`${prefixCls}-with-marks`]: markList.length
|
||||
}),
|
||||
style: style,
|
||||
onMouseDown: onSliderMouseDown,
|
||||
id: id
|
||||
}, /*#__PURE__*/React.createElement("div", {
|
||||
className: (0, _clsx.clsx)(`${prefixCls}-rail`, classNames?.rail),
|
||||
style: {
|
||||
...railStyle,
|
||||
...styles?.rail
|
||||
}
|
||||
}), track !== false && /*#__PURE__*/React.createElement(_Tracks.default, {
|
||||
prefixCls: prefixCls,
|
||||
style: trackStyle,
|
||||
values: rawValues,
|
||||
startPoint: startPoint,
|
||||
onStartMove: mergedDraggableTrack ? onStartMove : undefined
|
||||
}), /*#__PURE__*/React.createElement(_Steps.default, {
|
||||
prefixCls: prefixCls,
|
||||
marks: markList,
|
||||
dots: dots,
|
||||
style: dotStyle,
|
||||
activeStyle: activeDotStyle
|
||||
}), /*#__PURE__*/React.createElement(_Handles.default, {
|
||||
ref: handlesRef,
|
||||
prefixCls: prefixCls,
|
||||
style: handleStyle,
|
||||
values: cacheValues,
|
||||
draggingIndex: draggingIndex,
|
||||
draggingDelete: draggingDelete,
|
||||
onStartMove: onStartMove,
|
||||
onOffsetChange: onHandleOffsetChange,
|
||||
onFocus: onFocus,
|
||||
onBlur: onBlur,
|
||||
handleRender: handleRender,
|
||||
activeHandleRender: activeHandleRender,
|
||||
onChangeComplete: finishChange,
|
||||
onDelete: rangeEditable ? onDelete : undefined
|
||||
}), /*#__PURE__*/React.createElement(_Marks.default, {
|
||||
prefixCls: prefixCls,
|
||||
marks: markList,
|
||||
onClick: changeToCloseValue
|
||||
})));
|
||||
});
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
Slider.displayName = 'Slider';
|
||||
}
|
||||
var _default = exports.default = Slider;
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
import * as React from 'react';
|
||||
export interface DotProps {
|
||||
prefixCls: string;
|
||||
value: number;
|
||||
style?: React.CSSProperties | ((dotValue: number) => React.CSSProperties);
|
||||
activeStyle?: React.CSSProperties | ((dotValue: number) => React.CSSProperties);
|
||||
}
|
||||
declare const Dot: React.FC<DotProps>;
|
||||
export default Dot;
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var _clsx = require("clsx");
|
||||
var React = _interopRequireWildcard(require("react"));
|
||||
var _context = _interopRequireDefault(require("../context"));
|
||||
var _util = require("../util");
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
const Dot = props => {
|
||||
const {
|
||||
prefixCls,
|
||||
value,
|
||||
style,
|
||||
activeStyle
|
||||
} = props;
|
||||
const {
|
||||
min,
|
||||
max,
|
||||
direction,
|
||||
included,
|
||||
includedStart,
|
||||
includedEnd
|
||||
} = React.useContext(_context.default);
|
||||
const dotClassName = `${prefixCls}-dot`;
|
||||
const active = included && includedStart <= value && value <= includedEnd;
|
||||
|
||||
// ============================ Offset ============================
|
||||
let mergedStyle = {
|
||||
...(0, _util.getDirectionStyle)(direction, value, min, max),
|
||||
...(typeof style === 'function' ? style(value) : style)
|
||||
};
|
||||
if (active) {
|
||||
mergedStyle = {
|
||||
...mergedStyle,
|
||||
...(typeof activeStyle === 'function' ? activeStyle(value) : activeStyle)
|
||||
};
|
||||
}
|
||||
return /*#__PURE__*/React.createElement("span", {
|
||||
className: (0, _clsx.clsx)(dotClassName, {
|
||||
[`${dotClassName}-active`]: active
|
||||
}),
|
||||
style: mergedStyle
|
||||
});
|
||||
};
|
||||
var _default = exports.default = Dot;
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import * as React from 'react';
|
||||
import type { InternalMarkObj } from '../Marks';
|
||||
export interface StepsProps {
|
||||
prefixCls: string;
|
||||
marks: InternalMarkObj[];
|
||||
dots?: boolean;
|
||||
style?: React.CSSProperties | ((dotValue: number) => React.CSSProperties);
|
||||
activeStyle?: React.CSSProperties | ((dotValue: number) => React.CSSProperties);
|
||||
}
|
||||
declare const Steps: React.FC<StepsProps>;
|
||||
export default Steps;
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var React = _interopRequireWildcard(require("react"));
|
||||
var _context = _interopRequireDefault(require("../context"));
|
||||
var _Dot = _interopRequireDefault(require("./Dot"));
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
const Steps = props => {
|
||||
const {
|
||||
prefixCls,
|
||||
marks,
|
||||
dots,
|
||||
style,
|
||||
activeStyle
|
||||
} = props;
|
||||
const {
|
||||
min,
|
||||
max,
|
||||
step
|
||||
} = React.useContext(_context.default);
|
||||
const stepDots = React.useMemo(() => {
|
||||
const dotSet = new Set();
|
||||
|
||||
// Add marks
|
||||
marks.forEach(mark => {
|
||||
dotSet.add(mark.value);
|
||||
});
|
||||
|
||||
// Fill dots
|
||||
if (dots && step !== null) {
|
||||
let current = min;
|
||||
while (current <= max) {
|
||||
dotSet.add(current);
|
||||
current += step;
|
||||
}
|
||||
}
|
||||
return Array.from(dotSet);
|
||||
}, [min, max, step, dots, marks]);
|
||||
return /*#__PURE__*/React.createElement("div", {
|
||||
className: `${prefixCls}-step`
|
||||
}, stepDots.map(dotValue => /*#__PURE__*/React.createElement(_Dot.default, {
|
||||
prefixCls: prefixCls,
|
||||
key: dotValue,
|
||||
value: dotValue,
|
||||
style: style,
|
||||
activeStyle: activeStyle
|
||||
})));
|
||||
};
|
||||
var _default = exports.default = Steps;
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
import * as React from 'react';
|
||||
import type { OnStartMove } from '../interface';
|
||||
export interface TrackProps {
|
||||
prefixCls: string;
|
||||
style?: React.CSSProperties;
|
||||
/** Replace with origin prefix concat className */
|
||||
replaceCls?: string;
|
||||
start: number;
|
||||
end: number;
|
||||
index: number;
|
||||
onStartMove?: OnStartMove;
|
||||
}
|
||||
declare const Track: React.FC<TrackProps>;
|
||||
export default Track;
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var _clsx = require("clsx");
|
||||
var React = _interopRequireWildcard(require("react"));
|
||||
var _context = _interopRequireDefault(require("../context"));
|
||||
var _util = require("../util");
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
const Track = props => {
|
||||
const {
|
||||
prefixCls,
|
||||
style,
|
||||
start,
|
||||
end,
|
||||
index,
|
||||
onStartMove,
|
||||
replaceCls
|
||||
} = props;
|
||||
const {
|
||||
direction,
|
||||
min,
|
||||
max,
|
||||
disabled,
|
||||
range,
|
||||
classNames
|
||||
} = React.useContext(_context.default);
|
||||
const trackPrefixCls = `${prefixCls}-track`;
|
||||
const offsetStart = (0, _util.getOffset)(start, min, max);
|
||||
const offsetEnd = (0, _util.getOffset)(end, min, max);
|
||||
|
||||
// ============================ Events ============================
|
||||
const onInternalStartMove = e => {
|
||||
if (!disabled && onStartMove) {
|
||||
onStartMove(e, -1);
|
||||
}
|
||||
};
|
||||
|
||||
// ============================ Render ============================
|
||||
const positionStyle = {};
|
||||
switch (direction) {
|
||||
case 'rtl':
|
||||
positionStyle.right = `${offsetStart * 100}%`;
|
||||
positionStyle.width = `${offsetEnd * 100 - offsetStart * 100}%`;
|
||||
break;
|
||||
case 'btt':
|
||||
positionStyle.bottom = `${offsetStart * 100}%`;
|
||||
positionStyle.height = `${offsetEnd * 100 - offsetStart * 100}%`;
|
||||
break;
|
||||
case 'ttb':
|
||||
positionStyle.top = `${offsetStart * 100}%`;
|
||||
positionStyle.height = `${offsetEnd * 100 - offsetStart * 100}%`;
|
||||
break;
|
||||
default:
|
||||
positionStyle.left = `${offsetStart * 100}%`;
|
||||
positionStyle.width = `${offsetEnd * 100 - offsetStart * 100}%`;
|
||||
}
|
||||
const className = replaceCls || (0, _clsx.clsx)(trackPrefixCls, {
|
||||
[`${trackPrefixCls}-${index + 1}`]: index !== null && range,
|
||||
[`${prefixCls}-track-draggable`]: onStartMove
|
||||
}, classNames.track);
|
||||
return /*#__PURE__*/React.createElement("div", {
|
||||
className: className,
|
||||
style: {
|
||||
...positionStyle,
|
||||
...style
|
||||
},
|
||||
onMouseDown: onInternalStartMove,
|
||||
onTouchStart: onInternalStartMove
|
||||
});
|
||||
};
|
||||
var _default = exports.default = Track;
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import * as React from 'react';
|
||||
import type { OnStartMove } from '../interface';
|
||||
export interface TrackProps {
|
||||
prefixCls: string;
|
||||
style?: React.CSSProperties | React.CSSProperties[];
|
||||
values: number[];
|
||||
onStartMove?: OnStartMove;
|
||||
startPoint?: number;
|
||||
}
|
||||
declare const Tracks: React.FC<TrackProps>;
|
||||
export default Tracks;
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var _clsx = require("clsx");
|
||||
var React = _interopRequireWildcard(require("react"));
|
||||
var _context = _interopRequireDefault(require("../context"));
|
||||
var _util = require("../util");
|
||||
var _Track = _interopRequireDefault(require("./Track"));
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
const Tracks = props => {
|
||||
const {
|
||||
prefixCls,
|
||||
style,
|
||||
values,
|
||||
startPoint,
|
||||
onStartMove
|
||||
} = props;
|
||||
const {
|
||||
included,
|
||||
range,
|
||||
min,
|
||||
styles,
|
||||
classNames
|
||||
} = React.useContext(_context.default);
|
||||
|
||||
// =========================== List ===========================
|
||||
const trackList = React.useMemo(() => {
|
||||
if (!range) {
|
||||
// null value do not have track
|
||||
if (values.length === 0) {
|
||||
return [];
|
||||
}
|
||||
const startValue = startPoint ?? min;
|
||||
const endValue = values[0];
|
||||
return [{
|
||||
start: Math.min(startValue, endValue),
|
||||
end: Math.max(startValue, endValue)
|
||||
}];
|
||||
}
|
||||
|
||||
// Multiple
|
||||
const list = [];
|
||||
for (let i = 0; i < values.length - 1; i += 1) {
|
||||
list.push({
|
||||
start: values[i],
|
||||
end: values[i + 1]
|
||||
});
|
||||
}
|
||||
return list;
|
||||
}, [values, range, startPoint, min]);
|
||||
if (!included) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// ========================== Render ==========================
|
||||
const tracksNode = trackList?.length && (classNames.tracks || styles.tracks) ? /*#__PURE__*/React.createElement(_Track.default, {
|
||||
index: null,
|
||||
prefixCls: prefixCls,
|
||||
start: trackList[0].start,
|
||||
end: trackList[trackList.length - 1].end,
|
||||
replaceCls: (0, _clsx.clsx)(classNames.tracks, `${prefixCls}-tracks`),
|
||||
style: styles.tracks
|
||||
}) : null;
|
||||
return /*#__PURE__*/React.createElement(React.Fragment, null, tracksNode, trackList.map(({
|
||||
start,
|
||||
end
|
||||
}, index) => /*#__PURE__*/React.createElement(_Track.default, {
|
||||
index: index,
|
||||
prefixCls: prefixCls,
|
||||
style: {
|
||||
...(0, _util.getIndex)(style, index),
|
||||
...styles.track
|
||||
},
|
||||
start: start,
|
||||
end: end,
|
||||
key: index,
|
||||
onStartMove: onStartMove
|
||||
})));
|
||||
};
|
||||
var _default = exports.default = Tracks;
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
import * as React from 'react';
|
||||
import type { AriaValueFormat, Direction, SliderClassNames, SliderStyles } from './interface';
|
||||
export interface SliderContextProps {
|
||||
min: number;
|
||||
max: number;
|
||||
includedStart: number;
|
||||
includedEnd: number;
|
||||
direction: Direction;
|
||||
disabled?: boolean;
|
||||
keyboard?: boolean;
|
||||
included?: boolean;
|
||||
step: number | null;
|
||||
range?: boolean;
|
||||
tabIndex: number | number[];
|
||||
ariaLabelForHandle?: string | string[];
|
||||
ariaLabelledByForHandle?: string | string[];
|
||||
ariaRequired?: boolean;
|
||||
ariaValueTextFormatterForHandle?: AriaValueFormat | AriaValueFormat[];
|
||||
classNames: SliderClassNames;
|
||||
styles: SliderStyles;
|
||||
}
|
||||
declare const SliderContext: React.Context<SliderContextProps>;
|
||||
export default SliderContext;
|
||||
export interface UnstableContextProps {
|
||||
onDragStart?: (info: {
|
||||
rawValues: number[];
|
||||
draggingIndex: number;
|
||||
draggingValue: number;
|
||||
}) => void;
|
||||
onDragChange?: (info: {
|
||||
rawValues: number[];
|
||||
deleteIndex: number;
|
||||
draggingIndex: number;
|
||||
draggingValue: number;
|
||||
}) => void;
|
||||
}
|
||||
/** @private NOT PROMISE AVAILABLE. DO NOT USE IN PRODUCTION. */
|
||||
export declare const UnstableContext: React.Context<UnstableContextProps>;
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = exports.UnstableContext = void 0;
|
||||
var React = _interopRequireWildcard(require("react"));
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
const SliderContext = /*#__PURE__*/React.createContext({
|
||||
min: 0,
|
||||
max: 0,
|
||||
direction: 'ltr',
|
||||
step: 1,
|
||||
includedStart: 0,
|
||||
includedEnd: 0,
|
||||
tabIndex: 0,
|
||||
keyboard: true,
|
||||
styles: {},
|
||||
classNames: {}
|
||||
});
|
||||
var _default = exports.default = SliderContext;
|
||||
/** @private NOT PROMISE AVAILABLE. DO NOT USE IN PRODUCTION. */
|
||||
const UnstableContext = exports.UnstableContext = /*#__PURE__*/React.createContext({});
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import * as React from 'react';
|
||||
import type { Direction, OnStartMove } from '../interface';
|
||||
import type { OffsetValues } from './useOffset';
|
||||
declare function useDrag(containerRef: React.RefObject<HTMLDivElement>, direction: Direction, rawValues: number[], min: number, max: number, formatValue: (value: number) => number, triggerChange: (values: number[]) => void, finishChange: (draggingDelete: boolean) => void, offsetValues: OffsetValues, editable: boolean, minCount: number): [
|
||||
draggingIndex: number,
|
||||
draggingValue: number,
|
||||
draggingDelete: boolean,
|
||||
returnValues: number[],
|
||||
onStartMove: OnStartMove
|
||||
];
|
||||
export default useDrag;
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var React = _interopRequireWildcard(require("react"));
|
||||
var _useEvent = _interopRequireDefault(require("@rc-component/util/lib/hooks/useEvent"));
|
||||
var _useLayoutEffect = _interopRequireDefault(require("@rc-component/util/lib/hooks/useLayoutEffect"));
|
||||
var _context = require("../context");
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
/** Drag to delete offset. It's a user experience number for dragging out */
|
||||
const REMOVE_DIST = 130;
|
||||
function getPosition(e) {
|
||||
const obj = 'targetTouches' in e ? e.targetTouches[0] : e;
|
||||
return {
|
||||
pageX: obj.pageX,
|
||||
pageY: obj.pageY
|
||||
};
|
||||
}
|
||||
function useDrag(containerRef, direction, rawValues, min, max, formatValue, triggerChange, finishChange, offsetValues, editable, minCount) {
|
||||
const [draggingValue, setDraggingValue] = React.useState(null);
|
||||
const [draggingIndex, setDraggingIndex] = React.useState(-1);
|
||||
const [draggingDelete, setDraggingDelete] = React.useState(false);
|
||||
const [cacheValues, setCacheValues] = React.useState(rawValues);
|
||||
const [originValues, setOriginValues] = React.useState(rawValues);
|
||||
const mouseMoveEventRef = React.useRef(null);
|
||||
const mouseUpEventRef = React.useRef(null);
|
||||
const touchEventTargetRef = React.useRef(null);
|
||||
const {
|
||||
onDragStart,
|
||||
onDragChange
|
||||
} = React.useContext(_context.UnstableContext);
|
||||
(0, _useLayoutEffect.default)(() => {
|
||||
if (draggingIndex === -1) {
|
||||
setCacheValues(rawValues);
|
||||
}
|
||||
}, [rawValues, draggingIndex]);
|
||||
|
||||
// Clean up event
|
||||
React.useEffect(() => () => {
|
||||
document.removeEventListener('mousemove', mouseMoveEventRef.current);
|
||||
document.removeEventListener('mouseup', mouseUpEventRef.current);
|
||||
if (touchEventTargetRef.current) {
|
||||
touchEventTargetRef.current.removeEventListener('touchmove', mouseMoveEventRef.current);
|
||||
touchEventTargetRef.current.removeEventListener('touchend', mouseUpEventRef.current);
|
||||
}
|
||||
}, []);
|
||||
const flushValues = (nextValues, nextValue, deleteMark) => {
|
||||
// Perf: Only update state when value changed
|
||||
if (nextValue !== undefined) {
|
||||
setDraggingValue(nextValue);
|
||||
}
|
||||
setCacheValues(nextValues);
|
||||
let changeValues = nextValues;
|
||||
if (deleteMark) {
|
||||
changeValues = nextValues.filter((_, i) => i !== draggingIndex);
|
||||
}
|
||||
triggerChange(changeValues);
|
||||
if (onDragChange) {
|
||||
onDragChange({
|
||||
rawValues: nextValues,
|
||||
deleteIndex: deleteMark ? draggingIndex : -1,
|
||||
draggingIndex,
|
||||
draggingValue: nextValue
|
||||
});
|
||||
}
|
||||
};
|
||||
const updateCacheValue = (0, _useEvent.default)((valueIndex, offsetPercent, deleteMark) => {
|
||||
if (valueIndex === -1) {
|
||||
// >>>> Dragging on the track
|
||||
const startValue = originValues[0];
|
||||
const endValue = originValues[originValues.length - 1];
|
||||
const maxStartOffset = min - startValue;
|
||||
const maxEndOffset = max - endValue;
|
||||
|
||||
// Get valid offset
|
||||
let offset = offsetPercent * (max - min);
|
||||
offset = Math.max(offset, maxStartOffset);
|
||||
offset = Math.min(offset, maxEndOffset);
|
||||
|
||||
// Use first value to revert back of valid offset (like steps marks)
|
||||
const formatStartValue = formatValue(startValue + offset);
|
||||
offset = formatStartValue - startValue;
|
||||
const cloneCacheValues = originValues.map(val => val + offset);
|
||||
flushValues(cloneCacheValues);
|
||||
} else {
|
||||
// >>>> Dragging on the handle
|
||||
const offsetDist = (max - min) * offsetPercent;
|
||||
|
||||
// Always start with the valueIndex origin value
|
||||
const cloneValues = [...cacheValues];
|
||||
cloneValues[valueIndex] = originValues[valueIndex];
|
||||
const next = offsetValues(cloneValues, offsetDist, valueIndex, 'dist');
|
||||
flushValues(next.values, next.value, deleteMark);
|
||||
}
|
||||
});
|
||||
const onStartMove = (e, valueIndex, startValues) => {
|
||||
e.stopPropagation();
|
||||
|
||||
// 如果是点击 track 触发的,需要传入变化后的初始值,而不能直接用 rawValues
|
||||
const initialValues = startValues || rawValues;
|
||||
const originValue = initialValues[valueIndex];
|
||||
setDraggingIndex(valueIndex);
|
||||
setDraggingValue(originValue);
|
||||
setOriginValues(initialValues);
|
||||
setCacheValues(initialValues);
|
||||
setDraggingDelete(false);
|
||||
const {
|
||||
pageX: startX,
|
||||
pageY: startY
|
||||
} = getPosition(e);
|
||||
|
||||
// We declare it here since closure can't get outer latest value
|
||||
let deleteMark = false;
|
||||
|
||||
// Internal trigger event
|
||||
if (onDragStart) {
|
||||
onDragStart({
|
||||
rawValues: initialValues,
|
||||
draggingIndex: valueIndex,
|
||||
draggingValue: originValue
|
||||
});
|
||||
}
|
||||
|
||||
// Moving
|
||||
const onMouseMove = event => {
|
||||
event.preventDefault();
|
||||
const {
|
||||
pageX: moveX,
|
||||
pageY: moveY
|
||||
} = getPosition(event);
|
||||
const offsetX = moveX - startX;
|
||||
const offsetY = moveY - startY;
|
||||
const {
|
||||
width,
|
||||
height
|
||||
} = containerRef.current.getBoundingClientRect();
|
||||
let offSetPercent;
|
||||
let removeDist;
|
||||
switch (direction) {
|
||||
case 'btt':
|
||||
offSetPercent = -offsetY / height;
|
||||
removeDist = offsetX;
|
||||
break;
|
||||
case 'ttb':
|
||||
offSetPercent = offsetY / height;
|
||||
removeDist = offsetX;
|
||||
break;
|
||||
case 'rtl':
|
||||
offSetPercent = -offsetX / width;
|
||||
removeDist = offsetY;
|
||||
break;
|
||||
default:
|
||||
offSetPercent = offsetX / width;
|
||||
removeDist = offsetY;
|
||||
}
|
||||
|
||||
// Check if need mark remove
|
||||
deleteMark = editable ? Math.abs(removeDist) > REMOVE_DIST && minCount < cacheValues.length : false;
|
||||
setDraggingDelete(deleteMark);
|
||||
updateCacheValue(valueIndex, offSetPercent, deleteMark);
|
||||
};
|
||||
|
||||
// End
|
||||
const onMouseUp = event => {
|
||||
event.preventDefault();
|
||||
document.removeEventListener('mouseup', onMouseUp);
|
||||
document.removeEventListener('mousemove', onMouseMove);
|
||||
if (touchEventTargetRef.current) {
|
||||
touchEventTargetRef.current.removeEventListener('touchmove', mouseMoveEventRef.current);
|
||||
touchEventTargetRef.current.removeEventListener('touchend', mouseUpEventRef.current);
|
||||
}
|
||||
mouseMoveEventRef.current = null;
|
||||
mouseUpEventRef.current = null;
|
||||
touchEventTargetRef.current = null;
|
||||
finishChange(deleteMark);
|
||||
setDraggingIndex(-1);
|
||||
setDraggingDelete(false);
|
||||
};
|
||||
document.addEventListener('mouseup', onMouseUp);
|
||||
document.addEventListener('mousemove', onMouseMove);
|
||||
e.currentTarget.addEventListener('touchend', onMouseUp);
|
||||
e.currentTarget.addEventListener('touchmove', onMouseMove);
|
||||
mouseMoveEventRef.current = onMouseMove;
|
||||
mouseUpEventRef.current = onMouseUp;
|
||||
touchEventTargetRef.current = e.currentTarget;
|
||||
};
|
||||
|
||||
// Only return cache value when it mapping with rawValues
|
||||
const returnValues = React.useMemo(() => {
|
||||
const sourceValues = [...rawValues].sort((a, b) => a - b);
|
||||
const targetValues = [...cacheValues].sort((a, b) => a - b);
|
||||
const counts = {};
|
||||
targetValues.forEach(val => {
|
||||
counts[val] = (counts[val] || 0) + 1;
|
||||
});
|
||||
sourceValues.forEach(val => {
|
||||
counts[val] = (counts[val] || 0) - 1;
|
||||
});
|
||||
const maxDiffCount = editable ? 1 : 0;
|
||||
const diffCount = Object.values(counts).reduce((prev, next) => prev + Math.abs(next), 0);
|
||||
return diffCount <= maxDiffCount ? cacheValues : rawValues;
|
||||
}, [rawValues, cacheValues, editable]);
|
||||
return [draggingIndex, draggingValue, draggingDelete, returnValues, onStartMove];
|
||||
}
|
||||
var _default = exports.default = useDrag;
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import type { InternalMarkObj } from '../Marks';
|
||||
/** Format value align with step & marks */
|
||||
type FormatValue = (value: number) => number;
|
||||
type OffsetMode = 'unit' | 'dist';
|
||||
export type OffsetValues = (values: number[], offset: number | 'min' | 'max', valueIndex: number, mode?: OffsetMode) => {
|
||||
value: number;
|
||||
values: number[];
|
||||
};
|
||||
export default function useOffset(min: number, max: number, step: number, markList: InternalMarkObj[], allowCross: boolean, pushable: false | number): [FormatValue, OffsetValues];
|
||||
export {};
|
||||
+214
@@ -0,0 +1,214 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = useOffset;
|
||||
var React = _interopRequireWildcard(require("react"));
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
/** Format the value in the range of [min, max] */
|
||||
|
||||
/** Format value align with step */
|
||||
|
||||
/** Format value align with step & marks */
|
||||
|
||||
function useOffset(min, max, step, markList, allowCross, pushable) {
|
||||
const formatRangeValue = React.useCallback(val => Math.max(min, Math.min(max, val)), [min, max]);
|
||||
const formatStepValue = React.useCallback(val => {
|
||||
if (step !== null) {
|
||||
const stepValue = min + Math.round((formatRangeValue(val) - min) / step) * step;
|
||||
|
||||
// Cut number in case to be like 0.30000000000000004
|
||||
const getDecimal = num => (String(num).split('.')[1] || '').length;
|
||||
const maxDecimal = Math.max(getDecimal(step), getDecimal(max), getDecimal(min));
|
||||
const fixedValue = Number(stepValue.toFixed(maxDecimal));
|
||||
return min <= fixedValue && fixedValue <= max ? fixedValue : null;
|
||||
}
|
||||
return null;
|
||||
}, [step, min, max, formatRangeValue]);
|
||||
const formatValue = React.useCallback(val => {
|
||||
const formatNextValue = formatRangeValue(val);
|
||||
|
||||
// List align values
|
||||
const alignValues = markList.map(mark => mark.value);
|
||||
if (step !== null) {
|
||||
alignValues.push(formatStepValue(val));
|
||||
}
|
||||
|
||||
// min & max
|
||||
alignValues.push(min, max);
|
||||
|
||||
// Align with marks
|
||||
let closeValue = alignValues[0];
|
||||
let closeDist = max - min;
|
||||
alignValues.forEach(alignValue => {
|
||||
const dist = Math.abs(formatNextValue - alignValue);
|
||||
if (dist <= closeDist) {
|
||||
closeValue = alignValue;
|
||||
closeDist = dist;
|
||||
}
|
||||
});
|
||||
return closeValue;
|
||||
}, [min, max, markList, step, formatRangeValue, formatStepValue]);
|
||||
|
||||
// ========================== Offset ==========================
|
||||
// Single Value
|
||||
const offsetValue = (values, offset, valueIndex, mode = 'unit') => {
|
||||
if (typeof offset === 'number') {
|
||||
let nextValue;
|
||||
const originValue = values[valueIndex];
|
||||
|
||||
// Only used for `dist` mode
|
||||
const targetDistValue = originValue + offset;
|
||||
|
||||
// Compare next step value & mark value which is best match
|
||||
let potentialValues = [];
|
||||
markList.forEach(mark => {
|
||||
potentialValues.push(mark.value);
|
||||
});
|
||||
|
||||
// Min & Max
|
||||
potentialValues.push(min, max);
|
||||
|
||||
// In case origin value is align with mark but not with step
|
||||
potentialValues.push(formatStepValue(originValue));
|
||||
|
||||
// Put offset step value also
|
||||
const sign = offset > 0 ? 1 : -1;
|
||||
if (mode === 'unit') {
|
||||
potentialValues.push(formatStepValue(originValue + sign * step));
|
||||
} else {
|
||||
potentialValues.push(formatStepValue(targetDistValue));
|
||||
}
|
||||
|
||||
// Find close one
|
||||
potentialValues = potentialValues.filter(val => val !== null)
|
||||
// Remove reverse value
|
||||
.filter(val => offset < 0 ? val <= originValue : val >= originValue);
|
||||
if (mode === 'unit') {
|
||||
// `unit` mode can not contain itself
|
||||
potentialValues = potentialValues.filter(val => val !== originValue);
|
||||
}
|
||||
const compareValue = mode === 'unit' ? originValue : targetDistValue;
|
||||
nextValue = potentialValues[0];
|
||||
let valueDist = Math.abs(nextValue - compareValue);
|
||||
potentialValues.forEach(potentialValue => {
|
||||
const dist = Math.abs(potentialValue - compareValue);
|
||||
if (dist < valueDist) {
|
||||
nextValue = potentialValue;
|
||||
valueDist = dist;
|
||||
}
|
||||
});
|
||||
|
||||
// Out of range will back to range
|
||||
if (nextValue === undefined) {
|
||||
return offset < 0 ? min : max;
|
||||
}
|
||||
|
||||
// `dist` mode
|
||||
if (mode === 'dist') {
|
||||
return nextValue;
|
||||
}
|
||||
|
||||
// `unit` mode may need another round
|
||||
if (Math.abs(offset) > 1) {
|
||||
const cloneValues = [...values];
|
||||
cloneValues[valueIndex] = nextValue;
|
||||
return offsetValue(cloneValues, offset - sign, valueIndex, mode);
|
||||
}
|
||||
return nextValue;
|
||||
} else if (offset === 'min') {
|
||||
return min;
|
||||
} else if (offset === 'max') {
|
||||
return max;
|
||||
}
|
||||
};
|
||||
|
||||
/** Same as `offsetValue` but return `changed` mark to tell value changed */
|
||||
const offsetChangedValue = (values, offset, valueIndex, mode = 'unit') => {
|
||||
const originValue = values[valueIndex];
|
||||
const nextValue = offsetValue(values, offset, valueIndex, mode);
|
||||
return {
|
||||
value: nextValue,
|
||||
changed: nextValue !== originValue
|
||||
};
|
||||
};
|
||||
const needPush = dist => {
|
||||
return pushable === null && dist === 0 || typeof pushable === 'number' && dist < pushable;
|
||||
};
|
||||
|
||||
// Values
|
||||
const offsetValues = (values, offset, valueIndex, mode = 'unit') => {
|
||||
const nextValues = values.map(formatValue);
|
||||
const originValue = nextValues[valueIndex];
|
||||
const nextValue = offsetValue(nextValues, offset, valueIndex, mode);
|
||||
nextValues[valueIndex] = nextValue;
|
||||
if (allowCross === false) {
|
||||
// >>>>> Allow Cross
|
||||
const pushNum = pushable || 0;
|
||||
|
||||
// ============ AllowCross ===============
|
||||
if (valueIndex > 0 && nextValues[valueIndex - 1] !== originValue) {
|
||||
nextValues[valueIndex] = Math.max(nextValues[valueIndex], nextValues[valueIndex - 1] + pushNum);
|
||||
}
|
||||
if (valueIndex < nextValues.length - 1 && nextValues[valueIndex + 1] !== originValue) {
|
||||
nextValues[valueIndex] = Math.min(nextValues[valueIndex], nextValues[valueIndex + 1] - pushNum);
|
||||
}
|
||||
} else if (typeof pushable === 'number' || pushable === null) {
|
||||
// >>>>> Pushable
|
||||
// =============== Push ==================
|
||||
|
||||
// >>>>>> Basic push
|
||||
// End values
|
||||
for (let i = valueIndex + 1; i < nextValues.length; i += 1) {
|
||||
let changed = true;
|
||||
while (needPush(nextValues[i] - nextValues[i - 1]) && changed) {
|
||||
({
|
||||
value: nextValues[i],
|
||||
changed
|
||||
} = offsetChangedValue(nextValues, 1, i));
|
||||
}
|
||||
}
|
||||
|
||||
// Start values
|
||||
for (let i = valueIndex; i > 0; i -= 1) {
|
||||
let changed = true;
|
||||
while (needPush(nextValues[i] - nextValues[i - 1]) && changed) {
|
||||
({
|
||||
value: nextValues[i - 1],
|
||||
changed
|
||||
} = offsetChangedValue(nextValues, -1, i - 1));
|
||||
}
|
||||
}
|
||||
|
||||
// >>>>> Revert back to safe push range
|
||||
// End to Start
|
||||
for (let i = nextValues.length - 1; i > 0; i -= 1) {
|
||||
let changed = true;
|
||||
while (needPush(nextValues[i] - nextValues[i - 1]) && changed) {
|
||||
({
|
||||
value: nextValues[i - 1],
|
||||
changed
|
||||
} = offsetChangedValue(nextValues, -1, i - 1));
|
||||
}
|
||||
}
|
||||
|
||||
// Start to End
|
||||
for (let i = 0; i < nextValues.length - 1; i += 1) {
|
||||
let changed = true;
|
||||
while (needPush(nextValues[i + 1] - nextValues[i]) && changed) {
|
||||
({
|
||||
value: nextValues[i + 1],
|
||||
changed
|
||||
} = offsetChangedValue(nextValues, 1, i + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
value: nextValues[valueIndex],
|
||||
values: nextValues
|
||||
};
|
||||
};
|
||||
return [formatValue, offsetValues];
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
import type { SliderProps } from '../Slider';
|
||||
export default function useRange(range?: SliderProps['range']): [
|
||||
range: boolean,
|
||||
rangeEditable: boolean,
|
||||
rangeDraggableTrack: boolean,
|
||||
minCount: number,
|
||||
maxCount?: number
|
||||
];
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = useRange;
|
||||
var _warning = require("@rc-component/util/lib/warning");
|
||||
var _react = require("react");
|
||||
function useRange(range) {
|
||||
return (0, _react.useMemo)(() => {
|
||||
if (range === true || !range) {
|
||||
return [!!range, false, false, 0];
|
||||
}
|
||||
const {
|
||||
editable,
|
||||
draggableTrack,
|
||||
minCount,
|
||||
maxCount
|
||||
} = range;
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
(0, _warning.warning)(!editable || !draggableTrack, '`editable` can not work with `draggableTrack`.');
|
||||
}
|
||||
return [true, editable, !editable && draggableTrack, minCount || 0, maxCount];
|
||||
}, [range]);
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
import type { SliderProps, SliderRef } from './Slider';
|
||||
import Slider from './Slider';
|
||||
export { UnstableContext } from './context';
|
||||
export type { SliderProps, SliderRef };
|
||||
export default Slider;
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
Object.defineProperty(exports, "UnstableContext", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _context.UnstableContext;
|
||||
}
|
||||
});
|
||||
exports.default = void 0;
|
||||
var _Slider = _interopRequireDefault(require("./Slider"));
|
||||
var _context = require("./context");
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
var _default = exports.default = _Slider.default;
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import type React from 'react';
|
||||
export type Direction = 'rtl' | 'ltr' | 'ttb' | 'btt';
|
||||
export type OnStartMove = (e: React.MouseEvent | React.TouchEvent, valueIndex: number, startValues?: number[]) => void;
|
||||
export type AriaValueFormat = (value: number) => string;
|
||||
export type SemanticName = 'tracks' | 'track' | 'rail' | 'handle';
|
||||
export type SliderClassNames = Partial<Record<SemanticName, string>>;
|
||||
export type SliderStyles = Partial<Record<SemanticName, React.CSSProperties>>;
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
/// <reference types="react" />
|
||||
import type { Direction } from './interface';
|
||||
export declare function getOffset(value: number, min: number, max: number): number;
|
||||
export declare function getDirectionStyle(direction: Direction, value: number, min: number, max: number): import("react").CSSProperties;
|
||||
/** Return index value if is list or return value directly */
|
||||
export declare function getIndex<T>(value: T | T[], index: number): T;
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.getDirectionStyle = getDirectionStyle;
|
||||
exports.getIndex = getIndex;
|
||||
exports.getOffset = getOffset;
|
||||
function getOffset(value, min, max) {
|
||||
return (value - min) / (max - min);
|
||||
}
|
||||
function getDirectionStyle(direction, value, min, max) {
|
||||
const offset = getOffset(value, min, max);
|
||||
const positionStyle = {};
|
||||
switch (direction) {
|
||||
case 'rtl':
|
||||
positionStyle.right = `${offset * 100}%`;
|
||||
positionStyle.transform = 'translateX(50%)';
|
||||
break;
|
||||
case 'btt':
|
||||
positionStyle.bottom = `${offset * 100}%`;
|
||||
positionStyle.transform = 'translateY(50%)';
|
||||
break;
|
||||
case 'ttb':
|
||||
positionStyle.top = `${offset * 100}%`;
|
||||
positionStyle.transform = 'translateY(-50%)';
|
||||
break;
|
||||
default:
|
||||
positionStyle.left = `${offset * 100}%`;
|
||||
positionStyle.transform = 'translateX(-50%)';
|
||||
break;
|
||||
}
|
||||
return positionStyle;
|
||||
}
|
||||
|
||||
/** Return index value if is list or return value directly */
|
||||
function getIndex(value, index) {
|
||||
return Array.isArray(value) ? value[index] : value;
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
{
|
||||
"name": "@rc-component/slider",
|
||||
"version": "1.0.1",
|
||||
"description": "Slider UI component for React",
|
||||
"keywords": [
|
||||
"react",
|
||||
"react-component",
|
||||
"react-slider",
|
||||
"slider",
|
||||
"input",
|
||||
"range"
|
||||
],
|
||||
"homepage": "https://react-component.github.io/slider",
|
||||
"bugs": {
|
||||
"url": "http://github.com/react-component/slider/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git@github.com:react-component/slider.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "./lib/index",
|
||||
"module": "./es/index",
|
||||
"types": "./lib/index.d.ts",
|
||||
"style": "./assets/index.css",
|
||||
"files": [
|
||||
"assets/*.css",
|
||||
"lib",
|
||||
"es"
|
||||
],
|
||||
"scripts": {
|
||||
"compile": "father build && lessc assets/index.less assets/index.css",
|
||||
"coverage": "rc-test --coverage",
|
||||
"docs:build": "dumi build",
|
||||
"docs:deploy": "gh-pages -d .doc",
|
||||
"lint": "eslint src/ --ext .ts,.tsx,.jsx,.js,.md",
|
||||
"now-build": "npm run docs:build",
|
||||
"prepublishOnly": "npm run compile && rc-np",
|
||||
"prettier": "prettier --write \"**/*.{ts,tsx,js,jsx,json,md}\"",
|
||||
"start": "dumi dev",
|
||||
"test": "rc-test",
|
||||
"tsc": "bunx tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@rc-component/util": "^1.3.0",
|
||||
"clsx": "^2.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rc-component/father-plugin": "^2.1.3",
|
||||
"@rc-component/np": "^1.0.0",
|
||||
"@rc-component/tooltip": "^1.2.1",
|
||||
"@rc-component/trigger": "^3.5.2",
|
||||
"@testing-library/jest-dom": "^6.1.5",
|
||||
"@testing-library/react": "^12.1.3",
|
||||
"@types/jest": "^29.5.1",
|
||||
"@types/node": "^22.5.0",
|
||||
"@types/react": "^18.2.42",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"@umijs/fabric": "^4.0.1",
|
||||
"cross-env": "^7.0.0",
|
||||
"dumi": "^2.2.10",
|
||||
"eslint": "^8.54.0",
|
||||
"eslint-plugin-jest": "^28.2.0",
|
||||
"eslint-plugin-unicorn": "^54.0.0",
|
||||
"father": "^4.3.5",
|
||||
"father-build": "^1.18.6",
|
||||
"gh-pages": "^6.1.0",
|
||||
"glob": "^7.1.6",
|
||||
"less": "^4.1.3",
|
||||
"rc-test": "^7.0.15",
|
||||
"react": "^16.0.0",
|
||||
"react-dom": "^16.0.0",
|
||||
"regenerator-runtime": "^0.14.0",
|
||||
"typescript": "^5.1.6"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.9.0",
|
||||
"react-dom": ">=16.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.x"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user