@typeonce/effect-machine-devtools 0.27.0 → 0.28.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.
@@ -455,8 +455,10 @@ button {
455
455
 
456
456
  .chart-state {
457
457
  position: absolute;
458
- display: block;
459
- padding: 16px;
458
+ display: flex;
459
+ flex-direction: column;
460
+ justify-content: center;
461
+ padding: 12px;
460
462
  border: 1px solid #30363f;
461
463
  border-radius: 4px;
462
464
  color: #d9dce1;
@@ -493,7 +495,6 @@ button {
493
495
 
494
496
  .chart-state-heading,
495
497
  .chart-state-identity,
496
- .chart-field-row,
497
498
  .chart-activity-row {
498
499
  display: flex;
499
500
  min-width: 0;
@@ -523,18 +524,7 @@ button {
523
524
  box-shadow: 0 0 0 3px rgb(117 167 255 / 10%);
524
525
  }
525
526
 
526
- .chart-state-status.is-initial {
527
- border-color: #d9a441;
528
- background: #d9a441;
529
- box-shadow: 0 0 0 3px rgb(217 164 65 / 12%);
530
- }
531
-
532
- .chart-state-status.is-active.is-initial {
533
- box-shadow: 0 0 0 2px #14181d, 0 0 0 4px var(--accent);
534
- }
535
-
536
527
  .chart-state-name,
537
- .chart-field-name,
538
528
  .chart-activity-name {
539
529
  min-width: 0;
540
530
  overflow: hidden;
@@ -546,8 +536,6 @@ button {
546
536
  font-size: 12px;
547
537
  }
548
538
 
549
- .chart-section-label,
550
- .chart-field-type,
551
539
  .chart-activity-kind,
552
540
  .chart-more {
553
541
  color: #7e8792;
@@ -555,28 +543,20 @@ button {
555
543
  line-height: 1.3;
556
544
  }
557
545
 
558
- .chart-section-label,
559
546
  .chart-activity-kind {
560
547
  text-transform: uppercase;
561
548
  }
562
549
 
563
550
  .chart-state-section {
564
551
  width: min(300px, 100%);
565
- margin-top: 11px;
566
- padding-top: 8px;
552
+ margin-top: 8px;
553
+ padding-top: 7px;
567
554
  border-top: 1px solid #242a31;
568
555
  }
569
556
 
570
- .chart-section-label {
571
- margin-bottom: 4px;
572
- letter-spacing: 0.06em;
573
- }
574
-
575
- .chart-field-row,
576
557
  .chart-activity-row {
577
558
  display: grid;
578
- min-height: 22px;
579
- grid-template-columns: minmax(0, 1fr) auto;
559
+ min-height: 20px;
580
560
  gap: 10px;
581
561
  }
582
562
 
@@ -584,13 +564,11 @@ button {
584
564
  grid-template-columns: auto minmax(0, 1fr);
585
565
  }
586
566
 
587
- .chart-field-name,
588
567
  .chart-activity-name {
589
568
  color: #c4c9d0;
590
569
  font-size: 10px;
591
570
  }
592
571
 
593
- .chart-field-type,
594
572
  .chart-activity-kind {
595
573
  flex: 0 1 auto;
596
574
  overflow: hidden;
@@ -646,15 +624,15 @@ button {
646
624
  }
647
625
 
648
626
  .chart-more {
649
- min-height: 18px;
650
- padding-top: 3px;
627
+ min-height: 16px;
628
+ padding-top: 2px;
651
629
  }
652
630
 
653
631
  .chart-initial {
654
632
  position: absolute;
655
633
  border-radius: 50%;
656
- background: #9ba3ae;
657
- box-shadow: 0 0 0 3px rgb(155 163 174 / 8%);
634
+ background: #b0965d;
635
+ box-shadow: 0 0 0 2px rgb(176 150 93 / 10%);
658
636
  pointer-events: none;
659
637
  }
660
638
 
@@ -680,6 +658,13 @@ button {
680
658
  fill: none;
681
659
  }
682
660
 
661
+ .chart-edge-parent-origin {
662
+ fill: #101318;
663
+ stroke: #89929e;
664
+ stroke-width: 1.8;
665
+ vector-effect: non-scaling-stroke;
666
+ }
667
+
683
668
  .chart-edge-casing {
684
669
  stroke: #0b0c0e;
685
670
  stroke-width: 5.5;
@@ -698,7 +683,8 @@ button {
698
683
  }
699
684
 
700
685
  .chart-edge-initial .chart-edge-line {
701
- stroke: #89929e;
686
+ stroke: #9f8a5c;
687
+ stroke-width: 1.2;
702
688
  }
703
689
 
704
690
  .chart-edge-hit {
@@ -709,7 +695,8 @@ button {
709
695
  }
710
696
 
711
697
  #chart-arrow path,
712
- #chart-direction path {
698
+ #chart-direction path,
699
+ #chart-initial-arrow path {
713
700
  fill: context-stroke;
714
701
  }
715
702
 
@@ -729,6 +716,23 @@ button {
729
716
  user-select: none;
730
717
  }
731
718
 
719
+ .chart-edge-group.chart-edge-parent-child .chart-edge-line,
720
+ .chart-edge-group.chart-edge-parent-child .chart-edge-direction,
721
+ .chart-edge-group.chart-edge-parent-child .chart-edge-parent-origin {
722
+ stroke: #9187a7;
723
+ }
724
+
725
+ .chart-edge-group.chart-edge-parent-child .chart-edge-parent-origin {
726
+ fill: #1b1820;
727
+ }
728
+
729
+ .chart-edge-label-parent-child {
730
+ border-color: #4d465a;
731
+ color: #aea5c1;
732
+ background: #17151b;
733
+ box-shadow: inset 2px 0 #6f6681;
734
+ }
735
+
732
736
  .chart-edge-label:not(:disabled):hover,
733
737
  .chart-edge-label:focus-visible,
734
738
  .chart-edge-group.is-hovered + .chart-edge-label {
@@ -744,7 +748,8 @@ button {
744
748
  }
745
749
 
746
750
  .chart-edge-group.is-hovered .chart-edge-line,
747
- .chart-edge-group.is-hovered .chart-edge-direction {
751
+ .chart-edge-group.is-hovered .chart-edge-direction,
752
+ .chart-edge-group.is-hovered .chart-edge-parent-origin {
748
753
  stroke: #7c9ed2;
749
754
  stroke-width: 1.8;
750
755
  }
@@ -774,7 +779,12 @@ button {
774
779
  .chart-edge-group.chart-edge-activity-effect .chart-edge-direction,
775
780
  .chart-edge-group.chart-edge-activity-timer .chart-edge-direction,
776
781
  .chart-edge-group.chart-edge-activity-stream .chart-edge-direction,
777
- .chart-edge-group.chart-edge-activity-machine .chart-edge-direction {
782
+ .chart-edge-group.chart-edge-activity-machine .chart-edge-direction,
783
+ .chart-edge-group.chart-edge-activity-process .chart-edge-parent-origin,
784
+ .chart-edge-group.chart-edge-activity-effect .chart-edge-parent-origin,
785
+ .chart-edge-group.chart-edge-activity-timer .chart-edge-parent-origin,
786
+ .chart-edge-group.chart-edge-activity-stream .chart-edge-parent-origin,
787
+ .chart-edge-group.chart-edge-activity-machine .chart-edge-parent-origin {
778
788
  stroke: var(--chart-activity-color);
779
789
  }
780
790
 
@@ -789,19 +799,22 @@ button {
789
799
  }
790
800
 
791
801
  .chart-edge-group.is-incoming .chart-edge-line,
792
- .chart-edge-group.is-incoming .chart-edge-direction {
802
+ .chart-edge-group.is-incoming .chart-edge-direction,
803
+ .chart-edge-group.is-incoming .chart-edge-parent-origin {
793
804
  stroke: #ed6a70;
794
805
  stroke-width: 2;
795
806
  }
796
807
 
797
808
  .chart-edge-group.is-outgoing .chart-edge-line,
798
- .chart-edge-group.is-outgoing .chart-edge-direction {
809
+ .chart-edge-group.is-outgoing .chart-edge-direction,
810
+ .chart-edge-group.is-outgoing .chart-edge-parent-origin {
799
811
  stroke: #6eb6dc;
800
812
  stroke-width: 2;
801
813
  }
802
814
 
803
815
  .chart-edge-group.is-selected .chart-edge-line,
804
- .chart-edge-group.is-selected .chart-edge-direction {
816
+ .chart-edge-group.is-selected .chart-edge-direction,
817
+ .chart-edge-group.is-selected .chart-edge-parent-origin {
805
818
  stroke: #8ab5ff;
806
819
  stroke-width: 2.5;
807
820
  }
@@ -1580,7 +1593,7 @@ button {
1580
1593
  gap: 12px;
1581
1594
  }
1582
1595
 
1583
- .input-field-identity,
1596
+ .input-field-contract,
1584
1597
  .input-constraints {
1585
1598
  display: flex;
1586
1599
  min-width: 0;
@@ -1589,6 +1602,12 @@ button {
1589
1602
  gap: 6px;
1590
1603
  }
1591
1604
 
1605
+ .input-field-contract {
1606
+ flex: 0 0 auto;
1607
+ justify-content: flex-end;
1608
+ margin-left: auto;
1609
+ }
1610
+
1592
1611
  .input-label,
1593
1612
  .input-required,
1594
1613
  .input-optional {
@@ -1648,6 +1667,18 @@ button {
1648
1667
  color: #d7a5a2;
1649
1668
  }
1650
1669
 
1670
+ .value-shape-block {
1671
+ margin: 0;
1672
+ padding: 12px;
1673
+ border: 1px solid var(--line-soft);
1674
+ color: #b8c1ce;
1675
+ background: var(--surface-raised);
1676
+ font: 10px/1.55 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
1677
+ overflow-x: auto;
1678
+ tab-size: 2;
1679
+ white-space: pre;
1680
+ }
1681
+
1651
1682
  .trace-topology {
1652
1683
  display: grid;
1653
1684
  gap: 10px;
@@ -271,13 +271,12 @@ const renderContractField = (
271
271
  if (omit.has(label)) return null
272
272
  const row = createElement("div", "input-contract-field")
273
273
  const heading = createElement("div", "input-field-heading")
274
- const identity = createElement("div", "input-field-identity")
275
- identity.append(
276
- createElement("span", "input-label", label),
274
+ const contract = createElement("div", "input-field-contract")
275
+ contract.append(
277
276
  createElement("span", "input-field-type", inputType(field)),
278
277
  createElement("span", required ? "input-required" : "input-optional", required ? "required" : "optional")
279
278
  )
280
- heading.append(identity)
279
+ heading.append(createElement("span", "input-label", label), contract)
281
280
  row.append(heading)
282
281
  const constraints = inputConstraints(field)
283
282
  if (constraints.length > 0) {
@@ -350,6 +349,55 @@ const contractSummary = (schema: InputSchema | null): string | null => {
350
349
  ) + (fields.length > 3 ? ` · +${fields.length - 3}` : "")
351
350
  }
352
351
 
352
+ type ValueShape = string | ReadonlyArray<ValueShape> | { readonly [key: string]: ValueShape }
353
+
354
+ const typePreview = (field: InputField): string => {
355
+ switch (field._tag) {
356
+ case "String":
357
+ return field.format === undefined ? "string" : `string (${field.format})`
358
+ case "Number":
359
+ return field.integer ? "integer" : "number"
360
+ case "Boolean":
361
+ return "boolean"
362
+ case "Enum":
363
+ return field.values.map(String).join(" | ")
364
+ case "Literal":
365
+ return String(field.value)
366
+ case "Object":
367
+ return "object"
368
+ case "Array":
369
+ return `${typePreview(field.item)}[]`
370
+ case "Union":
371
+ return [...new Set(field.alternatives.map(typePreview))].join(" | ")
372
+ case "Unsupported":
373
+ return "unknown"
374
+ }
375
+ }
376
+
377
+ const fieldValueShape = (field: InputField): ValueShape => {
378
+ if (field._tag === "Object") {
379
+ return Object.fromEntries(
380
+ field.fields
381
+ .filter(({ key }) => key !== "_tag")
382
+ .map(({ key, required, field }) => [required ? key : `${key}?`, fieldValueShape(field)])
383
+ )
384
+ }
385
+ if (field._tag === "Array") return [fieldValueShape(field.item)]
386
+ return typePreview(field)
387
+ }
388
+
389
+ export const valueShape = (schema: InputSchema): ValueShape => fieldValueShape(projectInputSchema(schema))
390
+
391
+ const renderValueShape = (title: string, schema: InputSchema): HTMLElement => {
392
+ const section = createElement("section", "inspector-section value-shape-section")
393
+ section.append(inspectionSection(title))
394
+ const code = createElement("code", undefined, JSON.stringify(valueShape(schema), null, 2))
395
+ const block = createElement("pre", "value-shape-block")
396
+ block.append(code)
397
+ section.append(block)
398
+ return section
399
+ }
400
+
353
401
  const triggerName = (trigger: Trigger): string => {
354
402
  switch (trigger.type) {
355
403
  case "event":
@@ -518,6 +566,13 @@ export const renderVisualizer = (
518
566
  }
519
567
  inspectorContent.append(header)
520
568
 
569
+ if (
570
+ inspection.state.valueSchema !== null &&
571
+ contractSummary(inspection.state.valueSchema) !== null
572
+ ) {
573
+ inspectorContent.append(renderValueShape("Value", inspection.state.valueSchema))
574
+ }
575
+
521
576
  if (inspection.outgoing.length > 0) {
522
577
  const transitions = createElement("section", "inspector-section")
523
578
  transitions.append(inspectionSection("Transitions", inspection.outgoing.length))