11import React , { useContext , useMemo } from "react" ;
2- import { Link } from "react-router-dom" ;
2+ import { Link , useNavigate } from "react-router-dom" ;
33import styled from "styled-components" ;
44import * as api from "./api" ;
55import { SchemaTypeView , MetadataTags } from "./SchemaType" ;
66import { ReferencedBy } from "./ReferencedBy" ;
77import { KindIcon } from "./utils/components" ;
88import { DeclarationsContext } from "./DeclarationsContext" ;
9- import { useSearchWords } from "./utils/filtering" ;
9+ import { useSearchWords , useSearchOffsets } from "./utils/filtering" ;
1010import {
1111 CommonGroupMembers ,
1212 CommonGroupSignature ,
@@ -41,6 +41,21 @@ const FieldRow = styled.div<{ $highlighted?: boolean }>`
4141const FieldSignature = styled . div `
4242 font-weight: 600;
4343 font-size: 16px;
44+ display: flex;
45+ align-items: baseline;
46+ gap: 6px;
47+ ` ;
48+
49+ const FieldOffset = styled . span `
50+ font-size: 14px;
51+ font-weight: 500;
52+ color: ${ ( props ) => props . theme . textDim } ;
53+ font-variant-numeric: tabular-nums;
54+ cursor: pointer;
55+
56+ &:hover {
57+ color: ${ ( props ) => props . theme . highlight } ;
58+ }
4459` ;
4560
4661const CollapsedFieldsLink = styled ( Link ) `
@@ -55,9 +70,13 @@ const CollapsedFieldsLink = styled(Link)`
5570 }
5671` ;
5772
58- export const ModuleBadge : React . FC < { module : string } > = ( { module } ) => (
59- < StyledModuleBadge > { module } </ StyledModuleBadge >
60- ) ;
73+ export const ModuleBadge : React . FC < { module : string } > = ( { module } ) => {
74+ const { root } = useContext ( DeclarationsContext ) ;
75+ const navigate = useNavigate ( ) ;
76+ return (
77+ < StyledModuleBadge onClick = { ( ) => navigate ( `${ root } ?search=${ encodeURIComponent ( `module:${ module } ` ) } ` ) } > { module } </ StyledModuleBadge >
78+ ) ;
79+ } ;
6180
6281const StyledModuleBadge = styled . span `
6382 font-size: 14px;
@@ -69,6 +88,11 @@ const StyledModuleBadge = styled.span`
6988 border-radius: 6px;
7089 margin-left: 8px;
7190 vertical-align: middle;
91+ cursor: pointer;
92+
93+ &:hover {
94+ border-color: ${ ( props ) => props . theme . highlight } ;
95+ }
7296` ;
7397
7498export function matchesWords ( name : string , words : string [ ] ) : boolean {
@@ -83,17 +107,21 @@ export const SchemaClassView: React.FC<{
83107} > = ( { className, style, declaration } ) => {
84108 const { root } = useContext ( DeclarationsContext ) ;
85109 const searchWords = useSearchWords ( ) ;
110+ const searchOffsets = useSearchOffsets ( ) ;
86111
87- const nameMatches = searchWords . length === 0 || matchesWords ( declaration . name , searchWords ) ;
88- const collapseNonMatching = searchWords . length > 0 && ! nameMatches ;
112+ const isSearching = searchWords . length > 0 || searchOffsets . length > 0 ;
113+ const nameMatches = searchWords . length > 0 && matchesWords ( declaration . name , searchWords ) ;
114+ const collapseNonMatching = isSearching && ! nameMatches ;
89115
90116 const { matchingFields, hiddenCount } = useMemo ( ( ) => {
91117 if ( ! collapseNonMatching ) {
92118 return { matchingFields : declaration . fields , hiddenCount : 0 } ;
93119 }
94- const matching = declaration . fields . filter ( ( f ) => matchesWords ( f . name , searchWords ) ) ;
120+ const matching = declaration . fields . filter ( ( f ) =>
121+ ( searchWords . length > 0 && matchesWords ( f . name , searchWords ) ) || ( searchOffsets . length > 0 && searchOffsets . includes ( f . offset ) ) ,
122+ ) ;
95123 return { matchingFields : matching , hiddenCount : declaration . fields . length - matching . length } ;
96- } , [ declaration . fields , searchWords , collapseNonMatching ] ) ;
124+ } , [ declaration . fields , searchWords , searchOffsets , collapseNonMatching ] ) ;
97125
98126 return (
99127 < CommonGroupWrapper className = { className } style = { style } >
@@ -120,7 +148,7 @@ export const SchemaClassView: React.FC<{
120148 { ( matchingFields . length > 0 || hiddenCount > 0 ) && (
121149 < ClassMembers >
122150 { matchingFields . map ( ( field ) => (
123- < SchemaFieldView key = { field . name } field = { field } highlighted = { searchWords . length > 0 && matchesWords ( field . name , searchWords ) } />
151+ < SchemaFieldView key = { field . name } field = { field } highlighted = { ( searchWords . length > 0 && matchesWords ( field . name , searchWords ) ) || ( searchOffsets . length > 0 && searchOffsets . includes ( field . offset ) ) } />
124152 ) ) }
125153 { hiddenCount > 0 && (
126154 < CollapsedFieldsLink to = { `${ root } /${ declaration . module } /${ declaration . name } ` } >
@@ -135,10 +163,14 @@ export const SchemaClassView: React.FC<{
135163} ;
136164
137165function SchemaFieldView ( { field, highlighted } : { field : api . SchemaField ; highlighted : boolean } ) {
166+ const { root } = useContext ( DeclarationsContext ) ;
167+ const navigate = useNavigate ( ) ;
168+ const offsetHex = `0x${ field . offset . toString ( 16 ) . toUpperCase ( ) } ` ;
138169 return (
139170 < FieldRow $highlighted = { highlighted } >
140171 < FieldSignature >
141172 < KindIcon kind = "field" size = "small" />
173+ < FieldOffset onClick = { ( ) => navigate ( `${ root } ?search=${ encodeURIComponent ( `offset:${ offsetHex } ` ) } ` ) } > { offsetHex } </ FieldOffset >
142174 { field . name } : < SchemaTypeView type = { field . type } />
143175 </ FieldSignature >
144176 < MetadataTags metadata = { field . metadata } />
0 commit comments