@react-three/uikit-default
Version:
Default (shadcn) kit for @react-three/uikit
71 lines (70 loc) • 3.51 kB
JavaScript
import { Container } from '@react-three/uikit';
import { colors } from './theme.js';
import React, { forwardRef, useImperativeHandle, useMemo, useRef, useState } from 'react';
import { Vector3 } from 'three';
import { Signal, computed } from '@preact/signals-core';
const vectorHelper = new Vector3();
export const Slider = forwardRef(({ disabled = false, value: providedValue, defaultValue, onValueChange, min = 0, max = 100, step = 1, ...props }, ref) => {
const [uncontrolled, setUncontrolled] = useState(defaultValue);
const value = providedValue ?? uncontrolled ?? 50;
const percentage = useMemo(() => computed(() => {
const range = readReactive(max) - readReactive(min);
return `${(100 * readReactive(value)) / range}%`;
}), [min, max, value]);
const internalRef = useRef(null);
const onChange = useRef(onValueChange);
onChange.current = onValueChange;
const hasProvidedValue = providedValue != null;
const handler = useMemo(() => {
let downPointerId;
function setValue(e) {
if (internalRef.current == null) {
return;
}
vectorHelper.copy(e.point);
internalRef.current.interactionPanel.worldToLocal(vectorHelper);
const minValue = readReactive(min);
const maxValue = readReactive(max);
const newValue = Math.min(Math.max(Math.round(((vectorHelper.x + 0.5) * (maxValue - minValue) + minValue) / step) * step, minValue), maxValue);
if (!hasProvidedValue) {
setUncontrolled(newValue);
}
onChange.current?.(newValue);
e.stopPropagation();
}
return {
onPointerDown(e) {
if (downPointerId != null) {
return;
}
downPointerId = e.pointerId;
setValue(e);
e.target.setPointerCapture(e.pointerId);
},
onPointerMove(e) {
if (downPointerId != e.pointerId) {
return;
}
setValue(e);
},
onPointerUp(e) {
if (downPointerId == null) {
return;
}
downPointerId = undefined;
e.stopPropagation();
},
};
}, [max, min, hasProvidedValue, step]);
useImperativeHandle(ref, () => internalRef.current);
return (React.createElement(Container, { ...(disabled ? {} : handler), positionType: "relative", flexDirection: "column", height: 8, width: "100%", alignItems: "center", ref: internalRef, ...props },
React.createElement(Container, { height: 8, positionType: "absolute", positionLeft: 0, positionRight: 0, flexGrow: 1, borderRadius: 1000, backgroundColor: colors.secondary },
React.createElement(Container, { height: "100%", width: percentage, borderRadius: 1000, backgroundColor: colors.primary })),
React.createElement(Container, { zIndexOffset: { minor: 100 }, positionType: "absolute", positionLeft: percentage, transformTranslateX: -10, transformTranslateY: -6, cursor: "pointer", borderOpacity: disabled ? 0.5 : undefined, backgroundOpacity: disabled ? 0.5 : undefined, height: 20, width: 20, borderWidth: 2, borderRadius: 1000, borderColor: colors.primary, backgroundColor: colors.background })));
});
function readReactive(s) {
if (s instanceof Signal) {
return s.value;
}
return s;
}