@imperosoft/cris-webui-components 1.1.2-beta.2 → 1.1.2-beta.20

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.mjs CHANGED
@@ -100,6 +100,8 @@ function CrisButton({
100
100
  const pressedRef = useRef(false);
101
101
  const touchingRef = useRef(false);
102
102
  const touchStartedHereRef = useRef(false);
103
+ const touchStartYRef = useRef(0);
104
+ const touchMovedRef = useRef(false);
103
105
  const feedbackJoin = joinFeedback ?? join;
104
106
  const feedback = useDigital(feedbackJoin ?? 0);
105
107
  const enabledJoin = useDigital(joinEnable ?? 0);
@@ -182,30 +184,42 @@ function CrisButton({
182
184
  dSet(join, false);
183
185
  }
184
186
  };
185
- const handleTouchStart = () => {
187
+ const SCROLL_THRESHOLD = 8;
188
+ const handleTouchStart = (e) => {
186
189
  log("handleTouchStart");
187
190
  touchStart();
188
191
  touchingRef.current = true;
189
192
  touchStartedHereRef.current = true;
190
- handlePress();
193
+ touchMovedRef.current = false;
194
+ touchStartYRef.current = e.touches[0]?.clientY ?? 0;
195
+ };
196
+ const handleTouchMove = (e) => {
197
+ if (touchMovedRef.current) return;
198
+ const dy = Math.abs((e.touches[0]?.clientY ?? 0) - touchStartYRef.current);
199
+ if (dy > SCROLL_THRESHOLD) {
200
+ touchMovedRef.current = true;
201
+ log("touchMove: scroll detected, dy:", dy);
202
+ }
191
203
  };
192
204
  const handleTouchEnd = () => {
193
- log("handleTouchEnd", { touchStartedHereRef: touchStartedHereRef.current });
205
+ log("handleTouchEnd", { touchStartedHere: touchStartedHereRef.current, moved: touchMovedRef.current });
194
206
  touchEnd();
195
207
  touchingRef.current = true;
196
- if (touchStartedHereRef.current) {
208
+ if (touchStartedHereRef.current && !touchMovedRef.current) {
197
209
  touchStartedHereRef.current = false;
210
+ handlePress();
198
211
  handleRelease();
199
212
  } else {
200
- log("SKIPPED handleRelease: touch did not start here");
213
+ touchStartedHereRef.current = false;
214
+ log("SKIPPED: touch moved or did not start here");
201
215
  }
202
216
  };
203
217
  const handleTouchCancel = () => {
204
- log("handleTouchCancel");
218
+ log("handleTouchCancel (scroll detected)");
205
219
  touchEnd();
206
220
  touchingRef.current = true;
207
221
  touchStartedHereRef.current = false;
208
- handleRelease();
222
+ touchMovedRef.current = false;
209
223
  };
210
224
  const handleMouseDown = () => {
211
225
  if (isTouchActive() || touchingRef.current) return;
@@ -306,7 +320,7 @@ function CrisButton({
306
320
  cursor: suppressKeyClicks ? "default" : "pointer",
307
321
  position: isFreePositioned ? void 0 : "relative",
308
322
  overflow: isFreePositioned ? void 0 : "hidden",
309
- touchAction: "none",
323
+ touchAction: "pan-x pan-y",
310
324
  userSelect: "none",
311
325
  WebkitUserSelect: "none"
312
326
  },
@@ -314,6 +328,7 @@ function CrisButton({
314
328
  onMouseUp: handleMouseUp,
315
329
  onMouseLeave: handleMouseLeave,
316
330
  onTouchStart: handleTouchStart,
331
+ onTouchMove: handleTouchMove,
317
332
  onTouchEnd: handleTouchEnd,
318
333
  onTouchCancel: handleTouchCancel,
319
334
  children: [
@@ -1291,9 +1306,401 @@ function CrisCoDebug({
1291
1306
  }
1292
1307
  );
1293
1308
  }
1309
+
1310
+ // src/components/CrisCoMatrixListsTie.tsx
1311
+ import { useCustomObject as useCustomObject2, useCustomObjectSend as useCustomObjectSend2 } from "@imperosoft/cris-webui-ch5-core";
1312
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
1313
+ var colors = {
1314
+ itemBg: "#4f5152",
1315
+ itemActiveBg: "#007ca0",
1316
+ vmActiveBg: "#dc2626",
1317
+ text: "#ffffff",
1318
+ headerText: "#6b7280",
1319
+ ioOn: "#4caf50",
1320
+ ioOff: "#f44336",
1321
+ sgOn: "#2196f3",
1322
+ sgOff: "#666666"
1323
+ };
1324
+ var defaults = {
1325
+ container: {
1326
+ display: "flex",
1327
+ flexDirection: "row",
1328
+ gap: "1.5rem",
1329
+ padding: "1rem 2rem",
1330
+ height: "100%",
1331
+ width: "100%"
1332
+ },
1333
+ list: {
1334
+ flex: 1,
1335
+ display: "flex",
1336
+ flexDirection: "column",
1337
+ overflow: "hidden",
1338
+ minHeight: 0
1339
+ },
1340
+ header: {
1341
+ fontSize: "1.5em",
1342
+ fontWeight: 700,
1343
+ padding: "0.5rem 0.75rem",
1344
+ textTransform: "uppercase",
1345
+ letterSpacing: "0.05em",
1346
+ color: colors.headerText,
1347
+ flexShrink: 0,
1348
+ textAlign: "center"
1349
+ },
1350
+ scroll: {
1351
+ flex: 1,
1352
+ minHeight: 0,
1353
+ overflow: "auto",
1354
+ scrollbarWidth: "none",
1355
+ WebkitOverflowScrolling: "touch",
1356
+ display: "flex",
1357
+ flexDirection: "column",
1358
+ gap: "0.15rem"
1359
+ },
1360
+ item: {
1361
+ display: "flex",
1362
+ alignItems: "stretch",
1363
+ gap: "0.5rem",
1364
+ padding: "0 0.4rem 0 0",
1365
+ minHeight: "3.7rem",
1366
+ cursor: "pointer",
1367
+ userSelect: "none",
1368
+ background: colors.itemBg,
1369
+ borderRadius: "0.5rem",
1370
+ transition: "background 0.15s"
1371
+ },
1372
+ itemActive: {
1373
+ background: colors.itemActiveBg
1374
+ },
1375
+ itemBtn: {
1376
+ flex: 1,
1377
+ minWidth: 0,
1378
+ display: "flex",
1379
+ alignItems: "stretch",
1380
+ background: "transparent",
1381
+ border: "none",
1382
+ textAlign: "left",
1383
+ color: colors.text,
1384
+ height: "100%",
1385
+ borderRadius: "0.5rem",
1386
+ cursor: "pointer"
1387
+ },
1388
+ itemBtnInner: {
1389
+ display: "flex",
1390
+ alignItems: "center",
1391
+ gap: "0.4rem",
1392
+ width: "100%",
1393
+ flex: 1,
1394
+ padding: "0.5rem 0.9rem"
1395
+ },
1396
+ channelNum: {
1397
+ flexShrink: 0,
1398
+ opacity: 0.6,
1399
+ minWidth: "1.7em",
1400
+ textAlign: "right",
1401
+ fontWeight: 400,
1402
+ marginRight: "0.4em"
1403
+ },
1404
+ itemLabel: {
1405
+ flex: 1,
1406
+ fontSize: "1.4em",
1407
+ fontWeight: 700,
1408
+ whiteSpace: "nowrap",
1409
+ overflow: "hidden",
1410
+ textOverflow: "ellipsis",
1411
+ color: colors.text
1412
+ },
1413
+ indicators: {
1414
+ display: "flex",
1415
+ gap: "0.25rem",
1416
+ alignItems: "center"
1417
+ },
1418
+ indicator: {
1419
+ width: "1rem",
1420
+ height: "1rem",
1421
+ borderRadius: "50%",
1422
+ flexShrink: 0
1423
+ },
1424
+ vmBtn: {
1425
+ flexShrink: 0,
1426
+ alignSelf: "stretch",
1427
+ display: "flex",
1428
+ alignItems: "center",
1429
+ background: colors.itemBg,
1430
+ color: colors.text,
1431
+ border: "none",
1432
+ borderRadius: "0.4rem",
1433
+ padding: "0 0.6rem",
1434
+ margin: "0.3rem 0.3rem 0.3rem 0",
1435
+ fontSize: "0.85em",
1436
+ fontWeight: 700,
1437
+ cursor: "pointer",
1438
+ transition: "background 0.15s"
1439
+ },
1440
+ vmBtnActive: {
1441
+ background: colors.vmActiveBg,
1442
+ color: colors.text
1443
+ }
1444
+ };
1445
+ var INJECTED_CSS = `
1446
+ .cris-co-matrix-scroll::-webkit-scrollbar { display: none; }
1447
+ .cris-co-matrix-item > div:first-child > .cris-button { width: 100%; height: 100%; }
1448
+ `;
1449
+ var scrollbarStyleInjected = false;
1450
+ function injectScrollbarStyle() {
1451
+ if (scrollbarStyleInjected) return;
1452
+ scrollbarStyleInjected = true;
1453
+ const style = document.createElement("style");
1454
+ style.textContent = INJECTED_CSS;
1455
+ document.head.appendChild(style);
1456
+ }
1457
+ function DefaultIoIndicator({ on }) {
1458
+ return /* @__PURE__ */ jsx8(
1459
+ "div",
1460
+ {
1461
+ style: {
1462
+ ...defaults.indicator,
1463
+ backgroundColor: on ? colors.ioOn : colors.ioOff
1464
+ },
1465
+ title: on ? "Online" : "Offline"
1466
+ }
1467
+ );
1468
+ }
1469
+ function DefaultSignalIndicator({ on }) {
1470
+ return /* @__PURE__ */ jsx8(
1471
+ "div",
1472
+ {
1473
+ style: {
1474
+ ...defaults.indicator,
1475
+ backgroundColor: on ? colors.sgOn : colors.sgOff
1476
+ },
1477
+ title: on ? "Signal detected" : "No signal"
1478
+ }
1479
+ );
1480
+ }
1481
+ function MatrixItemRow({
1482
+ item,
1483
+ type,
1484
+ active,
1485
+ showChannels,
1486
+ vmText,
1487
+ onSelect,
1488
+ onToggleVideoMute,
1489
+ itemClassName,
1490
+ itemStyle: itemStyleProp,
1491
+ itemActiveClassName,
1492
+ itemActiveStyle,
1493
+ itemDisabledClassName,
1494
+ vmButtonClassName,
1495
+ vmButtonActiveClassName,
1496
+ renderIoIndicator,
1497
+ renderSignalIndicator
1498
+ }) {
1499
+ const isActive = active;
1500
+ const isEnabled = item.sl.en;
1501
+ const useDefaults = !itemClassName;
1502
+ const classes = [
1503
+ "cris-co-matrix-item",
1504
+ itemClassName,
1505
+ isActive && (itemActiveClassName || "active"),
1506
+ !isEnabled && (itemDisabledClassName || "disabled")
1507
+ ].filter(Boolean).join(" ");
1508
+ const computedStyle = useDefaults ? {
1509
+ ...defaults.item,
1510
+ ...itemStyleProp,
1511
+ ...isActive ? { ...defaults.itemActive, ...itemActiveStyle } : void 0,
1512
+ opacity: isEnabled ? 1 : 0.4
1513
+ } : { ...itemStyleProp };
1514
+ return /* @__PURE__ */ jsxs7("div", { className: classes, style: computedStyle, children: [
1515
+ useDefaults ? /* @__PURE__ */ jsx8("div", { style: defaults.itemBtn, children: /* @__PURE__ */ jsx8(
1516
+ CrisButton,
1517
+ {
1518
+ selected: isActive,
1519
+ enabled: isEnabled,
1520
+ onPress: onSelect,
1521
+ showLocalFeedback: false,
1522
+ children: /* @__PURE__ */ jsxs7("div", { style: defaults.itemBtnInner, children: [
1523
+ showChannels && /* @__PURE__ */ jsx8("span", { className: "cris-co-matrix-ch", style: defaults.channelNum, children: item.id }),
1524
+ /* @__PURE__ */ jsx8("span", { style: defaults.itemLabel, children: item.lb || `${type === "input" ? "Input" : "Output"} ${item.id}` }),
1525
+ /* @__PURE__ */ jsxs7("div", { style: defaults.indicators, children: [
1526
+ item.io.vs && (renderIoIndicator ? renderIoIndicator(item.io.on) : /* @__PURE__ */ jsx8(DefaultIoIndicator, { on: item.io.on })),
1527
+ item.sg.vs && (renderSignalIndicator ? renderSignalIndicator(item.sg.on) : /* @__PURE__ */ jsx8(DefaultSignalIndicator, { on: item.sg.on }))
1528
+ ] })
1529
+ ] })
1530
+ }
1531
+ ) }) : /* @__PURE__ */ jsx8(
1532
+ CrisButton,
1533
+ {
1534
+ selected: isActive,
1535
+ enabled: isEnabled,
1536
+ onPress: onSelect,
1537
+ className: `cris-co-matrix-item-btn ${itemActiveClassName ?? ""}`,
1538
+ classActive: itemActiveClassName,
1539
+ children: /* @__PURE__ */ jsxs7("div", { style: { display: "flex", alignItems: "center", gap: "0.4rem", width: "100%" }, children: [
1540
+ showChannels && /* @__PURE__ */ jsx8("span", { className: "cris-co-matrix-ch", style: { flexShrink: 0, opacity: 0.6 }, children: item.id }),
1541
+ /* @__PURE__ */ jsx8("span", { style: { flex: 1, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }, children: item.lb || `${type === "input" ? "Input" : "Output"} ${item.id}` }),
1542
+ /* @__PURE__ */ jsxs7("div", { style: defaults.indicators, children: [
1543
+ item.io.vs && (renderIoIndicator ? renderIoIndicator(item.io.on) : /* @__PURE__ */ jsx8(DefaultIoIndicator, { on: item.io.on })),
1544
+ item.sg.vs && (renderSignalIndicator ? renderSignalIndicator(item.sg.on) : /* @__PURE__ */ jsx8(DefaultSignalIndicator, { on: item.sg.on }))
1545
+ ] })
1546
+ ] })
1547
+ }
1548
+ ),
1549
+ item.vm.vs && (useDefaults && !vmButtonClassName ? /* @__PURE__ */ jsx8("div", { style: {
1550
+ ...defaults.vmBtn,
1551
+ ...item.vm.on ? defaults.vmBtnActive : void 0,
1552
+ opacity: item.vm.en ? 1 : 0.4,
1553
+ pointerEvents: item.vm.en ? "auto" : "none"
1554
+ }, children: /* @__PURE__ */ jsx8(
1555
+ CrisButton,
1556
+ {
1557
+ selected: item.vm.on,
1558
+ enabled: item.vm.en,
1559
+ text: vmText,
1560
+ onPress: onToggleVideoMute,
1561
+ showLocalFeedback: false
1562
+ }
1563
+ ) }) : /* @__PURE__ */ jsx8(
1564
+ CrisButton,
1565
+ {
1566
+ selected: item.vm.on,
1567
+ enabled: item.vm.en,
1568
+ text: vmText,
1569
+ onPress: onToggleVideoMute,
1570
+ className: vmButtonClassName,
1571
+ classActive: vmButtonActiveClassName
1572
+ }
1573
+ ))
1574
+ ] });
1575
+ }
1576
+ function CrisCoMatrixListsTie({
1577
+ oid,
1578
+ inputTitle = "Inputs",
1579
+ outputTitle = "Outputs",
1580
+ showChannels = true,
1581
+ className,
1582
+ style,
1583
+ listClassName,
1584
+ listStyle,
1585
+ headerClassName,
1586
+ headerStyle,
1587
+ itemClassName,
1588
+ itemStyle,
1589
+ itemActiveClassName,
1590
+ itemActiveStyle,
1591
+ itemDisabledClassName,
1592
+ vmText = "Mute",
1593
+ vmButtonClassName,
1594
+ vmButtonActiveClassName,
1595
+ renderIoIndicator,
1596
+ renderSignalIndicator
1597
+ }) {
1598
+ const matrix = useCustomObject2(oid);
1599
+ const send = useCustomObjectSend2();
1600
+ injectScrollbarStyle();
1601
+ if (!matrix) return null;
1602
+ const { si, ip: inputs, op: outputs } = matrix;
1603
+ const handleSelectInput = (id) => {
1604
+ send(oid, { action: "selectInput", id });
1605
+ };
1606
+ const handleTie = (id) => {
1607
+ send(oid, { action: "tie", id });
1608
+ };
1609
+ const handleToggleVideoMute = (type, id) => {
1610
+ send(oid, { action: "toggleVideoMute", type, id });
1611
+ };
1612
+ return /* @__PURE__ */ jsxs7(
1613
+ "div",
1614
+ {
1615
+ className,
1616
+ style: className ? style : { ...defaults.container, ...style },
1617
+ children: [
1618
+ /* @__PURE__ */ jsxs7(
1619
+ "div",
1620
+ {
1621
+ className: listClassName,
1622
+ style: listClassName ? listStyle : { ...defaults.list, ...listStyle },
1623
+ children: [
1624
+ /* @__PURE__ */ jsx8(
1625
+ "div",
1626
+ {
1627
+ className: headerClassName,
1628
+ style: headerClassName ? headerStyle : { ...defaults.header, ...headerStyle },
1629
+ children: inputTitle
1630
+ }
1631
+ ),
1632
+ /* @__PURE__ */ jsx8("div", { className: "cris-co-matrix-scroll", style: defaults.scroll, children: inputs?.map((item) => /* @__PURE__ */ jsx8(
1633
+ MatrixItemRow,
1634
+ {
1635
+ item,
1636
+ type: "input",
1637
+ active: si === item.id,
1638
+ showChannels,
1639
+ vmText,
1640
+ onSelect: () => handleSelectInput(item.id),
1641
+ onToggleVideoMute: () => handleToggleVideoMute("input", item.id),
1642
+ itemClassName,
1643
+ itemStyle,
1644
+ itemActiveClassName,
1645
+ itemActiveStyle,
1646
+ itemDisabledClassName,
1647
+ vmButtonClassName,
1648
+ vmButtonActiveClassName,
1649
+ renderIoIndicator,
1650
+ renderSignalIndicator
1651
+ },
1652
+ item.id
1653
+ )) })
1654
+ ]
1655
+ }
1656
+ ),
1657
+ /* @__PURE__ */ jsxs7(
1658
+ "div",
1659
+ {
1660
+ className: listClassName,
1661
+ style: listClassName ? listStyle : { ...defaults.list, ...listStyle },
1662
+ children: [
1663
+ /* @__PURE__ */ jsx8(
1664
+ "div",
1665
+ {
1666
+ className: headerClassName,
1667
+ style: headerClassName ? headerStyle : { ...defaults.header, ...headerStyle },
1668
+ children: outputTitle
1669
+ }
1670
+ ),
1671
+ /* @__PURE__ */ jsx8("div", { className: "cris-co-matrix-scroll", style: defaults.scroll, children: outputs?.map((item) => /* @__PURE__ */ jsx8(
1672
+ MatrixItemRow,
1673
+ {
1674
+ item,
1675
+ type: "output",
1676
+ active: item.ti === si,
1677
+ showChannels,
1678
+ vmText,
1679
+ onSelect: () => handleTie(item.id),
1680
+ onToggleVideoMute: () => handleToggleVideoMute("output", item.id),
1681
+ itemClassName,
1682
+ itemStyle,
1683
+ itemActiveClassName,
1684
+ itemActiveStyle,
1685
+ itemDisabledClassName,
1686
+ vmButtonClassName,
1687
+ vmButtonActiveClassName,
1688
+ renderIoIndicator,
1689
+ renderSignalIndicator
1690
+ },
1691
+ item.id
1692
+ )) })
1693
+ ]
1694
+ }
1695
+ )
1696
+ ]
1697
+ }
1698
+ );
1699
+ }
1294
1700
  export {
1295
1701
  CrisButton,
1296
1702
  CrisCoDebug,
1703
+ CrisCoMatrixListsTie,
1297
1704
  CrisGauge,
1298
1705
  CrisOfflinePage,
1299
1706
  CrisSlider,