mirror of
https://github.com/noodlapp/noodl.git
synced 2026-01-12 15:22:52 +01:00
Initial commit
Co-Authored-By: Eric Tuvesson <eric.tuvesson@gmail.com> Co-Authored-By: mikaeltellhed <2311083+mikaeltellhed@users.noreply.github.com> Co-Authored-By: kotte <14197736+mrtamagotchi@users.noreply.github.com> Co-Authored-By: Anders Larsson <64838990+anders-topp@users.noreply.github.com> Co-Authored-By: Johan <4934465+joolsus@users.noreply.github.com> Co-Authored-By: Tore Knudsen <18231882+torekndsn@users.noreply.github.com> Co-Authored-By: victoratndl <99176179+victoratndl@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,183 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import Layout from '../../../layout';
|
||||
import Utils from '../../../nodes/controls/utils';
|
||||
import { Noodl } from '../../../types';
|
||||
|
||||
export interface SliderProps extends Noodl.ReactProps {
|
||||
_nodeId: string;
|
||||
id: string;
|
||||
enabled: boolean;
|
||||
|
||||
value: number;
|
||||
min: number;
|
||||
max: number;
|
||||
step: number;
|
||||
|
||||
thumbHeight: string;
|
||||
thumbWidth: string;
|
||||
thumbColor: string;
|
||||
|
||||
trackHeight: string;
|
||||
trackActiveColor: string;
|
||||
trackColor: string;
|
||||
|
||||
onClick: () => void;
|
||||
updateOutputValue: (value: number) => void;
|
||||
}
|
||||
|
||||
function _styleTemplate(_class: string, props: SliderProps) {
|
||||
return `.${_class}::-webkit-slider-thumb {
|
||||
width: ${props.thumbWidth};
|
||||
}`;
|
||||
}
|
||||
|
||||
function setBorderStyle(style: React.CSSProperties, prefix: string, props: SliderProps) {
|
||||
function setBorder(style: React.CSSProperties, group: string) {
|
||||
const width = `${prefix}Border${group}Width`;
|
||||
const color = `${prefix}Border${group}Color`;
|
||||
const borderStyle = `${prefix}Border${group}Style`;
|
||||
|
||||
const w = props[width] || props[`${prefix}BorderWidth`];
|
||||
if (w !== undefined) style[`border${group}Width`] = w;
|
||||
|
||||
const c = (style[color] = props[color] || props[`${prefix}BorderColor`]);
|
||||
if (c !== undefined) style[`border${group}Color`] = c;
|
||||
|
||||
const s = props[borderStyle] || props[`${prefix}BorderStyle`];
|
||||
if (s !== undefined) style[`border${group}Style`] = s;
|
||||
}
|
||||
|
||||
setBorder(style, 'Top');
|
||||
setBorder(style, 'Right');
|
||||
setBorder(style, 'Bottom');
|
||||
setBorder(style, 'Left');
|
||||
}
|
||||
|
||||
function setBorderRadius(style: React.CSSProperties, prefix: string, props: SliderProps) {
|
||||
const radius = props[`${prefix}BorderRadius`];
|
||||
const tl = props[`${prefix}BorderTopLeftRadius`] || radius;
|
||||
const tr = props[`${prefix}BorderTopRightRadius`] || radius;
|
||||
const br = props[`${prefix}BorderBottomRightRadius`] || radius;
|
||||
const bl = props[`${prefix}BorderBottomLeftRadius`] || radius;
|
||||
|
||||
style.borderRadius = `${tl} ${tr} ${br} ${bl}`;
|
||||
}
|
||||
|
||||
function setShadow(style: React.CSSProperties, prefix: string, props: SliderProps) {
|
||||
if (!props[`${prefix}BoxShadowEnabled`]) return;
|
||||
|
||||
const inset = props[`${prefix}BoxShadowInset`];
|
||||
const x = props[`${prefix}BoxShadowOffsetX`];
|
||||
const y = props[`${prefix}BoxShadowOffsetY`];
|
||||
const blur = props[`${prefix}BoxShadowBlurRadius`];
|
||||
const spread = props[`${prefix}BoxShadowSpreadRadius`];
|
||||
const color = props[`${prefix}BoxShadowColor`];
|
||||
|
||||
style.boxShadow = `${inset ? 'inset ' : ''}${x} ${y} ${blur} ${spread} ${color}`;
|
||||
}
|
||||
|
||||
function hasUnitPx(value: string) {
|
||||
return value && value[value.length - 1] === 'x';
|
||||
}
|
||||
|
||||
export function Slider(props: SliderProps) {
|
||||
const [value, setValue] = useState(props.value);
|
||||
|
||||
useEffect(() => {
|
||||
onValueChanged(props.value);
|
||||
}, [props.value]);
|
||||
|
||||
function onValueChanged(value: number) {
|
||||
setValue(value);
|
||||
props.updateOutputValue(value);
|
||||
}
|
||||
|
||||
const style: React.CSSProperties = { ...props.style };
|
||||
Layout.size(style, props);
|
||||
Layout.align(style, props);
|
||||
|
||||
const instanceClassId = 'ndl-controls-range-' + props._nodeId;
|
||||
Utils.updateStylesForClass(instanceClassId, props, _styleTemplate);
|
||||
|
||||
const className = `ndl-controls-range2 ${instanceClassId} ${props.className ? props.className : ''} `;
|
||||
|
||||
const inputProps: React.InputHTMLAttributes<HTMLInputElement> = {
|
||||
id: props.id,
|
||||
style: {
|
||||
width: '100%',
|
||||
opacity: 0
|
||||
},
|
||||
onClick: props.onClick,
|
||||
min: props.min,
|
||||
max: props.max
|
||||
};
|
||||
|
||||
if (props.step) {
|
||||
inputProps.step = props.step;
|
||||
}
|
||||
|
||||
//make the input as tall as the tallest element, track or thumb, so the entire area becomes interactive
|
||||
//Makes it possible to design sliders with thin tracks and tall thumbs
|
||||
|
||||
if (hasUnitPx(props.thumbHeight)) {
|
||||
if (hasUnitPx(props.trackHeight)) {
|
||||
const thumbHeight = Number(props.thumbHeight.slice(0, -2));
|
||||
const trackHeight = Number(props.trackHeight.slice(0, -2));
|
||||
inputProps.style.height = Math.max(thumbHeight, trackHeight) + 'px';
|
||||
} else {
|
||||
inputProps.style.height = props.thumbHeight;
|
||||
}
|
||||
} else {
|
||||
inputProps.style.height = props.trackHeight;
|
||||
}
|
||||
|
||||
const divStyle = {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
...style
|
||||
};
|
||||
|
||||
const valueFactor = (value - props.min) / (props.max - props.min);
|
||||
|
||||
const trackStyle: React.CSSProperties = {
|
||||
position: 'absolute',
|
||||
width: '100%',
|
||||
height: props.trackHeight,
|
||||
background: `linear-gradient(to right, ${props.trackActiveColor} 0%, ${props.trackActiveColor} ${
|
||||
valueFactor * 100
|
||||
}%, ${props.trackColor} ${valueFactor * 100}%, ${props.trackColor} 100%)`
|
||||
};
|
||||
|
||||
setBorderStyle(trackStyle, 'track', props);
|
||||
setBorderRadius(trackStyle, 'track', props);
|
||||
setShadow(trackStyle, 'track', props);
|
||||
|
||||
const thumbStyle: React.CSSProperties = {
|
||||
position: 'absolute',
|
||||
left: 'calc((100% - ' + props.thumbWidth + ') * ' + valueFactor + ')',
|
||||
width: props.thumbWidth,
|
||||
height: props.thumbHeight,
|
||||
backgroundColor: props.thumbColor
|
||||
};
|
||||
|
||||
setBorderStyle(thumbStyle, 'thumb', props);
|
||||
setBorderRadius(thumbStyle, 'thumb', props);
|
||||
setShadow(thumbStyle, 'thumb', props);
|
||||
|
||||
return (
|
||||
<div style={divStyle}>
|
||||
<div style={trackStyle} />
|
||||
<div style={thumbStyle} />
|
||||
<input
|
||||
className={className}
|
||||
{...Utils.controlEvents(props)}
|
||||
type="range"
|
||||
{...inputProps}
|
||||
value={value}
|
||||
disabled={!props.enabled}
|
||||
onChange={(e) => onValueChanged(Number(e.target.value))}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user