@@ -43,12 +43,14 @@ import {
4343 getTokenAtPosition ,
4444 HoveredToken ,
4545} from './token_position'
46- import { EMODENOTFOUND , HoverMerged , LOADING } from './types'
47- import { FileSpec , LineOrPositionOrRange , RepoSpec , ResolvedRevSpec , RevSpec } from './url'
46+ import { EMODENOTFOUND , HoverMerged , LineOrPositionOrRange , LOADING } from './types'
4847
4948export { HoveredToken }
5049
51- export interface HoverifierOptions {
50+ /**
51+ * @template C Extra context for the hovered token.
52+ */
53+ export interface HoverifierOptions < C extends object > {
5254 /**
5355 * Emit the HoverOverlay element on this after it was rerendered when its content changed and it needs to be repositioned.
5456 */
@@ -86,17 +88,20 @@ export interface HoverifierOptions {
8688 */
8789 logTelemetryEvent ?: ( event : string , data ?: any ) => void
8890
89- fetchHover : HoverFetcher
90- fetchJumpURL : JumpURLFetcher
91+ fetchHover : HoverFetcher < C >
92+ fetchJumpURL : JumpURLFetcher < C >
93+ getReferencesURL : ( hoverToken : HoveredToken & C ) => string | null
9194}
9295
9396/**
9497 * A Hoverifier is a function that hoverifies one code view element in the DOM.
9598 * It will do very dirty things to it. Only call it if you're into that.
9699 *
97100 * There can be multiple code views in the DOM, which will only show a single HoverOverlay if the same Hoverifier was used.
101+ *
102+ * @template C Extra context for the hovered token.
98103 */
99- export interface Hoverifier {
104+ export interface Hoverifier < C extends object > {
100105 /**
101106 * The current Hover state. You can use this to read the initial state synchronously.
102107 */
@@ -109,7 +114,7 @@ export interface Hoverifier {
109114 /**
110115 * Hoverifies a code view.
111116 */
112- hoverify ( options : HoverifyOptions ) : Subscription
117+ hoverify ( options : HoverifyOptions < C > ) : Subscription
113118
114119 unsubscribe ( ) : void
115120}
@@ -139,31 +144,42 @@ export enum AdjustmentDirection {
139144 ActualToCodeView ,
140145}
141146
142- export interface AdjustPositionProps {
147+ /**
148+ * @template C Extra context for the hovered token.
149+ */
150+ export interface AdjustPositionProps < C extends object > {
143151 /** The code view the token is in. */
144152 codeView : HTMLElement
145153 /** The position the token is at. */
146- position : HoveredToken & HoveredTokenContext
154+ position : HoveredToken & C
147155 /** The direction the adjustment should go. */
148156 direction : AdjustmentDirection
149157}
150158
151159/**
152160 * Function to adjust positions coming into and out of hoverifier. It can be used to correct the position used in HoverFetcher and
153161 * JumpURLFetcher requests and the position of th etoken to highlight in the code view. This is useful for code hosts that convert whitespace.
162+ *
163+ *
164+ * @template C Extra context for the hovered token.
154165 */
155- export type PositionAdjuster = ( props : AdjustPositionProps ) => SubscribableOrPromise < Position >
166+ export type PositionAdjuster < C extends object > = ( props : AdjustPositionProps < C > ) => SubscribableOrPromise < Position >
156167
157168/**
158169 * HoverifyOptions that need to be included internally with every event
170+ *
171+ * @template C Extra context for the hovered token.
159172 */
160- export interface EventOptions {
161- resolveContext : ContextResolver
162- adjustPosition ?: PositionAdjuster
173+ export interface EventOptions < C extends object > {
174+ resolveContext : ContextResolver < C >
175+ adjustPosition ?: PositionAdjuster < C >
163176 dom : DOMFunctions
164177}
165178
166- export interface HoverifyOptions extends EventOptions {
179+ /**
180+ * @template C Extra context for the hovered token.
181+ */
182+ export interface HoverifyOptions < C extends object > extends EventOptions < C > {
167183 positionEvents : Subscribable < PositionEvent >
168184
169185 /**
@@ -190,9 +206,13 @@ export interface HoverState {
190206 selectedPosition ?: LineOrPositionOrRange
191207}
192208
193- interface InternalHoverifierState {
209+ /**
210+ * @template C Extra context for the hovered token.
211+ */
212+ interface InternalHoverifierState < C extends object > {
194213 hoverOrError ?: typeof LOADING | HoverMerged | null | ErrorLike
195214 definitionURLOrError ?: typeof LOADING | { jumpURL : string } | null | ErrorLike
215+ referencesURL ?: string | null
196216
197217 hoverOverlayIsFixed : boolean
198218
@@ -206,7 +226,7 @@ interface InternalHoverifierState {
206226 clickedGoToDefinition : false | 'same-tab' | 'new-tab'
207227
208228 /** The currently hovered token */
209- hoveredToken ?: HoveredToken & HoveredTokenContext
229+ hoveredToken ?: HoveredToken & C
210230
211231 mouseIsMoving : boolean
212232
@@ -221,13 +241,13 @@ interface InternalHoverifierState {
221241/**
222242 * Returns true if the HoverOverlay component should be rendered according to the given state.
223243 */
224- const shouldRenderOverlay = ( state : InternalHoverifierState ) : boolean =>
244+ const shouldRenderOverlay = ( state : InternalHoverifierState < { } > ) : boolean =>
225245 ! ( ! state . hoverOverlayIsFixed && state . mouseIsMoving ) && overlayUIHasContent ( state )
226246
227247/**
228248 * Maps internal HoverifierState to the publicly exposed HoverState
229249 */
230- const internalToExternalState = ( internalState : InternalHoverifierState ) : HoverState => ( {
250+ const internalToExternalState = ( internalState : InternalHoverifierState < { } > ) : HoverState => ( {
231251 selectedPosition : internalState . selectedPosition ,
232252 hoverOverlayProps : shouldRenderOverlay ( internalState )
233253 ? {
@@ -238,6 +258,7 @@ const internalToExternalState = (internalState: InternalHoverifierState): HoverS
238258 isJumpURL ( internalState . definitionURLOrError ) || internalState . clickedGoToDefinition
239259 ? internalState . definitionURLOrError
240260 : undefined ,
261+ referencesURL : internalState . referencesURL ,
241262 hoveredToken : internalState . hoveredToken ,
242263 showCloseButton : internalState . hoverOverlayIsFixed ,
243264 }
@@ -250,40 +271,52 @@ export const LOADER_DELAY = 300
250271/** The time in ms after the mouse has stopped moving in which to show the tooltip */
251272export const TOOLTIP_DISPLAY_DELAY = 100
252273
253- export type HoverFetcher = ( position : HoveredToken & HoveredTokenContext ) => SubscribableOrPromise < HoverMerged | null >
254- export type JumpURLFetcher = ( position : HoveredToken & HoveredTokenContext ) => SubscribableOrPromise < string | null >
274+ /**
275+ * @template C Extra context for the hovered token.
276+ */
277+ export type HoverFetcher < C extends object > = ( position : HoveredToken & C ) => SubscribableOrPromise < HoverMerged | null >
278+
279+ /**
280+ * @template C Extra context for the hovered token.
281+ */
282+ export type JumpURLFetcher < C extends object > = ( position : HoveredToken & C ) => SubscribableOrPromise < string | null >
255283
256284/**
257285 * Function responsible for resolving the position of a hovered token
258286 * and its diff part to a full context including repository, commit ID and file path.
287+ *
288+ * @template C Extra context for the hovered token.
259289 */
260- export type ContextResolver = ( hoveredToken : HoveredToken ) => HoveredTokenContext
290+ export type ContextResolver < C extends object > = ( hoveredToken : HoveredToken ) => C
261291
262- export interface HoveredTokenContext extends RepoSpec , RevSpec , FileSpec , ResolvedRevSpec { }
263-
264- export const createHoverifier = ( {
292+ /**
293+ * @template C Extra context for the hovered token.
294+ */
295+ export function createHoverifier < C extends object > ( {
265296 goToDefinitionClicks,
266297 closeButtonClicks,
267298 hoverOverlayRerenders,
268299 pushHistory,
269300 fetchHover,
270301 fetchJumpURL,
302+ getReferencesURL,
271303 logTelemetryEvent = noop ,
272- } : HoverifierOptions ) : Hoverifier = > {
304+ } : HoverifierOptions < C > ) : Hoverifier < C > {
273305 // Internal state that is not exposed to the caller
274306 // Shared between all hoverified code views
275- const container = createObservableStateContainer < InternalHoverifierState > ( {
307+ const container = createObservableStateContainer < InternalHoverifierState < C > > ( {
276308 hoverOverlayIsFixed : false ,
277309 clickedGoToDefinition : false ,
278310 definitionURLOrError : undefined ,
311+ referencesURL : undefined ,
279312 hoveredToken : undefined ,
280313 hoverOrError : undefined ,
281314 hoverOverlayPosition : undefined ,
282315 mouseIsMoving : false ,
283316 selectedPosition : undefined ,
284317 } )
285318
286- interface MouseEventTrigger extends PositionEvent , EventOptions { }
319+ interface MouseEventTrigger extends PositionEvent , EventOptions < C > { }
287320
288321 // These Subjects aggregate all events from all hoverified code views
289322 const allPositionsFromEvents = new Subject < MouseEventTrigger > ( )
@@ -295,7 +328,7 @@ export const createHoverifier = ({
295328 const allCodeMouseOvers = allPositionsFromEvents . pipe ( filter ( isEventType ( 'mouseover' ) ) )
296329 const allCodeClicks = allPositionsFromEvents . pipe ( filter ( isEventType ( 'click' ) ) )
297330
298- const allPositionJumps = new Subject < PositionJump & EventOptions > ( )
331+ const allPositionJumps = new Subject < PositionJump & EventOptions < C > > ( )
299332
300333 const subscription = new Subscription ( )
301334
@@ -489,6 +522,13 @@ export const createHoverifier = ({
489522 share ( )
490523 )
491524
525+ /** Emits new referencesURL values. */
526+ subscription . add (
527+ resolvedPositions
528+ . pipe ( map ( ( { position } ) => ( position ? getReferencesURL ( position ) : null ) ) )
529+ . subscribe ( referencesURL => container . update ( { referencesURL } ) )
530+ )
531+
492532 /**
493533 * For every position, emits an Observable with new values for the `hoverOrError` state.
494534 * This is a higher-order Observable (Observable that emits Observables).
@@ -498,10 +538,10 @@ export const createHoverifier = ({
498538 eventType : SupportedMouseEvent | 'jump'
499539 dom : DOMFunctions
500540 target : HTMLElement
501- adjustPosition ?: PositionAdjuster
541+ adjustPosition ?: PositionAdjuster < C >
502542 codeView : HTMLElement
503543 hoverOrError ?: typeof LOADING | HoverMerged | Error | null
504- position ?: HoveredToken & HoveredTokenContext
544+ position ?: HoveredToken & C
505545 part ?: DiffPart
506546 } >
507547 > = resolvedPositions . pipe (
@@ -611,7 +651,7 @@ export const createHoverifier = ({
611651 zip ( resolvedPositions , hoverObservables )
612652 . pipe (
613653 distinctUntilChanged ( ( [ positionA ] , [ positionB ] ) => isEqual ( positionA , positionB ) ) ,
614- switchMap ( ( [ position , hoverObservable ] ) => hoverObservable ) ,
654+ switchMap ( ( [ , hoverObservable ] ) => hoverObservable ) ,
615655 filter ( ( { hoverOrError } ) => HoverMerged . is ( hoverOrError ) )
616656 )
617657 . subscribe ( ( ) => {
@@ -768,7 +808,7 @@ export const createHoverifier = ({
768808 map ( internalToExternalState ) ,
769809 distinctUntilChanged ( ( a , b ) => isEqual ( a , b ) )
770810 ) ,
771- hoverify ( { positionEvents, positionJumps = EMPTY , ...eventOptions } : HoverifyOptions ) : Subscription {
811+ hoverify ( { positionEvents, positionJumps = EMPTY , ...eventOptions } : HoverifyOptions < C > ) : Subscription {
772812 const subscription = new Subscription ( )
773813 const eventWithOptions = map ( ( event : PositionEvent ) => ( { ...event , ...eventOptions } ) )
774814 // Broadcast all events from this code view
0 commit comments