Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Font Setting - Added draggable slider #10126

Closed
14 changes: 14 additions & 0 deletions res/css/views/elements/_Slider.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,27 @@ limitations under the License.
z-index: 10;
}

.mx_Slider_selectionDotInner {
position: absolute;
width: 100%;
height: 100%;
border-radius: 50%;
/* background-color: white; */
background-color: $accent;
z-index: 10;
pointer-events: all;
}

.mx_Slider_selectionText {
color: $muted-fg-color;
font-size: $font-14px;
position: relative;
text-align: center;
top: 30px;
width: 100%;
-webkit-user-select: none; /* Safari */
-ms-user-select: none; /* IE 10 and IE 11 */
user-select: none; /* Standard syntax */
}

.mx_Slider_selection > hr {
Expand Down
55 changes: 55 additions & 0 deletions src/components/views/elements/Slider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ interface IProps {
}

export default class Slider extends React.Component<IProps> {
// state to keep track of the current index and percent
state = {
index: this.props.values.indexOf(this.props.value),
percent: this.offset(this.props.values, this.props.value),
};

// offset is a terrible inverse approximation.
// if the values represents some function f(x) = y where x is the
// index of the array and y = values[x] then offset(f, y) = x
Expand Down Expand Up @@ -83,11 +89,60 @@ export default class Slider extends React.Component<IProps> {

let selection = null;

const onDrag = (e: React.DragEvent) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

There's a lot of logic overlap on onDrag and onDragEnd could we consolidate those ?

Copy link
Author

Choose a reason for hiding this comment

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

Even I had that in my mind. Will make a separate function for common operations.


const target = e.target as HTMLElement;
if (!target.parentNode) return null;
const parent = target.parentNode as HTMLElement;
if (!parent.parentNode) return null;
const slider = parent.parentNode as HTMLElement;
Copy link
Contributor

Choose a reason for hiding this comment

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

We should use the non-null operand here

Suggested change
const slider = parent.parentNode as HTMLElement;
const slider = parent.parentNode!;

Comment on lines +94 to +98
Copy link
Contributor

Choose a reason for hiding this comment

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

I believe we should rely on react refs instead of traversing the DOM.
The advantage I see is that we explicitely declare refs on the DOM element we wish to track.
With your approach, we rely on the fact that the DOM structure, and that is subject to change in the future

const rect = slider.getBoundingClientRect();

const x = e.clientX - rect.left; //x position within the element.
const width = rect.width;
const percent = x / width;
const value = Math.round(percent * (this.props.values.length - 1));
this.setState({ index: value, percent: percent * 100 });

//put the inner dot to the correct position
const innerDot = target.parentNode as any;
if (!innerDot) return null;
const offset = this.offset(this.props.values, this.props.values[value]);
innerDot.style.left = `calc(-1.195em + " + ${offset} + "%)`;
Copy link
Contributor

Choose a reason for hiding this comment

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

What does -1.195em relate to? How could we avoid that magic number?
If and we can't avoid it, we should add a thorough comment explaining how we got there


};

const onDragEnd = (e: any) => {
const innerDot = e.target.parentNode;
const target = e.target as HTMLElement;
if (!target.parentNode) return null;
const parent = target.parentNode as HTMLElement;
if (!parent.parentNode) return null;
const slider = parent.parentNode as HTMLElement;
const rect = slider.getBoundingClientRect();
const x = e.clientX - rect.left; //x position within the element.
// console.log(x);
if(x < -10 || x > rect.width + 10) return null;
const width = rect.width;

const percent = x / width;
const value = Math.round(percent * (this.props.values.length - 1));
const offset = this.offset(this.props.values, this.props.values[value]);
innerDot.style.left = `calc(-1.195em + " + ${offset} + "%)`;
this.props.onSelectionChange(this.props.values[value]);
};

if (!this.props.disabled) {
const offset = this.offset(this.props.values, this.props.value);
selection = (
<div className="mx_Slider_selection">
<div className="mx_Slider_selectionDot" style={{ left: "calc(-1.195em + " + offset + "%)" }}>
<div
onDrag={onDrag}
onDragEnd={onDragEnd}
draggable={true}
className="mx_Slider_selectionDotInner"
></div>
<div className="mx_Slider_selectionText">{this.props.value}</div>
</div>
<hr style={{ width: offset + "%" }} />
Expand Down