feat(slider): add editable value display and enhance reset button functionality

This commit is contained in:
alexsparkes
2024-12-16 22:24:35 +00:00
parent 45959408c5
commit 15f1e523b4

View File

@@ -2,7 +2,7 @@ import variables from 'config/variables';
import { useState, useCallback, memo, useMemo } from 'react';
import { toast } from 'react-toastify';
import ReactSlider from 'react-slider';
import { MdRefresh } from 'react-icons/md';
import { MdRefresh, MdEdit } from 'react-icons/md';
import EventBus from 'utils/eventbus';
import clsx from 'clsx';
@@ -15,6 +15,15 @@ const buttonStyles = {
transitions: 'transition-colors duration-200',
};
const inputStyles = {
base: 'w-20 text-sm px-3 py-1.5 rounded-md font-medium text-center',
colors: 'bg-neutral-200 hover:bg-neutral-300 focus:bg-neutral-300',
darkMode: 'dark:bg-white/10 dark:hover:bg-white/15 dark:focus:bg-white/15',
text: 'text-neutral-800 dark:text-white',
focus: 'focus:outline-none focus:ring-2 focus:ring-neutral-400 dark:focus:ring-white/40',
transitions: 'transition-colors duration-200',
};
const thumbStyles = {
base: [
'w-5 h-5 rounded-full cursor-pointer',
@@ -67,15 +76,68 @@ const MULTIPLIER_MARKS = {
};
// Memoized value display component
const ValueDisplay = memo(({ value, display }) => (
<span className="text-sm bg-neutral-200 dark:bg-white/15 text-neutral-800 dark:text-white px-3 py-1.5 rounded-md font-medium">
{value}
{display}
</span>
));
const ValueDisplay = memo(({ value, display, onChange }) => {
const [isEditing, setIsEditing] = useState(false);
const [inputValue, setInputValue] = useState(value);
const handleBlur = () => {
setIsEditing(false);
const newValue = Number(inputValue);
if (!isNaN(newValue)) {
onChange(newValue);
} else {
setInputValue(value);
}
};
const handleKeyDown = (e) => {
if (e.key === 'Enter') {
handleBlur();
} else if (e.key === 'Escape') {
setIsEditing(false);
setInputValue(value);
}
};
if (isEditing) {
return (
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
onBlur={handleBlur}
onKeyDown={handleKeyDown}
className={clsx(
inputStyles.base,
inputStyles.colors,
inputStyles.darkMode,
inputStyles.text,
inputStyles.focus,
inputStyles.transitions,
)}
autoFocus
/>
);
}
return (
<div className="flex items-center gap-2">
<span className="text-sm bg-neutral-200 dark:bg-white/15 text-neutral-800 dark:text-white px-3 py-1.5 rounded-md font-medium">
{value}
{display}
</span>
<button
onClick={() => setIsEditing(true)}
className="p-1.5 rounded-md hover:bg-neutral-300 dark:hover:bg-white/15 transition-colors duration-200"
aria-label="Edit value"
>
<MdEdit className="w-4 h-4 text-neutral-600 dark:text-white/70" />
</button>
</div>
);
});
// Memoized reset button component
const ResetButton = memo(({ onClick }) => (
const ResetButton = memo(({ onClick, defaultValue }) => (
<button
onClick={onClick}
className={clsx(
@@ -84,9 +146,11 @@ const ResetButton = memo(({ onClick }) => (
buttonStyles.darkMode,
buttonStyles.text,
buttonStyles.transitions,
'group focus:outline-none focus:ring-2 focus:ring-neutral-400 dark:focus:ring-white/40',
)}
aria-label={`Reset to default value: ${defaultValue}`}
>
<MdRefresh className="w-4 h-4 mr-1.5" />
<MdRefresh className="w-4 h-4 mr-1.5 group-hover:rotate-180 transition-transform duration-300" />
{variables.getMessage('settings:buttons.reset')}
</button>
));
@@ -194,8 +258,8 @@ function SliderComponent(props) {
<div className="flex items-center justify-between mb-2">
<span className="text-sm font-medium text-neutral-800 dark:text-white">{props.title}</span>
<div className="flex items-center gap-2 justify-between w-full">
<ValueDisplay value={value} display={props.display} />
<ResetButton onClick={resetItem} />
<ValueDisplay value={value} display={props.display} onChange={handleChange} />
<ResetButton onClick={resetItem} defaultValue={props.default} />
</div>
</div>