@yuneta/gobj-ui 7.23.179 → 7.23.180

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.
@@ -76430,6 +76430,41 @@ function ensure_dev_style() {
76430
76430
  .YDEV_TITLE { display: flex; align-items: baseline; gap: 8px; }
76431
76431
  .YDEV_TITLE_MAIN { font-weight: 700; }
76432
76432
  .YDEV_TITLE_SUB { opacity: 0.7; font-size: 12px; }
76433
+ /* The ink of the log.
76434
+ *
76435
+ * It used to be one grey dimmed with opacity per role -- 0.85 for a key,
76436
+ * 0.5 for a preview, 0.45 for the source -- which is what washed the window
76437
+ * out: opacity blends text TOWARDS the background, so the more a line
76438
+ * mattered the less of it was left. Measured on the dark scheme the preview
76439
+ * came out at 4.39:1 and the source at 3.78:1, both under the 4.5 floor,
76440
+ * and everything that was legible was the same grey as everything else.
76441
+ *
76442
+ * Explicit colours now, one per ROLE and measured against the entry's own
76443
+ * background (#1b1e24 dark, #fafafa light): a key, a string, a number and a
76444
+ * boolean read apart from each other the way they do in a browser console,
76445
+ * which is the point of colouring a payload at all.
76446
+ * Ratios: dark 11.20 / 6.32 / 9.83 / 6.00 / 6.77 / 6.49 / 4.82,
76447
+ * light 7.38 / 7.52 / 5.16 / 8.35 / 5.59 / 7.21 / 4.35. */
76448
+ :root {
76449
+ --ydev-ink: #1f2937;
76450
+ --ydev-key: #0451a5;
76451
+ --ydev-str: #a31515;
76452
+ --ydev-num: #067a4e;
76453
+ --ydev-bool: #6b21a8;
76454
+ --ydev-dim: #5b6675;
76455
+ --ydev-src: #4a5568;
76456
+ --ydev-bullet: #6b7789;
76457
+ }
76458
+ :root[data-theme="dark"] {
76459
+ --ydev-ink: #e5e7eb;
76460
+ --ydev-key: #9cdcfe;
76461
+ --ydev-str: #ce9178;
76462
+ --ydev-num: #b5cea8;
76463
+ --ydev-bool: #c586c0;
76464
+ --ydev-dim: #9aa6b8;
76465
+ --ydev-src: #8fa3bf;
76466
+ --ydev-bullet: #7b8ba3;
76467
+ }
76433
76468
  /* -------- entries (shared) -------- */
76434
76469
  .TRAFFIC_ENTRY {
76435
76470
  border-left: 3px solid #94a3b8; border-radius: 3px;
@@ -76443,15 +76478,15 @@ function ensure_dev_style() {
76443
76478
  .TRAFFIC_HEADER { display: flex; align-items: baseline; gap: 8px; }
76444
76479
  .TRAFFIC_ARROW { font-weight: 700; }
76445
76480
  .TRAFFIC_EVENT { font-weight: 700; }
76446
- .TRAFFIC_CMD { opacity: 0.75; font-weight: 600; }
76481
+ .TRAFFIC_CMD { color: var(--ydev-dim); font-weight: 600; }
76447
76482
  /* Where the message went through. min-width 0 and flex 0 1 auto so it is the
76448
76483
  part that gives way when the row runs out of width -- the event name and
76449
76484
  the size/time must not be the ones to go. */
76450
- .TRAFFIC_SRC { opacity: 0.45; font-size: 11px; flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
76485
+ .TRAFFIC_SRC { color: var(--ydev-src); font-size: 11px; flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
76451
76486
  .dir-out .TRAFFIC_ARROW, .dir-out .TRAFFIC_EVENT { color: #2563eb; }
76452
76487
  .dir-in .TRAFFIC_ARROW, .dir-in .TRAFFIC_EVENT { color: #059669; }
76453
76488
  .dir-err .TRAFFIC_ARROW, .dir-err .TRAFFIC_EVENT { color: #dc2626; }
76454
- .TRAFFIC_META { margin-left: auto; opacity: 0.6; font-size: 11px; white-space: nowrap; }
76489
+ .TRAFFIC_META { margin-left: auto; color: var(--ydev-dim); font-size: 11px; white-space: nowrap; }
76455
76490
  /* The indent of a nested block is NOT a hover effect: it used to be given
76456
76491
  only on .TRAFFIC_ENTRY:hover, so moving the cursor across the log made
76457
76492
  every payload under it jump 16px sideways and reflow. A payload being
@@ -76460,29 +76495,40 @@ function ensure_dev_style() {
76460
76495
  .TRAFFIC_KW { margin: 2px 0 0 16px; }
76461
76496
  .TRAFFIC_FULL { margin: 4px 0 0 16px; padding: 6px 8px; font-family: monospace; font-size: 11px; line-height: 1.4; white-space: pre-wrap; word-break: break-word; background: rgba(0,0,0,0.04); border-radius: 4px; overflow-x: auto; }
76462
76497
  .TRAFFIC_ROW { display: flex; gap: 6px; align-items: baseline; }
76463
- .TRAFFIC_BULLET { opacity: 0.45; flex: 0 0 auto; }
76464
- .TRAFFIC_KEY { opacity: 0.85; flex: 0 0 auto; }
76465
- .TRAFFIC_VAL { word-break: break-word; }
76466
- .TRAFFIC_VAL.t-num { color: #0891b2; }
76467
- .TRAFFIC_VAL.t-bool { color: #9333ea; }
76468
- .TRAFFIC_VAL.t-null { color: #9333ea; font-style: italic; }
76469
- .TRAFFIC_VAL.t-empty { opacity: 0.5; }
76470
- .TRAFFIC_TS { opacity: 0.6; margin-left: 8px; }
76498
+ .TRAFFIC_BULLET { color: var(--ydev-bullet); flex: 0 0 auto; }
76499
+ .TRAFFIC_KEY { color: var(--ydev-key); flex: 0 0 auto; }
76500
+ .TRAFFIC_VAL { color: var(--ydev-ink); word-break: break-word; }
76501
+ .TRAFFIC_VAL.t-str { color: var(--ydev-str); }
76502
+ .TRAFFIC_VAL.t-num { color: var(--ydev-num); }
76503
+ .TRAFFIC_VAL.t-bool { color: var(--ydev-bool); }
76504
+ .TRAFFIC_VAL.t-null { color: var(--ydev-bool); font-style: italic; }
76505
+ .TRAFFIC_VAL.t-empty { color: var(--ydev-dim); }
76506
+ .TRAFFIC_TS { color: var(--ydev-dim); margin-left: 8px; }
76471
76507
  details.TRAFFIC_NEST > summary { cursor: pointer; list-style: none; display: flex; gap: 6px; align-items: baseline; }
76472
76508
  details.TRAFFIC_NEST > summary::-webkit-details-marker { display: none; }
76473
- .TRAFFIC_NEST_KEY { opacity: 0.85; }
76474
- .TRAFFIC_NEST_HINT { opacity: 0.5; margin-left: 4px; }
76475
- .YDEV_EMPTY { opacity: 0.5; font-size: 12px; padding: 18px 10px; text-align: center; }
76509
+ .TRAFFIC_NEST_KEY { color: var(--ydev-key); }
76510
+ .TRAFFIC_NEST_HINT { color: var(--ydev-dim); margin-left: 4px; }
76511
+ /* The folded preview, painted with the same ink as the expanded rows: a key
76512
+ is a key and a string is a string wherever it is read. */
76513
+ .TRAFFIC_NEST_HINT_WRAP { margin-left: 4px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
76514
+ .TRAFFIC_PREV.p-punct { color: var(--ydev-dim); }
76515
+ .TRAFFIC_PREV.p-key { color: var(--ydev-key); }
76516
+ .TRAFFIC_PREV.t-str { color: var(--ydev-str); }
76517
+ .TRAFFIC_PREV.t-num { color: var(--ydev-num); }
76518
+ .TRAFFIC_PREV.t-bool { color: var(--ydev-bool); }
76519
+ .TRAFFIC_PREV.t-null { color: var(--ydev-bool); font-style: italic; }
76520
+ .TRAFFIC_PREV.t-empty { color: var(--ydev-dim); }
76521
+ .YDEV_EMPTY { color: var(--ydev-dim); font-size: 12px; padding: 18px 10px; text-align: center; }
76476
76522
  /* -------- mirrored console logs (error/warning/info/debug/msg; the automata trace shows as debug) -------- */
76477
76523
  .YDEV_LOGROW { display: flex; align-items: baseline; gap: 8px; margin: 1px 0; padding: 2px 8px; border-left: 3px solid #94a3b8; border-radius: 3px; font-family: "DejaVu Sans Mono", monospace, consolas, monaco; font-size: 12px; background: rgba(0,0,0,0.015); }
76478
- .YDEV_LOG_LVL { flex: 0 0 auto; text-transform: uppercase; font-size: 9px; font-weight: 700; letter-spacing: 0.04em; opacity: 0.8; min-width: 48px; }
76479
- .YDEV_LOG_TXT { flex: 1 1 auto; min-width: 0; white-space: pre-wrap; word-break: break-word; opacity: 0.9; }
76524
+ .YDEV_LOG_LVL { flex: 0 0 auto; text-transform: uppercase; font-size: 9px; font-weight: 700; letter-spacing: 0.04em; color: var(--ydev-dim); min-width: 48px; }
76525
+ .YDEV_LOG_TXT { flex: 1 1 auto; min-width: 0; white-space: pre-wrap; word-break: break-word; color: var(--ydev-ink); }
76480
76526
  .YDEV_LOG_error { border-left-color: #dc2626; } .YDEV_LOG_error .YDEV_LOG_LVL { color: #dc2626; }
76481
76527
  .YDEV_LOG_warning { border-left-color: #d97706; } .YDEV_LOG_warning .YDEV_LOG_LVL { color: #d97706; }
76482
76528
  .YDEV_LOG_info { border-left-color: #2563eb; } .YDEV_LOG_info .YDEV_LOG_LVL { color: #2563eb; }
76483
76529
  .YDEV_LOG_msg { border-left-color: #0891b2; } .YDEV_LOG_msg .YDEV_LOG_LVL { color: #0891b2; }
76484
- .YDEV_LOG_debug { border-left-color: #94a3b8; } .YDEV_LOG_debug .YDEV_LOG_LVL { color: #94a3b8; } .YDEV_LOG_debug .YDEV_LOG_TXT { opacity: 0.72; }
76485
- .YDEV_LOG_json { border-left-color: #9333ea; align-items: flex-start; } .YDEV_LOG_json .YDEV_LOG_LVL { color: #9333ea; } .YDEV_LOG_json .YDEV_LOG_TXT { font-size: 11px; line-height: 1.35; opacity: 0.8; }
76530
+ .YDEV_LOG_debug { border-left-color: #94a3b8; } .YDEV_LOG_debug .YDEV_LOG_LVL { color: #94a3b8; } .YDEV_LOG_debug .YDEV_LOG_TXT { color: var(--ydev-dim); }
76531
+ .YDEV_LOG_json { border-left-color: #9333ea; align-items: flex-start; } .YDEV_LOG_json .YDEV_LOG_LVL { color: #9333ea; } .YDEV_LOG_json .YDEV_LOG_TXT { font-size: 11px; line-height: 1.35; color: var(--ydev-dim); }
76486
76532
  /* -------- dark theme -------- */
76487
76533
  :root[data-theme="dark"] .TRAFFIC_FULL { background: rgba(255,255,255,0.05); }
76488
76534
  :root[data-theme="dark"] .YDEV_BAR, :root[data-theme="dark"] .YDEV_STATS { background: rgba(255,255,255,0.04); }
@@ -76497,7 +76543,7 @@ details.TRAFFIC_NEST > summary::-webkit-details-marker { display: none; }
76497
76543
  :root[data-theme="dark"] .dir-err .TRAFFIC_ARROW, :root[data-theme="dark"] .dir-err .TRAFFIC_EVENT { color: #f87171; }
76498
76544
  :root[data-theme="dark"] .YDEV_STAT.s-out { color: #60a5fa; } :root[data-theme="dark"] .YDEV_STAT.s-in { color: #34d399; } :root[data-theme="dark"] .YDEV_STAT.s-err { color: #f87171; }
76499
76545
  :root[data-theme="dark"] .YDEV_STAT.s-warn { color: #fbbf24; }
76500
- :root[data-theme="dark"] .TRAFFIC_VAL.t-num { color: #22d3ee; }
76546
+
76501
76547
  :root[data-theme="dark"] .TRAFFIC_VAL.t-bool, :root[data-theme="dark"] .TRAFFIC_VAL.t-null { color: #c084fc; }
76502
76548
  :root[data-theme="dark"] .YDEV_CHIP.is-active { background: rgba(96,165,250,0.2); border-color: #60a5fa; color: #93c5fd; }
76503
76549
  :root[data-theme="dark"] .YDEV_SEG_BTN.is-active { background: #2563eb; color: #fff; }
@@ -76571,24 +76617,65 @@ var PREVIEW_MAX_KEYS = 4;
76571
76617
  var PREVIEW_MAX_CHARS = 90;
76572
76618
  var PREVIEW_MAX_VALUE = 28;
76573
76619
  function preview_scalar(v) {
76574
- if (v === null) return "null";
76575
- if (typeof v === "string") return "\"" + (v.length > PREVIEW_MAX_VALUE ? v.slice(0, PREVIEW_MAX_VALUE) + "…" : v) + "\"";
76576
- if (typeof v === "object") return Array.isArray(v) ? "[…]" : "{…}";
76577
- return String(v);
76620
+ if (v === null) return {
76621
+ text: "null",
76622
+ cls: "t-null"
76623
+ };
76624
+ if (typeof v === "string") return {
76625
+ text: "\"" + (v.length > PREVIEW_MAX_VALUE ? v.slice(0, PREVIEW_MAX_VALUE) + "…" : v) + "\"",
76626
+ cls: "t-str"
76627
+ };
76628
+ if (typeof v === "object") return {
76629
+ text: Array.isArray(v) ? "[…]" : "{…}",
76630
+ cls: "t-empty"
76631
+ };
76632
+ if (typeof v === "boolean") return {
76633
+ text: String(v),
76634
+ cls: "t-bool"
76635
+ };
76636
+ return {
76637
+ text: String(v),
76638
+ cls: "t-num"
76639
+ };
76578
76640
  }
76579
- function object_preview(obj, count) {
76641
+ function object_preview_parts(obj, count) {
76580
76642
  let keys = Object.keys(obj);
76581
- let parts = [];
76643
+ let out = [{
76644
+ text: "{",
76645
+ cls: "p-punct"
76646
+ }];
76647
+ let fields = 0;
76582
76648
  let used = 0;
76583
76649
  for (let k of keys) {
76584
- if (parts.length >= PREVIEW_MAX_KEYS) break;
76585
- let part = k + ": " + preview_scalar(obj[k]);
76586
- if (parts.length > 0 && used + part.length > PREVIEW_MAX_CHARS) break;
76587
- parts.push(part);
76588
- used += part.length + 2;
76650
+ if (fields >= PREVIEW_MAX_KEYS) break;
76651
+ let val = preview_scalar(obj[k]);
76652
+ let width = k.length + 2 + val.text.length;
76653
+ if (fields > 0 && used + width > PREVIEW_MAX_CHARS) break;
76654
+ if (fields > 0) out.push({
76655
+ text: ", ",
76656
+ cls: "p-punct"
76657
+ });
76658
+ out.push({
76659
+ text: k,
76660
+ cls: "p-key"
76661
+ });
76662
+ out.push({
76663
+ text: ": ",
76664
+ cls: "p-punct"
76665
+ });
76666
+ out.push(val);
76667
+ fields++;
76668
+ used += width + 2;
76589
76669
  }
76590
- if (parts.length < count) parts.push("…");
76591
- return "{" + parts.join(", ") + "}";
76670
+ if (fields < count) out.push({
76671
+ text: fields > 0 ? ", …" : "…",
76672
+ cls: "p-punct"
76673
+ });
76674
+ out.push({
76675
+ text: "}",
76676
+ cls: "p-punct"
76677
+ });
76678
+ return out;
76592
76679
  }
76593
76680
  /************************************************************
76594
76681
  * One field of any type. Scalars → a bullet row; objects and
@@ -76620,7 +76707,15 @@ function traffic_value_node(key, value) {
76620
76707
  ]
76621
76708
  ]
76622
76709
  ];
76623
- let hint = is_arr ? `[${count}]` : object_preview(value, count);
76710
+ let hint = is_arr ? [[
76711
+ "span",
76712
+ { class: "TRAFFIC_NEST_HINT" },
76713
+ `[${count}]`
76714
+ ]] : object_preview_parts(value, count).map((t) => [
76715
+ "span",
76716
+ { class: "TRAFFIC_PREV " + t.cls },
76717
+ t.text
76718
+ ]);
76624
76719
  return [
76625
76720
  "details",
76626
76721
  { class: "TRAFFIC_NEST" },
@@ -76640,7 +76735,7 @@ function traffic_value_node(key, value) {
76640
76735
  ],
76641
76736
  [
76642
76737
  "span",
76643
- { class: "TRAFFIC_NEST_HINT" },
76738
+ { class: "TRAFFIC_NEST_HINT_WRAP" },
76644
76739
  hint
76645
76740
  ]
76646
76741
  ]
@@ -76425,6 +76425,41 @@ function ensure_dev_style() {
76425
76425
  .YDEV_TITLE { display: flex; align-items: baseline; gap: 8px; }
76426
76426
  .YDEV_TITLE_MAIN { font-weight: 700; }
76427
76427
  .YDEV_TITLE_SUB { opacity: 0.7; font-size: 12px; }
76428
+ /* The ink of the log.
76429
+ *
76430
+ * It used to be one grey dimmed with opacity per role -- 0.85 for a key,
76431
+ * 0.5 for a preview, 0.45 for the source -- which is what washed the window
76432
+ * out: opacity blends text TOWARDS the background, so the more a line
76433
+ * mattered the less of it was left. Measured on the dark scheme the preview
76434
+ * came out at 4.39:1 and the source at 3.78:1, both under the 4.5 floor,
76435
+ * and everything that was legible was the same grey as everything else.
76436
+ *
76437
+ * Explicit colours now, one per ROLE and measured against the entry's own
76438
+ * background (#1b1e24 dark, #fafafa light): a key, a string, a number and a
76439
+ * boolean read apart from each other the way they do in a browser console,
76440
+ * which is the point of colouring a payload at all.
76441
+ * Ratios: dark 11.20 / 6.32 / 9.83 / 6.00 / 6.77 / 6.49 / 4.82,
76442
+ * light 7.38 / 7.52 / 5.16 / 8.35 / 5.59 / 7.21 / 4.35. */
76443
+ :root {
76444
+ --ydev-ink: #1f2937;
76445
+ --ydev-key: #0451a5;
76446
+ --ydev-str: #a31515;
76447
+ --ydev-num: #067a4e;
76448
+ --ydev-bool: #6b21a8;
76449
+ --ydev-dim: #5b6675;
76450
+ --ydev-src: #4a5568;
76451
+ --ydev-bullet: #6b7789;
76452
+ }
76453
+ :root[data-theme="dark"] {
76454
+ --ydev-ink: #e5e7eb;
76455
+ --ydev-key: #9cdcfe;
76456
+ --ydev-str: #ce9178;
76457
+ --ydev-num: #b5cea8;
76458
+ --ydev-bool: #c586c0;
76459
+ --ydev-dim: #9aa6b8;
76460
+ --ydev-src: #8fa3bf;
76461
+ --ydev-bullet: #7b8ba3;
76462
+ }
76428
76463
  /* -------- entries (shared) -------- */
76429
76464
  .TRAFFIC_ENTRY {
76430
76465
  border-left: 3px solid #94a3b8; border-radius: 3px;
@@ -76438,15 +76473,15 @@ function ensure_dev_style() {
76438
76473
  .TRAFFIC_HEADER { display: flex; align-items: baseline; gap: 8px; }
76439
76474
  .TRAFFIC_ARROW { font-weight: 700; }
76440
76475
  .TRAFFIC_EVENT { font-weight: 700; }
76441
- .TRAFFIC_CMD { opacity: 0.75; font-weight: 600; }
76476
+ .TRAFFIC_CMD { color: var(--ydev-dim); font-weight: 600; }
76442
76477
  /* Where the message went through. min-width 0 and flex 0 1 auto so it is the
76443
76478
  part that gives way when the row runs out of width -- the event name and
76444
76479
  the size/time must not be the ones to go. */
76445
- .TRAFFIC_SRC { opacity: 0.45; font-size: 11px; flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
76480
+ .TRAFFIC_SRC { color: var(--ydev-src); font-size: 11px; flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
76446
76481
  .dir-out .TRAFFIC_ARROW, .dir-out .TRAFFIC_EVENT { color: #2563eb; }
76447
76482
  .dir-in .TRAFFIC_ARROW, .dir-in .TRAFFIC_EVENT { color: #059669; }
76448
76483
  .dir-err .TRAFFIC_ARROW, .dir-err .TRAFFIC_EVENT { color: #dc2626; }
76449
- .TRAFFIC_META { margin-left: auto; opacity: 0.6; font-size: 11px; white-space: nowrap; }
76484
+ .TRAFFIC_META { margin-left: auto; color: var(--ydev-dim); font-size: 11px; white-space: nowrap; }
76450
76485
  /* The indent of a nested block is NOT a hover effect: it used to be given
76451
76486
  only on .TRAFFIC_ENTRY:hover, so moving the cursor across the log made
76452
76487
  every payload under it jump 16px sideways and reflow. A payload being
@@ -76455,29 +76490,40 @@ function ensure_dev_style() {
76455
76490
  .TRAFFIC_KW { margin: 2px 0 0 16px; }
76456
76491
  .TRAFFIC_FULL { margin: 4px 0 0 16px; padding: 6px 8px; font-family: monospace; font-size: 11px; line-height: 1.4; white-space: pre-wrap; word-break: break-word; background: rgba(0,0,0,0.04); border-radius: 4px; overflow-x: auto; }
76457
76492
  .TRAFFIC_ROW { display: flex; gap: 6px; align-items: baseline; }
76458
- .TRAFFIC_BULLET { opacity: 0.45; flex: 0 0 auto; }
76459
- .TRAFFIC_KEY { opacity: 0.85; flex: 0 0 auto; }
76460
- .TRAFFIC_VAL { word-break: break-word; }
76461
- .TRAFFIC_VAL.t-num { color: #0891b2; }
76462
- .TRAFFIC_VAL.t-bool { color: #9333ea; }
76463
- .TRAFFIC_VAL.t-null { color: #9333ea; font-style: italic; }
76464
- .TRAFFIC_VAL.t-empty { opacity: 0.5; }
76465
- .TRAFFIC_TS { opacity: 0.6; margin-left: 8px; }
76493
+ .TRAFFIC_BULLET { color: var(--ydev-bullet); flex: 0 0 auto; }
76494
+ .TRAFFIC_KEY { color: var(--ydev-key); flex: 0 0 auto; }
76495
+ .TRAFFIC_VAL { color: var(--ydev-ink); word-break: break-word; }
76496
+ .TRAFFIC_VAL.t-str { color: var(--ydev-str); }
76497
+ .TRAFFIC_VAL.t-num { color: var(--ydev-num); }
76498
+ .TRAFFIC_VAL.t-bool { color: var(--ydev-bool); }
76499
+ .TRAFFIC_VAL.t-null { color: var(--ydev-bool); font-style: italic; }
76500
+ .TRAFFIC_VAL.t-empty { color: var(--ydev-dim); }
76501
+ .TRAFFIC_TS { color: var(--ydev-dim); margin-left: 8px; }
76466
76502
  details.TRAFFIC_NEST > summary { cursor: pointer; list-style: none; display: flex; gap: 6px; align-items: baseline; }
76467
76503
  details.TRAFFIC_NEST > summary::-webkit-details-marker { display: none; }
76468
- .TRAFFIC_NEST_KEY { opacity: 0.85; }
76469
- .TRAFFIC_NEST_HINT { opacity: 0.5; margin-left: 4px; }
76470
- .YDEV_EMPTY { opacity: 0.5; font-size: 12px; padding: 18px 10px; text-align: center; }
76504
+ .TRAFFIC_NEST_KEY { color: var(--ydev-key); }
76505
+ .TRAFFIC_NEST_HINT { color: var(--ydev-dim); margin-left: 4px; }
76506
+ /* The folded preview, painted with the same ink as the expanded rows: a key
76507
+ is a key and a string is a string wherever it is read. */
76508
+ .TRAFFIC_NEST_HINT_WRAP { margin-left: 4px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
76509
+ .TRAFFIC_PREV.p-punct { color: var(--ydev-dim); }
76510
+ .TRAFFIC_PREV.p-key { color: var(--ydev-key); }
76511
+ .TRAFFIC_PREV.t-str { color: var(--ydev-str); }
76512
+ .TRAFFIC_PREV.t-num { color: var(--ydev-num); }
76513
+ .TRAFFIC_PREV.t-bool { color: var(--ydev-bool); }
76514
+ .TRAFFIC_PREV.t-null { color: var(--ydev-bool); font-style: italic; }
76515
+ .TRAFFIC_PREV.t-empty { color: var(--ydev-dim); }
76516
+ .YDEV_EMPTY { color: var(--ydev-dim); font-size: 12px; padding: 18px 10px; text-align: center; }
76471
76517
  /* -------- mirrored console logs (error/warning/info/debug/msg; the automata trace shows as debug) -------- */
76472
76518
  .YDEV_LOGROW { display: flex; align-items: baseline; gap: 8px; margin: 1px 0; padding: 2px 8px; border-left: 3px solid #94a3b8; border-radius: 3px; font-family: "DejaVu Sans Mono", monospace, consolas, monaco; font-size: 12px; background: rgba(0,0,0,0.015); }
76473
- .YDEV_LOG_LVL { flex: 0 0 auto; text-transform: uppercase; font-size: 9px; font-weight: 700; letter-spacing: 0.04em; opacity: 0.8; min-width: 48px; }
76474
- .YDEV_LOG_TXT { flex: 1 1 auto; min-width: 0; white-space: pre-wrap; word-break: break-word; opacity: 0.9; }
76519
+ .YDEV_LOG_LVL { flex: 0 0 auto; text-transform: uppercase; font-size: 9px; font-weight: 700; letter-spacing: 0.04em; color: var(--ydev-dim); min-width: 48px; }
76520
+ .YDEV_LOG_TXT { flex: 1 1 auto; min-width: 0; white-space: pre-wrap; word-break: break-word; color: var(--ydev-ink); }
76475
76521
  .YDEV_LOG_error { border-left-color: #dc2626; } .YDEV_LOG_error .YDEV_LOG_LVL { color: #dc2626; }
76476
76522
  .YDEV_LOG_warning { border-left-color: #d97706; } .YDEV_LOG_warning .YDEV_LOG_LVL { color: #d97706; }
76477
76523
  .YDEV_LOG_info { border-left-color: #2563eb; } .YDEV_LOG_info .YDEV_LOG_LVL { color: #2563eb; }
76478
76524
  .YDEV_LOG_msg { border-left-color: #0891b2; } .YDEV_LOG_msg .YDEV_LOG_LVL { color: #0891b2; }
76479
- .YDEV_LOG_debug { border-left-color: #94a3b8; } .YDEV_LOG_debug .YDEV_LOG_LVL { color: #94a3b8; } .YDEV_LOG_debug .YDEV_LOG_TXT { opacity: 0.72; }
76480
- .YDEV_LOG_json { border-left-color: #9333ea; align-items: flex-start; } .YDEV_LOG_json .YDEV_LOG_LVL { color: #9333ea; } .YDEV_LOG_json .YDEV_LOG_TXT { font-size: 11px; line-height: 1.35; opacity: 0.8; }
76525
+ .YDEV_LOG_debug { border-left-color: #94a3b8; } .YDEV_LOG_debug .YDEV_LOG_LVL { color: #94a3b8; } .YDEV_LOG_debug .YDEV_LOG_TXT { color: var(--ydev-dim); }
76526
+ .YDEV_LOG_json { border-left-color: #9333ea; align-items: flex-start; } .YDEV_LOG_json .YDEV_LOG_LVL { color: #9333ea; } .YDEV_LOG_json .YDEV_LOG_TXT { font-size: 11px; line-height: 1.35; color: var(--ydev-dim); }
76481
76527
  /* -------- dark theme -------- */
76482
76528
  :root[data-theme="dark"] .TRAFFIC_FULL { background: rgba(255,255,255,0.05); }
76483
76529
  :root[data-theme="dark"] .YDEV_BAR, :root[data-theme="dark"] .YDEV_STATS { background: rgba(255,255,255,0.04); }
@@ -76492,7 +76538,7 @@ details.TRAFFIC_NEST > summary::-webkit-details-marker { display: none; }
76492
76538
  :root[data-theme="dark"] .dir-err .TRAFFIC_ARROW, :root[data-theme="dark"] .dir-err .TRAFFIC_EVENT { color: #f87171; }
76493
76539
  :root[data-theme="dark"] .YDEV_STAT.s-out { color: #60a5fa; } :root[data-theme="dark"] .YDEV_STAT.s-in { color: #34d399; } :root[data-theme="dark"] .YDEV_STAT.s-err { color: #f87171; }
76494
76540
  :root[data-theme="dark"] .YDEV_STAT.s-warn { color: #fbbf24; }
76495
- :root[data-theme="dark"] .TRAFFIC_VAL.t-num { color: #22d3ee; }
76541
+
76496
76542
  :root[data-theme="dark"] .TRAFFIC_VAL.t-bool, :root[data-theme="dark"] .TRAFFIC_VAL.t-null { color: #c084fc; }
76497
76543
  :root[data-theme="dark"] .YDEV_CHIP.is-active { background: rgba(96,165,250,0.2); border-color: #60a5fa; color: #93c5fd; }
76498
76544
  :root[data-theme="dark"] .YDEV_SEG_BTN.is-active { background: #2563eb; color: #fff; }
@@ -76566,24 +76612,65 @@ var PREVIEW_MAX_KEYS = 4;
76566
76612
  var PREVIEW_MAX_CHARS = 90;
76567
76613
  var PREVIEW_MAX_VALUE = 28;
76568
76614
  function preview_scalar(v) {
76569
- if (v === null) return "null";
76570
- if (typeof v === "string") return "\"" + (v.length > PREVIEW_MAX_VALUE ? v.slice(0, PREVIEW_MAX_VALUE) + "…" : v) + "\"";
76571
- if (typeof v === "object") return Array.isArray(v) ? "[…]" : "{…}";
76572
- return String(v);
76615
+ if (v === null) return {
76616
+ text: "null",
76617
+ cls: "t-null"
76618
+ };
76619
+ if (typeof v === "string") return {
76620
+ text: "\"" + (v.length > PREVIEW_MAX_VALUE ? v.slice(0, PREVIEW_MAX_VALUE) + "…" : v) + "\"",
76621
+ cls: "t-str"
76622
+ };
76623
+ if (typeof v === "object") return {
76624
+ text: Array.isArray(v) ? "[…]" : "{…}",
76625
+ cls: "t-empty"
76626
+ };
76627
+ if (typeof v === "boolean") return {
76628
+ text: String(v),
76629
+ cls: "t-bool"
76630
+ };
76631
+ return {
76632
+ text: String(v),
76633
+ cls: "t-num"
76634
+ };
76573
76635
  }
76574
- function object_preview(obj, count) {
76636
+ function object_preview_parts(obj, count) {
76575
76637
  let keys = Object.keys(obj);
76576
- let parts = [];
76638
+ let out = [{
76639
+ text: "{",
76640
+ cls: "p-punct"
76641
+ }];
76642
+ let fields = 0;
76577
76643
  let used = 0;
76578
76644
  for (let k of keys) {
76579
- if (parts.length >= PREVIEW_MAX_KEYS) break;
76580
- let part = k + ": " + preview_scalar(obj[k]);
76581
- if (parts.length > 0 && used + part.length > PREVIEW_MAX_CHARS) break;
76582
- parts.push(part);
76583
- used += part.length + 2;
76645
+ if (fields >= PREVIEW_MAX_KEYS) break;
76646
+ let val = preview_scalar(obj[k]);
76647
+ let width = k.length + 2 + val.text.length;
76648
+ if (fields > 0 && used + width > PREVIEW_MAX_CHARS) break;
76649
+ if (fields > 0) out.push({
76650
+ text: ", ",
76651
+ cls: "p-punct"
76652
+ });
76653
+ out.push({
76654
+ text: k,
76655
+ cls: "p-key"
76656
+ });
76657
+ out.push({
76658
+ text: ": ",
76659
+ cls: "p-punct"
76660
+ });
76661
+ out.push(val);
76662
+ fields++;
76663
+ used += width + 2;
76584
76664
  }
76585
- if (parts.length < count) parts.push("…");
76586
- return "{" + parts.join(", ") + "}";
76665
+ if (fields < count) out.push({
76666
+ text: fields > 0 ? ", …" : "…",
76667
+ cls: "p-punct"
76668
+ });
76669
+ out.push({
76670
+ text: "}",
76671
+ cls: "p-punct"
76672
+ });
76673
+ return out;
76587
76674
  }
76588
76675
  /************************************************************
76589
76676
  * One field of any type. Scalars → a bullet row; objects and
@@ -76615,7 +76702,15 @@ function traffic_value_node(key, value) {
76615
76702
  ]
76616
76703
  ]
76617
76704
  ];
76618
- let hint = is_arr ? `[${count}]` : object_preview(value, count);
76705
+ let hint = is_arr ? [[
76706
+ "span",
76707
+ { class: "TRAFFIC_NEST_HINT" },
76708
+ `[${count}]`
76709
+ ]] : object_preview_parts(value, count).map((t) => [
76710
+ "span",
76711
+ { class: "TRAFFIC_PREV " + t.cls },
76712
+ t.text
76713
+ ]);
76619
76714
  return [
76620
76715
  "details",
76621
76716
  { class: "TRAFFIC_NEST" },
@@ -76635,7 +76730,7 @@ function traffic_value_node(key, value) {
76635
76730
  ],
76636
76731
  [
76637
76732
  "span",
76638
- { class: "TRAFFIC_NEST_HINT" },
76733
+ { class: "TRAFFIC_NEST_HINT_WRAP" },
76639
76734
  hint
76640
76735
  ]
76641
76736
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuneta/gobj-ui",
3
- "version": "7.23.179",
3
+ "version": "7.23.180",
4
4
  "type": "module",
5
5
  "main": "dist/gobj-ui.cjs.js",
6
6
  "module": "dist/gobj-ui.es.js",
package/src/yui_dev.js CHANGED
@@ -450,6 +450,41 @@ function ensure_dev_style()
450
450
  .YDEV_TITLE { display: flex; align-items: baseline; gap: 8px; }
451
451
  .YDEV_TITLE_MAIN { font-weight: 700; }
452
452
  .YDEV_TITLE_SUB { opacity: 0.7; font-size: 12px; }
453
+ /* The ink of the log.
454
+ *
455
+ * It used to be one grey dimmed with opacity per role -- 0.85 for a key,
456
+ * 0.5 for a preview, 0.45 for the source -- which is what washed the window
457
+ * out: opacity blends text TOWARDS the background, so the more a line
458
+ * mattered the less of it was left. Measured on the dark scheme the preview
459
+ * came out at 4.39:1 and the source at 3.78:1, both under the 4.5 floor,
460
+ * and everything that was legible was the same grey as everything else.
461
+ *
462
+ * Explicit colours now, one per ROLE and measured against the entry's own
463
+ * background (#1b1e24 dark, #fafafa light): a key, a string, a number and a
464
+ * boolean read apart from each other the way they do in a browser console,
465
+ * which is the point of colouring a payload at all.
466
+ * Ratios: dark 11.20 / 6.32 / 9.83 / 6.00 / 6.77 / 6.49 / 4.82,
467
+ * light 7.38 / 7.52 / 5.16 / 8.35 / 5.59 / 7.21 / 4.35. */
468
+ :root {
469
+ --ydev-ink: #1f2937;
470
+ --ydev-key: #0451a5;
471
+ --ydev-str: #a31515;
472
+ --ydev-num: #067a4e;
473
+ --ydev-bool: #6b21a8;
474
+ --ydev-dim: #5b6675;
475
+ --ydev-src: #4a5568;
476
+ --ydev-bullet: #6b7789;
477
+ }
478
+ :root[data-theme="dark"] {
479
+ --ydev-ink: #e5e7eb;
480
+ --ydev-key: #9cdcfe;
481
+ --ydev-str: #ce9178;
482
+ --ydev-num: #b5cea8;
483
+ --ydev-bool: #c586c0;
484
+ --ydev-dim: #9aa6b8;
485
+ --ydev-src: #8fa3bf;
486
+ --ydev-bullet: #7b8ba3;
487
+ }
453
488
  /* -------- entries (shared) -------- */
454
489
  .TRAFFIC_ENTRY {
455
490
  border-left: 3px solid #94a3b8; border-radius: 3px;
@@ -463,15 +498,15 @@ function ensure_dev_style()
463
498
  .TRAFFIC_HEADER { display: flex; align-items: baseline; gap: 8px; }
464
499
  .TRAFFIC_ARROW { font-weight: 700; }
465
500
  .TRAFFIC_EVENT { font-weight: 700; }
466
- .TRAFFIC_CMD { opacity: 0.75; font-weight: 600; }
501
+ .TRAFFIC_CMD { color: var(--ydev-dim); font-weight: 600; }
467
502
  /* Where the message went through. min-width 0 and flex 0 1 auto so it is the
468
503
  part that gives way when the row runs out of width -- the event name and
469
504
  the size/time must not be the ones to go. */
470
- .TRAFFIC_SRC { opacity: 0.45; font-size: 11px; flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
505
+ .TRAFFIC_SRC { color: var(--ydev-src); font-size: 11px; flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
471
506
  .dir-out .TRAFFIC_ARROW, .dir-out .TRAFFIC_EVENT { color: #2563eb; }
472
507
  .dir-in .TRAFFIC_ARROW, .dir-in .TRAFFIC_EVENT { color: #059669; }
473
508
  .dir-err .TRAFFIC_ARROW, .dir-err .TRAFFIC_EVENT { color: #dc2626; }
474
- .TRAFFIC_META { margin-left: auto; opacity: 0.6; font-size: 11px; white-space: nowrap; }
509
+ .TRAFFIC_META { margin-left: auto; color: var(--ydev-dim); font-size: 11px; white-space: nowrap; }
475
510
  /* The indent of a nested block is NOT a hover effect: it used to be given
476
511
  only on .TRAFFIC_ENTRY:hover, so moving the cursor across the log made
477
512
  every payload under it jump 16px sideways and reflow. A payload being
@@ -480,29 +515,40 @@ function ensure_dev_style()
480
515
  .TRAFFIC_KW { margin: 2px 0 0 16px; }
481
516
  .TRAFFIC_FULL { margin: 4px 0 0 16px; padding: 6px 8px; font-family: monospace; font-size: 11px; line-height: 1.4; white-space: pre-wrap; word-break: break-word; background: rgba(0,0,0,0.04); border-radius: 4px; overflow-x: auto; }
482
517
  .TRAFFIC_ROW { display: flex; gap: 6px; align-items: baseline; }
483
- .TRAFFIC_BULLET { opacity: 0.45; flex: 0 0 auto; }
484
- .TRAFFIC_KEY { opacity: 0.85; flex: 0 0 auto; }
485
- .TRAFFIC_VAL { word-break: break-word; }
486
- .TRAFFIC_VAL.t-num { color: #0891b2; }
487
- .TRAFFIC_VAL.t-bool { color: #9333ea; }
488
- .TRAFFIC_VAL.t-null { color: #9333ea; font-style: italic; }
489
- .TRAFFIC_VAL.t-empty { opacity: 0.5; }
490
- .TRAFFIC_TS { opacity: 0.6; margin-left: 8px; }
518
+ .TRAFFIC_BULLET { color: var(--ydev-bullet); flex: 0 0 auto; }
519
+ .TRAFFIC_KEY { color: var(--ydev-key); flex: 0 0 auto; }
520
+ .TRAFFIC_VAL { color: var(--ydev-ink); word-break: break-word; }
521
+ .TRAFFIC_VAL.t-str { color: var(--ydev-str); }
522
+ .TRAFFIC_VAL.t-num { color: var(--ydev-num); }
523
+ .TRAFFIC_VAL.t-bool { color: var(--ydev-bool); }
524
+ .TRAFFIC_VAL.t-null { color: var(--ydev-bool); font-style: italic; }
525
+ .TRAFFIC_VAL.t-empty { color: var(--ydev-dim); }
526
+ .TRAFFIC_TS { color: var(--ydev-dim); margin-left: 8px; }
491
527
  details.TRAFFIC_NEST > summary { cursor: pointer; list-style: none; display: flex; gap: 6px; align-items: baseline; }
492
528
  details.TRAFFIC_NEST > summary::-webkit-details-marker { display: none; }
493
- .TRAFFIC_NEST_KEY { opacity: 0.85; }
494
- .TRAFFIC_NEST_HINT { opacity: 0.5; margin-left: 4px; }
495
- .YDEV_EMPTY { opacity: 0.5; font-size: 12px; padding: 18px 10px; text-align: center; }
529
+ .TRAFFIC_NEST_KEY { color: var(--ydev-key); }
530
+ .TRAFFIC_NEST_HINT { color: var(--ydev-dim); margin-left: 4px; }
531
+ /* The folded preview, painted with the same ink as the expanded rows: a key
532
+ is a key and a string is a string wherever it is read. */
533
+ .TRAFFIC_NEST_HINT_WRAP { margin-left: 4px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
534
+ .TRAFFIC_PREV.p-punct { color: var(--ydev-dim); }
535
+ .TRAFFIC_PREV.p-key { color: var(--ydev-key); }
536
+ .TRAFFIC_PREV.t-str { color: var(--ydev-str); }
537
+ .TRAFFIC_PREV.t-num { color: var(--ydev-num); }
538
+ .TRAFFIC_PREV.t-bool { color: var(--ydev-bool); }
539
+ .TRAFFIC_PREV.t-null { color: var(--ydev-bool); font-style: italic; }
540
+ .TRAFFIC_PREV.t-empty { color: var(--ydev-dim); }
541
+ .YDEV_EMPTY { color: var(--ydev-dim); font-size: 12px; padding: 18px 10px; text-align: center; }
496
542
  /* -------- mirrored console logs (error/warning/info/debug/msg; the automata trace shows as debug) -------- */
497
543
  .YDEV_LOGROW { display: flex; align-items: baseline; gap: 8px; margin: 1px 0; padding: 2px 8px; border-left: 3px solid #94a3b8; border-radius: 3px; font-family: "DejaVu Sans Mono", monospace, consolas, monaco; font-size: 12px; background: rgba(0,0,0,0.015); }
498
- .YDEV_LOG_LVL { flex: 0 0 auto; text-transform: uppercase; font-size: 9px; font-weight: 700; letter-spacing: 0.04em; opacity: 0.8; min-width: 48px; }
499
- .YDEV_LOG_TXT { flex: 1 1 auto; min-width: 0; white-space: pre-wrap; word-break: break-word; opacity: 0.9; }
544
+ .YDEV_LOG_LVL { flex: 0 0 auto; text-transform: uppercase; font-size: 9px; font-weight: 700; letter-spacing: 0.04em; color: var(--ydev-dim); min-width: 48px; }
545
+ .YDEV_LOG_TXT { flex: 1 1 auto; min-width: 0; white-space: pre-wrap; word-break: break-word; color: var(--ydev-ink); }
500
546
  .YDEV_LOG_error { border-left-color: #dc2626; } .YDEV_LOG_error .YDEV_LOG_LVL { color: #dc2626; }
501
547
  .YDEV_LOG_warning { border-left-color: #d97706; } .YDEV_LOG_warning .YDEV_LOG_LVL { color: #d97706; }
502
548
  .YDEV_LOG_info { border-left-color: #2563eb; } .YDEV_LOG_info .YDEV_LOG_LVL { color: #2563eb; }
503
549
  .YDEV_LOG_msg { border-left-color: #0891b2; } .YDEV_LOG_msg .YDEV_LOG_LVL { color: #0891b2; }
504
- .YDEV_LOG_debug { border-left-color: #94a3b8; } .YDEV_LOG_debug .YDEV_LOG_LVL { color: #94a3b8; } .YDEV_LOG_debug .YDEV_LOG_TXT { opacity: 0.72; }
505
- .YDEV_LOG_json { border-left-color: #9333ea; align-items: flex-start; } .YDEV_LOG_json .YDEV_LOG_LVL { color: #9333ea; } .YDEV_LOG_json .YDEV_LOG_TXT { font-size: 11px; line-height: 1.35; opacity: 0.8; }
550
+ .YDEV_LOG_debug { border-left-color: #94a3b8; } .YDEV_LOG_debug .YDEV_LOG_LVL { color: #94a3b8; } .YDEV_LOG_debug .YDEV_LOG_TXT { color: var(--ydev-dim); }
551
+ .YDEV_LOG_json { border-left-color: #9333ea; align-items: flex-start; } .YDEV_LOG_json .YDEV_LOG_LVL { color: #9333ea; } .YDEV_LOG_json .YDEV_LOG_TXT { font-size: 11px; line-height: 1.35; color: var(--ydev-dim); }
506
552
  /* -------- dark theme -------- */
507
553
  :root[data-theme="dark"] .TRAFFIC_FULL { background: rgba(255,255,255,0.05); }
508
554
  :root[data-theme="dark"] .YDEV_BAR, :root[data-theme="dark"] .YDEV_STATS { background: rgba(255,255,255,0.04); }
@@ -517,7 +563,7 @@ details.TRAFFIC_NEST > summary::-webkit-details-marker { display: none; }
517
563
  :root[data-theme="dark"] .dir-err .TRAFFIC_ARROW, :root[data-theme="dark"] .dir-err .TRAFFIC_EVENT { color: #f87171; }
518
564
  :root[data-theme="dark"] .YDEV_STAT.s-out { color: #60a5fa; } :root[data-theme="dark"] .YDEV_STAT.s-in { color: #34d399; } :root[data-theme="dark"] .YDEV_STAT.s-err { color: #f87171; }
519
565
  :root[data-theme="dark"] .YDEV_STAT.s-warn { color: #fbbf24; }
520
- :root[data-theme="dark"] .TRAFFIC_VAL.t-num { color: #22d3ee; }
566
+
521
567
  :root[data-theme="dark"] .TRAFFIC_VAL.t-bool, :root[data-theme="dark"] .TRAFFIC_VAL.t-null { color: #c084fc; }
522
568
  :root[data-theme="dark"] .YDEV_CHIP.is-active { background: rgba(96,165,250,0.2); border-color: #60a5fa; color: #93c5fd; }
523
569
  :root[data-theme="dark"] .YDEV_SEG_BTN.is-active { background: #2563eb; color: #fff; }
@@ -603,44 +649,66 @@ const PREVIEW_MAX_VALUE = 28;
603
649
  function preview_scalar(v)
604
650
  {
605
651
  if(v === null) {
606
- return "null";
652
+ return {text: "null", cls: "t-null"};
607
653
  }
608
654
  if(typeof v === "string") {
609
655
  let text = (v.length > PREVIEW_MAX_VALUE) ?
610
656
  v.slice(0, PREVIEW_MAX_VALUE) + "…" : v;
611
- return '"' + text + '"';
657
+ return {text: '"' + text + '"', cls: "t-str"};
612
658
  }
613
659
  if(typeof v === "object") {
614
- return Array.isArray(v) ? "[…]" : "{…}";
660
+ return {text: Array.isArray(v) ? "[…]" : "{…}", cls: "t-empty"};
615
661
  }
616
- return String(v);
662
+ if(typeof v === "boolean") {
663
+ return {text: String(v), cls: "t-bool"};
664
+ }
665
+ return {text: String(v), cls: "t-num"};
617
666
  }
618
667
 
619
- function object_preview(obj, count)
668
+ /* The preview as TOKENS, so the renderer can paint a key, a string and a
669
+ number the way the expanded rows paint them. A preview in one flat grey
670
+ is the thing this window was asked to stop doing. */
671
+ function object_preview_parts(obj, count)
620
672
  {
621
673
  let keys = Object.keys(obj);
622
- let parts = [];
674
+ let out = [{text: "{", cls: "p-punct"}];
675
+ let fields = 0;
623
676
  let used = 0;
624
677
 
625
678
  for(let k of keys) {
626
- if(parts.length >= PREVIEW_MAX_KEYS) {
679
+ if(fields >= PREVIEW_MAX_KEYS) {
627
680
  break;
628
681
  }
629
- let part = k + ": " + preview_scalar(obj[k]);
682
+ let val = preview_scalar(obj[k]);
683
+ let width = k.length + 2 + val.text.length;
630
684
  /* Stop at the width, but never with an empty preview: one field
631
685
  too wide still says more than a number. */
632
- if(parts.length > 0 && used + part.length > PREVIEW_MAX_CHARS) {
686
+ if(fields > 0 && used + width > PREVIEW_MAX_CHARS) {
633
687
  break;
634
688
  }
635
- parts.push(part);
636
- used += part.length + 2;
689
+ if(fields > 0) {
690
+ out.push({text: ", ", cls: "p-punct"});
691
+ }
692
+ out.push({text: k, cls: "p-key"});
693
+ out.push({text: ": ", cls: "p-punct"});
694
+ out.push(val);
695
+ fields++;
696
+ used += width + 2;
637
697
  }
638
698
 
639
- if(parts.length < count) {
640
- parts.push("…");
699
+ if(fields < count) {
700
+ out.push({text: fields > 0 ? ", …" : "…", cls: "p-punct"});
641
701
  }
702
+ out.push({text: "}", cls: "p-punct"});
642
703
 
643
- return "{" + parts.join(", ") + "}";
704
+ return out;
705
+ }
706
+
707
+ /* The same preview as one string. What the tests assert on, and what any
708
+ caller wanting a plain line would use. */
709
+ function object_preview(obj, count)
710
+ {
711
+ return object_preview_parts(obj, count).map((t) => t.text).join("");
644
712
  }
645
713
 
646
714
  /************************************************************
@@ -664,12 +732,16 @@ function traffic_value_node(key, value)
664
732
  ]];
665
733
  }
666
734
 
667
- let hint = is_arr ? `[${count}]` : object_preview(value, count);
735
+ let hint = is_arr ?
736
+ [['span', {class: 'TRAFFIC_NEST_HINT'}, `[${count}]`]] :
737
+ object_preview_parts(value, count).map(
738
+ (t) => ['span', {class: 'TRAFFIC_PREV ' + t.cls}, t.text]
739
+ );
668
740
  return ['details', {class: 'TRAFFIC_NEST'}, [
669
741
  ['summary', {}, [
670
742
  ['span', {class: 'TRAFFIC_BULLET'}, '▸'],
671
743
  ['span', {class: 'TRAFFIC_NEST_KEY'}, key],
672
- ['span', {class: 'TRAFFIC_NEST_HINT'}, hint],
744
+ ['span', {class: 'TRAFFIC_NEST_HINT_WRAP'}, hint],
673
745
  ]],
674
746
  ['div', {class: 'TRAFFIC_KW'}, traffic_bullets(value)],
675
747
  ]];
@@ -1787,5 +1859,5 @@ export {
1787
1859
  guards this file from a syntax error nothing else would catch --
1788
1860
  the stylesheet below is a template literal, so one backtick in a CSS
1789
1861
  comment stops the whole module from parsing. */
1790
- object_preview,
1862
+ object_preview, object_preview_parts,
1791
1863
  };
@@ -13,7 +13,7 @@
13
13
  * All Rights Reserved.
14
14
  ***********************************************************************/
15
15
  import {describe, it, expect} from "vitest";
16
- import {object_preview} from "./yui_dev.js";
16
+ import {object_preview, object_preview_parts} from "./yui_dev.js";
17
17
 
18
18
  describe("object_preview", () => {
19
19
  it("names the first fields instead of counting them", () => {
@@ -56,3 +56,23 @@ describe("object_preview", () => {
56
56
  expect(object_preview({a: null, b: true}, 2)).toBe("{a: null, b: true}");
57
57
  });
58
58
  });
59
+
60
+ describe("object_preview_parts", () => {
61
+ it("gives every token the class its ink is chosen by", () => {
62
+ const parts = object_preview_parts({a: "s", b: 1, c: true, d: null}, 4);
63
+ const seen = parts.filter((t) => t.cls !== "p-punct")
64
+ .map((t) => [t.text, t.cls]);
65
+ expect(seen).toEqual([
66
+ ["a", "p-key"], ['"s"', "t-str"],
67
+ ["b", "p-key"], ["1", "t-num"],
68
+ ["c", "p-key"], ["true", "t-bool"],
69
+ ["d", "p-key"], ["null", "t-null"],
70
+ ]);
71
+ });
72
+
73
+ it("joins back into exactly what object_preview says", () => {
74
+ const o = {header: "id", fillspace: 18, flag: ["x"], hidden: false, more: 1};
75
+ const joined = object_preview_parts(o, 5).map((t) => t.text).join("");
76
+ expect(joined).toBe(object_preview(o, 5));
77
+ });
78
+ });