1- import React , { useContext , useMemo , useState } from "react" ;
1+ import React , { useContext , useEffect , useMemo , useRef , useState } from "react" ;
22import { useNavigate } from "react-router-dom" ;
33import { styled } from "@linaria/react" ;
44import * as api from "./api" ;
@@ -14,10 +14,12 @@ import {
1414 useSearchWords ,
1515 useSearchOffsets ,
1616 useSearchMetadata ,
17+ useFieldParam ,
1718} from "./utils/filtering" ;
1819import { formatHexOffset } from "./utils/format" ;
1920import { computeBitfieldInfo , type BitfieldInfo } from "./utils/bitfields" ;
2021import {
22+ AnchorName ,
2123 CollapsedItemsLink ,
2224 CommonGroupMembers ,
2325 CommonGroupSignature ,
@@ -50,6 +52,11 @@ const FieldRow = styled.div`
5052 &[data-highlighted] {
5153 background-color: var(--search-highlight);
5254 }
55+
56+ &[data-anchored] {
57+ background-color: var(--search-highlight);
58+ border-color: var(--highlight);
59+ }
5360` ;
5461
5562const FieldIcon = styled . div `
@@ -147,6 +154,7 @@ export const SchemaClassView: React.FC<{
147154 const searchWords = useSearchWords ( ) ;
148155 const searchOffsets = useSearchOffsets ( ) ;
149156 const searchMetadata = useSearchMetadata ( ) ;
157+ const fieldParam = useFieldParam ( ) ;
150158
151159 const isSearching = searchWords . length > 0 || searchOffsets . size > 0 || searchMetadata . length > 0 ;
152160
@@ -213,13 +221,15 @@ export const SchemaClassView: React.FC<{
213221 < SchemaFieldView
214222 key = { `${ field . name } -${ field . offset } ` }
215223 field = { field }
224+ fieldUrlBase = { `${ root } /${ declaration . module } /${ declaration . name } ` }
216225 bitfield = { bitfieldInfo . get ( field ) }
217226 highlighted = {
218227 collapseNonMatching ||
219228 ( searchWords . length > 0 && matchesWords ( field . name , searchWords ) ) ||
220229 ( searchOffsets . size > 0 && searchOffsets . has ( field . offset ) ) ||
221230 ( searchMetadata . length > 0 && matchesMetadataKeys ( field . metadata , searchMetadata ) )
222231 }
232+ anchored = { fieldParam === field . name }
223233 />
224234 ) ) }
225235 { hiddenCount > 0 && (
@@ -365,25 +375,52 @@ const BitfieldPadding = styled.div`
365375
366376function SchemaFieldView ( {
367377 field,
378+ fieldUrlBase,
368379 bitfield,
369380 highlighted,
381+ anchored,
370382} : {
371383 field : api . SchemaField ;
384+ fieldUrlBase : string ;
372385 bitfield ?: BitfieldInfo ;
373386 highlighted : boolean ;
387+ anchored : boolean ;
374388} ) {
375389 const { root } = useContext ( DeclarationsContext ) ;
376390 const navigate = useNavigate ( ) ;
377391 const offsetHex = formatHexOffset ( field . offset ) ;
392+ const rowRef = useRef < HTMLDivElement > ( null ) ;
393+
394+ useEffect ( ( ) => {
395+ if ( anchored && rowRef . current ) {
396+ rowRef . current . scrollIntoView ( { behavior : "smooth" , block : "center" } ) ;
397+ }
398+ } , [ anchored ] ) ;
399+
400+ const copyAnchorLink = ( e : React . MouseEvent ) => {
401+ e . preventDefault ( ) ;
402+ const fieldUrl = `${ fieldUrlBase } ?field=${ encodeURIComponent ( field . name ) } ` ;
403+ const fullUrl = `${ window . location . origin } ${ window . location . pathname } #${ fieldUrl } ` ;
404+ navigator . clipboard . writeText ( fullUrl ) ;
405+ navigate ( fieldUrl , { replace : true } ) ;
406+ } ;
407+
378408 return (
379409 < >
380- < FieldRow data-highlighted = { highlighted || undefined } >
410+ < FieldRow
411+ ref = { rowRef }
412+ data-highlighted = { highlighted || undefined }
413+ data-anchored = { anchored || undefined }
414+ >
381415 < FieldIcon >
382416 < KindIcon kind = "field" size = "small" />
383417 </ FieldIcon >
384418 < FieldContent >
385419 < FieldSignature >
386- { field . name } : < SchemaTypeView type = { field . type } />
420+ < AnchorName onClick = { copyAnchorLink } title = "Copy link to field" >
421+ { field . name }
422+ </ AnchorName >
423+ : < SchemaTypeView type = { field . type } />
387424 { bitfield && (
388425 < BitRange >
389426 bit{ bitfield . bitCount !== 1 ? "s" : "" } { bitfield . bitOffset }
0 commit comments