zds-pickers 4.0.8 → 4.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs.js +12 -12
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +1265 -1890
- package/dist/index.es.js.map +1 -1
- package/dist/types/midi/export.d.ts +8 -9
- package/dist/types/pickers/StatusPicker.d.ts +2 -2
- package/lib/hooks/useComponentSize.js +40 -0
- package/lib/hooks/useStateWithDynamicDefault.js +9 -0
- package/lib/index.js +21 -0
- package/lib/midi/ccValues.js +134 -0
- package/lib/midi/export.js +27 -0
- package/lib/midi/export.ts +2 -3
- package/lib/other/DefaultTooltip.js +3 -0
- package/lib/other/OctavePlayer.js +48 -0
- package/lib/other/SVGText.js +109 -0
- package/lib/other/SoundFontProvider.js +87 -0
- package/lib/pickers/CCPicker.js +6 -0
- package/lib/pickers/ChannelMappingPicker.js +50 -0
- package/lib/pickers/ChannelPicker.js +21 -0
- package/lib/pickers/Knob.js +49 -0
- package/lib/pickers/KnobPicker.js +29 -0
- package/lib/pickers/LatchPicker.js +9 -0
- package/lib/pickers/MappingPicker.js +37 -0
- package/lib/pickers/NotePicker.js +45 -0
- package/lib/pickers/PianoPicker.js +27 -0
- package/lib/pickers/PolarityPicker.js +11 -0
- package/lib/pickers/ResponseCurve.js +154 -0
- package/lib/pickers/ResponseCurvePicker.js +19 -0
- package/lib/pickers/Select.js +79 -0
- package/lib/pickers/StatusPicker.js +5 -0
- package/lib/pickers/ValuePicker.js +23 -0
- package/lib/pickers/knobSkin10.js +93 -0
- package/lib/rotaryKnob/InternalInput.js +22 -0
- package/lib/rotaryKnob/Types.js +1 -0
- package/lib/rotaryKnob/helpers/DrawCircle.js +9 -0
- package/lib/rotaryKnob/helpers/DrawLine.js +9 -0
- package/lib/rotaryKnob/helpers/HelpersOverlay.js +26 -0
- package/lib/rotaryKnob/helpers/KnobVisualHelpers.js +52 -0
- package/lib/rotaryKnob/index.js +244 -0
- package/lib/rotaryKnob/knobdefaultskin.js +56 -0
- package/lib/rotaryKnob/utils.js +106 -0
- package/lib/utils.js +21 -0
- package/package.json +2 -3
- package/tsconfig.json +1 -1
- package/vite.config.ts +3 -19
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import utils from '../utils';
|
|
4
|
+
import DrawCircle from './DrawCircle';
|
|
5
|
+
import DrawLine from './DrawLine';
|
|
6
|
+
import HelpersOverlay from './HelpersOverlay';
|
|
7
|
+
class KnobVisualHelpers extends React.Component {
|
|
8
|
+
constructor() {
|
|
9
|
+
super(...arguments);
|
|
10
|
+
Object.defineProperty(this, "state", {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
configurable: true,
|
|
13
|
+
writable: true,
|
|
14
|
+
value: {
|
|
15
|
+
centerX: 0,
|
|
16
|
+
centerY: 0,
|
|
17
|
+
valueMarkerX: 0,
|
|
18
|
+
valueMarkerY: 0,
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
static getDerivedStateFromProps(props, state) {
|
|
23
|
+
//Calculate position
|
|
24
|
+
if (!props.svgRef)
|
|
25
|
+
return state;
|
|
26
|
+
const vbox = props.svgRef.getBoundingClientRect();
|
|
27
|
+
const halfWidth = vbox.width / 2;
|
|
28
|
+
//Calculate current angle segment end point
|
|
29
|
+
//Note: Not sure why we need to subtract 90 here
|
|
30
|
+
const valueMarkerX = props.radius * Math.cos(utils.toRadians(props.valueAngle - 90));
|
|
31
|
+
const valueMarkerY = props.radius * Math.sin(utils.toRadians(props.valueAngle - 90));
|
|
32
|
+
return {
|
|
33
|
+
...state,
|
|
34
|
+
centerX: vbox.left + halfWidth,
|
|
35
|
+
centerY: vbox.top + halfWidth,
|
|
36
|
+
valueMarkerX,
|
|
37
|
+
valueMarkerY,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
render() {
|
|
41
|
+
const markCircleColor = this.props.minimumDragDistance <= this.props.radius ? 'green' : 'grey';
|
|
42
|
+
const fillColor = this.props.minimumDragDistance <= this.props.radius
|
|
43
|
+
? '#88E22D'
|
|
44
|
+
: '#D8D8D8';
|
|
45
|
+
const minDistanceCueVisible = this.props.minimumDragDistance >= this.props.radius;
|
|
46
|
+
return (_jsx(HelpersOverlay, { children: _jsxs("svg", { style: { position: 'absolute', top: '0', left: '0' }, width: "100%", height: "100%", children: [_jsx("defs", { children: _jsx("marker", { id: "Triangle", viewBox: "0 0 10 10", refX: "1", refY: "5", markerWidth: "6", markerHeight: "6", orient: "auto", children: _jsx("path", { d: "M 0 0 L 10 5 L 0 10 z" }) }) }), _jsx(DrawCircle, { borderColor: markCircleColor, fillColor: fillColor, fillOpacity: 0.02, r: this.props.radius, cx: this.state.centerX, cy: this.state.centerY }), minDistanceCueVisible && (_jsx(DrawCircle, { borderColor: markCircleColor, fillColor: fillColor, fillOpacity: 0, r: this.props.minimumDragDistance, cx: this.state.centerX, cy: this.state.centerY })), _jsx(DrawLine, { p1: { x: this.state.centerX, y: this.state.centerY }, p2: {
|
|
47
|
+
x: this.state.valueMarkerX + this.state.centerX,
|
|
48
|
+
y: this.state.valueMarkerY + this.state.centerY,
|
|
49
|
+
}, markerEnd: "url(#Triangle)" })] }) }));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export { KnobVisualHelpers };
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Show the rotation circle and marker
|
|
4
|
+
* dispatches drag events
|
|
5
|
+
*/
|
|
6
|
+
import { drag } from 'd3-drag';
|
|
7
|
+
import { scaleLinear } from 'd3-scale';
|
|
8
|
+
import { select } from 'd3-selection';
|
|
9
|
+
import { useEffect, useRef, useState } from 'react';
|
|
10
|
+
import { SvgLoader, SvgProxy } from 'react-svgmt';
|
|
11
|
+
import InternalInput from './InternalInput';
|
|
12
|
+
import { KnobVisualHelpers } from './helpers/KnobVisualHelpers';
|
|
13
|
+
import defaultSkin from './knobdefaultskin';
|
|
14
|
+
import utils from './utils';
|
|
15
|
+
// function printDebugValues(obj) {
|
|
16
|
+
// console.log('------------')
|
|
17
|
+
// Object.keys(obj).forEach(key => {
|
|
18
|
+
// const value =
|
|
19
|
+
// typeof obj[key] === 'object' ? JSON.stringify(obj[key]) : obj[key]
|
|
20
|
+
// console.log(`${key}: ${value}`)
|
|
21
|
+
// })
|
|
22
|
+
// console.log('------------')
|
|
23
|
+
// }
|
|
24
|
+
/**
|
|
25
|
+
* Generic knob component
|
|
26
|
+
*/
|
|
27
|
+
const RotaryKnob = (props) => {
|
|
28
|
+
const { clampMax = 360, clampMin = 0, defaultValue = 0, disabled = false, format = (val) => val.toFixed(0), max = 100, min = 0, onChange = () => { }, onEnd = () => { }, onStart = () => { }, preciseMode = true, rotateDegrees = 0, skin = defaultSkin, step = 1, style, unlockDistance = 100, value, ...rest } = props;
|
|
29
|
+
const [isControlled, setIsControlled] = useState(value !== undefined);
|
|
30
|
+
const container = useRef(null);
|
|
31
|
+
const inputRef = useRef(null);
|
|
32
|
+
let scale;
|
|
33
|
+
let scaleProps;
|
|
34
|
+
const [state, setState] = useState({
|
|
35
|
+
svgRef: undefined,
|
|
36
|
+
dragging: false,
|
|
37
|
+
dragDistance: 0,
|
|
38
|
+
mousePos: { x: 0, y: 0 },
|
|
39
|
+
valueAngle: 0,
|
|
40
|
+
uncontrolledValue: 0,
|
|
41
|
+
});
|
|
42
|
+
// returns angles between 0 and 360 for values lower 0 or greater 360
|
|
43
|
+
const normalizeAngle = (angle) => {
|
|
44
|
+
if (angle < 0) {
|
|
45
|
+
//E.g -1 turns 359
|
|
46
|
+
return angle + 360;
|
|
47
|
+
}
|
|
48
|
+
if (angle > 360) {
|
|
49
|
+
return angle - 360;
|
|
50
|
+
}
|
|
51
|
+
return angle;
|
|
52
|
+
};
|
|
53
|
+
// converts a value to an angle for the knob respecting the additional rotateDegrees prop
|
|
54
|
+
const convertValueToAngle = (value) => {
|
|
55
|
+
const angle = (getScale()(value) + rotateDegrees) % 360;
|
|
56
|
+
return normalizeAngle(angle);
|
|
57
|
+
};
|
|
58
|
+
// converts an angle to a value for the knob respecting the additional rotateDegrees prop
|
|
59
|
+
const convertAngleToValue = (angle) => {
|
|
60
|
+
const angle2 = angle - rotateDegrees;
|
|
61
|
+
return getScale().invert(normalizeAngle(angle2));
|
|
62
|
+
};
|
|
63
|
+
const getScale = () => {
|
|
64
|
+
// Memoize scale so it's not recalculated every time
|
|
65
|
+
if (!scaleProps ||
|
|
66
|
+
scaleProps.min !== min ||
|
|
67
|
+
scaleProps.max !== max ||
|
|
68
|
+
scaleProps.clampMin !== clampMin ||
|
|
69
|
+
scaleProps.clampMax !== clampMax) {
|
|
70
|
+
if (rotateDegrees < 270 && rotateDegrees > 90) {
|
|
71
|
+
scale = scaleLinear().domain([min, max]).range([clampMin, clampMax]);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
scale = scaleLinear().domain([max, min]).range([clampMax, clampMin]);
|
|
75
|
+
}
|
|
76
|
+
scale.clamp(true);
|
|
77
|
+
scaleProps = {
|
|
78
|
+
min: min,
|
|
79
|
+
max: max,
|
|
80
|
+
clampMin: clampMin,
|
|
81
|
+
clampMax: clampMax,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
return scale;
|
|
85
|
+
};
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
setIsControlled(value !== undefined);
|
|
88
|
+
setState(prevState => ({
|
|
89
|
+
...prevState,
|
|
90
|
+
uncontrolledValue: value ?? defaultValue ?? 0,
|
|
91
|
+
}));
|
|
92
|
+
if (container.current) {
|
|
93
|
+
// Remove existing drag behavior
|
|
94
|
+
select(container.current).on('.drag', null);
|
|
95
|
+
// Only setup new drag if not disabled
|
|
96
|
+
if (!disabled) {
|
|
97
|
+
setupDragging(select(container.current));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}, [value, defaultValue, disabled]);
|
|
101
|
+
const saveRef = (elem) => {
|
|
102
|
+
if (!state.svgRef) {
|
|
103
|
+
setState({ ...state, svgRef: elem });
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
const onAngleChanged = (angle) => {
|
|
107
|
+
//Calculate domain value
|
|
108
|
+
const domainValue = convertAngleToValue(angle);
|
|
109
|
+
if (!isControlled) {
|
|
110
|
+
/**
|
|
111
|
+
* If the mode is 'uncontrolled' we need to update our local state
|
|
112
|
+
*/
|
|
113
|
+
setState(st => {
|
|
114
|
+
return { ...st, uncontrolledValue: domainValue };
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
if (!disabled)
|
|
118
|
+
onChange(domainValue);
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Returns the current value (depending on controlled/uncontrolled mode)
|
|
122
|
+
*/
|
|
123
|
+
const getValue = () => isControlled ? (value ?? 0) : (state.uncontrolledValue ?? 0);
|
|
124
|
+
const setupDragging = (elem) => {
|
|
125
|
+
if (!elem?.node())
|
|
126
|
+
return;
|
|
127
|
+
const node = elem.node();
|
|
128
|
+
if (!node)
|
|
129
|
+
return;
|
|
130
|
+
let vbox = node.getBoundingClientRect();
|
|
131
|
+
const cx = vbox.width / 2;
|
|
132
|
+
const cy = vbox.height / 2;
|
|
133
|
+
// Shared state via closure
|
|
134
|
+
let startPos;
|
|
135
|
+
let startAngle;
|
|
136
|
+
let initialAngle;
|
|
137
|
+
let monitoring = false;
|
|
138
|
+
function started(event) {
|
|
139
|
+
if (!event?.sourceEvent)
|
|
140
|
+
return;
|
|
141
|
+
if (!node)
|
|
142
|
+
return;
|
|
143
|
+
const currentValue = getValue();
|
|
144
|
+
vbox = node.getBoundingClientRect();
|
|
145
|
+
elem.classed('dragging', true);
|
|
146
|
+
onStart();
|
|
147
|
+
startPos = { x: event.x - cx, y: event.y - cy };
|
|
148
|
+
startAngle = utils.getAngleForPoint(startPos.x, startPos.y);
|
|
149
|
+
initialAngle = convertValueToAngle(currentValue);
|
|
150
|
+
monitoring = false;
|
|
151
|
+
// ...existing setState code...
|
|
152
|
+
}
|
|
153
|
+
function dragged(event) {
|
|
154
|
+
const currentPos = { x: event.x - cx, y: event.y - cy };
|
|
155
|
+
const distanceFromCenter = Math.sqrt(currentPos.x ** 2 + currentPos.y ** 2);
|
|
156
|
+
if (preciseMode) {
|
|
157
|
+
if (!monitoring && distanceFromCenter >= unlockDistance) {
|
|
158
|
+
startPos = currentPos;
|
|
159
|
+
startAngle = utils.getAngleForPoint(currentPos.x, currentPos.y);
|
|
160
|
+
monitoring = true;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
monitoring = true;
|
|
165
|
+
}
|
|
166
|
+
const currentAngle = utils.getAngleForPoint(currentPos.x, currentPos.y);
|
|
167
|
+
const deltaAngle = currentAngle - startAngle;
|
|
168
|
+
let finalAngle = initialAngle + deltaAngle;
|
|
169
|
+
finalAngle = normalizeAngle(finalAngle);
|
|
170
|
+
if (monitoring) {
|
|
171
|
+
onAngleChanged(finalAngle);
|
|
172
|
+
}
|
|
173
|
+
setState(prevState => ({
|
|
174
|
+
...prevState,
|
|
175
|
+
dragDistance: distanceFromCenter,
|
|
176
|
+
mousePos: {
|
|
177
|
+
x: event.sourceEvent.clientX,
|
|
178
|
+
y: event.sourceEvent.clientY,
|
|
179
|
+
},
|
|
180
|
+
valueAngle: monitoring ? finalAngle : initialAngle,
|
|
181
|
+
}));
|
|
182
|
+
}
|
|
183
|
+
function ended() {
|
|
184
|
+
elem.classed('dragging', false);
|
|
185
|
+
setState(prevState => ({ ...prevState, dragging: false }));
|
|
186
|
+
onEnd();
|
|
187
|
+
inputRef.current?.focus();
|
|
188
|
+
}
|
|
189
|
+
const dragInstance = drag()
|
|
190
|
+
.container(() => node)
|
|
191
|
+
.on('start', started)
|
|
192
|
+
.on('drag', dragged)
|
|
193
|
+
.on('end', ended);
|
|
194
|
+
elem.call(dragInstance);
|
|
195
|
+
};
|
|
196
|
+
const onFormControlChange = (newVal) => {
|
|
197
|
+
if (!isControlled) {
|
|
198
|
+
/**
|
|
199
|
+
* If the mode is 'uncontrolled' we need to update our local state
|
|
200
|
+
*/
|
|
201
|
+
setState(prevState => ({ ...prevState, uncontrolledValue: newVal }));
|
|
202
|
+
}
|
|
203
|
+
if (!disabled)
|
|
204
|
+
onChange(newVal);
|
|
205
|
+
};
|
|
206
|
+
const currentValue = getValue();
|
|
207
|
+
const angle = convertValueToAngle(currentValue);
|
|
208
|
+
const styles = {
|
|
209
|
+
container: Object.assign({}, {
|
|
210
|
+
width: '50px',
|
|
211
|
+
height: '50px',
|
|
212
|
+
overflow: 'hidden',
|
|
213
|
+
position: 'relative',
|
|
214
|
+
userSelect: 'none',
|
|
215
|
+
cursor: 'crosshair',
|
|
216
|
+
}, style),
|
|
217
|
+
input: {
|
|
218
|
+
width: '50%',
|
|
219
|
+
position: 'absolute',
|
|
220
|
+
top: '0',
|
|
221
|
+
left: '-100%',
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
//Get custom updates defined by the skin
|
|
225
|
+
//Transform the updateAttributes array into a SvgProxy array
|
|
226
|
+
const updateAttrs = skin.updateAttributes;
|
|
227
|
+
const skinElemUpdates = updateAttrs
|
|
228
|
+
? updateAttrs.map((elemUpdate, ix) => {
|
|
229
|
+
let elemContent = null;
|
|
230
|
+
if (elemUpdate.content) {
|
|
231
|
+
elemContent = elemUpdate.content(props, currentValue);
|
|
232
|
+
}
|
|
233
|
+
const attributes = {};
|
|
234
|
+
//Call value function
|
|
235
|
+
//TODO: support string values
|
|
236
|
+
for (const attr of elemUpdate.attrs || []) {
|
|
237
|
+
attributes[attr.name] = attr.value(props, currentValue);
|
|
238
|
+
}
|
|
239
|
+
return (_jsx(SvgProxy, { selector: elemUpdate.element, ...attributes, children: elemContent }, ix));
|
|
240
|
+
})
|
|
241
|
+
: null;
|
|
242
|
+
return (_jsxs(_Fragment, { children: [_jsxs("div", { ref: container, style: styles.container, ...rest, children: [_jsx(InternalInput, { disabled: disabled, inputRef: inputRef, style: styles.input, value: currentValue, min: min, max: max, step: step, onChange: onFormControlChange }), _jsxs(SvgLoader, { height: "100%", svgXML: skin.svg, width: "100%", onSVGReady: saveRef, children: [_jsx(SvgProxy, { selector: "#knob", transform: `$ORIGINAL rotate(${angle}, ${skin.knobX}, ${skin.knobY})` }), skinElemUpdates] })] }), state.dragging && preciseMode && (_jsx(KnobVisualHelpers, { svgRef: state.svgRef, radius: state.dragDistance, mousePos: state.mousePos, minimumDragDistance: unlockDistance, valueAngle: state.valueAngle }))] }));
|
|
243
|
+
};
|
|
244
|
+
export default RotaryKnob;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
knobX: 71,
|
|
3
|
+
knobY: 71,
|
|
4
|
+
svg: `
|
|
5
|
+
|
|
6
|
+
<svg width="204px" height="204px" viewBox="0 0 204 204" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
7
|
+
<!-- Generator: Sketch 47.1 (45422) - http://www.bohemiancoding.com/sketch -->
|
|
8
|
+
<desc>Created with Sketch.</desc>
|
|
9
|
+
<defs>
|
|
10
|
+
<linearGradient x1="50%" y1="50%" x2="50%" y2="100%" id="linearGradient-1">
|
|
11
|
+
<stop stop-color="#444040" stop-opacity="0.51098279" offset="0%"></stop>
|
|
12
|
+
<stop stop-color="#131111" stop-opacity="0.893200861" offset="100%"></stop>
|
|
13
|
+
</linearGradient>
|
|
14
|
+
<circle id="path-2" cx="98.0400009" cy="98.0400009" r="98.0400009"></circle>
|
|
15
|
+
<filter x="-3.3%" y="-3.3%" width="106.6%" height="106.6%" filterUnits="objectBoundingBox" id="filter-3">
|
|
16
|
+
<feMorphology radius="0.5" operator="dilate" in="SourceAlpha" result="shadowSpreadOuter1"></feMorphology>
|
|
17
|
+
<feOffset dx="0" dy="0" in="shadowSpreadOuter1" result="shadowOffsetOuter1"></feOffset>
|
|
18
|
+
<feGaussianBlur stdDeviation="2" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
|
19
|
+
<feComposite in="shadowBlurOuter1" in2="SourceAlpha" operator="out" result="shadowBlurOuter1"></feComposite>
|
|
20
|
+
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
|
|
21
|
+
</filter>
|
|
22
|
+
<linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="linearGradient-4">
|
|
23
|
+
<stop stop-color="#FFFFFF" stop-opacity="0.5" offset="0%"></stop>
|
|
24
|
+
<stop stop-color="#000000" stop-opacity="0.5" offset="100%"></stop>
|
|
25
|
+
</linearGradient>
|
|
26
|
+
<circle id="path-5" cx="98" cy="98" r="86"></circle>
|
|
27
|
+
<filter x="-4.1%" y="-3.5%" width="108.1%" height="108.1%" filterUnits="objectBoundingBox" id="filter-6">
|
|
28
|
+
<feMorphology radius="0.5" operator="dilate" in="SourceAlpha" result="shadowSpreadOuter1"></feMorphology>
|
|
29
|
+
<feOffset dx="0" dy="1" in="shadowSpreadOuter1" result="shadowOffsetOuter1"></feOffset>
|
|
30
|
+
<feGaussianBlur stdDeviation="2" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
|
31
|
+
<feComposite in="shadowBlurOuter1" in2="SourceAlpha" operator="out" result="shadowBlurOuter1"></feComposite>
|
|
32
|
+
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
|
|
33
|
+
</filter>
|
|
34
|
+
</defs>
|
|
35
|
+
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
|
36
|
+
<g id="s13" transform="translate(4.000000, 4.000000)">
|
|
37
|
+
<g id="container">
|
|
38
|
+
<g id="Oval-2">
|
|
39
|
+
<use fill="black" fill-opacity="1" filter="url(#filter-3)" xlink:href="#path-2"></use>
|
|
40
|
+
<use stroke="#979797" stroke-width="1" fill="url(#linearGradient-1)" fill-rule="evenodd" xlink:href="#path-2"></use>
|
|
41
|
+
</g>
|
|
42
|
+
<g id="Oval-2">
|
|
43
|
+
<use fill="black" fill-opacity="1" filter="url(#filter-6)" xlink:href="#path-5"></use>
|
|
44
|
+
<use fill="" fill-rule="evenodd" xlink:href="#path-5"></use>
|
|
45
|
+
<use stroke="#4A4A4A" stroke-width="1" fill="url(#linearGradient-4)" fill-rule="evenodd" xlink:href="#path-5"></use>
|
|
46
|
+
</g>
|
|
47
|
+
<g id="knob" transform="translate(27.431373, 27.431373)">
|
|
48
|
+
<circle id="Oval-5" fill="#322E2E" cx="71" cy="71" r="71"></circle>
|
|
49
|
+
<path d="M70.0686275,4.17063061 L86.5686275,65.2689929 C81.3642501,66.811221 75.8642501,67.5735686 70.0686275,67.5560356 C64.2730048,67.5385027 58.7730048,66.7761551 53.5686275,65.2689929 L70.0686275,4.17063061 Z" id="Rectangle-Copy" fill="#E6D7D7" transform="translate(70.068627, 35.863481) scale(1, -1) translate(-70.068627, -35.863481) "></path>
|
|
50
|
+
</g>
|
|
51
|
+
</g>
|
|
52
|
+
</g>
|
|
53
|
+
</g>
|
|
54
|
+
</svg>
|
|
55
|
+
`,
|
|
56
|
+
};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/** Note on viewbox/width
|
|
2
|
+
* This methods only work when the pixels match the svg units.
|
|
3
|
+
* when the viewbox is changed, or width is set they won't return
|
|
4
|
+
* the correct results
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Returns the global coordinates of a position given
|
|
8
|
+
* for a specific coordinate system
|
|
9
|
+
* @param {*} svgdoc
|
|
10
|
+
* @param {*} elem
|
|
11
|
+
* @param {*} x
|
|
12
|
+
* @param {*} y
|
|
13
|
+
*/
|
|
14
|
+
// function toGlobalCoordinates(svgdoc: any, elem: any, x: number, y: number) {
|
|
15
|
+
// var offset = svgdoc.getBoundingClientRect()
|
|
16
|
+
// var matrix = elem.getScreenCTM()
|
|
17
|
+
// return {
|
|
18
|
+
// x: matrix.a * x + matrix.c * y + matrix.e - offset.left,
|
|
19
|
+
// y: matrix.b * x + matrix.d * y + matrix.f - offset.top,
|
|
20
|
+
// }
|
|
21
|
+
// }
|
|
22
|
+
/**
|
|
23
|
+
* Converts a global position to a local one
|
|
24
|
+
* @param {*} svgdoc
|
|
25
|
+
* @param {*} elem
|
|
26
|
+
* @param {*} x
|
|
27
|
+
* @param {*} y
|
|
28
|
+
*/
|
|
29
|
+
// function toLocalCoordinates(svgdoc: any, elem: any, x: number, y: number) {
|
|
30
|
+
// const offset = svgdoc.getBoundingClientRect()
|
|
31
|
+
// const matrix = elem.getScreenCTM().inverse()
|
|
32
|
+
// return {
|
|
33
|
+
// x: matrix.a * x + matrix.c * y + matrix.e - offset.left,
|
|
34
|
+
// y: matrix.b * x + matrix.d * y + matrix.f - offset.top,
|
|
35
|
+
// }
|
|
36
|
+
// }
|
|
37
|
+
function toRadians(angle) {
|
|
38
|
+
return (angle * Math.PI) / 180;
|
|
39
|
+
}
|
|
40
|
+
function getQuadrant(x, y) {
|
|
41
|
+
if (x >= 0 && y >= 0)
|
|
42
|
+
return 1;
|
|
43
|
+
if (x <= 0 && y >= 0)
|
|
44
|
+
return 2;
|
|
45
|
+
if (x <= 0 && y <= 0)
|
|
46
|
+
return 3;
|
|
47
|
+
if (x >= 0 && y <= 0)
|
|
48
|
+
return 4;
|
|
49
|
+
return 1;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Returns the angle (degrees) given a point.
|
|
53
|
+
* Assumes 0,0 as the center of the circle
|
|
54
|
+
* @param {number} x
|
|
55
|
+
* @param {number} y
|
|
56
|
+
*/
|
|
57
|
+
function getAngleForPoint(x, y) {
|
|
58
|
+
if (x === 0 && y === 0)
|
|
59
|
+
return 0;
|
|
60
|
+
const angle = Math.atan(x / y);
|
|
61
|
+
let angleDeg = (angle * 180) / Math.PI;
|
|
62
|
+
//The final value depends on the quadrant
|
|
63
|
+
const quadrant = getQuadrant(x, y);
|
|
64
|
+
if (quadrant === 1) {
|
|
65
|
+
angleDeg = 90 - angleDeg;
|
|
66
|
+
}
|
|
67
|
+
if (quadrant === 2) {
|
|
68
|
+
angleDeg = 90 - angleDeg;
|
|
69
|
+
}
|
|
70
|
+
if (quadrant === 3) {
|
|
71
|
+
angleDeg = 270 - angleDeg;
|
|
72
|
+
}
|
|
73
|
+
if (quadrant === 4) {
|
|
74
|
+
angleDeg = 270 - angleDeg;
|
|
75
|
+
}
|
|
76
|
+
return angleDeg;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Transforms the top/left variables of the rectangle
|
|
80
|
+
* returned by getBoundingClientRect to document based coordinates
|
|
81
|
+
* without the scroll.
|
|
82
|
+
* UPDATE
|
|
83
|
+
* @param {Rect} box
|
|
84
|
+
*/
|
|
85
|
+
function transformBoundingClientRectToDocument(box) {
|
|
86
|
+
let t;
|
|
87
|
+
t = document.documentElement || document.body.parentNode;
|
|
88
|
+
const scrollX = (typeof t.scrollLeft === 'number' ? t : document.body)
|
|
89
|
+
.scrollLeft;
|
|
90
|
+
t = document.documentElement || document.body.parentNode;
|
|
91
|
+
const scrollY = (typeof t.scrollTop === 'number' ? t : document.body)
|
|
92
|
+
.scrollTop;
|
|
93
|
+
//This assumes width == height
|
|
94
|
+
const ttop = box.top - scrollY;
|
|
95
|
+
const tleft = box.left - scrollX;
|
|
96
|
+
//info needed to draw line from center to mousepos
|
|
97
|
+
return { top: ttop, left: tleft, width: box.width, height: box.height };
|
|
98
|
+
}
|
|
99
|
+
export default {
|
|
100
|
+
// toGlobalCoordinates,
|
|
101
|
+
// toLocalCoordinates,
|
|
102
|
+
toRadians,
|
|
103
|
+
getQuadrant,
|
|
104
|
+
getAngleForPoint,
|
|
105
|
+
transformBoundingClientRectToDocument,
|
|
106
|
+
};
|
package/lib/utils.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// this just creates and fills a zero-indexed array array; 0, 1, 2, 3, etc
|
|
2
|
+
const arraySequence = (numberOfElements) => Array.from(new Array(numberOfElements).keys());
|
|
3
|
+
const assertRange = (value, max = 127, min = 0) => {
|
|
4
|
+
let result = typeof value === 'string' ? Number.parseInt(value, 10) : value;
|
|
5
|
+
if (Number.isNaN(result) || result === null) {
|
|
6
|
+
result = min;
|
|
7
|
+
}
|
|
8
|
+
return result >= min ? (result <= max ? result : max) : min;
|
|
9
|
+
};
|
|
10
|
+
const findObj = (key, value) => (arr) => arr?.find(item => item?.[key] === value);
|
|
11
|
+
const omit = (...keys) => (obj) => Object.entries(obj)
|
|
12
|
+
.filter(([key]) => !keys.flat().map(String).includes(key))
|
|
13
|
+
.reduce((_obj, [key, val]) => Object.assign(_obj, { [key]: val }), {});
|
|
14
|
+
const pick = (...keys) => (obj) => Object.entries(obj)
|
|
15
|
+
.filter(([key]) => keys.flat().map(String).includes(key))
|
|
16
|
+
.reduce((_obj, [key, val]) => Object.assign(_obj, { [key]: val }), {});
|
|
17
|
+
const set = (key, value) => (obj) => ({
|
|
18
|
+
...obj,
|
|
19
|
+
[key]: value,
|
|
20
|
+
});
|
|
21
|
+
export { arraySequence, assertRange, findObj, omit, pick, set };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zds-pickers",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.9",
|
|
4
4
|
"main": "./dist/index.cjs.js",
|
|
5
5
|
"module": "./dist/index.es.js",
|
|
6
6
|
"types": "./dist/types/index.d.ts",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|
|
32
32
|
"dev": "vite",
|
|
33
|
-
"build": "vite build && tsc
|
|
33
|
+
"build": "vite build && tsc",
|
|
34
34
|
"build-storybook": "storybook build",
|
|
35
35
|
"lint": "biome check --write",
|
|
36
36
|
"preview": "vite preview",
|
|
@@ -62,7 +62,6 @@
|
|
|
62
62
|
"react": "18.2.0",
|
|
63
63
|
"storybook": "8.5.0",
|
|
64
64
|
"typescript": "5.7.3",
|
|
65
|
-
"vite-plugin-dts": "4.5.0",
|
|
66
65
|
"vite": "6.0.7",
|
|
67
66
|
"zds-mappings": "1.4.9"
|
|
68
67
|
},
|
package/tsconfig.json
CHANGED
package/vite.config.ts
CHANGED
|
@@ -1,19 +1,9 @@
|
|
|
1
1
|
import { resolve } from 'node:path'
|
|
2
2
|
import react from '@vitejs/plugin-react-swc'
|
|
3
3
|
import { defineConfig } from 'vite'
|
|
4
|
-
import dts from 'vite-plugin-dts'
|
|
5
4
|
|
|
6
5
|
export default defineConfig({
|
|
7
|
-
plugins: [
|
|
8
|
-
react(),
|
|
9
|
-
dts({
|
|
10
|
-
tsconfigPath: resolve(__dirname, 'tsconfig.json'),
|
|
11
|
-
include: ['lib'],
|
|
12
|
-
rollupTypes: true,
|
|
13
|
-
entryRoot: 'lib',
|
|
14
|
-
outDir: 'dist/types',
|
|
15
|
-
}),
|
|
16
|
-
],
|
|
6
|
+
plugins: [react()],
|
|
17
7
|
build: {
|
|
18
8
|
lib: {
|
|
19
9
|
entry: resolve(__dirname, 'lib/index'),
|
|
@@ -21,6 +11,7 @@ export default defineConfig({
|
|
|
21
11
|
formats: ['es', 'cjs'],
|
|
22
12
|
name: 'zds-pickers',
|
|
23
13
|
},
|
|
14
|
+
outDir: 'dist',
|
|
24
15
|
sourcemap: true,
|
|
25
16
|
rollupOptions: {
|
|
26
17
|
external: [
|
|
@@ -33,14 +24,7 @@ export default defineConfig({
|
|
|
33
24
|
'd3-selection',
|
|
34
25
|
],
|
|
35
26
|
output: {
|
|
36
|
-
|
|
37
|
-
react: 'React',
|
|
38
|
-
'react-dom': 'ReactDOM',
|
|
39
|
-
'react-select': 'ReactSelect',
|
|
40
|
-
'd3-drag': 'd3',
|
|
41
|
-
'd3-scale': 'd3',
|
|
42
|
-
'd3-selection': 'd3',
|
|
43
|
-
},
|
|
27
|
+
exports: 'named',
|
|
44
28
|
},
|
|
45
29
|
},
|
|
46
30
|
// minify: true,
|