@fseehawer/react-circular-slider
Version:
A customizable circular slider with no dependencies.
1 lines • 48.9 kB
Source Map (JSON)
{"version":3,"sources":["../src/CircularSlider/index.tsx","../src/redux/reducer.ts","../src/hooks/useEventListener.ts","../src/hooks/useIsServer.ts","../src/Knob/index.tsx","../src/Labels/index.tsx","../src/Svg/index.tsx","../src/index.ts"],"sourcesContent":["\"use client\";\nimport React, {useCallback, useEffect, useReducer, useRef, forwardRef, useImperativeHandle} from 'react';\nimport reducer from '../redux/reducer';\nimport useEventListener from '../hooks/useEventListener';\nimport useIsServer from '../hooks/useIsServer';\nimport Knob from '../Knob';\nimport Labels from '../Labels';\nimport Svg from '../Svg';\n\nconst spreadDegrees = 360;\nconst knobOffsetConsts = {\n top: Math.PI / 2,\n right: 0,\n bottom: -Math.PI / 2,\n left: -Math.PI,\n} as const;\n\nexport type KnobPosition = keyof typeof knobOffsetConsts | number | string;\n\nexport interface CircularSliderProps {\n label?: string;\n width?: number;\n direction?: 1 | -1;\n min?: number;\n max?: number;\n initialValue?: number;\n value?: number;\n knobColor?: string;\n knobSize?: number;\n knobPosition?: KnobPosition;\n labelColor?: string;\n labelBottom?: boolean;\n labelFontSize?: string;\n valueFontSize?: string;\n appendToValue?: string;\n prependToValue?: string;\n verticalOffset?: string;\n hideLabelValue?: boolean;\n hideKnob?: boolean;\n hideKnobRing?: boolean;\n knobDraggable?: boolean;\n progressColorFrom?: string;\n progressColorTo?: string;\n useMouseAdditionalToTouch?: boolean;\n progressSize?: number;\n trackColor?: string;\n trackSize?: number;\n trackDraggable?: boolean;\n data?: (string | number)[];\n dataIndex?: number;\n progressLineCap?: 'round' | 'butt';\n renderLabelValue?: React.ReactNode;\n onChange?: (value: string | number) => void;\n isDragging?: (dragging: boolean) => void;\n children?: React.ReactNode;\n}\n\n// Export the handle type for TypeScript users\nexport interface CircularSliderHandle {\n refresh: () => void;\n}\n\nconst getSliderRotation = (value: number) => (value < 0 ? -1 : 1);\nconst getRadians = (degrees: number) => (degrees * Math.PI) / 180;\nconst generateRange = (min: number, max: number) => Array.from({ length: max - min + 1 }, (_, i) => i + min);\nconst getKnobOffsetAmount = (knobPosition: KnobPosition): number => {\n if (typeof knobPosition === 'string' && knobPosition in knobOffsetConsts) {\n return knobOffsetConsts[knobPosition as keyof typeof knobOffsetConsts];\n }\n const parsed = typeof knobPosition === 'number' ? knobPosition : parseFloat(knobPosition);\n return getRadians(parsed);\n};\n\nconst CircularSlider = forwardRef<CircularSliderHandle, CircularSliderProps>((props, ref) => {\n const {\n label = 'ANGLE',\n width = 280,\n direction = 1,\n min = 0,\n max = 360,\n initialValue = 0,\n value = null,\n knobColor = '#4e63ea',\n knobSize = 36,\n knobPosition = 'top',\n labelColor = '#272b77',\n labelBottom = false,\n labelFontSize = '1rem',\n valueFontSize = '3rem',\n appendToValue = '',\n prependToValue = '',\n verticalOffset = '1.5rem',\n hideLabelValue = false,\n hideKnob = false,\n hideKnobRing = false,\n knobDraggable = true,\n progressColorFrom = '#80C3F3',\n progressColorTo = '#4990E2',\n useMouseAdditionalToTouch = false,\n progressSize = 8,\n trackColor = '#DDDEFB',\n trackSize = 8,\n trackDraggable = false,\n data = [],\n dataIndex = 0,\n progressLineCap = 'round',\n renderLabelValue = null,\n children,\n onChange = () => {},\n isDragging = () => {},\n } = props;\n\n const resizeObserverRef = useRef<ResizeObserver | null>(null);\n\n // Reference to track dragging state internally\n const draggingRef = useRef(false);\n\n // Prevent reset issues by tracking the current value position\n const currentPositionRef = useRef<{\n radians: number;\n label: string | number;\n knob: { x: number; y: number };\n dashOffset: number;\n } | null>(null);\n\n // Store the last data index to detect changes\n const lastDataIndexRef = useRef(dataIndex);\n\n // Flag to track if a click operation is in progress\n const clickInProgressRef = useRef(false);\n\n // Flag to disable effects temporarily\n const disableEffectsRef = useRef(false);\n\n // Flag to prevent effect execution during specific operations\n const preventPositionResetRef = useRef(false);\n\n // Initialize state with proper data\n const dataArray = data.length > 0 ? [...data] : [...generateRange(min, max)];\n\n const initialState = {\n mounted: false,\n isDragging: false,\n width,\n radius: width / 2,\n knobOffset: getKnobOffsetAmount(knobPosition),\n label: initialValue,\n data: dataArray,\n radians: 0,\n offset: 0,\n knob: { x: 0, y: 0 },\n dashFullArray: 0,\n dashFullOffset: 0,\n };\n\n const isServer = useIsServer();\n const [state, dispatch] = useReducer(reducer, initialState);\n const circularSlider = useRef<HTMLDivElement | null>(null);\n const svgFullPath = useRef<SVGPathElement | null>(null);\n const touchSupported = !isServer && 'ontouchstart' in window;\n const useMouse = !touchSupported || (touchSupported && useMouseAdditionalToTouch);\n\n // Use ref for valueFromParent instead of state to prevent render cycles\n const valueFromParentRef = useRef<number | undefined>(undefined);\n const initCompletedRef = useRef(false);\n\n // Track if the component is currently mounted to prevent state updates after unmount\n const isMountedRef = useRef(false);\n\n // Track if the current position was set by dragging\n const positionSetByDragRef = useRef(false);\n\n // Add this to setKnobPosition to ensure the SVG path is correctly initialized at zero\n const setKnobPosition = useCallback((radians: number, fromDrag = false) => {\n // Skip updates if disabled\n if (disableEffectsRef.current && !fromDrag) return;\n\n // Track if this position was set by dragging\n if (fromDrag) {\n positionSetByDragRef.current = true;\n // Reset after a short delay\n setTimeout(() => {\n positionSetByDragRef.current = false;\n }, 300);\n }\n\n // Calculate position\n const radius = state.radius - trackSize / 2;\n const offsetRadians = radians + getKnobOffsetAmount(knobPosition);\n\n // Convert radians to degrees (0-360)\n let degrees = ((offsetRadians > 0 ? offsetRadians : (2 * Math.PI) + offsetRadians) * spreadDegrees) / (2 * Math.PI);\n\n // Apply direction\n degrees = getSliderRotation(direction) === -1 ? spreadDegrees - degrees : degrees;\n\n // Calculate dash offset for SVG path\n const dashOffset = (degrees / spreadDegrees) * state.dashFullArray;\n const dashOffsetValue = getSliderRotation(direction) === -1 ? dashOffset : state.dashFullArray - dashOffset;\n\n // Map the angle to an index in the data array\n // Ensure we map to the full 360 degrees range\n const dataArrayLength = state.data.length;\n const normalizedDegrees = (degrees + 360) % 360; // Ensure positive value 0-360\n const dataPointIndex = Math.round((normalizedDegrees / 360) * (dataArrayLength - 1));\n\n // Ensure the index is within bounds\n const safeIndex = Math.min(Math.max(0, dataPointIndex), dataArrayLength - 1);\n const labelValue = state.data[safeIndex];\n\n // Calculate the knob x,y position\n const knobXY = {\n x: radius * Math.cos(radians) + radius,\n y: radius * Math.sin(radians) + radius,\n };\n\n // Handle special case for zero value\n // Only apply the special case if we're at the true zero and not in the\n // middle of a drag operation\n const isZeroValue = (\n (!fromDrag && dataIndex === 0) ||\n (!fromDrag && safeIndex === 0 && dataArrayLength > 1) ||\n (typeof labelValue === 'number' && labelValue === 0 && !fromDrag) ||\n (typeof labelValue === 'string' && labelValue === '0' && !fromDrag)\n );\n\n // If it's a true zero value (not during dragging), set dashFullOffset appropriately\n const finalDashOffset = isZeroValue ? state.dashFullArray : dashOffsetValue;\n\n // Save this position as the current position\n currentPositionRef.current = {\n radians,\n label: labelValue,\n knob: knobXY,\n dashOffset: finalDashOffset\n };\n\n // Trigger onChange if needed and not in initial setup\n if (labelValue !== state.label && initCompletedRef.current) {\n onChange(labelValue);\n }\n\n // Update state with new position\n dispatch({\n type: 'setKnobPosition',\n payload: {\n dashFullOffset: finalDashOffset,\n label: labelValue,\n knob: knobXY,\n },\n });\n }, [state, trackSize, knobPosition, direction, onChange, dataIndex]);\n\n // Position the dataIndex to the correct position in the circle\n const positionForDataIndex = useCallback(() => {\n if (!state.mounted || state.data.length === 0) return;\n\n // Don't reposition if this position was set by dragging\n if (positionSetByDragRef.current) return;\n\n // Don't reposition if we're trying to prevent reset\n if (preventPositionResetRef.current) return;\n\n // Ensure dataIndex is within bounds\n const dataIndexSafe = Math.min(Math.max(0, dataIndex), state.data.length - 1);\n\n // Calculate the angle in degrees based on the dataIndex\n // Map the dataIndex to the full 360-degree circle\n const degrees = (dataIndexSafe / (state.data.length - 1)) * 360 * getSliderRotation(direction);\n\n // Convert to radians and adjust for knob offset\n const radians = getRadians(degrees) - state.knobOffset;\n\n // Apply the position\n setKnobPosition(radians);\n\n // Update last known data index\n lastDataIndexRef.current = dataIndex;\n }, [dataIndex, state.mounted, state.data.length, state.knobOffset, direction, setKnobPosition]);\n\n const onMouseDown = (event: React.MouseEvent | React.TouchEvent) => {\n // Prevent clicking during ongoing drag operation\n if (clickInProgressRef.current) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n\n // Set flags to track dragging state\n draggingRef.current = true;\n disableEffectsRef.current = true;\n clickInProgressRef.current = true;\n preventPositionResetRef.current = true;\n\n // Notify parent\n isDragging(true);\n\n // Update component state\n dispatch({ type: 'onMouseDown', payload: { isDragging: true } });\n\n // Reset click flag after a short delay\n setTimeout(() => {\n clickInProgressRef.current = false;\n }, 100);\n };\n\n const onMouseUp = () => {\n // Only process if we're actually dragging\n if (state.isDragging) {\n // Update dragging state\n isDragging(false);\n draggingRef.current = false;\n\n // Update component state\n dispatch({ type: 'onMouseUp', payload: { isDragging: false } });\n\n // Keep prevention active for a bit longer to avoid reset on release\n setTimeout(() => {\n if (isMountedRef.current) {\n disableEffectsRef.current = false;\n\n // Keep preventing position reset for longer\n setTimeout(() => {\n if (isMountedRef.current) {\n preventPositionResetRef.current = false;\n }\n }, 250);\n }\n }, 50);\n }\n };\n\n const onMouseMove = useCallback((event: MouseEvent | TouchEvent) => {\n if (!state.isDragging || (!knobDraggable && !trackDraggable) || (event.type === 'mousemove' && !useMouse)) return;\n\n // Prevent default to avoid browser behaviors\n event.preventDefault();\n\n // Get mouse/touch position\n const touch = (event as TouchEvent).type === 'touchmove' ? (event as TouchEvent).changedTouches[0] : null;\n const getOffset = (ref: React.RefObject<HTMLElement | null>): { top: number; left: number } => {\n const element = ref.current;\n if (!element) {\n return { top: 0, left: 0 };\n }\n const rect: DOMRect = element.getBoundingClientRect();\n const scrollLeft = window.pageXOffset ?? document.documentElement.scrollLeft ?? 0;\n const scrollTop = window.pageYOffset ?? document.documentElement.scrollTop ?? 0;\n return {\n top: rect.top + scrollTop,\n left: rect.left + scrollLeft,\n };\n };\n\n // Calculate mouse position relative to component center\n const offset = getOffset(circularSlider);\n const pageX = touch ? touch.pageX : (event as MouseEvent).pageX;\n const pageY = touch ? touch.pageY : (event as MouseEvent).pageY;\n const mouseX = pageX - (offset.left + state.radius);\n const mouseY = pageY - (offset.top + state.radius);\n\n // Convert to radians\n const radians = Math.atan2(mouseY, mouseX);\n\n // Apply the new position, specifying it comes from drag\n setKnobPosition(radians, true);\n }, [state.isDragging, state.radius, knobDraggable, trackDraggable, useMouse, setKnobPosition]);\n\n // Function to recalculate and update values when resized\n const refresh = useCallback(() => {\n if (!circularSlider.current || !svgFullPath.current || !isMountedRef.current) return;\n\n // Don't refresh during dragging\n if (draggingRef.current) return;\n\n // Get new measurements\n const newWidth = width;\n const newRadius = newWidth / 2;\n\n // Update state with new dimensions\n dispatch({\n type: 'updateDimensions',\n payload: {\n width: newWidth,\n radius: newRadius,\n dashFullArray: svgFullPath.current?.getTotalLength() || 0,\n },\n });\n\n // Reposition the knob based on the last position\n if (currentPositionRef.current) {\n // Small timeout to let the dimensions update first\n setTimeout(() => {\n if (!draggingRef.current && currentPositionRef.current && isMountedRef.current) {\n disableEffectsRef.current = true;\n\n // Use the current position's radians to preserve exact position\n setKnobPosition(currentPositionRef.current?.radians ?? 0);\n\n // Re-enable effects after a short delay\n setTimeout(() => {\n if (isMountedRef.current) {\n disableEffectsRef.current = false;\n }\n }, 50);\n }\n }, 10);\n }\n }, [width, setKnobPosition]);\n\n // Expose the refresh method via ref\n useImperativeHandle(ref, () => ({\n refresh,\n }));\n\n // Initialize the component\n useEffect(() => {\n isMountedRef.current = true;\n disableEffectsRef.current = true;\n\n dispatch({\n type: 'init',\n payload: {\n mounted: true,\n dashFullArray: svgFullPath.current?.getTotalLength?.() ?? 0,\n },\n });\n\n // Re-enable effects after initialization\n setTimeout(() => {\n if (isMountedRef.current) {\n disableEffectsRef.current = false;\n }\n }, 100);\n\n // Cleanup on unmount\n return () => {\n isMountedRef.current = false;\n };\n }, []);\n\n // Setup initial position\n useEffect(() => {\n if (!state.mounted || state.dashFullArray === 0 || disableEffectsRef.current || initCompletedRef.current) return;\n\n // Initialize with offset configuration\n dispatch({\n type: 'setInitialKnobPosition',\n payload: {\n radians: Math.PI / 2 - state.knobOffset,\n offset: 0,\n },\n });\n\n // Initialize with correct data index position\n positionForDataIndex();\n\n // Mark initialization as complete\n initCompletedRef.current = true;\n }, [state.mounted, state.dashFullArray, state.knobOffset, positionForDataIndex]);\n\n // Handle dataIndex changes after initialization\n useEffect(() => {\n if (!state.mounted || !initCompletedRef.current || disableEffectsRef.current || draggingRef.current) return;\n\n // Only update if the dataIndex actually changed\n if (dataIndex !== lastDataIndexRef.current) {\n // Update position when dataIndex changes\n positionForDataIndex();\n }\n }, [dataIndex, positionForDataIndex, state.mounted]);\n\n // Handle external value prop changes\n useEffect(() => {\n if (!state.mounted || disableEffectsRef.current || draggingRef.current || preventPositionResetRef.current) return;\n\n if (typeof value === 'number' && value !== valueFromParentRef.current) {\n valueFromParentRef.current = value;\n const radians = getRadians(value);\n const offsetRadians = -state.knobOffset + radians * getSliderRotation(direction);\n\n // Use a small delay to break the update cycle\n setTimeout(() => {\n if (!draggingRef.current && isMountedRef.current && !preventPositionResetRef.current) {\n setKnobPosition(offsetRadians);\n }\n }, 0);\n }\n }, [direction, state.knobOffset, value, state.mounted, setKnobPosition]);\n\n // Setup ResizeObserver to watch for container size changes\n useEffect(() => {\n if (typeof ResizeObserver === 'undefined') return;\n\n const observeResize = () => {\n if (circularSlider.current) {\n resizeObserverRef.current = new ResizeObserver(() => {\n if (!draggingRef.current && isMountedRef.current) {\n refresh();\n }\n });\n resizeObserverRef.current?.observe(circularSlider.current);\n }\n };\n\n observeResize();\n\n return () => {\n if (resizeObserverRef.current) {\n resizeObserverRef.current?.disconnect();\n }\n };\n }, [refresh]);\n\n // Window resize fallback\n useEffect(() => {\n const handleResize = () => {\n if (!draggingRef.current && isMountedRef.current) {\n refresh();\n }\n };\n\n window.addEventListener('resize', handleResize);\n return () => {\n window.removeEventListener('resize', handleResize);\n };\n }, [refresh]);\n\n useEventListener('touchend', onMouseUp);\n useEventListener('mouseup', onMouseUp);\n useEventListener('touchmove', onMouseMove);\n useEventListener('mousemove', onMouseMove);\n\n const sanitizedLabel = label.replace(/[^a-zA-Z0-9-_]/g, '_');\n const sliderStyle: React.CSSProperties = {\n position: 'relative',\n display: 'inline-block',\n width: 'max-content',\n opacity: state.mounted ? 1 : 0,\n transition: 'opacity 1s ease-in',\n };\n\n // Prepare display value from either parent prop or internal state\n const displayValue = typeof valueFromParentRef.current !== 'undefined'\n ? `${valueFromParentRef.current}`\n : `${state.label}`;\n\n return (\n <div style={sliderStyle} ref={circularSlider}>\n <Svg\n width={width}\n label={sanitizedLabel}\n direction={direction}\n strokeDasharray={state.dashFullArray}\n strokeDashoffset={state.dashFullOffset}\n svgFullPath={svgFullPath}\n progressSize={progressSize}\n progressColorFrom={progressColorFrom}\n progressColorTo={progressColorTo}\n progressLineCap={progressLineCap as 'round' | 'butt'}\n trackColor={trackColor}\n trackSize={trackSize}\n radiansOffset={state.radians}\n onMouseDown={trackDraggable ? onMouseDown : undefined}\n isDragging={state.isDragging}\n />\n <Knob\n isDragging={state.isDragging}\n knobPosition={state.knob}\n knobSize={knobSize}\n knobColor={knobColor}\n trackSize={trackSize}\n hideKnob={hideKnob}\n hideKnobRing={hideKnobRing}\n knobDraggable={knobDraggable}\n onMouseDown={onMouseDown}\n >\n {children}\n </Knob>\n {renderLabelValue ?? (\n <Labels\n label={label}\n labelColor={labelColor}\n labelBottom={labelBottom}\n labelFontSize={labelFontSize}\n verticalOffset={verticalOffset}\n valueFontSize={valueFontSize}\n appendToValue={appendToValue}\n prependToValue={prependToValue}\n hideLabelValue={hideLabelValue}\n value={displayValue}\n />\n )}\n </div>\n );\n});\n\nexport default CircularSlider;","// reducer.ts\nexport type ActionType =\n | { type: 'init'; payload: Partial<State> }\n | { type: 'setKnobPosition'; payload: Partial<State> }\n | { type: 'onMouseDown'; payload: Partial<State> }\n | { type: 'onMouseUp'; payload: Partial<State> }\n | { type: 'setInitialKnobPosition'; payload: Partial<State> }\n | { type: 'updateDimensions'; payload: Partial<State> };\n\nexport interface State {\n mounted: boolean;\n isDragging: boolean;\n width: number;\n radius: number;\n knobOffset: number;\n label: string | number;\n data: (string | number)[];\n radians: number;\n offset: number;\n knob: {\n x: number;\n y: number;\n };\n dashFullArray: number;\n dashFullOffset: number;\n}\n\nconst reducer = (state: State, action: ActionType): State => {\n switch (action.type) {\n case 'init':\n case 'setKnobPosition':\n case 'onMouseDown':\n case 'onMouseUp':\n case 'setInitialKnobPosition':\n case 'updateDimensions':\n return {\n ...state,\n ...action.payload,\n };\n default:\n throw new Error('Unknown action type');\n }\n};\n\nexport default reducer;","import { useEffect, useRef } from 'react';\n\nfunction useEventListener<K extends keyof WindowEventMap>(\n eventName: K,\n handler: (event: WindowEventMap[K]) => void\n): void {\n const savedHandler = useRef<((event: WindowEventMap[K]) => void) | undefined>(undefined);\n\n useEffect(() => {\n savedHandler.current = handler;\n }, [handler]);\n\n useEffect(() => {\n if (typeof window !== 'undefined' && window.addEventListener) {\n const eventListener = (event: WindowEventMap[K]) => {\n if (savedHandler.current) savedHandler.current(event);\n };\n window.addEventListener(eventName, eventListener, { passive: false });\n return () => {\n window.removeEventListener(eventName, eventListener);\n };\n }\n }, [eventName]);\n}\n\nexport default useEventListener;\n","import { useEffect, useState } from 'react';\n\nconst useIsServer = (): boolean => {\n const [isServer, setIsServer] = useState(true);\n\n useEffect(() => {\n setIsServer(false);\n }, []);\n\n return isServer;\n};\n\nexport default useIsServer;","import React from 'react';\nimport './index.css';\n\nexport interface KnobProps {\n\tisDragging: boolean;\n\tknobPosition: { x: number; y: number };\n\tknobColor: string;\n\tknobSize: number;\n\thideKnob?: boolean;\n\thideKnobRing?: boolean;\n\tknobDraggable?: boolean;\n\ttrackSize: number;\n\tchildren?: React.ReactNode;\n\tonMouseDown?: (event: React.MouseEvent | React.TouchEvent) => void;\n}\n\nconst Knob: React.FC<KnobProps> = ({\n isDragging,\n knobPosition,\n knobColor,\n knobSize,\n hideKnob = false,\n hideKnobRing = false,\n knobDraggable = true,\n trackSize,\n children,\n onMouseDown,\n\t\t\t\t\t\t\t\t }) => {\n\tconst styles: { [key: string]: React.CSSProperties } = {\n\t\tknob: {\n\t\t\tposition: 'absolute',\n\t\t\tleft: `-${knobSize / 2 - trackSize / 2}px`,\n\t\t\ttop: `-${knobSize / 2 - trackSize / 2}px`,\n\t\t\tcursor: knobDraggable ? 'grab' : 'auto',\n\t\t\tzIndex: 3,\n\t\t},\n\t\tdragging: {\n\t\t\tcursor: 'grabbing',\n\t\t},\n\t\tpause: {\n\t\t\tanimationPlayState: 'paused',\n\t\t},\n\t\tanimation: {\n\t\t\ttransformOrigin: '50% 50%',\n\t\t\tanimationTimingFunction: 'ease-out',\n\t\t\tanimationDuration: '1500ms',\n\t\t\tanimationIterationCount: 'infinite',\n\t\t\tanimationName: 'pulse',\n\t\t},\n\t\thide: {\n\t\t\topacity: 0,\n\t\t},\n\t};\n\n\treturn (\n\t\t<div\n\t\t\tstyle={{\n\t\t\t\ttransform: `translate(${knobPosition.x}px, ${knobPosition.y}px)`,\n\t\t\t\t...styles.knob,\n\t\t\t\t...(isDragging ? styles.dragging : {}),\n\t\t\t\t...(hideKnob ? styles.hide : {}),\n\t\t\t}}\n\t\t\tonMouseDown={onMouseDown}\n\t\t\tonTouchStart={onMouseDown}\n\t\t>\n\t\t\t<svg width={knobSize} height={knobSize} viewBox={`0 0 ${knobSize} ${knobSize}`}>\n\t\t\t\t{!hideKnobRing && (\n\t\t\t\t\t<circle\n\t\t\t\t\t\tstyle={{ ...styles.animation, ...(isDragging ? styles.pause : {}) }}\n\t\t\t\t\t\tfill={knobColor}\n\t\t\t\t\t\tfillOpacity={0.2}\n\t\t\t\t\t\tstroke='none'\n\t\t\t\t\t\tcx={knobSize / 2}\n\t\t\t\t\t\tcy={knobSize / 2}\n\t\t\t\t\t\tr={knobSize / 2}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t\t<circle\n\t\t\t\t\tfill={knobColor}\n\t\t\t\t\tstroke='none'\n\t\t\t\t\tcx={knobSize / 2}\n\t\t\t\t\tcy={knobSize / 2}\n\t\t\t\t\tr={(knobSize * 2) / 3 / 2}\n\t\t\t\t/>\n\t\t\t\t{children ?? (\n\t\t\t\t\t<svg width={knobSize} height={knobSize} viewBox='0 0 36 36'>\n\t\t\t\t\t\t<rect fill='#FFFFFF' x='14' y='14' width='8' height='1' />\n\t\t\t\t\t\t<rect fill='#FFFFFF' x='14' y='17' width='8' height='1' />\n\t\t\t\t\t\t<rect fill='#FFFFFF' x='14' y='20' width='8' height='1' />\n\t\t\t\t\t</svg>\n\t\t\t\t)}\n\t\t\t</svg>\n\t\t</div>\n\t);\n};\n\nexport default Knob;","import React from 'react';\n\nexport interface LabelsProps {\n\tlabel: string;\n\tvalue: string;\n\tlabelColor?: string;\n\tlabelBottom?: boolean;\n\tlabelFontSize?: string;\n\tvalueFontSize?: string;\n\tappendToValue?: string;\n\tprependToValue?: string;\n\tverticalOffset?: string;\n\thideLabelValue?: boolean;\n}\n\nconst Labels: React.FC<LabelsProps> = ({\n label,\n value,\n labelColor = '#000',\n labelBottom = false,\n labelFontSize = '1rem',\n valueFontSize = '3rem',\n appendToValue = '',\n prependToValue = '',\n verticalOffset = '1.5rem',\n hideLabelValue = false,\n}) => {\n\tconst styles: { [key: string]: React.CSSProperties } = {\n\t\tlabels: {\n\t\t\tposition: 'absolute',\n\t\t\ttop: '0',\n\t\t\tleft: '0',\n\t\t\twidth: '100%',\n\t\t\theight: '100%',\n\t\t\tdisplay: 'flex',\n\t\t\tflexDirection: 'column',\n\t\t\tjustifyContent: 'center',\n\t\t\talignItems: 'center',\n\t\t\tcolor: labelColor,\n\t\t\tuserSelect: 'none',\n\t\t\tzIndex: 1,\n\t\t},\n\t\tcodeTop: {\n\t\t\tverticalAlign: 'text-top',\n\t\t},\n\t\tvalue: {\n\t\t\tfontSize: valueFontSize,\n\t\t\tposition: 'relative',\n\t\t},\n\t\tbottomMargin: {\n\t\t\tmarginBottom: `calc(${verticalOffset})`,\n\t\t},\n\t\tappended: {\n\t\t\tposition: 'absolute',\n\t\t\tright: '0',\n\t\t\ttop: '0',\n\t\t\ttransform: 'translate(100%, 0)',\n\t\t},\n\t\tprepended: {\n\t\t\tposition: 'absolute',\n\t\t\tleft: '0',\n\t\t\ttop: '0',\n\t\t\ttransform: 'translate(-100%, 0)',\n\t\t},\n\t\thide: {\n\t\t\tdisplay: 'none',\n\t\t},\n\t};\n\n\treturn (\n\t\t<div style={{ ...styles.labels, ...(hideLabelValue ? styles.hide : {}) }}>\n\t\t\t{!labelBottom && <div style={{ fontSize: labelFontSize }}>{label}</div>}\n\t\t\t<div style={{ ...styles.value, ...(!labelBottom ? styles.bottomMargin : {}) }}>\n\t\t\t\t<code style={styles.codeTop}>\n\t\t\t\t\t<span style={styles.prepended}>{prependToValue}</span>\n\t\t\t\t\t{value}\n\t\t\t\t\t<span style={styles.appended}>{appendToValue}</span>\n\t\t\t\t</code>\n\t\t\t</div>\n\t\t\t{labelBottom && <div style={{ fontSize: labelFontSize, marginTop: '-0.5rem' }}>{label}</div>}\n\t\t</div>\n\t);\n};\n\nexport default Labels;\n","\"use client\";\nimport React, { useRef } from 'react';\n\nexport interface SvgProps {\n width: number;\n label: string;\n direction: number;\n strokeDasharray: number;\n strokeDashoffset: number;\n progressColorFrom: string;\n progressColorTo: string;\n progressLineCap?: 'round' | 'butt';\n progressSize: number;\n trackColor: string;\n trackSize: number;\n radiansOffset: number;\n svgFullPath: React.RefObject<SVGPathElement | null>;\n onMouseDown?: (event: React.MouseEvent | React.TouchEvent) => void;\n isDragging?: boolean;\n}\n\nconst Svg: React.FC<SvgProps> = ({\n width,\n label,\n direction,\n strokeDasharray,\n strokeDashoffset,\n progressColorFrom,\n progressColorTo,\n progressLineCap = 'round',\n progressSize,\n trackColor,\n trackSize,\n radiansOffset,\n svgFullPath,\n onMouseDown,\n isDragging,\n }) => {\n const circleRef = useRef<SVGCircleElement | null>(null);\n\n // Keep styles simple with no transitions\n const styles: { [key: string]: React.CSSProperties } = {\n svg: {\n position: 'relative',\n zIndex: 2,\n userSelect: isDragging ? 'none' : 'auto',\n },\n path: {\n transform: `rotate(${radiansOffset}rad) ${direction === -1 ? 'scale(-1, 1)' : 'scale(1, 1)'}`,\n transformOrigin: 'center center',\n // No transition to make movement instant\n transition: 'none',\n },\n };\n\n const halfTrack = trackSize / 2;\n const radius = width / 2 - halfTrack;\n\n const validatedLineCap: 'round' | 'butt' =\n progressLineCap === 'round' || progressLineCap === 'butt'\n ? progressLineCap\n : 'round';\n\n const handleClick = (event: React.MouseEvent | React.TouchEvent) => {\n if (!onMouseDown) return;\n const bounds = circleRef.current?.getBoundingClientRect();\n if (!bounds) return;\n\n const clientX = 'touches' in event ? event.touches[0].clientX : event.clientX;\n const clientY = 'touches' in event ? event.touches[0].clientY : event.clientY;\n const centerX = bounds.left + bounds.width / 2;\n const centerY = bounds.top + bounds.height / 2;\n const distance = Math.sqrt((clientX - centerX) ** 2 + (clientY - centerY) ** 2);\n const threshold = bounds.width / (isDragging ? 4 : 2) - trackSize;\n if (distance < threshold) return;\n onMouseDown();\n };\n\n // Create a unique gradient ID to avoid conflicts with multiple instances\n const gradientId = `radial-${label}-${Math.random().toString(36).substr(2, 9)}`;\n\n return (\n <svg\n width={`${width}px`}\n height={`${width}px`}\n viewBox={`0 0 ${width} ${width}`}\n overflow=\"visible\"\n style={styles.svg}\n onMouseDown={handleClick}\n onTouchStart={handleClick}\n >\n <defs>\n <linearGradient id={gradientId} x1=\"100%\" x2=\"0%\">\n <stop offset=\"0%\" stopColor={progressColorFrom}/>\n <stop offset=\"100%\" stopColor={progressColorTo}/>\n </linearGradient>\n </defs>\n <circle\n ref={circleRef}\n strokeWidth={trackSize}\n fill=\"none\"\n stroke={trackColor}\n cx={width / 2}\n cy={width / 2}\n r={radius}\n />\n <path\n style={styles.path}\n ref={svgFullPath}\n strokeDasharray={strokeDasharray || 0}\n strokeDashoffset={strokeDashoffset || 0}\n strokeWidth={progressSize}\n strokeLinecap={validatedLineCap}\n fill=\"none\"\n stroke={`url(#${gradientId})`}\n d={`\n M ${width / 2}, ${width / 2}\n m 0, -${radius}\n a ${radius},${radius} 0 0,1 0,${radius * 2}\n a -${radius},-${radius} 0 0,1 0,-${radius * 2}\n `}\n />\n </svg>\n );\n};\n\nexport default Svg;","\"use client\"\n\nimport CircularSlider from './CircularSlider';\n\nexport default CircularSlider;\n"],"mappings":"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","names":["React","useEffect","useRef","useEffect","React","React","React","useRef","useRef","React","useRef","ref","_a","useEffect","React"]}