@imperosoft/cris-webui-components 1.1.4 → 1.2.0
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.d.mts +296 -3
- package/dist/index.d.ts +296 -3
- package/dist/index.js +877 -43
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +867 -42
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -30,10 +30,19 @@ __export(index_exports, {
|
|
|
30
30
|
CrisSpinner: () => CrisSpinner,
|
|
31
31
|
CrisText: () => CrisText,
|
|
32
32
|
CrisTextInput: () => CrisTextInput,
|
|
33
|
+
CrisViewComm: () => CrisViewComm,
|
|
34
|
+
CrisViewDspFull: () => CrisViewDspFull,
|
|
35
|
+
buildMixerAxis: () => buildMixerAxis,
|
|
36
|
+
clampLevel: () => clampLevel,
|
|
37
|
+
collapseStrips: () => collapseStrips,
|
|
38
|
+
commIndicators: () => commIndicators,
|
|
33
39
|
configureIcons: () => configureIcons,
|
|
34
40
|
getIconConfig: () => getIconConfig,
|
|
35
41
|
getIconFilter: () => getIconFilter,
|
|
36
|
-
getIconUrl: () => getIconUrl
|
|
42
|
+
getIconUrl: () => getIconUrl,
|
|
43
|
+
levelToPercent: () => levelToPercent,
|
|
44
|
+
linksFor: () => linksFor,
|
|
45
|
+
normalizeLinked: () => normalizeLinked
|
|
37
46
|
});
|
|
38
47
|
module.exports = __toCommonJS(index_exports);
|
|
39
48
|
|
|
@@ -94,6 +103,7 @@ function isTouchActive() {
|
|
|
94
103
|
|
|
95
104
|
// src/components/CrisButton.tsx
|
|
96
105
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
106
|
+
var MIN_PRESS_VISUAL_MS = 120;
|
|
97
107
|
function CrisButton({
|
|
98
108
|
join,
|
|
99
109
|
joinFeedback,
|
|
@@ -126,6 +136,12 @@ function CrisButton({
|
|
|
126
136
|
children,
|
|
127
137
|
onPress,
|
|
128
138
|
onRelease,
|
|
139
|
+
onTap,
|
|
140
|
+
onLongPress,
|
|
141
|
+
holdMs = 2e3,
|
|
142
|
+
onHoldRepeat,
|
|
143
|
+
repeatMs = 150,
|
|
144
|
+
onHoldProgress,
|
|
129
145
|
debug = false
|
|
130
146
|
}) {
|
|
131
147
|
const debugRef = (0, import_react.useRef)(debug);
|
|
@@ -143,6 +159,12 @@ function CrisButton({
|
|
|
143
159
|
const touchMovedRef = (0, import_react.useRef)(false);
|
|
144
160
|
const touchPressTimerRef = (0, import_react.useRef)(null);
|
|
145
161
|
const touchPressedRef = (0, import_react.useRef)(false);
|
|
162
|
+
const holdTimerRef = (0, import_react.useRef)(null);
|
|
163
|
+
const repeatIntervalRef = (0, import_react.useRef)(null);
|
|
164
|
+
const progressRafRef = (0, import_react.useRef)(null);
|
|
165
|
+
const pressStartRef = (0, import_react.useRef)(0);
|
|
166
|
+
const gestureFiredRef = (0, import_react.useRef)(false);
|
|
167
|
+
const pressVisualTimerRef = (0, import_react.useRef)(null);
|
|
146
168
|
const feedbackJoin = joinFeedback ?? join;
|
|
147
169
|
const feedback = (0, import_cris_webui_ch5_core.useDigital)(feedbackJoin ?? 0);
|
|
148
170
|
const enabledJoin = (0, import_cris_webui_ch5_core.useDigital)(joinEnable ?? 0);
|
|
@@ -158,6 +180,12 @@ function CrisButton({
|
|
|
158
180
|
setPressed(false);
|
|
159
181
|
touchingRef.current = false;
|
|
160
182
|
touchStartedHereRef.current = false;
|
|
183
|
+
if (pressVisualTimerRef.current) {
|
|
184
|
+
clearTimeout(pressVisualTimerRef.current);
|
|
185
|
+
pressVisualTimerRef.current = null;
|
|
186
|
+
}
|
|
187
|
+
clearGestureTimers();
|
|
188
|
+
onHoldProgress?.(0);
|
|
161
189
|
if (join != null && smartId == null) {
|
|
162
190
|
log("sending release via dSet(false)");
|
|
163
191
|
dSet(join, false);
|
|
@@ -170,6 +198,22 @@ function CrisButton({
|
|
|
170
198
|
clearTimeout(touchPressTimerRef.current);
|
|
171
199
|
touchPressTimerRef.current = null;
|
|
172
200
|
}
|
|
201
|
+
if (holdTimerRef.current) {
|
|
202
|
+
clearTimeout(holdTimerRef.current);
|
|
203
|
+
holdTimerRef.current = null;
|
|
204
|
+
}
|
|
205
|
+
if (repeatIntervalRef.current) {
|
|
206
|
+
clearInterval(repeatIntervalRef.current);
|
|
207
|
+
repeatIntervalRef.current = null;
|
|
208
|
+
}
|
|
209
|
+
if (progressRafRef.current != null) {
|
|
210
|
+
cancelAnimationFrame(progressRafRef.current);
|
|
211
|
+
progressRafRef.current = null;
|
|
212
|
+
}
|
|
213
|
+
if (pressVisualTimerRef.current) {
|
|
214
|
+
clearTimeout(pressVisualTimerRef.current);
|
|
215
|
+
pressVisualTimerRef.current = null;
|
|
216
|
+
}
|
|
173
217
|
if (pressedRef.current && join != null && smartId == null) {
|
|
174
218
|
log("UNMOUNT RELEASE - component unmounting while pressed");
|
|
175
219
|
dSet(join, false);
|
|
@@ -185,6 +229,44 @@ function CrisButton({
|
|
|
185
229
|
} else if (hasControlFeedback && textSelected != null) {
|
|
186
230
|
currentText = textSelected;
|
|
187
231
|
}
|
|
232
|
+
const clearGestureTimers = () => {
|
|
233
|
+
if (holdTimerRef.current) {
|
|
234
|
+
clearTimeout(holdTimerRef.current);
|
|
235
|
+
holdTimerRef.current = null;
|
|
236
|
+
}
|
|
237
|
+
if (repeatIntervalRef.current) {
|
|
238
|
+
clearInterval(repeatIntervalRef.current);
|
|
239
|
+
repeatIntervalRef.current = null;
|
|
240
|
+
}
|
|
241
|
+
if (progressRafRef.current != null) {
|
|
242
|
+
cancelAnimationFrame(progressRafRef.current);
|
|
243
|
+
progressRafRef.current = null;
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
const armGestures = () => {
|
|
247
|
+
gestureFiredRef.current = false;
|
|
248
|
+
pressStartRef.current = Date.now();
|
|
249
|
+
if (onLongPress) {
|
|
250
|
+
holdTimerRef.current = setTimeout(() => {
|
|
251
|
+
holdTimerRef.current = null;
|
|
252
|
+
gestureFiredRef.current = true;
|
|
253
|
+
onLongPress();
|
|
254
|
+
}, holdMs);
|
|
255
|
+
}
|
|
256
|
+
if (onHoldProgress) {
|
|
257
|
+
const tick = () => {
|
|
258
|
+
const p = Math.min(1, (Date.now() - pressStartRef.current) / holdMs);
|
|
259
|
+
onHoldProgress(p);
|
|
260
|
+
progressRafRef.current = p < 1 ? requestAnimationFrame(tick) : null;
|
|
261
|
+
};
|
|
262
|
+
progressRafRef.current = requestAnimationFrame(tick);
|
|
263
|
+
}
|
|
264
|
+
if (onHoldRepeat) {
|
|
265
|
+
repeatIntervalRef.current = setInterval(() => {
|
|
266
|
+
onHoldRepeat();
|
|
267
|
+
}, repeatMs);
|
|
268
|
+
}
|
|
269
|
+
};
|
|
188
270
|
const handlePress = () => {
|
|
189
271
|
log("handlePress called", { suppressKeyClicks, pressedRef: pressedRef.current, isEnabled });
|
|
190
272
|
if (suppressKeyClicks) {
|
|
@@ -197,18 +279,24 @@ function CrisButton({
|
|
|
197
279
|
}
|
|
198
280
|
pressedRef.current = true;
|
|
199
281
|
setPressed(true);
|
|
282
|
+
pressStartRef.current = Date.now();
|
|
283
|
+
if (pressVisualTimerRef.current) {
|
|
284
|
+
clearTimeout(pressVisualTimerRef.current);
|
|
285
|
+
pressVisualTimerRef.current = null;
|
|
286
|
+
}
|
|
200
287
|
if (!isEnabled) {
|
|
201
288
|
log("SKIPPED dSet: not enabled");
|
|
202
289
|
return;
|
|
203
290
|
}
|
|
204
291
|
onPress?.();
|
|
292
|
+
armGestures();
|
|
205
293
|
if (join != null && smartId == null) {
|
|
206
294
|
log("SENDING PRESS via dSet(true)");
|
|
207
295
|
dSet(join, true);
|
|
208
296
|
}
|
|
209
297
|
};
|
|
210
|
-
const handleRelease = () => {
|
|
211
|
-
log("handleRelease called", { suppressKeyClicks, pressedRef: pressedRef.current, isEnabled });
|
|
298
|
+
const handleRelease = (clean = true) => {
|
|
299
|
+
log("handleRelease called", { clean, suppressKeyClicks, pressedRef: pressedRef.current, isEnabled });
|
|
212
300
|
if (suppressKeyClicks) {
|
|
213
301
|
log("BLOCKED: suppressKeyClicks");
|
|
214
302
|
return;
|
|
@@ -218,7 +306,17 @@ function CrisButton({
|
|
|
218
306
|
return;
|
|
219
307
|
}
|
|
220
308
|
pressedRef.current = false;
|
|
221
|
-
|
|
309
|
+
const heldMs = Date.now() - pressStartRef.current;
|
|
310
|
+
if (heldMs >= MIN_PRESS_VISUAL_MS) {
|
|
311
|
+
setPressed(false);
|
|
312
|
+
} else {
|
|
313
|
+
pressVisualTimerRef.current = setTimeout(() => {
|
|
314
|
+
pressVisualTimerRef.current = null;
|
|
315
|
+
setPressed(false);
|
|
316
|
+
}, MIN_PRESS_VISUAL_MS - heldMs);
|
|
317
|
+
}
|
|
318
|
+
clearGestureTimers();
|
|
319
|
+
onHoldProgress?.(0);
|
|
222
320
|
if (!isEnabled) {
|
|
223
321
|
log("SKIPPED dSet: not enabled");
|
|
224
322
|
return;
|
|
@@ -228,6 +326,9 @@ function CrisButton({
|
|
|
228
326
|
log("SENDING RELEASE via dSet(false)");
|
|
229
327
|
dSet(join, false);
|
|
230
328
|
}
|
|
329
|
+
if (clean && onTap && !gestureFiredRef.current) {
|
|
330
|
+
onTap();
|
|
331
|
+
}
|
|
231
332
|
};
|
|
232
333
|
const SCROLL_THRESHOLD = 8;
|
|
233
334
|
const PRESS_DELAY = 80;
|
|
@@ -263,7 +364,7 @@ function CrisButton({
|
|
|
263
364
|
cancelPressTimer();
|
|
264
365
|
if (touchPressedRef.current) {
|
|
265
366
|
touchPressedRef.current = false;
|
|
266
|
-
handleRelease();
|
|
367
|
+
handleRelease(false);
|
|
267
368
|
log("touchMove: scroll detected after press, releasing");
|
|
268
369
|
} else {
|
|
269
370
|
log("touchMove: scroll detected, press cancelled");
|
|
@@ -284,11 +385,11 @@ function CrisButton({
|
|
|
284
385
|
touchStartedHereRef.current = false;
|
|
285
386
|
if (touchPressedRef.current) {
|
|
286
387
|
touchPressedRef.current = false;
|
|
287
|
-
handleRelease();
|
|
388
|
+
handleRelease(true);
|
|
288
389
|
} else {
|
|
289
390
|
touchPressedRef.current = false;
|
|
290
391
|
handlePress();
|
|
291
|
-
handleRelease();
|
|
392
|
+
handleRelease(true);
|
|
292
393
|
}
|
|
293
394
|
};
|
|
294
395
|
const handleTouchCancel = () => {
|
|
@@ -299,7 +400,7 @@ function CrisButton({
|
|
|
299
400
|
touchStartedHereRef.current = false;
|
|
300
401
|
if (touchPressedRef.current) {
|
|
301
402
|
touchPressedRef.current = false;
|
|
302
|
-
handleRelease();
|
|
403
|
+
handleRelease(false);
|
|
303
404
|
}
|
|
304
405
|
touchMovedRef.current = false;
|
|
305
406
|
};
|
|
@@ -309,11 +410,11 @@ function CrisButton({
|
|
|
309
410
|
};
|
|
310
411
|
const handleMouseUp = () => {
|
|
311
412
|
if (isTouchActive() || touchingRef.current) return;
|
|
312
|
-
handleRelease();
|
|
413
|
+
handleRelease(true);
|
|
313
414
|
};
|
|
314
415
|
const handleMouseLeave = () => {
|
|
315
416
|
if (isTouchActive() || touchingRef.current) return;
|
|
316
|
-
handleRelease();
|
|
417
|
+
handleRelease(false);
|
|
317
418
|
};
|
|
318
419
|
if (!isVisible) return null;
|
|
319
420
|
const classes = [
|
|
@@ -489,6 +590,10 @@ function CrisSlider({
|
|
|
489
590
|
trackSizePercent = 20,
|
|
490
591
|
thumbSizePercent = 4,
|
|
491
592
|
delayMsAfterDragUpdateFeedback = 1e3,
|
|
593
|
+
value,
|
|
594
|
+
onChange,
|
|
595
|
+
onCommit,
|
|
596
|
+
changeThrottleMs = 100,
|
|
492
597
|
className = "",
|
|
493
598
|
style,
|
|
494
599
|
barClassName = "",
|
|
@@ -508,15 +613,27 @@ function CrisSlider({
|
|
|
508
613
|
const aSet = (0, import_cris_webui_ch5_core3.useJoinsStore)((state) => state.aSet);
|
|
509
614
|
const [ratioCurrent, setRatioCurrent] = (0, import_react2.useState)(0);
|
|
510
615
|
const [isDragging, setIsDragging] = (0, import_react2.useState)(false);
|
|
616
|
+
const draggingRef = (0, import_react2.useRef)(false);
|
|
511
617
|
const isDraggingOrJustAfterRef = (0, import_react2.useRef)(false);
|
|
512
618
|
const ratioBeforeDragRef = (0, import_react2.useRef)(0);
|
|
513
619
|
const afterDragTimeoutRef = (0, import_react2.useRef)(null);
|
|
514
620
|
const touchingRef = (0, import_react2.useRef)(false);
|
|
621
|
+
const changeTimerRef = (0, import_react2.useRef)(null);
|
|
622
|
+
const lastChangeAtRef = (0, import_react2.useRef)(0);
|
|
623
|
+
const latestValueRef = (0, import_react2.useRef)(0);
|
|
624
|
+
const touchStartXRef = (0, import_react2.useRef)(0);
|
|
625
|
+
const touchStartYRef = (0, import_react2.useRef)(0);
|
|
626
|
+
const touchDecidedRef = (0, import_react2.useRef)(false);
|
|
627
|
+
const valueRef = (0, import_react2.useRef)(value);
|
|
628
|
+
valueRef.current = value;
|
|
629
|
+
const analogValueRef = (0, import_react2.useRef)(analogValue);
|
|
630
|
+
analogValueRef.current = analogValue;
|
|
515
631
|
const isEnabled = joinEnable == null ? true : enabled;
|
|
516
632
|
const isVisible = joinVisible == null ? true : visible;
|
|
517
633
|
(0, import_react2.useEffect)(() => {
|
|
518
634
|
if (!isVisible && isDraggingOrJustAfterRef.current) {
|
|
519
635
|
setIsDragging(false);
|
|
636
|
+
draggingRef.current = false;
|
|
520
637
|
isDraggingOrJustAfterRef.current = false;
|
|
521
638
|
touchingRef.current = false;
|
|
522
639
|
if (effectiveDigitalJoin != null) {
|
|
@@ -526,16 +643,24 @@ function CrisSlider({
|
|
|
526
643
|
}, [isVisible, effectiveDigitalJoin, dSet]);
|
|
527
644
|
(0, import_react2.useEffect)(() => {
|
|
528
645
|
return () => {
|
|
646
|
+
if (changeTimerRef.current != null) {
|
|
647
|
+
clearTimeout(changeTimerRef.current);
|
|
648
|
+
changeTimerRef.current = null;
|
|
649
|
+
}
|
|
650
|
+
if (afterDragTimeoutRef.current !== null) {
|
|
651
|
+
window.clearTimeout(afterDragTimeoutRef.current);
|
|
652
|
+
afterDragTimeoutRef.current = null;
|
|
653
|
+
}
|
|
529
654
|
if (isDraggingOrJustAfterRef.current && effectiveDigitalJoin != null) {
|
|
530
655
|
dSet(effectiveDigitalJoin, false);
|
|
531
656
|
}
|
|
532
657
|
};
|
|
533
658
|
}, [effectiveDigitalJoin, dSet]);
|
|
534
659
|
const analogToRatio = (0, import_react2.useCallback)(
|
|
535
|
-
(
|
|
660
|
+
(value2) => {
|
|
536
661
|
const range = maxValue - minValue;
|
|
537
662
|
if (range <= 0) return 0;
|
|
538
|
-
return Math.max(0, Math.min(1, (
|
|
663
|
+
return Math.max(0, Math.min(1, (value2 - minValue) / range));
|
|
539
664
|
},
|
|
540
665
|
[minValue, maxValue]
|
|
541
666
|
);
|
|
@@ -547,16 +672,17 @@ function CrisSlider({
|
|
|
547
672
|
[minValue, maxValue]
|
|
548
673
|
);
|
|
549
674
|
const updateFromFeedback = (0, import_react2.useCallback)(() => {
|
|
550
|
-
if (
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
}, [
|
|
675
|
+
if (isDraggingOrJustAfterRef.current) return;
|
|
676
|
+
const v = valueRef.current !== void 0 ? valueRef.current : effectiveAnalogJoin != null ? analogValueRef.current : void 0;
|
|
677
|
+
if (v !== void 0) setRatioCurrent(analogToRatio(v));
|
|
678
|
+
}, [analogToRatio, effectiveAnalogJoin]);
|
|
554
679
|
(0, import_react2.useEffect)(() => {
|
|
555
680
|
updateFromFeedback();
|
|
556
|
-
}, [updateFromFeedback]);
|
|
681
|
+
}, [value, analogValue, updateFromFeedback]);
|
|
557
682
|
const handleDragStart = (0, import_react2.useCallback)(() => {
|
|
558
683
|
if (!isEnabled) return;
|
|
559
684
|
setIsDragging(true);
|
|
685
|
+
draggingRef.current = true;
|
|
560
686
|
if (effectiveDigitalJoin != null) {
|
|
561
687
|
dSet(effectiveDigitalJoin, true);
|
|
562
688
|
}
|
|
@@ -570,11 +696,17 @@ function CrisSlider({
|
|
|
570
696
|
}
|
|
571
697
|
}, [isEnabled, effectiveDigitalJoin, dSet, ratioCurrent]);
|
|
572
698
|
const handleDragEnd = (0, import_react2.useCallback)(() => {
|
|
573
|
-
if (!
|
|
699
|
+
if (!draggingRef.current) return;
|
|
700
|
+
draggingRef.current = false;
|
|
574
701
|
setIsDragging(false);
|
|
575
702
|
if (effectiveDigitalJoin != null) {
|
|
576
703
|
dSet(effectiveDigitalJoin, false);
|
|
577
704
|
}
|
|
705
|
+
if (changeTimerRef.current != null) {
|
|
706
|
+
clearTimeout(changeTimerRef.current);
|
|
707
|
+
changeTimerRef.current = null;
|
|
708
|
+
}
|
|
709
|
+
onCommit?.(latestValueRef.current);
|
|
578
710
|
if (delayMsAfterDragUpdateFeedback > 0) {
|
|
579
711
|
afterDragTimeoutRef.current = window.setTimeout(() => {
|
|
580
712
|
isDraggingOrJustAfterRef.current = false;
|
|
@@ -585,10 +717,10 @@ function CrisSlider({
|
|
|
585
717
|
isDraggingOrJustAfterRef.current = false;
|
|
586
718
|
updateFromFeedback();
|
|
587
719
|
}
|
|
588
|
-
}, [
|
|
720
|
+
}, [effectiveDigitalJoin, dSet, delayMsAfterDragUpdateFeedback, updateFromFeedback, onCommit]);
|
|
589
721
|
const handleMove = (0, import_react2.useCallback)(
|
|
590
722
|
(clientX, clientY, bounds) => {
|
|
591
|
-
if (!
|
|
723
|
+
if (!draggingRef.current) return;
|
|
592
724
|
let newRatio;
|
|
593
725
|
if (horizontal) {
|
|
594
726
|
newRatio = (clientX - bounds.left) / bounds.width;
|
|
@@ -597,11 +729,31 @@ function CrisSlider({
|
|
|
597
729
|
}
|
|
598
730
|
newRatio = Math.max(0, Math.min(1, newRatio));
|
|
599
731
|
setRatioCurrent(newRatio);
|
|
732
|
+
const outValue = ratioToAnalog(newRatio);
|
|
733
|
+
latestValueRef.current = outValue;
|
|
600
734
|
if (effectiveAnalogJoin != null) {
|
|
601
|
-
aSet(effectiveAnalogJoin,
|
|
735
|
+
aSet(effectiveAnalogJoin, outValue);
|
|
736
|
+
}
|
|
737
|
+
if (onChange) {
|
|
738
|
+
const now = Date.now();
|
|
739
|
+
const wait = changeThrottleMs - (now - lastChangeAtRef.current);
|
|
740
|
+
if (wait <= 0) {
|
|
741
|
+
if (changeTimerRef.current != null) {
|
|
742
|
+
clearTimeout(changeTimerRef.current);
|
|
743
|
+
changeTimerRef.current = null;
|
|
744
|
+
}
|
|
745
|
+
lastChangeAtRef.current = now;
|
|
746
|
+
onChange(outValue);
|
|
747
|
+
} else if (changeTimerRef.current == null) {
|
|
748
|
+
changeTimerRef.current = window.setTimeout(() => {
|
|
749
|
+
changeTimerRef.current = null;
|
|
750
|
+
lastChangeAtRef.current = Date.now();
|
|
751
|
+
onChange(latestValueRef.current);
|
|
752
|
+
}, wait);
|
|
753
|
+
}
|
|
602
754
|
}
|
|
603
755
|
},
|
|
604
|
-
[
|
|
756
|
+
[horizontal, effectiveAnalogJoin, aSet, ratioToAnalog, onChange, changeThrottleMs]
|
|
605
757
|
);
|
|
606
758
|
const handleMouseDown = (event) => {
|
|
607
759
|
if (isTouchActive() || touchingRef.current) return;
|
|
@@ -611,7 +763,7 @@ function CrisSlider({
|
|
|
611
763
|
handleMove(event.clientX, event.clientY, bounds);
|
|
612
764
|
};
|
|
613
765
|
const handleMouseMove = (event) => {
|
|
614
|
-
if (!
|
|
766
|
+
if (!draggingRef.current) return;
|
|
615
767
|
const bounds = event.currentTarget.getBoundingClientRect();
|
|
616
768
|
handleMove(event.clientX, event.clientY, bounds);
|
|
617
769
|
};
|
|
@@ -619,38 +771,58 @@ function CrisSlider({
|
|
|
619
771
|
handleDragEnd();
|
|
620
772
|
};
|
|
621
773
|
const handleMouseLeave = (event) => {
|
|
622
|
-
if (
|
|
774
|
+
if (draggingRef.current) {
|
|
623
775
|
const bounds = event.currentTarget.getBoundingClientRect();
|
|
624
776
|
handleMove(event.clientX, event.clientY, bounds);
|
|
625
777
|
}
|
|
626
778
|
handleDragEnd();
|
|
627
779
|
};
|
|
780
|
+
const TOUCH_SLOP = 8;
|
|
628
781
|
const handleTouchStart = (event) => {
|
|
629
782
|
touchStart();
|
|
630
783
|
touchingRef.current = true;
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
784
|
+
const t = event.touches[0];
|
|
785
|
+
touchStartXRef.current = t.clientX;
|
|
786
|
+
touchStartYRef.current = t.clientY;
|
|
787
|
+
touchDecidedRef.current = false;
|
|
635
788
|
};
|
|
636
789
|
const handleTouchMove = (event) => {
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
790
|
+
const t = event.touches[0];
|
|
791
|
+
if (!t) return;
|
|
792
|
+
if (draggingRef.current) {
|
|
793
|
+
handleMove(t.clientX, t.clientY, event.currentTarget.getBoundingClientRect());
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
if (touchDecidedRef.current) return;
|
|
797
|
+
const dx = Math.abs(t.clientX - touchStartXRef.current);
|
|
798
|
+
const dy = Math.abs(t.clientY - touchStartYRef.current);
|
|
799
|
+
if (dx < TOUCH_SLOP && dy < TOUCH_SLOP) return;
|
|
800
|
+
touchDecidedRef.current = true;
|
|
801
|
+
const along = horizontal ? dx : dy;
|
|
802
|
+
const cross = horizontal ? dy : dx;
|
|
803
|
+
if (along >= cross) {
|
|
804
|
+
handleDragStart();
|
|
805
|
+
handleMove(t.clientX, t.clientY, event.currentTarget.getBoundingClientRect());
|
|
806
|
+
}
|
|
641
807
|
};
|
|
642
|
-
const handleTouchEnd = () => {
|
|
808
|
+
const handleTouchEnd = (event) => {
|
|
643
809
|
touchEnd();
|
|
644
|
-
|
|
810
|
+
if (draggingRef.current) {
|
|
811
|
+
handleDragEnd();
|
|
812
|
+
} else if (!touchDecidedRef.current) {
|
|
813
|
+
const t = event.changedTouches[0];
|
|
814
|
+
if (t) {
|
|
815
|
+
handleDragStart();
|
|
816
|
+
handleMove(t.clientX, t.clientY, event.currentTarget.getBoundingClientRect());
|
|
817
|
+
handleDragEnd();
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
touchDecidedRef.current = false;
|
|
645
821
|
};
|
|
646
|
-
const handleTouchCancel = (
|
|
822
|
+
const handleTouchCancel = () => {
|
|
647
823
|
touchEnd();
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
const touch = event.touches[0];
|
|
651
|
-
handleMove(touch.clientX, touch.clientY, bounds);
|
|
652
|
-
}
|
|
653
|
-
handleDragEnd();
|
|
824
|
+
touchDecidedRef.current = false;
|
|
825
|
+
if (draggingRef.current) handleDragEnd();
|
|
654
826
|
};
|
|
655
827
|
if (!isVisible) return null;
|
|
656
828
|
const containerClasses = [
|
|
@@ -678,8 +850,10 @@ function CrisSlider({
|
|
|
678
850
|
computedBarStyle.height = `${height}%`;
|
|
679
851
|
computedBarStyle.top = `${top}%`;
|
|
680
852
|
}
|
|
853
|
+
const dragLayerStyle = isDragging ? { willChange: "transform" } : {};
|
|
681
854
|
const computedFillStyle = {
|
|
682
855
|
...fillStyle,
|
|
856
|
+
...dragLayerStyle,
|
|
683
857
|
position: "absolute"
|
|
684
858
|
};
|
|
685
859
|
if (horizontal) {
|
|
@@ -701,6 +875,7 @@ function CrisSlider({
|
|
|
701
875
|
}
|
|
702
876
|
const computedThumbStyle = {
|
|
703
877
|
...thumbStyle,
|
|
878
|
+
...dragLayerStyle,
|
|
704
879
|
position: "absolute"
|
|
705
880
|
};
|
|
706
881
|
if (horizontal) {
|
|
@@ -724,7 +899,9 @@ function CrisSlider({
|
|
|
724
899
|
...style,
|
|
725
900
|
position: "relative",
|
|
726
901
|
cursor: isEnabled ? "pointer" : "default",
|
|
727
|
-
|
|
902
|
+
// Let the browser scroll the cross-axis (so a horizontal swipe over a vertical
|
|
903
|
+
// fader scrolls the row); the slider handles drags along its own axis.
|
|
904
|
+
touchAction: horizontal ? "pan-y" : "pan-x",
|
|
728
905
|
userSelect: "none"
|
|
729
906
|
},
|
|
730
907
|
onMouseDown: handleMouseDown,
|
|
@@ -2159,6 +2336,654 @@ function CrisCoMatrixListsTie({
|
|
|
2159
2336
|
}
|
|
2160
2337
|
);
|
|
2161
2338
|
}
|
|
2339
|
+
|
|
2340
|
+
// src/components/CrisViewComm.tsx
|
|
2341
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
2342
|
+
var ETH = /* @__PURE__ */ new Set(["tcp", "udp", "ssh", "ws"]);
|
|
2343
|
+
function commIndicators(c) {
|
|
2344
|
+
const isEth = !!c?.kd && ETH.has(c.kd);
|
|
2345
|
+
return {
|
|
2346
|
+
eth: { visible: isEth || c?.kd === "native", on: !!c?.co },
|
|
2347
|
+
serial: { visible: c?.kd === "serial" || isEth && !!c?.so, on: !!c?.al }
|
|
2348
|
+
};
|
|
2349
|
+
}
|
|
2350
|
+
var COMM_DEFAULTS = {
|
|
2351
|
+
root: "flex items-center gap-[0.4em]",
|
|
2352
|
+
dot: "w-[2.2em] h-[2.2em] rounded-full flex items-center justify-center",
|
|
2353
|
+
dotOn: "bg-[#22c55e]",
|
|
2354
|
+
dotOff: "bg-[#dc2626]",
|
|
2355
|
+
icon: ""
|
|
2356
|
+
};
|
|
2357
|
+
function isNode(v) {
|
|
2358
|
+
return v !== void 0 && typeof v !== "string";
|
|
2359
|
+
}
|
|
2360
|
+
function IndicatorDot({ icon, on, iconScale, cls }) {
|
|
2361
|
+
const iconStyle = {
|
|
2362
|
+
width: iconScale,
|
|
2363
|
+
height: iconScale,
|
|
2364
|
+
filter: "brightness(0) invert(1)",
|
|
2365
|
+
opacity: on ? 1 : 0.5
|
|
2366
|
+
};
|
|
2367
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: `${cls.dot} ${on ? cls.dotOn : cls.dotOff}`, children: isNode(icon) ? icon : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("img", { className: cls.icon, src: getIconUrl(icon), alt: "", draggable: false, style: iconStyle }) });
|
|
2368
|
+
}
|
|
2369
|
+
function CrisViewComm({ comm, classes, icons, className }) {
|
|
2370
|
+
const cls = {
|
|
2371
|
+
root: classes?.root ?? COMM_DEFAULTS.root,
|
|
2372
|
+
dot: classes?.dot ?? COMM_DEFAULTS.dot,
|
|
2373
|
+
dotOn: classes?.dotOn ?? COMM_DEFAULTS.dotOn,
|
|
2374
|
+
dotOff: classes?.dotOff ?? COMM_DEFAULTS.dotOff,
|
|
2375
|
+
icon: classes?.icon ?? COMM_DEFAULTS.icon
|
|
2376
|
+
};
|
|
2377
|
+
const ethIcon = icons?.ethernet ?? "ind-ethernet";
|
|
2378
|
+
const serialIcon = icons?.serial ?? "rs232";
|
|
2379
|
+
const { eth, serial } = commIndicators(comm);
|
|
2380
|
+
if (!eth.visible && !serial.visible) return null;
|
|
2381
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: `${cls.root} ${className ?? ""}`, children: [
|
|
2382
|
+
eth.visible && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(IndicatorDot, { icon: ethIcon, on: eth.on, iconScale: "85%", cls }),
|
|
2383
|
+
serial.visible && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(IndicatorDot, { icon: serialIcon, on: serial.on, iconScale: "95%", cls })
|
|
2384
|
+
] });
|
|
2385
|
+
}
|
|
2386
|
+
|
|
2387
|
+
// src/components/dsp/CrisViewDspFull.tsx
|
|
2388
|
+
var import_react9 = require("react");
|
|
2389
|
+
var import_cris_webui_ch5_core11 = require("@imperosoft/cris-webui-ch5-core");
|
|
2390
|
+
|
|
2391
|
+
// src/components/dsp/DspIoPage.tsx
|
|
2392
|
+
var import_react6 = require("react");
|
|
2393
|
+
|
|
2394
|
+
// src/components/dsp/dspModel.ts
|
|
2395
|
+
function levelToPercent(lv) {
|
|
2396
|
+
return Math.round(clampLevel(lv) / 65535 * 100);
|
|
2397
|
+
}
|
|
2398
|
+
function clampLevel(lv) {
|
|
2399
|
+
if (!Number.isFinite(lv)) return 0;
|
|
2400
|
+
return Math.max(0, Math.min(65535, lv));
|
|
2401
|
+
}
|
|
2402
|
+
function normalizeLinked(raw) {
|
|
2403
|
+
return {
|
|
2404
|
+
label: raw.lb ?? "",
|
|
2405
|
+
channels: raw.ch ?? []
|
|
2406
|
+
};
|
|
2407
|
+
}
|
|
2408
|
+
function collapseStrips(channels, links) {
|
|
2409
|
+
const byId = new Map(channels.map((c) => [c.id, c]));
|
|
2410
|
+
const grouped = /* @__PURE__ */ new Set();
|
|
2411
|
+
const groups = [];
|
|
2412
|
+
for (const raw of links ?? []) {
|
|
2413
|
+
const { label, channels: members } = normalizeLinked(raw);
|
|
2414
|
+
if (members.length === 0) continue;
|
|
2415
|
+
members.forEach((id) => grouped.add(id));
|
|
2416
|
+
const primary = members.find((id) => byId.has(id));
|
|
2417
|
+
const ref = primary !== void 0 ? byId.get(primary) : void 0;
|
|
2418
|
+
groups.push({
|
|
2419
|
+
kind: "group",
|
|
2420
|
+
key: `g:${members.join("-")}`,
|
|
2421
|
+
label: label || ref?.lb || `Grupo ${members[0]}`,
|
|
2422
|
+
channels: members,
|
|
2423
|
+
lv: clampLevel(ref?.lv),
|
|
2424
|
+
mt: ref?.mt ?? false
|
|
2425
|
+
});
|
|
2426
|
+
}
|
|
2427
|
+
const singles = channels.filter((c) => !grouped.has(c.id)).map((c) => ({
|
|
2428
|
+
kind: "single",
|
|
2429
|
+
key: `c:${c.id}`,
|
|
2430
|
+
label: c.lb ?? `Canal ${c.id}`,
|
|
2431
|
+
channels: [c.id],
|
|
2432
|
+
lv: clampLevel(c.lv),
|
|
2433
|
+
mt: c.mt
|
|
2434
|
+
}));
|
|
2435
|
+
return [...singles, ...groups];
|
|
2436
|
+
}
|
|
2437
|
+
function linksFor(ln, io) {
|
|
2438
|
+
return io === "in" ? ln?.ip : ln?.op;
|
|
2439
|
+
}
|
|
2440
|
+
function buildMixerAxis(channels, links) {
|
|
2441
|
+
const items = channels.map((c) => ({
|
|
2442
|
+
id: c.id,
|
|
2443
|
+
channelLabel: c.lb ?? `${c.id}`
|
|
2444
|
+
}));
|
|
2445
|
+
const indexById = new Map(channels.map((c, idx) => [c.id, idx]));
|
|
2446
|
+
for (const raw of links ?? []) {
|
|
2447
|
+
const { label, channels: members } = normalizeLinked(raw);
|
|
2448
|
+
if (members.length < 2) continue;
|
|
2449
|
+
const sorted = [...members].sort((a, b) => a - b);
|
|
2450
|
+
const consecutiveNumbers = sorted.every((n, k) => k === 0 || n === sorted[k - 1] + 1);
|
|
2451
|
+
if (!consecutiveNumbers) continue;
|
|
2452
|
+
const idxs = sorted.map((n) => indexById.get(n));
|
|
2453
|
+
if (idxs.some((x) => x === void 0)) continue;
|
|
2454
|
+
const indices = idxs;
|
|
2455
|
+
const consecutiveIdx = indices.every((x, k) => k === 0 || x === indices[k - 1] + 1);
|
|
2456
|
+
if (!consecutiveIdx) continue;
|
|
2457
|
+
const startIdx = indices[0];
|
|
2458
|
+
items[startIdx].groupStart = true;
|
|
2459
|
+
items[startIdx].groupSpan = indices.length;
|
|
2460
|
+
for (const idx of indices) items[idx].groupCommon = label;
|
|
2461
|
+
}
|
|
2462
|
+
return items;
|
|
2463
|
+
}
|
|
2464
|
+
|
|
2465
|
+
// src/components/dsp/DspChannelStrip.tsx
|
|
2466
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
2467
|
+
function DspChannelStrip({ strip, io, oid, send, cls, icons }) {
|
|
2468
|
+
const primary = strip.channels[0];
|
|
2469
|
+
const sendLevel = (channel, value, queued) => send(oid, { action: "level.set", io, channel, value, queued });
|
|
2470
|
+
const streamLevel = (value) => {
|
|
2471
|
+
if (primary !== void 0) sendLevel(primary, value, false);
|
|
2472
|
+
};
|
|
2473
|
+
const commitLevel = (value) => {
|
|
2474
|
+
strip.channels.forEach((ch) => sendLevel(ch, value, true));
|
|
2475
|
+
};
|
|
2476
|
+
const toggleMute = () => {
|
|
2477
|
+
const value = !strip.mt;
|
|
2478
|
+
strip.channels.forEach(
|
|
2479
|
+
(channel) => send(oid, { action: "mute.set", io, channel, value, queued: false })
|
|
2480
|
+
);
|
|
2481
|
+
};
|
|
2482
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: cls.strip, style: { minWidth: 0 }, children: [
|
|
2483
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "w-full h-[4.1em] flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: cls.stripLabel, title: strip.label, children: strip.label }) }),
|
|
2484
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: cls.levelReadout, children: [
|
|
2485
|
+
levelToPercent(strip.lv),
|
|
2486
|
+
"%"
|
|
2487
|
+
] }),
|
|
2488
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2489
|
+
CrisSlider,
|
|
2490
|
+
{
|
|
2491
|
+
value: strip.lv,
|
|
2492
|
+
onChange: streamLevel,
|
|
2493
|
+
onCommit: commitLevel,
|
|
2494
|
+
minValue: 0,
|
|
2495
|
+
maxValue: 65535,
|
|
2496
|
+
thumbSizePercent: 7,
|
|
2497
|
+
className: "flex-1 w-full",
|
|
2498
|
+
barClassName: cls.faderBar,
|
|
2499
|
+
fillClassName: cls.faderFill,
|
|
2500
|
+
thumbClassName: cls.faderThumb
|
|
2501
|
+
}
|
|
2502
|
+
),
|
|
2503
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "w-full h-[3.8em] shrink-0 mt-[0.6em]", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2504
|
+
CrisButton,
|
|
2505
|
+
{
|
|
2506
|
+
selected: strip.mt,
|
|
2507
|
+
onPress: toggleMute,
|
|
2508
|
+
iconName: icons.muteOff,
|
|
2509
|
+
iconNameActive: icons.muteOn,
|
|
2510
|
+
iconSize: "3.6em",
|
|
2511
|
+
iconStyle: { filter: icons.muteOffFilter },
|
|
2512
|
+
iconStyleActive: { filter: icons.muteOnFilter },
|
|
2513
|
+
className: cls.mute,
|
|
2514
|
+
classActive: cls.muteActive
|
|
2515
|
+
}
|
|
2516
|
+
) })
|
|
2517
|
+
] });
|
|
2518
|
+
}
|
|
2519
|
+
|
|
2520
|
+
// src/components/dsp/useHorizontalWheel.ts
|
|
2521
|
+
var import_react5 = require("react");
|
|
2522
|
+
function useHorizontalWheel(ref) {
|
|
2523
|
+
(0, import_react5.useEffect)(() => {
|
|
2524
|
+
const el = ref.current;
|
|
2525
|
+
if (!el) return;
|
|
2526
|
+
const onWheel = (e) => {
|
|
2527
|
+
if (e.deltaY === 0) return;
|
|
2528
|
+
if (el.scrollWidth <= el.clientWidth) return;
|
|
2529
|
+
e.preventDefault();
|
|
2530
|
+
el.scrollLeft += e.deltaY;
|
|
2531
|
+
};
|
|
2532
|
+
el.addEventListener("wheel", onWheel, { passive: false });
|
|
2533
|
+
return () => el.removeEventListener("wheel", onWheel);
|
|
2534
|
+
}, [ref]);
|
|
2535
|
+
}
|
|
2536
|
+
|
|
2537
|
+
// src/components/dsp/DspIoPage.tsx
|
|
2538
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
2539
|
+
function DspIoPage({ status, io, oid, send, skip, cls, icons, emptyLabel }) {
|
|
2540
|
+
const scrollRef = (0, import_react6.useRef)(null);
|
|
2541
|
+
useHorizontalWheel(scrollRef);
|
|
2542
|
+
const skipSet = new Set(skip ?? []);
|
|
2543
|
+
const raw = (io === "in" ? status?.ip : status?.op) ?? [];
|
|
2544
|
+
const channels = skipSet.size ? raw.filter((c) => !skipSet.has(c.id)) : raw;
|
|
2545
|
+
const allLinks = linksFor(status?.ln, io);
|
|
2546
|
+
const links = skipSet.size ? allLinks?.filter((g) => (g.ch ?? []).some((id) => !skipSet.has(id))) : allLinks;
|
|
2547
|
+
const strips = collapseStrips(channels, links);
|
|
2548
|
+
if (strips.length === 0) {
|
|
2549
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: cls.message, children: emptyLabel });
|
|
2550
|
+
}
|
|
2551
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { ref: scrollRef, className: "w-full h-full overflow-x-auto no-scrollbar", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2552
|
+
"div",
|
|
2553
|
+
{
|
|
2554
|
+
className: "flex h-full items-stretch gap-[0.3em] px-[0.5em] py-[0.5em]",
|
|
2555
|
+
style: { minWidth: "min-content" },
|
|
2556
|
+
children: strips.map((strip) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2557
|
+
DspChannelStrip,
|
|
2558
|
+
{
|
|
2559
|
+
strip,
|
|
2560
|
+
io,
|
|
2561
|
+
oid,
|
|
2562
|
+
send,
|
|
2563
|
+
cls,
|
|
2564
|
+
icons
|
|
2565
|
+
},
|
|
2566
|
+
strip.key
|
|
2567
|
+
))
|
|
2568
|
+
}
|
|
2569
|
+
) });
|
|
2570
|
+
}
|
|
2571
|
+
|
|
2572
|
+
// src/components/dsp/DspMixer.tsx
|
|
2573
|
+
var import_react7 = require("react");
|
|
2574
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
2575
|
+
var COMMON_W = "9em";
|
|
2576
|
+
var CHAN_W = "3em";
|
|
2577
|
+
var COMMON_H = "2.4em";
|
|
2578
|
+
var CHAN_H = "2.1em";
|
|
2579
|
+
var CELL_W = "7.5em";
|
|
2580
|
+
var ROW_H = "4.5em";
|
|
2581
|
+
var DRAG_FACTOR = 0.6;
|
|
2582
|
+
function CrosspointOnIcon({ icon }) {
|
|
2583
|
+
if (typeof icon !== "string") return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_jsx_runtime14.Fragment, { children: icon });
|
|
2584
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2585
|
+
"img",
|
|
2586
|
+
{
|
|
2587
|
+
src: getIconUrl(icon),
|
|
2588
|
+
alt: "",
|
|
2589
|
+
draggable: false,
|
|
2590
|
+
className: "pointer-events-none",
|
|
2591
|
+
style: { width: "4.4em", height: "4.4em", filter: "brightness(0) invert(1)" }
|
|
2592
|
+
}
|
|
2593
|
+
);
|
|
2594
|
+
}
|
|
2595
|
+
function DspMixer({ status, oid, send, cls, icons }) {
|
|
2596
|
+
const scrollRef = (0, import_react7.useRef)(null);
|
|
2597
|
+
const startRef = (0, import_react7.useRef)(null);
|
|
2598
|
+
const movedRef = (0, import_react7.useRef)(false);
|
|
2599
|
+
const thresholdRef = (0, import_react7.useRef)(8);
|
|
2600
|
+
const pendingRef = (0, import_react7.useRef)(null);
|
|
2601
|
+
const inputs = status?.ip ?? [];
|
|
2602
|
+
const outputs = status?.op ?? [];
|
|
2603
|
+
const isOn = (output, input) => outputs.find((o) => o.id === output)?.xp?.[input] === true;
|
|
2604
|
+
const onPointerDown = (e) => {
|
|
2605
|
+
const el = scrollRef.current;
|
|
2606
|
+
if (!el) return;
|
|
2607
|
+
movedRef.current = false;
|
|
2608
|
+
thresholdRef.current = parseFloat(getComputedStyle(el).fontSize || "16") * DRAG_FACTOR;
|
|
2609
|
+
startRef.current = { x: e.clientX, y: e.clientY, sl: el.scrollLeft, st: el.scrollTop };
|
|
2610
|
+
const cell = e.target.closest("[data-cell]");
|
|
2611
|
+
pendingRef.current = cell ? { input: Number(cell.dataset.in), output: Number(cell.dataset.out) } : null;
|
|
2612
|
+
el.setPointerCapture(e.pointerId);
|
|
2613
|
+
};
|
|
2614
|
+
const onPointerMove = (e) => {
|
|
2615
|
+
const el = scrollRef.current;
|
|
2616
|
+
const s = startRef.current;
|
|
2617
|
+
if (!el || !s) return;
|
|
2618
|
+
const dx = e.clientX - s.x;
|
|
2619
|
+
const dy = e.clientY - s.y;
|
|
2620
|
+
if (!movedRef.current && Math.hypot(dx, dy) > thresholdRef.current) movedRef.current = true;
|
|
2621
|
+
if (movedRef.current) {
|
|
2622
|
+
el.scrollLeft = s.sl - dx;
|
|
2623
|
+
el.scrollTop = s.st - dy;
|
|
2624
|
+
}
|
|
2625
|
+
};
|
|
2626
|
+
const onPointerUp = (e) => {
|
|
2627
|
+
const el = scrollRef.current;
|
|
2628
|
+
el?.releasePointerCapture?.(e.pointerId);
|
|
2629
|
+
if (!movedRef.current && pendingRef.current) {
|
|
2630
|
+
const { input, output } = pendingRef.current;
|
|
2631
|
+
send(oid, {
|
|
2632
|
+
action: "crosspoint.set",
|
|
2633
|
+
input,
|
|
2634
|
+
output,
|
|
2635
|
+
value: !isOn(output, input),
|
|
2636
|
+
queued: true
|
|
2637
|
+
});
|
|
2638
|
+
}
|
|
2639
|
+
startRef.current = null;
|
|
2640
|
+
pendingRef.current = null;
|
|
2641
|
+
};
|
|
2642
|
+
if (inputs.length === 0 || outputs.length === 0) {
|
|
2643
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: cls.message, children: "Sin crosspoints" });
|
|
2644
|
+
}
|
|
2645
|
+
const inAxis = buildMixerAxis(inputs, linksFor(status?.ln, "in"));
|
|
2646
|
+
const outAxis = buildMixerAxis(outputs, linksFor(status?.ln, "out"));
|
|
2647
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2648
|
+
"div",
|
|
2649
|
+
{
|
|
2650
|
+
ref: scrollRef,
|
|
2651
|
+
onPointerDown,
|
|
2652
|
+
onPointerMove,
|
|
2653
|
+
onPointerUp,
|
|
2654
|
+
onPointerCancel: onPointerUp,
|
|
2655
|
+
className: "w-full h-full overflow-auto no-scrollbar relative touch-none select-none cursor-grab",
|
|
2656
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
2657
|
+
"div",
|
|
2658
|
+
{
|
|
2659
|
+
className: "grid",
|
|
2660
|
+
style: {
|
|
2661
|
+
// cols: [output common][output channel][inputs…] rows: [in common][in channel][outputs…]
|
|
2662
|
+
gridTemplateColumns: `${COMMON_W} ${CHAN_W} repeat(${inputs.length}, ${CELL_W})`,
|
|
2663
|
+
gridTemplateRows: `${COMMON_H} ${CHAN_H} repeat(${outputs.length}, ${ROW_H})`,
|
|
2664
|
+
minWidth: "min-content"
|
|
2665
|
+
},
|
|
2666
|
+
children: [
|
|
2667
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2668
|
+
"div",
|
|
2669
|
+
{
|
|
2670
|
+
className: cls.mixerCorner,
|
|
2671
|
+
style: { top: 0, left: 0, gridColumn: "1 / span 2", gridRow: "1 / span 2" },
|
|
2672
|
+
children: "OUT \\ IN"
|
|
2673
|
+
}
|
|
2674
|
+
),
|
|
2675
|
+
inAxis.flatMap((it, ii) => {
|
|
2676
|
+
const col = 3 + ii;
|
|
2677
|
+
if (it.groupCommon !== void 0) {
|
|
2678
|
+
const nodes = [
|
|
2679
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2680
|
+
"div",
|
|
2681
|
+
{
|
|
2682
|
+
className: `${cls.mixerChrome} z-20 px-[0.2em]`,
|
|
2683
|
+
style: { top: 0, gridRow: "1 / span 2", gridColumn: col, alignItems: "flex-end", paddingBottom: "0.3em" },
|
|
2684
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "line-clamp-1", children: it.channelLabel })
|
|
2685
|
+
},
|
|
2686
|
+
`ich:${it.id}`
|
|
2687
|
+
)
|
|
2688
|
+
];
|
|
2689
|
+
if (it.groupStart) {
|
|
2690
|
+
nodes.unshift(
|
|
2691
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2692
|
+
"div",
|
|
2693
|
+
{
|
|
2694
|
+
className: `${cls.mixerChrome} z-25 px-[0.2em] font-semibold`,
|
|
2695
|
+
style: { top: 0, gridRow: 1, gridColumn: `${col} / span ${it.groupSpan}` },
|
|
2696
|
+
title: it.groupCommon,
|
|
2697
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "line-clamp-2", children: it.groupCommon })
|
|
2698
|
+
},
|
|
2699
|
+
`icc:${it.id}`
|
|
2700
|
+
)
|
|
2701
|
+
);
|
|
2702
|
+
}
|
|
2703
|
+
return nodes;
|
|
2704
|
+
}
|
|
2705
|
+
return [
|
|
2706
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2707
|
+
"div",
|
|
2708
|
+
{
|
|
2709
|
+
className: `${cls.mixerChrome} z-20 px-[0.2em]`,
|
|
2710
|
+
style: { top: 0, gridRow: "1 / span 2", gridColumn: col, alignItems: "center" },
|
|
2711
|
+
title: it.channelLabel,
|
|
2712
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "line-clamp-3", children: it.channelLabel })
|
|
2713
|
+
},
|
|
2714
|
+
`is:${it.id}`
|
|
2715
|
+
)
|
|
2716
|
+
];
|
|
2717
|
+
}),
|
|
2718
|
+
outAxis.flatMap((it, oo) => {
|
|
2719
|
+
const row = 3 + oo;
|
|
2720
|
+
if (it.groupCommon !== void 0) {
|
|
2721
|
+
const nodes = [
|
|
2722
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2723
|
+
"div",
|
|
2724
|
+
{
|
|
2725
|
+
className: `${cls.mixerChrome} z-20`,
|
|
2726
|
+
style: { left: 0, gridColumn: "1 / span 2", gridRow: row, justifyContent: "flex-end", paddingRight: "0.6em" },
|
|
2727
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "line-clamp-1", children: it.channelLabel })
|
|
2728
|
+
},
|
|
2729
|
+
`och:${it.id}`
|
|
2730
|
+
)
|
|
2731
|
+
];
|
|
2732
|
+
if (it.groupStart) {
|
|
2733
|
+
nodes.unshift(
|
|
2734
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2735
|
+
"div",
|
|
2736
|
+
{
|
|
2737
|
+
className: `${cls.mixerChrome} z-25 justify-start px-[0.4em] font-semibold`,
|
|
2738
|
+
style: { left: 0, gridColumn: 1, gridRow: `${row} / span ${it.groupSpan}` },
|
|
2739
|
+
title: it.groupCommon,
|
|
2740
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "line-clamp-2 text-left", children: it.groupCommon })
|
|
2741
|
+
},
|
|
2742
|
+
`occ:${it.id}`
|
|
2743
|
+
)
|
|
2744
|
+
);
|
|
2745
|
+
}
|
|
2746
|
+
return nodes;
|
|
2747
|
+
}
|
|
2748
|
+
return [
|
|
2749
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2750
|
+
"div",
|
|
2751
|
+
{
|
|
2752
|
+
className: `${cls.mixerChrome} z-20 justify-start px-[0.4em]`,
|
|
2753
|
+
style: { left: 0, gridColumn: "1 / span 2", gridRow: row },
|
|
2754
|
+
title: it.channelLabel,
|
|
2755
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "line-clamp-2 text-left", children: it.channelLabel })
|
|
2756
|
+
},
|
|
2757
|
+
`os:${it.id}`
|
|
2758
|
+
)
|
|
2759
|
+
];
|
|
2760
|
+
}),
|
|
2761
|
+
outputs.map(
|
|
2762
|
+
(o, oo) => inputs.map((i, ii) => {
|
|
2763
|
+
const on = isOn(o.id, i.id);
|
|
2764
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2765
|
+
"div",
|
|
2766
|
+
{
|
|
2767
|
+
"data-cell": true,
|
|
2768
|
+
"data-in": i.id,
|
|
2769
|
+
"data-out": o.id,
|
|
2770
|
+
className: `${cls.cell} ${on ? cls.cellOn : cls.cellOff}`,
|
|
2771
|
+
style: { gridColumn: 3 + ii, gridRow: 3 + oo },
|
|
2772
|
+
children: on && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(CrosspointOnIcon, { icon: icons.crosspointOn })
|
|
2773
|
+
},
|
|
2774
|
+
`x:${i.id}:${o.id}`
|
|
2775
|
+
);
|
|
2776
|
+
})
|
|
2777
|
+
)
|
|
2778
|
+
]
|
|
2779
|
+
}
|
|
2780
|
+
)
|
|
2781
|
+
}
|
|
2782
|
+
);
|
|
2783
|
+
}
|
|
2784
|
+
|
|
2785
|
+
// src/components/dsp/DspPresets.tsx
|
|
2786
|
+
var import_react8 = require("react");
|
|
2787
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
2788
|
+
var HOLD_MS = 2e3;
|
|
2789
|
+
var SAVED_MS = 1e3;
|
|
2790
|
+
function PresetButton({ num, name, active, onCall, onSave, cls }) {
|
|
2791
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2792
|
+
CrisButton,
|
|
2793
|
+
{
|
|
2794
|
+
onTap: onCall,
|
|
2795
|
+
onLongPress: onSave,
|
|
2796
|
+
holdMs: HOLD_MS,
|
|
2797
|
+
selected: active,
|
|
2798
|
+
className: cls.preset,
|
|
2799
|
+
classActive: cls.presetActive,
|
|
2800
|
+
classPressed: cls.presetPressed,
|
|
2801
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "flex items-center justify-center gap-[0.5em]", children: [
|
|
2802
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-[1.6em] font-bold leading-none", children: num }),
|
|
2803
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-[1.2em] leading-none", children: name })
|
|
2804
|
+
] })
|
|
2805
|
+
}
|
|
2806
|
+
);
|
|
2807
|
+
}
|
|
2808
|
+
function DspPresets({
|
|
2809
|
+
oid,
|
|
2810
|
+
send,
|
|
2811
|
+
presets,
|
|
2812
|
+
activeDevice,
|
|
2813
|
+
activeLocal,
|
|
2814
|
+
sustainedFeedback = true,
|
|
2815
|
+
cls
|
|
2816
|
+
}) {
|
|
2817
|
+
const [saved, setSaved] = (0, import_react8.useState)(false);
|
|
2818
|
+
const savedTimer = (0, import_react8.useRef)(null);
|
|
2819
|
+
const call = (id) => send(oid, { action: "preset.call", value: id });
|
|
2820
|
+
const save = (id) => {
|
|
2821
|
+
send(oid, { action: "preset.save", value: id });
|
|
2822
|
+
setSaved(true);
|
|
2823
|
+
if (savedTimer.current !== null) clearTimeout(savedTimer.current);
|
|
2824
|
+
savedTimer.current = window.setTimeout(() => setSaved(false), SAVED_MS);
|
|
2825
|
+
};
|
|
2826
|
+
const isActive = (p) => {
|
|
2827
|
+
if (!sustainedFeedback) return false;
|
|
2828
|
+
return p.kind === "local" ? activeLocal === p.id : activeDevice === p.id;
|
|
2829
|
+
};
|
|
2830
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: cls.presetWrap, children: [
|
|
2831
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: cls.presetLabel, children: "Preset" }),
|
|
2832
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "relative flex-1 flex items-stretch gap-[0.3em] mt-[0.25em]", children: [
|
|
2833
|
+
presets.map((p) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2834
|
+
PresetButton,
|
|
2835
|
+
{
|
|
2836
|
+
num: p.id,
|
|
2837
|
+
name: p.name,
|
|
2838
|
+
active: isActive(p),
|
|
2839
|
+
onCall: () => call(p.id),
|
|
2840
|
+
onSave: p.saveAllowed === false ? void 0 : () => save(p.id),
|
|
2841
|
+
cls
|
|
2842
|
+
},
|
|
2843
|
+
p.id
|
|
2844
|
+
)),
|
|
2845
|
+
saved && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: cls.savedFlash, children: "Saved" })
|
|
2846
|
+
] })
|
|
2847
|
+
] });
|
|
2848
|
+
}
|
|
2849
|
+
|
|
2850
|
+
// src/components/dsp/dspClasses.ts
|
|
2851
|
+
var DSP_CLASS_DEFAULTS = {
|
|
2852
|
+
root: "w-full h-full flex flex-col",
|
|
2853
|
+
header: "relative w-full flex items-end justify-center gap-[0.3em] px-[1em] pt-[0.5em]",
|
|
2854
|
+
content: "w-full flex-1 min-h-0",
|
|
2855
|
+
tab: "w-[10.5em] h-[3.25em] rounded-b-none rounded-lg flex items-center justify-center transition-colors bg-[#4f5152] text-white text-[1.4em] font-bold",
|
|
2856
|
+
tabActive: "bg-[#007ca0]",
|
|
2857
|
+
message: "w-full h-full flex items-center justify-center text-gray-400 text-[2em]",
|
|
2858
|
+
presetWrap: "absolute left-[1em] bottom-[0.3em] h-[4.5em] flex flex-col items-center",
|
|
2859
|
+
presetLabel: "text-[#4f5152] text-[1.4em] leading-none",
|
|
2860
|
+
preset: "w-[8em] h-full rounded-lg flex items-center justify-center transition-colors bg-[#4f5152] text-white",
|
|
2861
|
+
presetActive: "bg-[#007ca0]",
|
|
2862
|
+
presetPressed: "bg-[#006080]",
|
|
2863
|
+
savedFlash: "absolute inset-0 flex items-center justify-center rounded bg-[#22c55e] text-white text-[1.2em] font-bold pointer-events-none",
|
|
2864
|
+
strip: "flex flex-col items-center gap-[0.4em] h-full w-[9em] flex-none px-[0.3em]",
|
|
2865
|
+
stripLabel: "text-[#4f5152] text-center leading-tight text-[1.1em] line-clamp-3",
|
|
2866
|
+
levelReadout: "text-[1.1em] text-[#4f5152] leading-none opacity-70 mt-[0.5em]",
|
|
2867
|
+
faderBar: "bg-[#c0c0c0] rounded",
|
|
2868
|
+
faderFill: "bg-[#007ca0] rounded",
|
|
2869
|
+
faderThumb: "bg-[#4f5152] rounded",
|
|
2870
|
+
mute: "w-full h-full rounded-lg flex items-center justify-center transition-colors bg-[#4f5152] text-white",
|
|
2871
|
+
muteActive: "bg-[#dc2626] text-white",
|
|
2872
|
+
mixerCorner: "sticky z-30 flex items-center justify-center bg-[#282C34] text-[#4f5152] text-[1.1em] font-bold border border-black/30",
|
|
2873
|
+
mixerChrome: "sticky flex items-center justify-center text-center bg-[#282C34] text-white text-[1.1em] leading-tight border border-black/30",
|
|
2874
|
+
cell: "z-10 flex items-center justify-center border border-black/30",
|
|
2875
|
+
cellOn: "bg-[#22c55e]",
|
|
2876
|
+
cellOff: "bg-[#4f5152]"
|
|
2877
|
+
};
|
|
2878
|
+
var DSP_ICON_DEFAULTS = {
|
|
2879
|
+
crosspointOn: "audio-volume-ok",
|
|
2880
|
+
muteOff: "audio-volume-high",
|
|
2881
|
+
muteOn: "audio-volume-mute",
|
|
2882
|
+
muteOffFilter: "invert(65%) sepia(70%) saturate(500%) hue-rotate(80deg) brightness(110%) contrast(95%)",
|
|
2883
|
+
muteOnFilter: "brightness(0) invert(1)"
|
|
2884
|
+
};
|
|
2885
|
+
function mergeDefined(defaults4, overrides) {
|
|
2886
|
+
if (!overrides) return { ...defaults4 };
|
|
2887
|
+
const out = { ...defaults4 };
|
|
2888
|
+
Object.keys(overrides).forEach((k) => {
|
|
2889
|
+
const v = overrides[k];
|
|
2890
|
+
if (v !== void 0) out[k] = v;
|
|
2891
|
+
});
|
|
2892
|
+
return out;
|
|
2893
|
+
}
|
|
2894
|
+
function resolveDspClasses(classes) {
|
|
2895
|
+
return mergeDefined(DSP_CLASS_DEFAULTS, classes);
|
|
2896
|
+
}
|
|
2897
|
+
function resolveDspIcons(icons) {
|
|
2898
|
+
return mergeDefined(DSP_ICON_DEFAULTS, icons);
|
|
2899
|
+
}
|
|
2900
|
+
|
|
2901
|
+
// src/components/dsp/CrisViewDspFull.tsx
|
|
2902
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
2903
|
+
function CrisViewDspFull({
|
|
2904
|
+
oid,
|
|
2905
|
+
presets,
|
|
2906
|
+
skipShowInput,
|
|
2907
|
+
skipShowOutput,
|
|
2908
|
+
skipCrosspoints = false,
|
|
2909
|
+
sustainedPresetFeedback = true,
|
|
2910
|
+
classes,
|
|
2911
|
+
icons,
|
|
2912
|
+
className,
|
|
2913
|
+
initialTab = "in"
|
|
2914
|
+
}) {
|
|
2915
|
+
const safeInitial = initialTab === "mix" && skipCrosspoints ? "in" : initialTab;
|
|
2916
|
+
const [tab, setTab] = (0, import_react9.useState)(safeInitial);
|
|
2917
|
+
const status = (0, import_cris_webui_ch5_core11.useCustomObject)(oid, { subscribe: true });
|
|
2918
|
+
const send = (0, import_cris_webui_ch5_core11.useCustomObjectSend)();
|
|
2919
|
+
const cls = resolveDspClasses(classes);
|
|
2920
|
+
const ic = resolveDspIcons(icons);
|
|
2921
|
+
const tabs = [
|
|
2922
|
+
{ id: "in", label: "Inputs" },
|
|
2923
|
+
...skipCrosspoints ? [] : [{ id: "mix", label: "Mixer" }],
|
|
2924
|
+
{ id: "out", label: "Outputs" }
|
|
2925
|
+
];
|
|
2926
|
+
const hasPresets = !!presets && presets.length > 0;
|
|
2927
|
+
const activeDevice = status?.pr?.dv ?? status?.ps?.dv;
|
|
2928
|
+
const activeLocal = status?.pr?.lc ?? status?.ps?.lc;
|
|
2929
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: `${cls.root} ${className ?? ""}`, children: [
|
|
2930
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: cls.header, children: [
|
|
2931
|
+
hasPresets && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2932
|
+
DspPresets,
|
|
2933
|
+
{
|
|
2934
|
+
oid,
|
|
2935
|
+
send,
|
|
2936
|
+
presets,
|
|
2937
|
+
activeDevice,
|
|
2938
|
+
activeLocal,
|
|
2939
|
+
sustainedFeedback: sustainedPresetFeedback,
|
|
2940
|
+
cls
|
|
2941
|
+
}
|
|
2942
|
+
),
|
|
2943
|
+
tabs.map((t) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2944
|
+
CrisButton,
|
|
2945
|
+
{
|
|
2946
|
+
text: t.label,
|
|
2947
|
+
selected: tab === t.id,
|
|
2948
|
+
onPress: () => setTab(t.id),
|
|
2949
|
+
className: cls.tab,
|
|
2950
|
+
classActive: cls.tabActive
|
|
2951
|
+
},
|
|
2952
|
+
t.id
|
|
2953
|
+
)),
|
|
2954
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(CrisViewComm, { comm: status?.cm, className: "absolute right-[1em] bottom-[0.3em] text-[1.25em]" })
|
|
2955
|
+
] }),
|
|
2956
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: cls.content, children: status === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: cls.message, children: "Conectando\u2026" }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
|
|
2957
|
+
tab === "in" && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2958
|
+
DspIoPage,
|
|
2959
|
+
{
|
|
2960
|
+
status,
|
|
2961
|
+
io: "in",
|
|
2962
|
+
oid,
|
|
2963
|
+
send,
|
|
2964
|
+
skip: skipShowInput,
|
|
2965
|
+
cls,
|
|
2966
|
+
icons: ic,
|
|
2967
|
+
emptyLabel: "Sin entradas"
|
|
2968
|
+
}
|
|
2969
|
+
),
|
|
2970
|
+
tab === "mix" && !skipCrosspoints && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DspMixer, { status, oid, send, cls, icons: ic }),
|
|
2971
|
+
tab === "out" && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2972
|
+
DspIoPage,
|
|
2973
|
+
{
|
|
2974
|
+
status,
|
|
2975
|
+
io: "out",
|
|
2976
|
+
oid,
|
|
2977
|
+
send,
|
|
2978
|
+
skip: skipShowOutput,
|
|
2979
|
+
cls,
|
|
2980
|
+
icons: ic,
|
|
2981
|
+
emptyLabel: "Sin salidas"
|
|
2982
|
+
}
|
|
2983
|
+
)
|
|
2984
|
+
] }) })
|
|
2985
|
+
] });
|
|
2986
|
+
}
|
|
2162
2987
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2163
2988
|
0 && (module.exports = {
|
|
2164
2989
|
CrisButton,
|
|
@@ -2171,9 +2996,18 @@ function CrisCoMatrixListsTie({
|
|
|
2171
2996
|
CrisSpinner,
|
|
2172
2997
|
CrisText,
|
|
2173
2998
|
CrisTextInput,
|
|
2999
|
+
CrisViewComm,
|
|
3000
|
+
CrisViewDspFull,
|
|
3001
|
+
buildMixerAxis,
|
|
3002
|
+
clampLevel,
|
|
3003
|
+
collapseStrips,
|
|
3004
|
+
commIndicators,
|
|
2174
3005
|
configureIcons,
|
|
2175
3006
|
getIconConfig,
|
|
2176
3007
|
getIconFilter,
|
|
2177
|
-
getIconUrl
|
|
3008
|
+
getIconUrl,
|
|
3009
|
+
levelToPercent,
|
|
3010
|
+
linksFor,
|
|
3011
|
+
normalizeLinked
|
|
2178
3012
|
});
|
|
2179
3013
|
//# sourceMappingURL=index.js.map
|