diff --git a/src/components/AdjustableProgressBar/index.tsx b/src/components/AdjustableProgressBar/index.tsx new file mode 100644 index 0000000..2d61da6 --- /dev/null +++ b/src/components/AdjustableProgressBar/index.tsx @@ -0,0 +1,159 @@ +import React, { useState, useRef, useEffect, type FC } from 'react'; +import { Retool } from '@tryretool/custom-component-support'; + +export const AdjustableProgressBar: FC = () => { + const [value, setValue] = Retool.useStateNumber({ + name: 'value', + initialValue: 0.30 + }); + + const [isDragging, setIsDragging] = useState(false); + const progressBarRef = useRef(null); + + const normalizedValue = value > 1 ? value / 100 : value; + + const getProgressColor = (val: number) => { + if (val <= 25) return '#ef4444'; + if (val <= 75) return '#3b82f6'; + return '#22c55e'; + }; + + const updateValue = (clientX: number) => { + if (!progressBarRef.current) return; + + const rect = progressBarRef.current.getBoundingClientRect(); + + let newValue = (clientX - rect.left) / rect.width; + + newValue = Math.min(1, Math.max(0, newValue)); + + setValue(Number(newValue.toFixed(2))); + }; + + const handleStart = ( + e: React.MouseEvent | React.TouchEvent + ) => { + setIsDragging(true); + + if ('clientX' in e) { + updateValue(e.clientX); + } else { + updateValue(e.touches[0].clientX); + } + }; + + useEffect(() => { + const handleMove = (e: MouseEvent | TouchEvent) => { + if (!isDragging) return; + + if ('touches' in e) { + updateValue(e.touches[0].clientX); + } else { + updateValue(e.clientX); + } + }; + + const handleEnd = () => { + setIsDragging(false); + }; + + window.addEventListener('mousemove', handleMove); + window.addEventListener('mouseup', handleEnd); + + window.addEventListener('touchmove', handleMove); + window.addEventListener('touchend', handleEnd); + + return () => { + window.removeEventListener('mousemove', handleMove); + window.removeEventListener('mouseup', handleEnd); + + window.removeEventListener('touchmove', handleMove); + window.removeEventListener('touchend', handleEnd); + }; + }, [isDragging]); + + return ( +
+ {/* Header */} +
+
+ {Math.round(normalizedValue * 100)}% +
+
+ + {/* Progress Bar */} +
+ {/* Filled area */} +
+ + {/* Thumb */} +
+
+
+ ); +}; \ No newline at end of file diff --git a/src/index.tsx b/src/index.tsx index 20ec2b1..eef0757 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -3,3 +3,4 @@ export { PasswordStrengthAnalyzer } from './components/PasswordStrengthAnalyzer' export { GanttChart } from './components/GanttChart' export { KanbanBoard } from './components/KanbanBoard' export { QRCodeGenerator } from './components/QRCodeGenerator' +export { AdjustableProgressBar } from './components/AdjustableProgressBar' \ No newline at end of file