@principal-ai/subsystems-react 0.56.11 → 0.56.13

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.
Files changed (38) hide show
  1. package/dist/subsystem/C4Graph.d.ts.map +1 -1
  2. package/dist/subsystem/C4Graph.js +10 -4
  3. package/dist/subsystem/C4Graph.js.map +1 -1
  4. package/dist/subsystem/DescriptionOverlay.d.ts +6 -0
  5. package/dist/subsystem/DescriptionOverlay.d.ts.map +1 -0
  6. package/dist/subsystem/DescriptionOverlay.js +58 -0
  7. package/dist/subsystem/DescriptionOverlay.js.map +1 -0
  8. package/dist/subsystem/DiagnosticToggle.d.ts.map +1 -1
  9. package/dist/subsystem/DiagnosticToggle.js +2 -1
  10. package/dist/subsystem/DiagnosticToggle.js.map +1 -1
  11. package/dist/subsystem/SubsystemComponentGraph.d.ts +2 -1
  12. package/dist/subsystem/SubsystemComponentGraph.d.ts.map +1 -1
  13. package/dist/subsystem/SubsystemComponentGraph.js +307 -284
  14. package/dist/subsystem/SubsystemComponentGraph.js.map +1 -1
  15. package/dist/subsystem/SubsystemFileTree.d.ts.map +1 -1
  16. package/dist/subsystem/SubsystemFileTree.js +2 -1
  17. package/dist/subsystem/SubsystemFileTree.js.map +1 -1
  18. package/dist/subsystem/TrailStepsNav.d.ts.map +1 -1
  19. package/dist/subsystem/TrailStepsNav.js +11 -8
  20. package/dist/subsystem/TrailStepsNav.js.map +1 -1
  21. package/dist/subsystem/TrailsPanel.d.ts +1 -1
  22. package/dist/subsystem/TrailsPanel.d.ts.map +1 -1
  23. package/dist/subsystem/TrailsPanel.js +42 -66
  24. package/dist/subsystem/TrailsPanel.js.map +1 -1
  25. package/package.json +1 -1
  26. package/src/stories/Canvases/C4/C4Draft.stories.tsx +238 -0
  27. package/src/stories/Canvases/Subsystem/TrailSidebarViews.stories.tsx +2 -2
  28. package/src/subsystem/C4Graph.tsx +10 -4
  29. package/src/subsystem/DescriptionOverlay.test.tsx +76 -0
  30. package/src/subsystem/DescriptionOverlay.tsx +101 -0
  31. package/src/subsystem/DiagnosticToggle.tsx +2 -1
  32. package/src/subsystem/SubsystemComponentGraph.sidebar.test.tsx +81 -10
  33. package/src/subsystem/SubsystemComponentGraph.tsx +68 -26
  34. package/src/subsystem/SubsystemFileTree.tsx +2 -1
  35. package/src/subsystem/TrailStepsNav.test.tsx +38 -0
  36. package/src/subsystem/TrailStepsNav.tsx +11 -8
  37. package/src/subsystem/TrailsPanel.test.tsx +99 -35
  38. package/src/subsystem/TrailsPanel.tsx +38 -85
@@ -13,7 +13,7 @@
13
13
  import { useCallback, useEffect, useRef, useState } from 'react';
14
14
  import type { DragEvent as ReactDragEvent, ReactNode } from 'react';
15
15
  import { useTheme } from '@principal-ade/industry-theme';
16
- import { Check, ChevronDown, Copy, Focus, GripVertical, Minimize2, Pause, Play, Route, Star } from 'lucide-react';
16
+ import { Check, ChevronDown, Focus, GripVertical, Minimize2, Pause, Play, Route, Star } from 'lucide-react';
17
17
  import { IndustryMarkdownSlide } from 'themed-markdown';
18
18
  import {
19
19
  reorderTargetIndex,
@@ -45,10 +45,10 @@ const EMPHASIS_COLOR = '#f5a524';
45
45
  */
46
46
  export const TRAIL_HOVER_PREVIEW_MS = 150;
47
47
 
48
- /** How long a step's copy button flashes its "copied" checkmark (ms). */
48
+ /** How long a step's number shows its "copied" checkmark (ms). */
49
49
  export const STEP_COPY_FEEDBACK_MS = 2000;
50
50
 
51
- /** Square size (px) of a trail header's Play/Collapse control. */
51
+ /** Width (px) of a trail header's Play/Collapse control. */
52
52
  const TRAIL_CONTROL_SIZE = 34;
53
53
 
54
54
  /** Drag state handed to a row's grip while a reorder is in flight. */
@@ -166,11 +166,6 @@ function TrailFlow({
166
166
  // A pending preview must not fire after the row unmounts or collapses.
167
167
  useEffect(() => () => cancelHoverPreview(), [cancelHoverPreview]);
168
168
  const stepButtonRefs = useRef<(HTMLButtonElement | null)[]>([]);
169
- // Per-step copy affordance: revealed while a row is hovered or holds focus.
170
- // `focusedStep` tracks focus-within (button or its copy control) so the icon
171
- // stays put while the pointer or focus moves between them.
172
- const [focusedStep, setFocusedStep] = useState<number | null>(null);
173
- const [copyHoverStep, setCopyHoverStep] = useState<number | null>(null);
174
169
  const [copiedStep, setCopiedStep] = useState<number | null>(null);
175
170
  const copyTimerRef = useRef<number | null>(null);
176
171
  // Autoplay: stepping through the flow's steps with a pause between each.
@@ -291,10 +286,9 @@ function TrailFlow({
291
286
  }}
292
287
  style={{
293
288
  display: 'flex',
294
- alignItems: 'center',
289
+ alignItems: 'flex-start',
295
290
  gap: 4,
296
- minHeight: TRAIL_CONTROL_SIZE,
297
- padding: '0 0 0 16px',
291
+ padding: '14px 16px',
298
292
  // A collapsed row follows the pointer, not the delayed graph preview.
299
293
  background: headerHover || (!collapsed && wholeFlowActive) ? hoverBg : 'transparent',
300
294
  }}
@@ -318,16 +312,10 @@ function TrailFlow({
318
312
  style={{
319
313
  flex: 1,
320
314
  display: 'flex',
321
- alignItems: 'center',
315
+ alignItems: 'flex-start',
322
316
  minWidth: 0,
323
317
  gap: 8,
324
- // Vertical padding, not just the row's min-height: a title that
325
- // wraps to two+ lines must grow the header past `minHeight`, and
326
- // without this the text sits flush against the row's top and bottom
327
- // edges (the controls stretch to the text height). 6px keeps a
328
- // one-line title under `TRAIL_CONTROL_SIZE`, so single-line rows
329
- // stay 34px.
330
- padding: '6px 0',
318
+ padding: 0,
331
319
  border: 'none',
332
320
  background: 'transparent',
333
321
  textAlign: 'left',
@@ -340,6 +328,7 @@ function TrailFlow({
340
328
  aria-hidden
341
329
  style={{
342
330
  flexShrink: 0,
331
+ marginTop: 3,
343
332
  color: headerHover || (!collapsed && wholeFlowActive) ? theme.colors.primary : muted,
344
333
  }}
345
334
  />
@@ -350,6 +339,7 @@ function TrailFlow({
350
339
  fontSize: theme.fontSizes[1],
351
340
  fontFamily: theme.fonts.monospace,
352
341
  fontWeight: 600,
342
+ lineHeight: '20px',
353
343
  color: theme.colors.text,
354
344
  }}
355
345
  >
@@ -365,6 +355,7 @@ function TrailFlow({
365
355
  gap: 2,
366
356
  flexShrink: 0,
367
357
  marginRight: 4,
358
+ height: 20,
368
359
  fontSize: theme.fontSizes[0],
369
360
  fontFamily: theme.fonts.monospace,
370
361
  color: theme.colors.accent ?? theme.colors.primary ?? muted,
@@ -401,7 +392,7 @@ function TrailFlow({
401
392
  alignItems: 'center',
402
393
  justifyContent: 'center',
403
394
  flexShrink: 0,
404
- alignSelf: 'stretch',
395
+ height: 20,
405
396
  width: TRAIL_CONTROL_SIZE,
406
397
  padding: 0,
407
398
  border: 'none',
@@ -434,7 +425,7 @@ function TrailFlow({
434
425
  alignItems: 'center',
435
426
  justifyContent: 'center',
436
427
  flexShrink: 0,
437
- alignSelf: 'stretch',
428
+ height: 20,
438
429
  width: TRAIL_CONTROL_SIZE,
439
430
  padding: 0,
440
431
  border: 'none',
@@ -463,7 +454,7 @@ function TrailFlow({
463
454
  alignItems: 'center',
464
455
  justifyContent: 'center',
465
456
  flexShrink: 0,
466
- alignSelf: 'stretch',
457
+ height: 20,
467
458
  width: TRAIL_CONTROL_SIZE,
468
459
  padding: 0,
469
460
  border: 'none',
@@ -496,8 +487,8 @@ function TrailFlow({
496
487
  display: 'inline-flex',
497
488
  alignItems: 'center',
498
489
  flexShrink: 0,
499
- marginRight: 8,
500
- padding: '2px 0',
490
+ height: 20,
491
+ padding: 0,
501
492
  color: gripHover || reorder.isDragging ? theme.colors.text : muted,
502
493
  cursor: reorder.isDragging ? 'grabbing' : 'grab',
503
494
  transition: 'color 120ms ease',
@@ -518,10 +509,7 @@ function TrailFlow({
518
509
  >
519
510
  {trail.steps.map((step, i) => {
520
511
  const stepActive = active !== null && active.stepIndex === i;
521
- const revealed =
522
- stepActive || hoveredStep === i || focusedStep === i || copiedStep === i;
523
512
  const copied = copiedStep === i;
524
- const copyHovered = copyHoverStep === i;
525
513
  const record = stepEmphasis?.get(emphasisKey(trail.id, step));
526
514
  const display = trailStepDisplay(step, componentByAlias);
527
515
  // Calls nest; uses/data steps sit at their anchor frame's depth.
@@ -530,6 +518,7 @@ function TrailFlow({
530
518
  i,
531
519
  componentByAlias,
532
520
  ).frames.length;
521
+ const stepInset = (hideHeader ? 12 : 16) + Math.max(0, stackDepth - 1) * 10;
533
522
  // The guidance body follows step focus: clicking a step opens it,
534
523
  // clicking the focused step again returns to the flow. Hover is
535
524
  // deliberately not enough — the list would flutter on sweep.
@@ -538,14 +527,8 @@ function TrailFlow({
538
527
  <div
539
528
  key={`${trailStepGraphEdgeId(step)}-${i}`}
540
529
  style={{ position: 'relative' }}
541
- onFocus={() => setFocusedStep(i)}
542
- onBlur={(e) => {
543
- if (!e.currentTarget.contains(e.relatedTarget as Node | null)) {
544
- setFocusedStep((cur) => (cur === i ? null : cur));
545
- }
546
- }}
547
530
  >
548
- {/* The row's absolute affordances (star, copy) are scoped to
531
+ {/* The row's absolute star is scoped to
549
532
  this wrapper so the guidance body below cannot stretch
550
533
  them — `top:0;bottom:0` on the outer row would grow their
551
534
  hit area with the markdown block. */}
@@ -559,16 +542,23 @@ function TrailFlow({
559
542
  setHoveredStep(i);
560
543
  scheduleHoverPreview(() => onHoverStep(trail, i));
561
544
  }}
562
- onClick={() => onFocusStep(trail, i)}
545
+ onClick={(e) => {
546
+ if (e.metaKey) {
547
+ e.preventDefault();
548
+ e.stopPropagation();
549
+ cancelHoverPreview();
550
+ copyStep(i);
551
+ return;
552
+ }
553
+ onFocusStep(trail, i);
554
+ }}
563
555
  style={{
564
556
  display: 'flex',
565
557
  alignItems: 'flex-start',
566
558
  gap: 8,
567
559
  minWidth: 0,
568
560
  width: '100%',
569
- padding: `8px 70px 8px ${
570
- 17 + Math.max(0, stackDepth - 1) * 10
571
- }px`,
561
+ padding: `14px 36px 14px ${stepInset}px`,
572
562
  textAlign: 'left',
573
563
  borderRadius: 0,
574
564
  border: 'none',
@@ -579,21 +569,26 @@ function TrailFlow({
579
569
  }}
580
570
  >
581
571
  <span
572
+ role={copied ? 'status' : undefined}
573
+ aria-label={copied ? 'Copied' : undefined}
582
574
  style={{
583
575
  flexShrink: 0,
584
576
  width: 14,
577
+ textAlign: 'center',
585
578
  paddingTop: 1,
586
579
  fontSize: theme.fontSizes[0],
587
580
  fontFamily: theme.fonts.monospace,
588
581
  fontWeight: record ? 700 : undefined,
589
- color: record
582
+ color: copied
583
+ ? theme.colors.primary
584
+ : record
590
585
  ? EMPHASIS_COLOR
591
586
  : stepActive
592
587
  ? theme.colors.text
593
588
  : muted,
594
589
  }}
595
590
  >
596
- {i + 1}
591
+ {copied ? <Check size={12} strokeWidth={2} aria-hidden /> : i + 1}
597
592
  </span>
598
593
  <span
599
594
  style={{
@@ -639,7 +634,7 @@ function TrailFlow({
639
634
  title="Key step"
640
635
  style={{
641
636
  position: 'absolute',
642
- right: 34,
637
+ right: 12,
643
638
  top: 0,
644
639
  bottom: 0,
645
640
  display: 'inline-flex',
@@ -654,54 +649,12 @@ function TrailFlow({
654
649
  <Star size={12} strokeWidth={2} fill={EMPHASIS_COLOR} />
655
650
  </span>
656
651
  )}
657
- {revealed && (
658
- <button
659
- type="button"
660
- aria-label={`Copy step ${i + 1} of ${trail.title} for an agent`}
661
- title={copied ? 'Copied' : 'Copy this step for an agent'}
662
- onMouseDown={(e) => e.preventDefault()}
663
- onMouseEnter={() => setCopyHoverStep(i)}
664
- onMouseLeave={() =>
665
- setCopyHoverStep((cur) => (cur === i ? null : cur))
666
- }
667
- onClick={() => copyStep(i)}
668
- style={{
669
- position: 'absolute',
670
- right: 0,
671
- top: 0,
672
- bottom: 0,
673
- display: 'inline-flex',
674
- alignItems: 'center',
675
- justifyContent: 'center',
676
- width: 'auto',
677
- aspectRatio: '1 / 1',
678
- padding: 0,
679
- border: 'none',
680
- borderRadius: 0,
681
- background: copied
682
- ? 'rgba(16,185,129,0.12)'
683
- : copyHovered
684
- ? theme.colors.border
685
- : 'transparent',
686
- color: copied ? '#10b981' : copyHovered ? theme.colors.text : muted,
687
- cursor: 'pointer',
688
- transition: 'background 120ms ease, color 120ms ease',
689
- }}
690
- >
691
- {copied ? (
692
- <Check size={12} strokeWidth={2} />
693
- ) : (
694
- <Copy size={12} strokeWidth={2} />
695
- )}
696
- </button>
697
- )}
698
652
  </div>
699
653
  {guidanceVisible && record?.guidance && (
700
654
  <div
701
655
  style={{
702
- // Align with the step text: 17px row inset + 14px number
703
- // column + 8px gap.
704
- padding: '2px 12px 10px 39px',
656
+ // Follow the row inset, number column, and text gap.
657
+ padding: `2px 12px 10px ${stepInset + 14 + 8}px`,
705
658
  fontSize: theme.fontSizes[0],
706
659
  lineHeight: 1.5,
707
660
  }}