MembersOutline.svelte 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. <!--
  2. A container's members in source order, with the two numbers that say which
  3. one to open (design spec §3.2).
  4. This replaces the body for anything over 80 lines, and the `← in → out`
  5. columns are why it is a better view than the body rather than a poorer one:
  6. a class's own fan-out is nearly always zero because a class calls nothing —
  7. its methods do — so scrolling 700 lines of braces tells you less about where
  8. the weight sits than twenty rows with their edge counts.
  9. -->
  10. <script lang="ts">
  11. import KindGlyph from '../KindGlyph.svelte';
  12. import type { WireNodeRef, WireOverride } from '../../lib/api';
  13. import type { OutlineRow } from '../../lib/symbol-model';
  14. interface Props {
  15. rows: OutlineRow[];
  16. total: number;
  17. truncated: boolean;
  18. onopen: (node: WireNodeRef) => void;
  19. }
  20. let { rows, total, truncated, onopen }: Props = $props();
  21. /**
  22. * The override mark is a NAME match inside a chain the graph links, not an
  23. * `overrides` edge — nothing in the engine emits one. The tooltip says so,
  24. * because "overrides Base" and "declares the same name as Base" are different
  25. * claims and only the second one was checked.
  26. */
  27. function overrideTitle(o: WireOverride): string {
  28. return o.relation === 'implements'
  29. ? `Declares a member ${o.baseTypeName} requires — matched by name.`
  30. : `Redeclares a member of ${o.baseTypeName} — matched by name.`;
  31. }
  32. </script>
  33. <div class="subh">
  34. <span>Members</span>
  35. <span class="n">{total}</span>
  36. </div>
  37. <div class="outline">
  38. {#each rows as row (row.member.id)}
  39. <button
  40. type="button"
  41. class="orow"
  42. class:nested={row.nested}
  43. class:dimmed={row.dimmed}
  44. onclick={() => onopen(row.member)}
  45. title={`${row.member.qualifiedName} — ${row.member.file}:${row.member.line}`}
  46. >
  47. <KindGlyph kind={row.member.kind} />
  48. <span class="nm">{row.member.name}</span>
  49. <span class="sig">
  50. {#if row.member.overrides}
  51. <span class="ovr" title={overrideTitle(row.member.overrides)}>
  52. {row.member.overrides.relation === 'implements' ? 'satisfies' : 'overrides'}
  53. {row.member.overrides.baseTypeName}
  54. </span>
  55. {/if}{row.member.signature ?? ''}</span>
  56. <span class="cnt">
  57. {#if row.member.fanIn}← {row.member.fanIn}{/if}{#if row.member.fanIn && row.member.fanOut}&nbsp;
  58. {/if}{#if row.member.fanOut}→ {row.member.fanOut}{/if}
  59. </span>
  60. </button>
  61. {/each}
  62. </div>
  63. {#if truncated}
  64. <div class="note">
  65. Showing {rows.length} of {total} members — open the file to see the rest.
  66. </div>
  67. {/if}
  68. <style>
  69. .subh {
  70. display: flex;
  71. align-items: baseline;
  72. gap: 8px;
  73. margin: 18px 0 4px;
  74. font-weight: 600;
  75. font-size: 13px;
  76. }
  77. .subh .n {
  78. color: var(--ink-3);
  79. font-weight: 400;
  80. }
  81. .outline {
  82. border-top: 1px solid var(--rule);
  83. }
  84. .orow {
  85. display: grid;
  86. grid-template-columns: 16px minmax(160px, auto) 1fr auto;
  87. gap: 10px;
  88. align-items: baseline;
  89. width: 100%;
  90. padding: 6px 4px;
  91. border-bottom: 1px solid var(--rule-faint);
  92. text-align: left;
  93. }
  94. .orow:hover {
  95. background: var(--press);
  96. }
  97. .orow.nested {
  98. padding-left: 22px;
  99. }
  100. .nm {
  101. font: 12.5px var(--mono);
  102. }
  103. .orow.dimmed .nm {
  104. color: var(--ink-3);
  105. }
  106. .ovr {
  107. margin-right: 6px;
  108. padding: 0 4px;
  109. border: 1px solid var(--rule-soft);
  110. color: var(--ink-2);
  111. font: 10.5px var(--mono);
  112. white-space: nowrap;
  113. }
  114. .sig {
  115. overflow: hidden;
  116. color: var(--ink-3);
  117. font: 11.5px var(--mono);
  118. text-overflow: ellipsis;
  119. white-space: nowrap;
  120. }
  121. .cnt {
  122. color: var(--ink-3);
  123. font: 11px var(--mono);
  124. font-variant-numeric: tabular-nums;
  125. white-space: nowrap;
  126. }
  127. .note {
  128. padding: 8px 0;
  129. color: var(--ink-3);
  130. font-size: 11.5px;
  131. }
  132. </style>