@imperosoft/cris-webui-components 1.1.2-beta.9 → 1.1.2

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: [
@@ -1295,12 +1310,25 @@ function CrisCoDebug({
1295
1310
  // src/components/CrisCoMatrixListsTie.tsx
1296
1311
  import { useCustomObject as useCustomObject2, useCustomObjectSend as useCustomObjectSend2 } from "@imperosoft/cris-webui-ch5-core";
1297
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
+ };
1298
1324
  var defaults = {
1299
1325
  container: {
1300
1326
  display: "flex",
1301
1327
  flexDirection: "row",
1302
- gap: 8,
1303
- height: "100%"
1328
+ gap: "1.5rem",
1329
+ padding: "1rem 2rem",
1330
+ height: "100%",
1331
+ width: "100%"
1304
1332
  },
1305
1333
  list: {
1306
1334
  flex: 1,
@@ -1310,57 +1338,129 @@ var defaults = {
1310
1338
  minHeight: 0
1311
1339
  },
1312
1340
  header: {
1313
- fontSize: 13,
1314
- fontWeight: 600,
1315
- padding: "6px 10px",
1341
+ fontSize: "1.5em",
1342
+ fontWeight: 700,
1343
+ padding: "0.5rem 0.75rem",
1316
1344
  textTransform: "uppercase",
1317
- opacity: 0.6,
1318
- flexShrink: 0
1345
+ letterSpacing: "0.05em",
1346
+ color: colors.headerText,
1347
+ flexShrink: 0,
1348
+ textAlign: "center"
1319
1349
  },
1320
1350
  scroll: {
1321
1351
  flex: 1,
1322
1352
  minHeight: 0,
1323
1353
  overflow: "auto",
1354
+ scrollbarWidth: "none",
1324
1355
  WebkitOverflowScrolling: "touch",
1325
1356
  display: "flex",
1326
1357
  flexDirection: "column",
1327
- gap: 2
1358
+ gap: "0.15rem"
1328
1359
  },
1329
1360
  item: {
1330
1361
  display: "flex",
1331
- alignItems: "center",
1332
- gap: 6,
1333
- padding: "6px 10px",
1334
- minHeight: 40,
1362
+ alignItems: "stretch",
1363
+ gap: "0.5rem",
1364
+ padding: "0 0.4rem 0 0",
1365
+ minHeight: "3.7rem",
1335
1366
  cursor: "pointer",
1336
- userSelect: "none"
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"
1337
1403
  },
1338
1404
  itemLabel: {
1339
1405
  flex: 1,
1340
- fontSize: 13,
1406
+ fontSize: "1.4em",
1407
+ fontWeight: 700,
1341
1408
  whiteSpace: "nowrap",
1342
1409
  overflow: "hidden",
1343
- textOverflow: "ellipsis"
1410
+ textOverflow: "ellipsis",
1411
+ color: colors.text
1344
1412
  },
1345
1413
  indicators: {
1346
1414
  display: "flex",
1347
- gap: 4,
1415
+ gap: "0.25rem",
1348
1416
  alignItems: "center"
1349
1417
  },
1350
1418
  indicator: {
1351
- width: 8,
1352
- height: 8,
1419
+ width: "1rem",
1420
+ height: "1rem",
1353
1421
  borderRadius: "50%",
1354
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
1355
1443
  }
1356
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
+ }
1357
1457
  function DefaultIoIndicator({ on }) {
1358
1458
  return /* @__PURE__ */ jsx8(
1359
1459
  "div",
1360
1460
  {
1361
1461
  style: {
1362
1462
  ...defaults.indicator,
1363
- backgroundColor: on ? "#4caf50" : "#f44336"
1463
+ backgroundColor: on ? colors.ioOn : colors.ioOff
1364
1464
  },
1365
1465
  title: on ? "Online" : "Offline"
1366
1466
  }
@@ -1372,7 +1472,7 @@ function DefaultSignalIndicator({ on }) {
1372
1472
  {
1373
1473
  style: {
1374
1474
  ...defaults.indicator,
1375
- backgroundColor: on ? "#2196f3" : "#666"
1475
+ backgroundColor: on ? colors.sgOn : colors.sgOff
1376
1476
  },
1377
1477
  title: on ? "Signal detected" : "No signal"
1378
1478
  }
@@ -1383,6 +1483,7 @@ function MatrixItemRow({
1383
1483
  type,
1384
1484
  active,
1385
1485
  showChannels,
1486
+ vmText,
1386
1487
  onSelect,
1387
1488
  onToggleVideoMute,
1388
1489
  itemClassName,
@@ -1397,20 +1498,37 @@ function MatrixItemRow({
1397
1498
  }) {
1398
1499
  const isActive = active;
1399
1500
  const isEnabled = item.sl.en;
1501
+ const useDefaults = !itemClassName;
1400
1502
  const classes = [
1401
1503
  "cris-co-matrix-item",
1402
1504
  itemClassName,
1403
1505
  isActive && (itemActiveClassName || "active"),
1404
1506
  !isEnabled && (itemDisabledClassName || "disabled")
1405
1507
  ].filter(Boolean).join(" ");
1406
- const computedStyle = itemClassName ? { ...itemStyleProp } : {
1508
+ const computedStyle = useDefaults ? {
1407
1509
  ...defaults.item,
1408
1510
  ...itemStyleProp,
1409
- ...isActive ? itemActiveStyle : void 0,
1511
+ ...isActive ? { ...defaults.itemActive, ...itemActiveStyle } : void 0,
1410
1512
  opacity: isEnabled ? 1 : 0.4
1411
- };
1513
+ } : { ...itemStyleProp };
1412
1514
  return /* @__PURE__ */ jsxs7("div", { className: classes, style: computedStyle, children: [
1413
- /* @__PURE__ */ jsx8(
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(
1414
1532
  CrisButton,
1415
1533
  {
1416
1534
  selected: isActive,
@@ -1418,9 +1536,9 @@ function MatrixItemRow({
1418
1536
  onPress: onSelect,
1419
1537
  className: `cris-co-matrix-item-btn ${itemActiveClassName ?? ""}`,
1420
1538
  classActive: itemActiveClassName,
1421
- children: /* @__PURE__ */ jsxs7("div", { style: { display: "flex", alignItems: "center", gap: 6, width: "100%" }, children: [
1539
+ children: /* @__PURE__ */ jsxs7("div", { style: { display: "flex", alignItems: "center", gap: "0.4rem", width: "100%" }, children: [
1422
1540
  showChannels && /* @__PURE__ */ jsx8("span", { className: "cris-co-matrix-ch", style: { flexShrink: 0, opacity: 0.6 }, children: item.id }),
1423
- /* @__PURE__ */ jsx8("span", { style: defaults.itemLabel, children: item.lb || `${type === "input" ? "Input" : "Output"} ${item.id}` }),
1541
+ /* @__PURE__ */ jsx8("span", { style: { flex: 1, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }, children: item.lb || `${type === "input" ? "Input" : "Output"} ${item.id}` }),
1424
1542
  /* @__PURE__ */ jsxs7("div", { style: defaults.indicators, children: [
1425
1543
  item.io.vs && (renderIoIndicator ? renderIoIndicator(item.io.on) : /* @__PURE__ */ jsx8(DefaultIoIndicator, { on: item.io.on })),
1426
1544
  item.sg.vs && (renderSignalIndicator ? renderSignalIndicator(item.sg.on) : /* @__PURE__ */ jsx8(DefaultSignalIndicator, { on: item.sg.on }))
@@ -1428,17 +1546,31 @@ function MatrixItemRow({
1428
1546
  ] })
1429
1547
  }
1430
1548
  ),
1431
- item.vm.vs && /* @__PURE__ */ jsx8(
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(
1432
1564
  CrisButton,
1433
1565
  {
1434
1566
  selected: item.vm.on,
1435
1567
  enabled: item.vm.en,
1436
- text: "VM",
1568
+ text: vmText,
1437
1569
  onPress: onToggleVideoMute,
1438
1570
  className: vmButtonClassName,
1439
1571
  classActive: vmButtonActiveClassName
1440
1572
  }
1441
- )
1573
+ ))
1442
1574
  ] });
1443
1575
  }
1444
1576
  function CrisCoMatrixListsTie({
@@ -1457,6 +1589,7 @@ function CrisCoMatrixListsTie({
1457
1589
  itemActiveClassName,
1458
1590
  itemActiveStyle,
1459
1591
  itemDisabledClassName,
1592
+ vmText = "Mute",
1460
1593
  vmButtonClassName,
1461
1594
  vmButtonActiveClassName,
1462
1595
  renderIoIndicator,
@@ -1464,6 +1597,7 @@ function CrisCoMatrixListsTie({
1464
1597
  }) {
1465
1598
  const matrix = useCustomObject2(oid);
1466
1599
  const send = useCustomObjectSend2();
1600
+ injectScrollbarStyle();
1467
1601
  if (!matrix) return null;
1468
1602
  const { si, ip: inputs, op: outputs } = matrix;
1469
1603
  const handleSelectInput = (id) => {
@@ -1495,13 +1629,14 @@ function CrisCoMatrixListsTie({
1495
1629
  children: inputTitle
1496
1630
  }
1497
1631
  ),
1498
- /* @__PURE__ */ jsx8("div", { style: defaults.scroll, children: inputs?.map((item) => /* @__PURE__ */ jsx8(
1632
+ /* @__PURE__ */ jsx8("div", { className: "cris-co-matrix-scroll", style: defaults.scroll, children: inputs?.map((item) => /* @__PURE__ */ jsx8(
1499
1633
  MatrixItemRow,
1500
1634
  {
1501
1635
  item,
1502
1636
  type: "input",
1503
1637
  active: si === item.id,
1504
1638
  showChannels,
1639
+ vmText,
1505
1640
  onSelect: () => handleSelectInput(item.id),
1506
1641
  onToggleVideoMute: () => handleToggleVideoMute("input", item.id),
1507
1642
  itemClassName,
@@ -1533,13 +1668,14 @@ function CrisCoMatrixListsTie({
1533
1668
  children: outputTitle
1534
1669
  }
1535
1670
  ),
1536
- /* @__PURE__ */ jsx8("div", { style: defaults.scroll, children: outputs?.map((item) => /* @__PURE__ */ jsx8(
1671
+ /* @__PURE__ */ jsx8("div", { className: "cris-co-matrix-scroll", style: defaults.scroll, children: outputs?.map((item) => /* @__PURE__ */ jsx8(
1537
1672
  MatrixItemRow,
1538
1673
  {
1539
1674
  item,
1540
1675
  type: "output",
1541
- active: !!item.sl.on,
1676
+ active: item.ti === si,
1542
1677
  showChannels,
1678
+ vmText,
1543
1679
  onSelect: () => handleTie(item.id),
1544
1680
  onToggleVideoMute: () => handleToggleVideoMute("output", item.id),
1545
1681
  itemClassName,