feat: implement custom Range component for opacity control (#9009)
Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>release
parent
d29c3db7f6
commit
bd1590fc74
@ -0,0 +1,59 @@
|
|||||||
|
@import "../css/variables.module.scss";
|
||||||
|
|
||||||
|
.excalidraw {
|
||||||
|
--Range-track-background: var(--button-bg);
|
||||||
|
--Range-track-background-active: var(--color-primary);
|
||||||
|
--Range-thumb-background: var(--color-on-surface);
|
||||||
|
--Range-legend-color: var(--text-primary-color);
|
||||||
|
|
||||||
|
.range-wrapper {
|
||||||
|
position: relative;
|
||||||
|
padding-top: 10px;
|
||||||
|
padding-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.range-input {
|
||||||
|
width: 100%;
|
||||||
|
height: 4px;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
background: var(--Range-track-background);
|
||||||
|
border-radius: 2px;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.range-input::-webkit-slider-thumb {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
background: var(--Range-thumb-background);
|
||||||
|
border-radius: 50%;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.range-input::-moz-range-thumb {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
background: var(--Range-thumb-background);
|
||||||
|
border-radius: 50%;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value-bubble {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--Range-legend-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.zero-label {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--Range-legend-color);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
import React, { useEffect } from "react";
|
||||||
|
import { getFormValue } from "../actions/actionProperties";
|
||||||
|
import { t } from "../i18n";
|
||||||
|
import "./Range.scss";
|
||||||
|
|
||||||
|
export type RangeProps = {
|
||||||
|
updateData: (value: number) => void;
|
||||||
|
appState: any;
|
||||||
|
elements: any;
|
||||||
|
testId?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Range = ({
|
||||||
|
updateData,
|
||||||
|
appState,
|
||||||
|
elements,
|
||||||
|
testId,
|
||||||
|
}: RangeProps) => {
|
||||||
|
const rangeRef = React.useRef<HTMLInputElement>(null);
|
||||||
|
const valueRef = React.useRef<HTMLDivElement>(null);
|
||||||
|
const value = getFormValue(
|
||||||
|
elements,
|
||||||
|
appState,
|
||||||
|
(element) => element.opacity,
|
||||||
|
true,
|
||||||
|
appState.currentItemOpacity,
|
||||||
|
);
|
||||||
|
useEffect(() => {
|
||||||
|
if (rangeRef.current && valueRef.current) {
|
||||||
|
const rangeElement = rangeRef.current;
|
||||||
|
const valueElement = valueRef.current;
|
||||||
|
const inputWidth = rangeElement.offsetWidth;
|
||||||
|
const thumbWidth = 15; // 15 is the width of the thumb
|
||||||
|
const position =
|
||||||
|
(value / 100) * (inputWidth - thumbWidth) + thumbWidth / 2;
|
||||||
|
valueElement.style.left = `${position}px`;
|
||||||
|
rangeElement.style.background = `linear-gradient(to right, var(--color-primary) 0%, var(--color-primary) ${value}%, var(--button-bg) ${value}%, var(--button-bg) 100%)`;
|
||||||
|
}
|
||||||
|
}, [value]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<label className="control-label">
|
||||||
|
{t("labels.opacity")}
|
||||||
|
<div className="range-wrapper">
|
||||||
|
<input
|
||||||
|
ref={rangeRef}
|
||||||
|
type="range"
|
||||||
|
min="0"
|
||||||
|
max="100"
|
||||||
|
step="10"
|
||||||
|
onChange={(event) => {
|
||||||
|
updateData(+event.target.value);
|
||||||
|
}}
|
||||||
|
value={value}
|
||||||
|
className="range-input"
|
||||||
|
data-testid={testId}
|
||||||
|
/>
|
||||||
|
<div className="value-bubble" ref={valueRef}>
|
||||||
|
{value !== 0 ? value : null}
|
||||||
|
</div>
|
||||||
|
<div className="zero-label">0</div>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
);
|
||||||
|
};
|
Loading…
Reference in New Issue