Skip to content

Commit 7d4108b

Browse files
committed
sliders now text typable.
1 parent cd3d81f commit 7d4108b

3 files changed

Lines changed: 100 additions & 31 deletions

File tree

src/components/OptimadeClient/DatabaseSelector.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ export function DatabaseSelector({ providers, onQueryUrlChange }) {
1010
const [customUrl, setCustomUrl] = useState("");
1111
const [loadingChildren, setLoadingChildren] = useState(false);
1212

13-
const handleCustomChange = debounce((val) => setCustomUrl(val), 300);
13+
// 700 ms between no typing before setting url.
14+
const handleCustomChange = debounce((val) => setCustomUrl(val), 700);
1415

1516
useEffect(() => {
1617
if (!selectedProvider || selectedProvider === "__custom__") {

src/components/common/HelpIcon.jsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ export default function HelpIcon({
4040
strokeWidth={strokeWidthBorder}
4141
strokeLinecap="round"
4242
strokeLinejoin="round"
43-
className="cursor-help"
4443
>
4544
<circle cx="12" cy="12" r="10" />
4645
<path

src/components/common/RangeSlider.jsx

Lines changed: 98 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,107 @@
11
import { Range } from "react-range";
2-
import React from "react";
2+
import React, { useState, useEffect } from "react";
3+
4+
// needed to make input look like normal text. may look awful on old browsers
5+
const inputOverride = `w-12 text-center text-sm md:text-base bg-transparent border-none outline-none p-0
6+
[&::-webkit-inner-spin-button]:appearance-none
7+
[&::-webkit-outer-spin-button]:appearance-none
8+
[-moz-appearance:textfield]`;
9+
10+
// slider settings
11+
const sliderBgStyle = "flex-1 h-2 bg-gray-300 rounded relative";
12+
const sliderFgStyle = "absolute h-2 bg-blue-500 rounded";
13+
const sliderThumbStyle =
14+
"w-4.5 h-4.5 bg-slate-100 border-2 border-slate-400 rounded-full transition-transform transform origin-center hover:scale-125";
315

416
export default function RangeSlider({ title, value, onChange, min, max }) {
17+
const [tempValue, setTempValue] = useState(value.map(String));
18+
19+
useEffect(() => {
20+
setTempValue(value.map(String));
21+
}, [value]);
22+
23+
const handleInputChange = (index, val) => {
24+
setTempValue((prev) => {
25+
const newVal = [...prev];
26+
newVal[index] = val; // keep as string
27+
return newVal;
28+
});
29+
30+
const numeric = parseFloat(val);
31+
if (!isNaN(numeric)) {
32+
let newValue = [...value];
33+
if (index === 0) {
34+
newValue[0] = Math.min(Math.max(numeric, min), value[1]);
35+
} else {
36+
newValue[1] = Math.max(Math.min(numeric, max), value[0]);
37+
}
38+
onChange(newValue);
39+
}
40+
};
41+
42+
const handleInputBlur = (index) => {
43+
const numeric = parseFloat(tempValue[index]);
44+
if (isNaN(numeric)) {
45+
// Reset to current slider value if entry is invalid
46+
setTempValue((prev) => {
47+
const newVal = [...prev];
48+
newVal[index] = String(value[index]);
49+
return newVal;
50+
});
51+
}
52+
};
53+
554
return (
655
<div className="my-4 text-sm md:text-base">
7-
<label className="block font mb-1">{title}</label>
8-
<Range
9-
step={1}
10-
min={min}
11-
max={max}
12-
values={value}
13-
onChange={onChange}
14-
renderTrack={({ props, children }) => (
15-
<div {...props} className="w-full h-2 bg-gray-300 rounded relative">
56+
<label className="block font-medium">{title}</label>
57+
<div className="flex space-x-2 items-center">
58+
<input
59+
type="number"
60+
value={tempValue[0]}
61+
placeholder={min}
62+
min={min}
63+
max={value[1]}
64+
onChange={(e) => handleInputChange(0, e.target.value)}
65+
onBlur={() => handleInputBlur(0)}
66+
className={inputOverride}
67+
/>
68+
<Range
69+
step={1}
70+
min={min}
71+
max={max}
72+
values={value}
73+
onChange={onChange}
74+
renderTrack={({ props, children }) => (
75+
<div {...props} className={sliderBgStyle}>
76+
<div
77+
className={sliderFgStyle}
78+
style={{
79+
left: `${((value[0] - min) / (max - min)) * 100}%`,
80+
width: `${((value[1] - value[0]) / (max - min)) * 100}%`,
81+
}}
82+
/>
83+
{children}
84+
</div>
85+
)}
86+
renderThumb={({ props }) => (
1687
<div
17-
className="absolute h-2 bg-blue-500 rounded"
18-
style={{
19-
left: `${((value[0] - min) / (max - min)) * 100}%`,
20-
width: `${((value[1] - value[0]) / (max - min)) * 100}%`,
21-
}}
22-
/>
23-
{children}
24-
</div>
25-
)}
26-
renderThumb={({ props }) => (
27-
<div
28-
{...props}
29-
className="w-5 h-5 bg-white border border-gray-500 rounded-full"
30-
/>
31-
)}
32-
/>
33-
<div className="flex justify-between text-xs md:text-sm pt-2">
34-
<span>{value[0]}</span>
35-
<span>{value[1]}</span>
88+
{...props}
89+
className="relative w-5 h-5 flex items-center justify-center"
90+
>
91+
<div className={sliderThumbStyle} />
92+
</div>
93+
)}
94+
/>
95+
<input
96+
type="number"
97+
value={tempValue[1]}
98+
placeholder={max}
99+
min={value[0]}
100+
max={max}
101+
onChange={(e) => handleInputChange(1, e.target.value)}
102+
onBlur={() => handleInputBlur(1)}
103+
className={inputOverride}
104+
/>
36105
</div>
37106
</div>
38107
);

0 commit comments

Comments
 (0)