diff --git a/packages/excalidraw/actions/actionProperties.tsx b/packages/excalidraw/actions/actionProperties.tsx index 5c4d7754f..3e0768b26 100644 --- a/packages/excalidraw/actions/actionProperties.tsx +++ b/packages/excalidraw/actions/actionProperties.tsx @@ -121,6 +121,7 @@ import { import { LinearElementEditor } from "../element/linearElementEditor"; import type { LocalPoint } from "../../math"; import { pointFrom } from "../../math"; +import { Range } from "../components/Range"; const FONT_SIZE_RELATIVE_INCREASE_STEP = 0.1; @@ -630,25 +631,12 @@ export const actionChangeOpacity = register({ }; }, PanelComponent: ({ elements, appState, updateData }) => ( - + ), }); diff --git a/packages/excalidraw/components/Range.scss b/packages/excalidraw/components/Range.scss new file mode 100644 index 000000000..292b95b4b --- /dev/null +++ b/packages/excalidraw/components/Range.scss @@ -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); + } +} diff --git a/packages/excalidraw/components/Range.tsx b/packages/excalidraw/components/Range.tsx new file mode 100644 index 000000000..ddc89cfa7 --- /dev/null +++ b/packages/excalidraw/components/Range.tsx @@ -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(null); + const valueRef = React.useRef(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 ( + + ); +}; diff --git a/packages/excalidraw/css/theme.scss b/packages/excalidraw/css/theme.scss index 69c28afda..40ecaf8ca 100644 --- a/packages/excalidraw/css/theme.scss +++ b/packages/excalidraw/css/theme.scss @@ -32,6 +32,7 @@ 0px 0px 3.1270833015441895px 0px rgba(0, 0, 0, 0.08), 0px 7px 14px 0px rgba(0, 0, 0, 0.05); + --button-bg: var(--color-surface-mid); --button-hover-bg: var(--color-surface-high); --button-active-bg: var(--color-surface-high); --button-active-border: var(--color-brand-active); @@ -171,6 +172,8 @@ --button-destructive-bg-color: #5a0000; --button-destructive-color: #{$oc-red-3}; + --button-bg: var(--color-surface-high); + --button-gray-1: #363636; --button-gray-2: #272727; --button-gray-3: #222; diff --git a/packages/excalidraw/tests/actionStyles.test.tsx b/packages/excalidraw/tests/actionStyles.test.tsx index c7e497a16..abe4a7c00 100644 --- a/packages/excalidraw/tests/actionStyles.test.tsx +++ b/packages/excalidraw/tests/actionStyles.test.tsx @@ -50,7 +50,7 @@ describe("actionStyles", () => { // Roughness fireEvent.click(screen.getByTitle("Cartoonist")); // Opacity - fireEvent.change(screen.getByLabelText("Opacity"), { + fireEvent.change(screen.getByTestId("opacity"), { target: { value: "60" }, }); diff --git a/packages/excalidraw/tests/contextmenu.test.tsx b/packages/excalidraw/tests/contextmenu.test.tsx index 42466c4f0..133c68222 100644 --- a/packages/excalidraw/tests/contextmenu.test.tsx +++ b/packages/excalidraw/tests/contextmenu.test.tsx @@ -338,7 +338,7 @@ describe("contextMenu element", () => { // Roughness fireEvent.click(screen.getByTitle("Cartoonist")); // Opacity - fireEvent.change(screen.getByLabelText("Opacity"), { + fireEvent.change(screen.getByTestId("opacity"), { target: { value: "60" }, });