@jirawatpyk/aura-react 5.33.0 → 5.35.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.
@@ -268,11 +268,16 @@ var th = {
268
268
  pageN: function(p) {
269
269
  return "\u0E2B\u0E19\u0E49\u0E32 " + p;
270
270
  },
271
- progressReserved: function(v, r, max) {
272
- return "\u0E43\u0E0A\u0E49\u0E41\u0E25\u0E49\u0E27 " + n(v) + " \u0E08\u0E32\u0E01 " + n(max) + " \u0E08\u0E2D\u0E07\u0E44\u0E27\u0E49 " + n(r);
271
+ progressReserved: function(v, r2, max) {
272
+ return "\u0E43\u0E0A\u0E49\u0E41\u0E25\u0E49\u0E27 " + n(v) + " \u0E08\u0E32\u0E01 " + n(max) + " \u0E08\u0E2D\u0E07\u0E44\u0E27\u0E49 " + n(r2);
273
273
  },
274
274
  breadcrumbMore: "\u0E41\u0E2A\u0E14\u0E07\u0E40\u0E2A\u0E49\u0E19\u0E17\u0E32\u0E07\u0E17\u0E31\u0E49\u0E07\u0E2B\u0E21\u0E14",
275
275
  stepError: "\u0E21\u0E35\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14",
276
+ statusDown: "\u0E25\u0E48\u0E21",
277
+ statusProblem: "\u0E21\u0E35\u0E1B\u0E31\u0E0D\u0E2B\u0E32",
278
+ statusMaintenance: "\u0E1B\u0E34\u0E14\u0E1B\u0E23\u0E31\u0E1A\u0E1B\u0E23\u0E38\u0E07",
279
+ statusOk: "\u0E1B\u0E01\u0E15\u0E34",
280
+ statusUnknown: "\u0E22\u0E31\u0E07\u0E44\u0E21\u0E48\u0E21\u0E35\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25",
276
281
  accepts: function(list, max) {
277
282
  return [list, max && "\u0E44\u0E21\u0E48\u0E40\u0E01\u0E34\u0E19 " + max + " \u0E15\u0E48\u0E2D\u0E44\u0E1F\u0E25\u0E4C"].filter(Boolean).join(" \xB7 ");
278
283
  }
@@ -399,11 +404,16 @@ var sv = {
399
404
  pageN: function(p) {
400
405
  return "Sida " + p;
401
406
  },
402
- progressReserved: function(v, r, max) {
403
- return nsv(v) + " av " + nsv(max) + " anv\xE4nda, " + nsv(r) + " reserverade";
407
+ progressReserved: function(v, r2, max) {
408
+ return nsv(v) + " av " + nsv(max) + " anv\xE4nda, " + nsv(r2) + " reserverade";
404
409
  },
405
410
  breadcrumbMore: "Visa hela s\xF6kv\xE4gen",
406
411
  stepError: "har fel",
412
+ statusDown: "Nere",
413
+ statusProblem: "Problem",
414
+ statusMaintenance: "Underh\xE5ll",
415
+ statusOk: "OK",
416
+ statusUnknown: "Ingen data",
407
417
  accepts: function(list, max) {
408
418
  return [list, max && "h\xF6gst " + max + " per fil"].filter(Boolean).join(", ");
409
419
  }
@@ -531,11 +541,16 @@ var STRINGS = {
531
541
  pageN: function(p) {
532
542
  return "Page " + p;
533
543
  },
534
- progressReserved: function(v, r, max) {
535
- return n2(v) + " of " + n2(max) + " used, " + n2(r) + " reserved";
544
+ progressReserved: function(v, r2, max) {
545
+ return n2(v) + " of " + n2(max) + " used, " + n2(r2) + " reserved";
536
546
  },
537
547
  breadcrumbMore: "Show the full path",
538
548
  stepError: "has errors",
549
+ statusDown: "Down",
550
+ statusProblem: "Problem",
551
+ statusMaintenance: "Maintenance",
552
+ statusOk: "OK",
553
+ statusUnknown: "No data",
539
554
  accepts: function(list, max) {
540
555
  return [list, max && "up to " + max + " each"].filter(Boolean).join(", ");
541
556
  }
@@ -546,14 +561,14 @@ var STRINGS = {
546
561
 
547
562
  // src/theme.ts
548
563
  function hexToRgb(hex) {
549
- let h5 = String(hex).trim().replace("#", "");
550
- if (h5.length === 3)
551
- h5 = h5.split("").map(function(c) {
564
+ let h6 = String(hex).trim().replace("#", "");
565
+ if (h6.length === 3)
566
+ h6 = h6.split("").map(function(c) {
552
567
  return c + c;
553
568
  }).join("");
554
- if (!/^[0-9a-f]{6}$/i.test(h5)) throw new Error('createTheme: "' + hex + '" is not a #rgb or #rrggbb colour');
569
+ if (!/^[0-9a-f]{6}$/i.test(h6)) throw new Error('createTheme: "' + hex + '" is not a #rgb or #rrggbb colour');
555
570
  return [0, 2, 4].map(function(i) {
556
- return parseInt(h5.slice(i, i + 2), 16) / 255;
571
+ return parseInt(h6.slice(i, i + 2), 16) / 255;
557
572
  });
558
573
  }
559
574
  function rgbToHex(rgb) {
@@ -569,10 +584,10 @@ function delin(c) {
569
584
  return c <= 31308e-7 ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
570
585
  }
571
586
  function rgbToOklch(rgb) {
572
- const r = lin(rgb[0]), g = lin(rgb[1]), b = lin(rgb[2]);
573
- const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);
574
- const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);
575
- const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);
587
+ const r2 = lin(rgb[0]), g = lin(rgb[1]), b = lin(rgb[2]);
588
+ const l = Math.cbrt(0.4122214708 * r2 + 0.5363325363 * g + 0.0514459929 * b);
589
+ const m = Math.cbrt(0.2119034982 * r2 + 0.6806995451 * g + 0.1073969566 * b);
590
+ const s = Math.cbrt(0.0883024619 * r2 + 0.2817188376 * g + 0.6299787005 * b);
576
591
  const L = 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s;
577
592
  const A = 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s;
578
593
  const B = 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s;
@@ -732,13 +747,13 @@ function createTheme(opts) {
732
747
  D["card-shadow-creative"] = "8px 8px 0px " + shadowDark;
733
748
  const checks = [];
734
749
  function check(theme, fg, bg, target, fgHex, bgHex) {
735
- const r = contrast(fgHex, bgHex);
750
+ const r2 = contrast(fgHex, bgHex);
736
751
  checks.push({
737
752
  theme,
738
753
  pair: fg + " on " + bg,
739
- ratio: Math.round(r * 100) / 100,
754
+ ratio: Math.round(r2 * 100) / 100,
740
755
  target,
741
- pass: r >= target - 5e-3
756
+ pass: r2 >= target - 5e-3
742
757
  });
743
758
  }
744
759
  [
@@ -858,6 +873,18 @@ function colorSchemeScript(options) {
858
873
 
859
874
  // src/breakpoints.ts
860
875
  var breakpoints = { sm: 640, md: 768, lg: 1024, xl: 1280 };
876
+ var ORDER = ["base", "sm", "md", "lg", "xl"];
877
+ function respVars(prefix, value, map2) {
878
+ const style = {};
879
+ if (value == null) return style;
880
+ if (typeof value !== "object") value = { base: value };
881
+ let byBp = value, cur;
882
+ ORDER.forEach(function(k) {
883
+ if (byBp[k] !== void 0) cur = map2 ? map2(byBp[k]) : byBp[k];
884
+ if (cur !== void 0) style["--" + prefix + "-" + k] = cur;
885
+ });
886
+ return style;
887
+ }
861
888
 
862
889
  // src/display.tsx
863
890
  import * as React3 from "react";
@@ -921,9 +948,9 @@ function iconSvg(shapes, props, ref) {
921
948
  ...a11y
922
949
  },
923
950
  shapes.map(function(s, i) {
924
- const attrs = { key: i };
925
- for (const k in s[1]) attrs[k === "stroke-width" ? "strokeWidth" : k] = s[1][k];
926
- return h(s[0], attrs);
951
+ const attrs2 = { key: i };
952
+ for (const k in s[1]) attrs2[k === "stroke-width" ? "strokeWidth" : k] = s[1][k];
953
+ return h(s[0], attrs2);
927
954
  })
928
955
  );
929
956
  }
@@ -1055,6 +1082,14 @@ var IconTrendingDown = /* @__PURE__ */ defineIcon("trending-down", [
1055
1082
  ["path", { d: "M16 17h6v-6" }],
1056
1083
  ["path", { d: "m22 17-8.5-8.5-5 5L2 7" }]
1057
1084
  ]);
1085
+ var IconWrench = /* @__PURE__ */ defineIcon("wrench", [
1086
+ [
1087
+ "path",
1088
+ {
1089
+ d: "M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.106-3.105c.32-.322.863-.22.983.218a6 6 0 0 1-8.259 7.057l-7.91 7.91a1 1 0 0 1-2.999-3l7.91-7.91a6 6 0 0 1 7.057-8.259c.438.12.54.662.219.984z"
1090
+ }
1091
+ ]
1092
+ ]);
1058
1093
 
1059
1094
  // src/display.tsx
1060
1095
  var h2 = React3.createElement;
@@ -1295,14 +1330,14 @@ function ServerAvatar(props) {
1295
1330
  import * as React4 from "react";
1296
1331
  var h3 = React4.createElement;
1297
1332
  var Container = React4.forwardRef(function Container2(props, ref) {
1298
- const attrs = {};
1333
+ const attrs2 = {};
1299
1334
  Object.keys(props).forEach(function(k) {
1300
1335
  if (k === "id" || k === "lang" || k === "dir" || /^(aria|data)-/.test(k))
1301
- attrs[k] = props[k];
1336
+ attrs2[k] = props[k];
1302
1337
  });
1303
1338
  return h3(
1304
1339
  props.as || "div",
1305
- Object.assign(attrs, {
1340
+ Object.assign(attrs2, {
1306
1341
  ref,
1307
1342
  className: cx(
1308
1343
  "aura-container",
@@ -1320,15 +1355,15 @@ var Container = React4.forwardRef(function Container2(props, ref) {
1320
1355
  import * as React5 from "react";
1321
1356
  var h4 = React5.createElement;
1322
1357
  var PageHeader = React5.forwardRef(function PageHeader2(props, ref) {
1323
- const attrs = {};
1358
+ const attrs2 = {};
1324
1359
  Object.keys(props).forEach(function(k) {
1325
1360
  if (k === "id" || k === "lang" || k === "dir" || k === "role" || /^(aria|data)-/.test(k))
1326
- attrs[k] = props[k];
1361
+ attrs2[k] = props[k];
1327
1362
  });
1328
1363
  const level = props.headingLevel || 1;
1329
1364
  return h4(
1330
1365
  "div",
1331
- Object.assign(attrs, { ref, className: cx("aura-page-header", props.className), style: props.style }),
1366
+ Object.assign(attrs2, { ref, className: cx("aura-page-header", props.className), style: props.style }),
1332
1367
  h4(
1333
1368
  "div",
1334
1369
  { className: "aura-page-header__text" },
@@ -1340,6 +1375,215 @@ var PageHeader = React5.forwardRef(function PageHeader2(props, ref) {
1340
1375
  props.actions != null && props.actions !== false ? h4("div", { className: "aura-page-header__actions" }, props.actions) : null
1341
1376
  );
1342
1377
  });
1378
+
1379
+ // src/tiles.tsx
1380
+ import * as React6 from "react";
1381
+ var h5 = React6.createElement;
1382
+ var STATUS_ICON = {
1383
+ down: IconCircleAlert,
1384
+ problem: IconTriangleAlert,
1385
+ maintenance: IconWrench,
1386
+ ok: IconCircleCheck,
1387
+ unknown: IconCircleDotDashed
1388
+ };
1389
+ var STATUS_TONE = {
1390
+ down: "danger",
1391
+ problem: "warning",
1392
+ maintenance: "accent",
1393
+ ok: "default",
1394
+ unknown: "default"
1395
+ };
1396
+ var STATUS_WORD = {
1397
+ down: "statusDown",
1398
+ problem: "statusProblem",
1399
+ maintenance: "statusMaintenance",
1400
+ ok: "statusOk",
1401
+ unknown: "statusUnknown"
1402
+ };
1403
+ function statusWord(status, t) {
1404
+ return String(t[STATUS_WORD[status]] || STATUS_WORD[status]);
1405
+ }
1406
+ function attrs(props) {
1407
+ const out = {};
1408
+ Object.keys(props).forEach(function(k) {
1409
+ if (k === "id" || k === "style" || k === "lang" || k === "dir" || /^(aria|data)-/.test(k))
1410
+ out[k] = props[k];
1411
+ });
1412
+ return out;
1413
+ }
1414
+ var comma = h5("span", { className: "aura-status-tile__sep" }, ",");
1415
+ function statusTileElement(props, ref, Link, t, titleRef) {
1416
+ const status = STATUS_ICON[props.status] ? props.status : "unknown";
1417
+ if (status !== props.status)
1418
+ devWarnOnce(
1419
+ "status-tile-status-" + String(props.status),
1420
+ 'StatusTile status="' + String(props.status) + '" is not down, problem, maintenance, ok or unknown: it shows as unknown ("No data"). Map your value first.'
1421
+ );
1422
+ const valueTone = props.valueTone || STATUS_TONE[status];
1423
+ const word = props.statusLabel || statusWord(status, t);
1424
+ const markers = (props.markers || []).filter(Boolean);
1425
+ const has = function(v) {
1426
+ return v != null && v !== false && v !== "";
1427
+ };
1428
+ const hasValue = has(props.value), hasMeta = has(props.meta);
1429
+ const Tag = props.href ? Link : "div";
1430
+ return h5(
1431
+ Tag,
1432
+ Object.assign(attrs(props), {
1433
+ ref,
1434
+ href: props.href,
1435
+ className: cx("aura-status-tile", "aura-status-tile--" + status, props.href && "is-interactive", props.className)
1436
+ }),
1437
+ h5(
1438
+ "span",
1439
+ { className: "aura-status-tile__head" },
1440
+ h5(Icon, { name: h5(STATUS_ICON[status]), size: 16, className: "aura-status-tile__icon" }),
1441
+ h5("span", { className: "aura-status-tile__title", ref: titleRef }, props.title, comma),
1442
+ h5("span", { className: "aura-sr-only" }, word + (hasValue || hasMeta || markers.length ? "," : "")),
1443
+ hasValue ? h5(
1444
+ "span",
1445
+ { className: cx("aura-status-tile__value", "is-" + valueTone) },
1446
+ props.value,
1447
+ hasMeta || markers.length ? comma : null
1448
+ ) : null
1449
+ ),
1450
+ hasMeta || markers.length ? h5(
1451
+ "span",
1452
+ { className: "aura-status-tile__foot" },
1453
+ hasMeta ? h5("span", { className: "aura-status-tile__meta" }, props.meta, markers.length ? comma : null) : null,
1454
+ markers.length ? h5(
1455
+ "span",
1456
+ { className: "aura-status-tile__markers" },
1457
+ markers.map(function(m, i) {
1458
+ return h5(
1459
+ "span",
1460
+ {
1461
+ key: i,
1462
+ className: cx("aura-status-tile__marker", "is-" + (m.tone || "neutral")),
1463
+ "data-aura-tip": m.label
1464
+ },
1465
+ h5(Icon, { name: m.icon, size: 14 }),
1466
+ h5("span", { className: "aura-sr-only" }, m.label + (i < markers.length - 1 ? "," : ""))
1467
+ );
1468
+ })
1469
+ ) : null
1470
+ ) : null
1471
+ );
1472
+ }
1473
+ function ServerStatusTile(props) {
1474
+ return statusTileElement(props, void 0, props.linkComponent || "a", STRINGS.en);
1475
+ }
1476
+ var TileGrid = React6.forwardRef(function TileGrid2(props, ref) {
1477
+ const style = Object.assign(
1478
+ {},
1479
+ respVars("aura-grid-cols", props.columns == null ? { base: 2, md: 3 } : props.columns),
1480
+ props.style
1481
+ );
1482
+ return h5(
1483
+ "ul",
1484
+ Object.assign(attrs(props), {
1485
+ ref,
1486
+ role: "list",
1487
+ className: cx("aura-grid-layout", "aura-tile-grid", props.className),
1488
+ style
1489
+ }),
1490
+ /* toArray drops null and booleans and keys each element; a Fragment's children are items too. */
1491
+ flat(props.children).map(function(c, i) {
1492
+ return h5("li", { key: React6.isValidElement(c) && c.key != null ? c.key : i }, c);
1493
+ })
1494
+ );
1495
+ });
1496
+ function flat(children) {
1497
+ const out = [];
1498
+ React6.Children.toArray(children).forEach(function(c) {
1499
+ if (React6.isValidElement(c) && c.type === React6.Fragment)
1500
+ flat(c.props.children).forEach(function(x) {
1501
+ out.push(React6.isValidElement(x) ? React6.cloneElement(x, { key: String(c.key) + "/" + String(x.key) }) : x);
1502
+ });
1503
+ else if (c !== "") out.push(c);
1504
+ });
1505
+ return out;
1506
+ }
1507
+ var SIZES2 = { sm: [80, 24], md: [120, 32] };
1508
+ var PAD = 2;
1509
+ function r(n3) {
1510
+ return Math.round(n3 * 100) / 100;
1511
+ }
1512
+ function num(v) {
1513
+ return typeof v === "number" && isFinite(v) ? v : null;
1514
+ }
1515
+ var Sparkline = React6.forwardRef(function Sparkline2(props, ref) {
1516
+ const wh = SIZES2[props.size || "sm"] || SIZES2.sm;
1517
+ const W = wh[0], H = wh[1];
1518
+ const data = (props.data || []).map(num);
1519
+ const n3 = data.length;
1520
+ const vals = data.filter(function(v) {
1521
+ return v != null;
1522
+ });
1523
+ let lo = num(props.min), hi = num(props.max);
1524
+ if (lo == null) lo = vals.length ? Math.min.apply(null, vals) : 0;
1525
+ if (hi == null) hi = vals.length ? Math.max.apply(null, vals) : 0;
1526
+ if (lo > hi) {
1527
+ const s = lo;
1528
+ lo = hi;
1529
+ hi = s;
1530
+ }
1531
+ const step = n3 > 1 ? (W - 2 * PAD) / (n3 - 1) : 0;
1532
+ const x = function(i) {
1533
+ return n3 > 1 ? PAD + i * step : W / 2;
1534
+ };
1535
+ const y = function(v) {
1536
+ if (hi === lo) return H / 2;
1537
+ const k = Math.max(0, Math.min(1, (v - lo) / (hi - lo)));
1538
+ return H - PAD - k * (H - 2 * PAD);
1539
+ };
1540
+ let d = "";
1541
+ const dots = [];
1542
+ data.forEach(function(v, i) {
1543
+ if (v == null) return;
1544
+ const prev = i > 0 && data[i - 1] != null, next = i < n3 - 1 && data[i + 1] != null;
1545
+ if (!prev && !next) dots.push(h5("circle", { key: "d" + i, cx: r(x(i)), cy: r(y(v)), r: 1.5 }));
1546
+ else d += (prev ? "L" : "M") + r(x(i)) + " " + r(y(v));
1547
+ });
1548
+ const mode = props.failures || "none";
1549
+ const fails = [];
1550
+ if (mode !== "none" && props.failed)
1551
+ data.forEach(function(_v, i) {
1552
+ if (!props.failed[i]) return;
1553
+ if (mode === "band") {
1554
+ const w = Math.max(2, step || W), left = Math.max(0, x(i) - w / 2), right = Math.min(W, x(i) + w / 2);
1555
+ fails.push(h5("rect", { key: "f" + i, x: r(left), y: 0, width: r(right - left), height: H }));
1556
+ } else
1557
+ fails.push(
1558
+ h5("rect", {
1559
+ key: "f" + i,
1560
+ x: r(Math.max(0, Math.min(W - 1.5, x(i) - 0.75))),
1561
+ y: H - 6,
1562
+ width: 1.5,
1563
+ height: 6
1564
+ })
1565
+ );
1566
+ });
1567
+ const named = !!props.label;
1568
+ return h5(
1569
+ "svg",
1570
+ Object.assign(attrs(props), {
1571
+ ref,
1572
+ className: cx("aura-sparkline", "is-" + (props.tone || "neutral"), props.className),
1573
+ width: W,
1574
+ height: H,
1575
+ viewBox: "0 0 " + W + " " + H,
1576
+ role: named ? "img" : void 0,
1577
+ "aria-label": named ? props.label : void 0,
1578
+ "aria-hidden": named ? void 0 : true,
1579
+ focusable: "false"
1580
+ }),
1581
+ fails.length && mode === "band" ? h5("g", { className: "aura-sparkline__band" }, fails) : null,
1582
+ d ? h5("path", { className: "aura-sparkline__line", d }) : null,
1583
+ dots.length ? h5("g", { className: "aura-sparkline__dots" }, dots) : null,
1584
+ fails.length && mode === "ticks" ? h5("g", { className: "aura-sparkline__ticks" }, fails) : null
1585
+ );
1586
+ });
1343
1587
  export {
1344
1588
  ServerAlert as Alert,
1345
1589
  ServerAvatar as Avatar,
@@ -1350,8 +1594,11 @@ export {
1350
1594
  Icon,
1351
1595
  PageHeader,
1352
1596
  STRINGS,
1597
+ Sparkline,
1353
1598
  ServerStat as Stat,
1354
1599
  ServerStatusPill as StatusPill,
1600
+ ServerStatusTile as StatusTile,
1601
+ TileGrid,
1355
1602
  scale as brandScale,
1356
1603
  breakpoints,
1357
1604
  buttonClass,
package/dist/styles.css CHANGED
@@ -864,8 +864,14 @@ a.aura-tab { text-decoration: none; }
864
864
  .aura-crumbs li.aura-crumbs__more { display: none; }
865
865
  /* "…" is the only way to the hidden items: a 24px target, 44px on touch screens. */
866
866
  .aura-crumbs__more > button { position: relative; min-width: 24px; min-height: 24px; display: inline-flex; align-items: center; justify-content: center; }
867
+ /* 5.35 (DxT Monitor 11): on a touch screen every crumb link and button (and "…") gets a 44px-tall hit area; the text
868
+ * doesn't move. The area reaches 12px into the gutter on each side (the gutter is 28px, so neighbours never overlap)
869
+ * and only 4px below the text, so it stops short of a PageHeader title 4px under the crumbs; the rest of the 44px is
870
+ * above. Wrapped rows sit 24px apart on touch screens so one row's areas never cover the next. */
867
871
  @media (pointer: coarse) {
868
- .aura-crumbs__more > button::after { content: ''; position: absolute; top: 50%; left: 50%; width: var(--aura-touch-target); height: var(--aura-touch-target); transform: translate(-50%, -50%); }
872
+ .aura-crumbs ol { row-gap: 24px; }
873
+ .aura-crumbs li > a, .aura-crumbs li > button { position: relative; }
874
+ .aura-crumbs li > a::after, .aura-crumbs li > button::after { content: ''; position: absolute; left: -12px; right: -12px; bottom: -4px; height: max(100% + 4px, var(--aura-touch-target)); }
869
875
  }
870
876
  @media (max-width: 639.98px) {
871
877
  .aura-crumbs--collapse-sm li.aura-crumbs__more { display: inline-flex; }
@@ -1072,6 +1078,10 @@ a.aura-tab { text-decoration: none; }
1072
1078
  --aura-shell-bar-height: 56px; /* 5.14 (Chamber-OS 104): the top bar's height, for sticky offsets under it */
1073
1079
  }
1074
1080
  .aura-shell--no-bar { --aura-shell-bar-height: 0px; }
1081
+ /* 5.35 (DxT Monitor 13): headerHideOnScroll — below lg the bar slides up out of view while the page scrolls down (its
1082
+ * shadow too); AppShell sets the bar-height token to 0 meanwhile. */
1083
+ .aura-shell__bar--hides { transition: transform var(--aura-duration-base) var(--aura-ease); }
1084
+ @media (max-width: 1023.98px) { .aura-shell__bar.is-away { transform: translateY(calc(-100% - 8px)); } }
1075
1085
  @media (min-width: 1024px) { .aura-shell--menu-bar { --aura-shell-bar-height: 0px; } }
1076
1086
  .aura-shell__nav { position: sticky; top: 0; height: 100vh; height: 100dvh; flex: none; }
1077
1087
  .aura-shell__main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
@@ -1164,6 +1174,69 @@ button.aura-stat { font: inherit; width: 100%; cursor: pointer; }
1164
1174
  /* Anything else interactive in the tile sits above the stretched link. No specificity, so a control's own position wins. */
1165
1175
  :where(.aura-stat--label-link) :where(a, button, input, select, textarea, label, summary, [tabindex]):not(:where(.aura-stat__link)) { position: relative; z-index: 1; }
1166
1176
 
1177
+ /* ---------- StatusTile, TileGrid, Sparkline (5.34, DxT Monitor S06) ---------- */
1178
+ .aura-tile-grid { list-style: none; margin: 0; padding: 0; --aura-grid-gap-base: var(--aura-space-2); --aura-grid-gap-sm: var(--aura-space-2); --aura-grid-gap-md: var(--aura-space-2); --aura-grid-gap-lg: var(--aura-space-2); --aura-grid-gap-xl: var(--aura-space-2); }
1179
+ .aura-tile-grid > li { display: flex; min-width: 0; container: aura-status-tile / inline-size; } /* the narrow-tile query reads the cell: a grid cell has a definite width */
1180
+ .aura-tile-grid > li > * { flex: 1; min-width: 0; }
1181
+ .aura-status-tile {
1182
+ position: relative; box-sizing: border-box; display: flex; flex-direction: column; gap: 2px; min-width: 0;
1183
+ padding: var(--aura-space-2) var(--aura-space-3); background: var(--aura-bg-surface); color: var(--aura-fg-primary);
1184
+ border: 1px solid var(--aura-border-default); border-radius: var(--aura-radius-sm);
1185
+ font-family: var(--font-sans); font-size: 13px; line-height: 18px; text-align: start; text-decoration: none;
1186
+ --aura-hover: var(--aura-bg-surface-hover);
1187
+ }
1188
+ .aura-status-tile--down { background: var(--aura-alert-danger-bg); border-color: var(--aura-alert-danger-border); }
1189
+ .aura-status-tile--problem { background: var(--aura-alert-warning-bg); border-color: var(--aura-alert-warning-border); }
1190
+ .aura-status-tile--maintenance { background: var(--aura-alert-info-bg); border-color: var(--aura-alert-info-border); }
1191
+ .aura-status-tile.is-interactive { cursor: pointer; transition: border-color var(--aura-duration-fast) var(--aura-ease); }
1192
+ .aura-status-tile.is-interactive:hover { border-color: var(--aura-border-strong); }
1193
+ .aura-status-tile.is-interactive:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: var(--aura-focus-ring-offset); }
1194
+ .aura-status-tile__head { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 0 var(--aura-space-2); min-width: 0; }
1195
+ .aura-status-tile__sep { font-size: 0; }
1196
+ .aura-status-tile__icon { flex: none; margin-top: 1px; color: var(--aura-fg-secondary); }
1197
+ .aura-status-tile--down .aura-status-tile__icon { color: var(--aura-alert-danger-fg); }
1198
+ .aura-status-tile--problem .aura-status-tile__icon { color: var(--aura-alert-warning-fg); }
1199
+ .aura-status-tile--maintenance .aura-status-tile__icon { color: var(--aura-alert-info-fg); }
1200
+ .aura-status-tile--unknown .aura-status-tile__icon { color: var(--aura-fg-tertiary); } /* 5.35: no data yet */
1201
+ /* Two lines at most: similar names stay apart. */
1202
+ .aura-status-tile__title {
1203
+ flex: 1 1 0; min-width: 0; font-weight: 600; overflow-wrap: break-word;
1204
+ display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden;
1205
+ }
1206
+ .aura-status-tile__value { flex: none; margin-inline-start: auto; font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
1207
+ .aura-status-tile__value.is-danger, .aura-status-tile__marker.is-danger { color: var(--aura-fg-danger); }
1208
+ .aura-status-tile__value.is-warning, .aura-status-tile__marker.is-warning { color: var(--aura-fg-warning); }
1209
+ .aura-status-tile__value.is-accent, .aura-status-tile__marker.is-accent { color: var(--aura-fg-accent); }
1210
+ .aura-status-tile__value.is-neutral, .aura-status-tile__marker.is-neutral { color: var(--aura-fg-secondary); }
1211
+ .aura-status-tile--down .aura-status-tile__value.is-danger { color: var(--aura-alert-danger-fg); }
1212
+ .aura-status-tile--problem .aura-status-tile__value.is-warning { color: var(--aura-alert-warning-fg); }
1213
+ .aura-status-tile--maintenance .aura-status-tile__value.is-accent { color: var(--aura-alert-info-fg); }
1214
+ /* A narrow tile in a TileGrid (two columns on a phone) puts the value on its own line under the title, in every tile
1215
+ * alike, rather than squeezing the title to a word. The grid's cells are the containers: on the tile itself, inline-size
1216
+ * containment would collapse a tile in a flex row or an inline block to nothing. */
1217
+ @container aura-status-tile (max-width: 225.98px) {
1218
+ .aura-status-tile__value { flex-basis: 100%; margin-inline-start: 0; padding-inline-start: 24px; }
1219
+ }
1220
+ /* The second line starts under the title. */
1221
+ .aura-status-tile__foot { display: flex; align-items: center; gap: var(--aura-space-2); min-width: 0; padding-inline-start: 24px; font-size: 12px; color: var(--aura-fg-secondary); }
1222
+ .aura-status-tile__meta { flex: 1; min-width: 0; overflow-wrap: anywhere; }
1223
+ .aura-status-tile__markers { display: inline-flex; align-items: center; gap: var(--aura-space-1); margin-inline-start: auto; flex: none; }
1224
+ .aura-status-tile__marker { display: inline-flex; }
1225
+ .aura-status-tile:lang(th) { line-height: 20px; }
1226
+ .aura-sparkline { display: inline-block; flex: none; vertical-align: middle; overflow: visible; color: var(--aura-fg-secondary); }
1227
+ .aura-sparkline.is-accent { color: var(--aura-fg-accent); }
1228
+ .aura-sparkline.is-danger { color: var(--aura-fg-danger); }
1229
+ .aura-sparkline.is-warning { color: var(--aura-fg-warning); }
1230
+ .aura-sparkline.is-positive { color: var(--aura-fg-positive); }
1231
+ .aura-sparkline__line { fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linejoin: round; stroke-linecap: round; }
1232
+ .aura-sparkline__dots { fill: currentColor; }
1233
+ .aura-sparkline__band { fill: var(--aura-fg-danger); opacity: 0.16; }
1234
+ .aura-sparkline__ticks { fill: var(--aura-fg-danger); }
1235
+ @media (forced-colors: active) {
1236
+ .aura-sparkline { color: CanvasText; }
1237
+ .aura-sparkline__band, .aura-sparkline__ticks { fill: Highlight; }
1238
+ }
1239
+
1167
1240
  /* ---------- TimePicker ---------- */
1168
1241
  .aura-time__popover { min-width: 160px; }
1169
1242
  .aura-time__option { min-height: 36px; font-variant-numeric: tabular-nums; }
@@ -1783,10 +1856,18 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
1783
1856
  @media (min-width: 1024px) { .aura-bottomnav.aura-bottomnav--below-lg, .aura-bottomnav-spacer.aura-bottomnav--below-lg { display: none; } }
1784
1857
  @media (min-width: 1280px) { .aura-bottomnav.aura-bottomnav--below-xl, .aura-bottomnav-spacer.aura-bottomnav--below-xl { display: none; } }
1785
1858
  /* While a BottomNav shows, viewport ActionBars and phone toasts sit on top of it. */
1786
- :root:has(.aura-bottomnav--always) { --aura-bottomnav-offset: calc(var(--aura-bottomnav-height) + env(safe-area-inset-bottom, 0px)); }
1787
- @media (max-width: 767.98px) { :root:has(.aura-bottomnav--below-md) { --aura-bottomnav-offset: calc(var(--aura-bottomnav-height) + env(safe-area-inset-bottom, 0px)); } }
1788
- @media (max-width: 1023.98px) { :root:has(.aura-bottomnav--below-lg) { --aura-bottomnav-offset: calc(var(--aura-bottomnav-height) + env(safe-area-inset-bottom, 0px)); } }
1789
- @media (max-width: 1279.98px) { :root:has(.aura-bottomnav--below-xl) { --aura-bottomnav-offset: calc(var(--aura-bottomnav-height) + env(safe-area-inset-bottom, 0px)); } }
1859
+ /* 5.35: not while it has slid away on scroll, nor on a page that hides it (data-aura-hide-bottomnav). */
1860
+ :root:has(nav.aura-bottomnav--always:not(.is-away)):not(:has([data-aura-hide-bottomnav])) { --aura-bottomnav-offset: calc(var(--aura-bottomnav-height) + env(safe-area-inset-bottom, 0px)); }
1861
+ @media (max-width: 767.98px) { :root:has(nav.aura-bottomnav--below-md:not(.is-away)):not(:has([data-aura-hide-bottomnav])) { --aura-bottomnav-offset: calc(var(--aura-bottomnav-height) + env(safe-area-inset-bottom, 0px)); } }
1862
+ @media (max-width: 1023.98px) { :root:has(nav.aura-bottomnav--below-lg:not(.is-away)):not(:has([data-aura-hide-bottomnav])) { --aura-bottomnav-offset: calc(var(--aura-bottomnav-height) + env(safe-area-inset-bottom, 0px)); } }
1863
+ @media (max-width: 1279.98px) { :root:has(nav.aura-bottomnav--below-xl:not(.is-away)):not(:has([data-aura-hide-bottomnav])) { --aura-bottomnav-offset: calc(var(--aura-bottomnav-height) + env(safe-area-inset-bottom, 0px)); } }
1864
+ /* 5.35 (DxT Monitor 14): hideOnScroll slides it down out of view (the spacer stays, so nothing shifts); a page with its
1865
+ * own bottom bar (ActionBar hidesBottomNav, or data-aura-hide-bottomnav on any element) has no BottomNav or spacer. */
1866
+ .aura-bottomnav--hides { transition: transform var(--aura-duration-base) var(--aura-ease); }
1867
+ .aura-bottomnav.is-away { transform: translateY(100%); }
1868
+ :root:has([data-aura-hide-bottomnav]) .aura-bottomnav, :root:has([data-aura-hide-bottomnav]) .aura-bottomnav-spacer { display: none; }
1869
+ .aura-actionbar--viewport { transition: bottom var(--aura-duration-base) var(--aura-ease); }
1870
+ @media (prefers-reduced-motion: reduce) { .aura-bottomnav--hides, .aura-actionbar--viewport, .aura-shell__bar--hides { transition: none; } }
1790
1871
  /* Toasts clear a BottomNav wherever it shows (phones and tablets), else the bottom safe-area inset (5.6). */
1791
1872
  .aura-toaster:not(.is-top) { bottom: calc(var(--aura-toaster-offset, var(--aura-space-6)) + var(--aura-bottomnav-offset, env(safe-area-inset-bottom, 0px))); }
1792
1873
  @media (max-width: 639.98px) { .aura-toaster:not(.is-top) { bottom: calc(var(--aura-toaster-offset, var(--aura-space-4)) + var(--aura-bottomnav-offset, env(safe-area-inset-bottom, 0px))); } }