Skip to content

Commit

Permalink
feat: Add Slider support vertical display mode
Browse files Browse the repository at this point in the history
  • Loading branch information
myxvisual committed Jun 20, 2017
1 parent 167e281 commit dcc0c20
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 28 deletions.
7 changes: 5 additions & 2 deletions docs/src/routes/Components/Slider/SimpleExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,25 @@ import * as PropTypes from "prop-types";

import Slider from "react-uwp/Slider";

const baseStyle: React.CSSProperties = { margin: 10 };
export default class SimpleExample extends React.Component<{}, void> {
static contextTypes = { theme: PropTypes.object };
context: { theme: ReactUWP.ThemeType };

render() {
return (
<div style={{ margin: "10px 0" }}>
<Slider />
<Slider style={baseStyle} />
<Slider style={{ ...baseStyle, height: 120 }} displayMode="vertical" initValue={0.75} />

<Slider
style={baseStyle}
initValue={250}
maxValue={500}
style={{ margin: 10 }}
/>

<Slider
style={baseStyle}
showValueInfo
initValue={.8}
numberToFixed={2}
Expand Down
14 changes: 10 additions & 4 deletions src/Slider/index.doc.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@
{
"name": "DataProps",
"members": [
{
"name": "displayMode",
"documentation": "Set the Slider display mode.",
"isRequired": false,
"type": "\"vertical\" | \"horizon\""
},
{
"name": "minValue",
"documentation": "Set the Slider minValue.",
Expand Down Expand Up @@ -200,7 +206,7 @@
},
{
"name": "defaultProps",
"initializerText": " {\n minValue: 0,\n maxValue: 1,\n initValue: 0,\n onChangeValue: emptyFunc,\n onChangedValue: emptyFunc,\n onChangeValueRatio: emptyFunc,\n onChangedValueRatio: emptyFunc,\n height: 24,\n barHeight: 2,\n controllerWidth: 8,\n showValueInfo: false,\n numberToFixed: 0,\n unit: \"\",\n transition: \"all 0.25s\",\n throttleTimer: 120 / 1000\n }",
"initializerText": " {\n displayMode: \"horizon\",\n minValue: 0,\n maxValue: 1,\n initValue: 0,\n onChangeValue: emptyFunc,\n onChangedValue: emptyFunc,\n onChangeValueRatio: emptyFunc,\n onChangedValueRatio: emptyFunc,\n height: 24,\n barHeight: 2,\n controllerWidth: 8,\n showValueInfo: false,\n numberToFixed: 0,\n unit: \"\",\n transition: \"all 0.25s\",\n throttleTimer: 120 / 1000\n }",
"documentation": "",
"type": "SliderProps"
},
Expand Down Expand Up @@ -302,19 +308,19 @@
},
{
"name": "handelMouseDown",
"initializerText": " (e: React.MouseEvent<HTMLDivElement>) => {\n this.setValueByEvent(e);\n Object.assign(document.body.style, {\n userSelect: \"none\",\n msUserSelect: \"none\",\n webkitUserSelect: \"none\",\n cursor: \"default\"\n });\n window.addEventListener(\"mousemove\", this.setValueByEvent);\n window.addEventListener(\"mouseup\", this.handelMouseUp);\n }",
"initializerText": " (e: React.MouseEvent<HTMLDivElement>) => {\n Object.assign(document.body.style, {\n userSelect: \"none\",\n msUserSelect: \"none\",\n webkitUserSelect: \"none\",\n cursor: \"default\"\n });\n window.addEventListener(\"mousemove\", this.setValueByEvent);\n window.addEventListener(\"mouseup\", this.handelMouseUp);\n }",
"documentation": "",
"type": "(e: MouseEvent<HTMLDivElement>) => void"
},
{
"name": "handelMouseUp",
"initializerText": " (e: any) => {\n Object.assign(document.body.style, {\n userSelect: void 0,\n msUserSelect: void 0,\n webkitUserSelect: void 0,\n cursor: void 0,\n ...this.originBodyStyle\n });\n this.setState({ dragging: false });\n window.removeEventListener(\"mousemove\", this.setValueByEvent);\n window.removeEventListener(\"mouseup\", this.handelMouseUp);\n }",
"initializerText": " (e: any) => {\n Object.assign(document.body.style, {\n userSelect: void 0,\n msUserSelect: void 0,\n webkitUserSelect: void 0,\n cursor: void 0,\n ...this.originBodyStyle\n });\n if (this.state.dragging) {\n this.setState({ dragging: false });\n }\n window.removeEventListener(\"mousemove\", this.setValueByEvent);\n window.removeEventListener(\"mouseup\", this.handelMouseUp);\n }",
"documentation": "",
"type": "(e: any) => void"
},
{
"name": "setValueByEvent",
"initializerText": " (e: any, type?: any) => {\n clearTimeout(this.onChangedValueTimer);\n if (e.type === \"mousemove\" && !this.state.dragging) {\n this.setState({ dragging: true });\n }\n const nowTime = performance ? performance.now() : Date.now();\n if (!this.throttleNow || (nowTime - this.throttleNow > this.props.throttleTimer)) {\n clearTimeout(this.throttleNowTimer);\n this.throttleNow = nowTime;\n } else {\n this.throttleNowTimer = setTimeout(() => {\n this.setValueByEvent(e, type);\n }, this.props.throttleTimer);\n return;\n }\n const {\n maxValue,\n minValue,\n barBackground,\n barBackgroundImage,\n label,\n numberToFixed,\n unit,\n onChangeValue,\n onChangedValue,\n onChangeValueRatio\n } = this.props;\n const useCustomBackground = barBackground || barBackgroundImage;\n const { left, width } = this.rootElm.getBoundingClientRect();\n const mouseLeft = e.clientX;\n const controllerWidth = this.controllerElm.getBoundingClientRect().width;\n let valueRatio = (mouseLeft - left) / (width - controllerWidth);\n valueRatio = valueRatio < 0 ? 0 : (valueRatio > 1 ? 1 : valueRatio);\n const currValue = minValue + (maxValue - minValue) * valueRatio;\n this.state.currValue = currValue;\n this.state.valueRatio = valueRatio;\n\n if (!useCustomBackground) {\n const barTransform = `translateX(${(valueRatio - 1) * 100}%)`;\n Object.assign(this.barElm.style, {\n transform: barTransform,\n webKitTransform: barTransform,\n msTransform: barTransform,\n mozTransform: barTransform\n } as React.CSSProperties);\n }\n\n const transform = `translateX(${valueRatio * 100}%)`;\n Object.assign(this.controllerWrapperElm.style, {\n transform,\n webKitTransform: transform,\n msTransform: transform,\n mozTransform: transform\n } as React.CSSProperties);\n\n if (label) this.labelElm.innerText = `${currValue.toFixed(numberToFixed)}${unit}`;\n\n if (e.type === \"mousedown\") {\n this.setState({ currValue });\n }\n onChangeValue(currValue);\n onChangeValueRatio(valueRatio);\n this.state.currValue = currValue;\n this.onChangedValueTimer = setTimeout(() => {\n this.setState({ currValue });\n onChangedValue(currValue);\n onChangeValueRatio(valueRatio);\n }, 500);\n }",
"initializerText": " (e: any, type?: any) => {\n clearTimeout(this.onChangedValueTimer);\n if (e.type === \"mousemove\" && !this.state.dragging) {\n this.setState({ dragging: true });\n }\n\n if (e.type === \"mousemove\") {\n const nowTime = performance ? performance.now() : Date.now();\n if (!this.throttleNow || (nowTime - this.throttleNow > this.props.throttleTimer)) {\n clearTimeout(this.throttleNowTimer);\n this.throttleNow = nowTime;\n } else {\n this.throttleNowTimer = setTimeout(() => {\n this.setValueByEvent(e, type);\n }, this.props.throttleTimer);\n return;\n }\n }\n\n const {\n displayMode,\n maxValue,\n minValue,\n barBackground,\n barBackgroundImage,\n label,\n numberToFixed,\n unit,\n onChangeValue,\n onChangedValue,\n onChangeValueRatio\n } = this.props;\n const isHorizonMode = displayMode === \"horizon\";\n const useCustomBackground = barBackground || barBackgroundImage;\n const { left, width, bottom, height } = this.rootElm.getBoundingClientRect();\n const { clientX, clientY } = e;\n const controllerClientRect = this.controllerElm.getBoundingClientRect();\n const controllerWidth = controllerClientRect.width;\n const controllerHeight = controllerClientRect.height;\n\n let valueRatio = isHorizonMode ? (clientX - left) / (width - controllerWidth) : -(clientY - bottom) / (height - controllerHeight);\n valueRatio = valueRatio < 0 ? 0 : (valueRatio > 1 ? 1 : valueRatio);\n const currValue = minValue + (maxValue - minValue) * valueRatio;\n\n this.state.currValue = currValue;\n this.state.valueRatio = valueRatio;\n\n if (e.type === \"click\") {\n this.setState({ currValue });\n } else {\n if (!useCustomBackground) {\n const barTransform = `translate${isHorizonMode ? \"X\" : \"Y\"}(${(isHorizonMode ? (valueRatio - 1) : (1 - valueRatio)) * 100}%)`;\n Object.assign(this.barElm.style, {\n transform: barTransform,\n webKitTransform: barTransform,\n msTransform: barTransform,\n mozTransform: barTransform\n } as React.CSSProperties);\n }\n\n const transform = `translate${isHorizonMode ? \"X\" : \"Y\"}(${(isHorizonMode ? valueRatio : 1 - valueRatio) * 100}%)`;\n Object.assign(this.controllerWrapperElm.style, {\n transform,\n webKitTransform: transform,\n msTransform: transform,\n mozTransform: transform\n } as React.CSSProperties);\n\n if (label) this.labelElm.innerText = `${currValue.toFixed(numberToFixed)}${unit}`;\n }\n\n onChangeValue(currValue);\n onChangeValueRatio(valueRatio);\n\n this.onChangedValueTimer = setTimeout(() => {\n onChangedValue(currValue);\n onChangeValueRatio(valueRatio);\n }, 0);\n }",
"documentation": "",
"type": "(e: any, type?: any) => void"
},
Expand Down
58 changes: 36 additions & 22 deletions src/Slider/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import * as React from "react";
import * as PropTypes from "prop-types";

export interface DataProps {
/**
* Set the Slider display mode.
*/
displayMode?: "vertical" | "horizon";
/**
* Set the Slider minValue.
*/
Expand Down Expand Up @@ -88,6 +92,7 @@ export interface SliderState {
const emptyFunc = () => {};
export class Slider extends React.Component<SliderProps, SliderState> {
static defaultProps: SliderProps = {
displayMode: "horizon",
minValue: 0,
maxValue: 1,
initValue: 0,
Expand Down Expand Up @@ -190,6 +195,7 @@ export class Slider extends React.Component<SliderProps, SliderState> {
}

const {
displayMode,
maxValue,
minValue,
barBackground,
Expand All @@ -201,11 +207,15 @@ export class Slider extends React.Component<SliderProps, SliderState> {
onChangedValue,
onChangeValueRatio
} = this.props;
const isHorizonMode = displayMode === "horizon";
const useCustomBackground = barBackground || barBackgroundImage;
const { left, width } = this.rootElm.getBoundingClientRect();
const mouseLeft = e.clientX;
const controllerWidth = this.controllerElm.getBoundingClientRect().width;
let valueRatio = (mouseLeft - left) / (width - controllerWidth);
const { left, width, bottom, height } = this.rootElm.getBoundingClientRect();
const { clientX, clientY } = e;
const controllerClientRect = this.controllerElm.getBoundingClientRect();
const controllerWidth = controllerClientRect.width;
const controllerHeight = controllerClientRect.height;

let valueRatio = isHorizonMode ? (clientX - left) / (width - controllerWidth) : -(clientY - bottom) / (height - controllerHeight);
valueRatio = valueRatio < 0 ? 0 : (valueRatio > 1 ? 1 : valueRatio);
const currValue = minValue + (maxValue - minValue) * valueRatio;

Expand All @@ -216,7 +226,7 @@ export class Slider extends React.Component<SliderProps, SliderState> {
this.setState({ currValue });
} else {
if (!useCustomBackground) {
const barTransform = `translateX(${(valueRatio - 1) * 100}%)`;
const barTransform = `translate${isHorizonMode ? "X" : "Y"}(${(isHorizonMode ? (valueRatio - 1) : (1 - valueRatio)) * 100}%)`;
Object.assign(this.barElm.style, {
transform: barTransform,
webKitTransform: barTransform,
Expand All @@ -225,7 +235,7 @@ export class Slider extends React.Component<SliderProps, SliderState> {
} as React.CSSProperties);
}

const transform = `translateX(${valueRatio * 100}%)`;
const transform = `translate${isHorizonMode ? "X" : "Y"}(${(isHorizonMode ? valueRatio : 1 - valueRatio) * 100}%)`;
Object.assign(this.controllerWrapperElm.style, {
transform,
webKitTransform: transform,
Expand Down Expand Up @@ -265,6 +275,7 @@ export class Slider extends React.Component<SliderProps, SliderState> {
customControllerStyle, // tslint:disable-line:no-unused-variable
transition,
throttleTimer,
displayMode,
...attributes
} = this.props;
const { currValue } = this.state;
Expand Down Expand Up @@ -293,7 +304,7 @@ export class Slider extends React.Component<SliderProps, SliderState> {
return (
<div {...attributes} style={styles.wrapper}>
{showValueInfo ? (
<div style={theme.prepareStyles({ display: "flex", flexDirection: "row", alignItems: "center" })}>
<div style={theme.prepareStyles({ display: "flex", flexDirection: displayMode === "horizon" ? "row" : "column", alignItems: "center" })}>
{normalRender}
<span
ref={labelElm => this.labelElm = labelElm}
Expand Down Expand Up @@ -330,7 +341,8 @@ function getStyles(slider: Slider): {
barBackgroundImage,
useSimpleController,
customControllerStyle,
showValueInfo
showValueInfo,
displayMode
},
state: {
currValue,
Expand All @@ -339,6 +351,7 @@ function getStyles(slider: Slider): {
}
} = slider;
const { prepareStyles } = theme;
const isHorizonMode = displayMode === "horizon";
const height2px: number = Number.parseFloat(height as any);
const barHeight2px: number = Number.parseFloat(barHeight as any);
const controllerWidth2px: number = Number.parseFloat(controllerWidth as any);
Expand All @@ -348,9 +361,10 @@ function getStyles(slider: Slider): {

return {
wrapper: prepareStyles({
width: 320,
width: isHorizonMode ? 320 : height2px,
height: isHorizonMode ? height2px : 320,
display: "inline-block",
padding: showValueInfo ? `0 ${controllerWidth2px}px` : void 0,
padding: showValueInfo ? height2px : void 0,
verticalAlign: "middle",
...style
}),
Expand All @@ -359,28 +373,28 @@ function getStyles(slider: Slider): {
display: "flex",
flexDirection: "row",
alignItems: "center",
width: "100%",
height: height2px,
width: isHorizonMode ? "100%" : height2px,
height: isHorizonMode ? height2px : "100%",
cursor: "default",
position: "relative"
}),
barContainer: {
background: theme.baseLow,
position: "absolute",
width: "100%",
width: isHorizonMode ? "100%" : barHeight,
height: isHorizonMode ? barHeight : "100%",
overflow: "hidden",
height: barHeight,
left: 0,
top: `calc(50% - ${barHeight2px / 2}px)`
left: isHorizonMode ? 0 : `calc(50% - ${barHeight2px / 2}px)`,
top: isHorizonMode ? `calc(50% - ${barHeight2px / 2}px)` : 0
},
bar: prepareStyles({
transition: currTransition,
background: useCustomBackground ? barBackground : theme.listAccentLow,
backgroundImage: barBackgroundImage,
position: "absolute",
width: "100%",
transform: useCustomBackground ? void 0 : `translateX(${(valueRatio - 1) * 100}%)`,
height: "100%",
transform: useCustomBackground ? void 0 : `translate${isHorizonMode ? "X" : "Y"}(${(isHorizonMode ? (valueRatio - 1) : (1 - valueRatio)) * 100}%)`,
left: 0,
top: 0
}),
Expand All @@ -389,8 +403,8 @@ function getStyles(slider: Slider): {
left: 0,
top: 0,
width: "100%",
height: 0,
transform: `translateX(${valueRatio * 100}%)`,
height: "100%",
transform: `translate${isHorizonMode ? "X" : "Y"}(${(isHorizonMode ? valueRatio : 1 - valueRatio) * 100}%)`,
pointerEvents: "none",
transition: currTransition
}),
Expand All @@ -400,10 +414,10 @@ function getStyles(slider: Slider): {
display: "inline-block",
background: (useSimpleController || dragging || hovered) ? theme.baseHigh : theme.accent,
borderRadius: controllerWidth2px / 2,
width: controllerWidth2px,
height: height2px,
width: isHorizonMode ? controllerWidth2px : height2px,
height: isHorizonMode ? height2px : controllerWidth2px,
float: "left",
transform: `translate3d(-${controllerWidth2px / 2}px, 0, 0)`,
transform: `translate3d(${isHorizonMode ? -controllerWidth2px / 2 : 0}px, 0, 0)`,
...customControllerStyle
}),
label: {
Expand Down

0 comments on commit dcc0c20

Please sign in to comment.