@@ -8,12 +8,49 @@ import useRouterContext from '~/components/shell/router-context';
8
8
import cn from 'classnames' ;
9
9
import './hero.scss' ;
10
10
11
- function useBookInfo ( book ) {
12
- const [ info , setInfo ] = useState ( [ ] ) ;
11
+ interface BookEntry {
12
+ title : string ;
13
+ meta : {
14
+ slug : string ;
15
+ } ;
16
+ }
17
+
18
+ interface HeroData {
19
+ aboutHeader : string ;
20
+ aboutText : string ;
21
+ aboutPopup : string ;
22
+ }
23
+
24
+ interface HeroProps {
25
+ book : string ;
26
+ }
27
+
28
+ interface HeroContentProps {
29
+ data : HeroData ;
30
+ }
31
+
32
+ interface PopTipProps {
33
+ html : string ;
34
+ isOpen : boolean ;
35
+ }
36
+
37
+ interface PopTipState {
38
+ isOpen : boolean ;
39
+ activate : ( ) => void ;
40
+ deactivate : ( ) => void ;
41
+ }
42
+
43
+ interface PopTipStyleResult {
44
+ ref : React . RefObject < HTMLDivElement > ;
45
+ style : { left : number | string } ;
46
+ }
47
+
48
+ function useBookInfo ( book : string ) : [ string , string ] {
49
+ const [ info , setInfo ] = useState < [ string , string ] > ( [ '' , '' ] ) ;
13
50
const { fail} = useRouterContext ( ) ;
14
51
15
52
useEffect ( ( ) => {
16
- bookPromise . then ( ( bookList ) => {
53
+ bookPromise . then ( ( bookList : BookEntry [ ] ) => {
17
54
const entry = bookList . find ( ( { title} ) => title === book ) ;
18
55
19
56
if ( entry ) {
@@ -30,23 +67,33 @@ function useBookInfo(book) {
30
67
return info ;
31
68
}
32
69
33
- const middle = '-135' ;
34
- const margin = 3 ;
70
+ const middle : string = '-135' ;
71
+ const margin : number = 3 ;
35
72
36
- function shiftIntoView ( ref , leftOffset , setLeftOffset ) {
73
+ function shiftIntoView (
74
+ ref : React . RefObject < HTMLDivElement > ,
75
+ leftOffset : number | string ,
76
+ setLeftOffset : ( value : number | string ) => void
77
+ ) : void {
78
+ if ( ! ref . current ) return ;
79
+
37
80
const { left, right} = ref . current . getBoundingClientRect ( ) ;
38
- const { right : pageRight } = ref . current . closest ( '.page' ) . getBoundingClientRect ( ) ;
81
+ const pageElement = ref . current . closest ( '.page' ) ;
82
+ if ( ! pageElement ) return ;
83
+
84
+ const { right : pageRight } = pageElement . getBoundingClientRect ( ) ;
39
85
const overRight = right - pageRight + margin ;
40
86
const overLeft = margin - left ;
41
- const rightWants = Math . min ( middle , leftOffset - overRight ) ;
42
- const leftWants = Math . max ( rightWants , leftOffset + overLeft ) ;
87
+ const leftOffsetNum = typeof leftOffset === 'string' ? parseInt ( leftOffset ) : leftOffset ;
88
+ const rightWants = Math . min ( parseInt ( middle ) , leftOffsetNum - overRight ) ;
89
+ const leftWants = Math . max ( rightWants , leftOffsetNum + overLeft ) ;
43
90
44
91
setLeftOffset ( leftWants ) ;
45
92
}
46
93
47
- function usePopTipStyle ( isOpen ) {
48
- const ref = React . useRef ( ) ;
49
- const [ leftOffset , setLeftOffset ] = React . useState ( middle ) ;
94
+ function usePopTipStyle ( isOpen : boolean ) : PopTipStyleResult {
95
+ const ref = React . useRef < HTMLDivElement > ( null ) ;
96
+ const [ leftOffset , setLeftOffset ] = React . useState < number | string > ( middle ) ;
50
97
51
98
useEffect (
52
99
( ) => shiftIntoView ( ref , leftOffset , setLeftOffset ) ,
@@ -56,7 +103,7 @@ function usePopTipStyle(isOpen) {
56
103
return { ref, style : { left : leftOffset } } ;
57
104
}
58
105
59
- function PopTip ( { html, isOpen} ) {
106
+ function PopTip ( { html, isOpen} : PopTipProps ) : React . ReactElement {
60
107
const { ref, style} = usePopTipStyle ( isOpen ) ;
61
108
62
109
return (
@@ -71,17 +118,17 @@ function PopTip({html, isOpen}) {
71
118
) ;
72
119
}
73
120
74
- function usePopTipState ( ) {
75
- const [ isOpen , setIsOpen ] = React . useState ( false ) ;
121
+ function usePopTipState ( ) : PopTipState {
122
+ const [ isOpen , setIsOpen ] = React . useState < boolean > ( false ) ;
76
123
77
124
return {
78
125
isOpen,
79
- activate ( ) { setIsOpen ( true ) ; } ,
80
- deactivate ( ) { setIsOpen ( false ) ; }
126
+ activate ( ) : void { setIsOpen ( true ) ; } ,
127
+ deactivate ( ) : void { setIsOpen ( false ) ; }
81
128
} ;
82
129
}
83
130
84
- function HeroContent ( { data} ) {
131
+ function HeroContent ( { data} : HeroContentProps ) : React . ReactElement {
85
132
const { isOpen, activate, deactivate} = usePopTipState ( ) ;
86
133
87
134
return (
@@ -92,7 +139,7 @@ function HeroContent({data}) {
92
139
{ ' ' }
93
140
< span
94
141
className = { cn ( 'with-tooltip' , { active : isOpen } ) }
95
- tabIndex = "0"
142
+ tabIndex = { 0 }
96
143
onMouseEnter = { activate } onMouseLeave = { deactivate }
97
144
onFocus = { activate } onBlur = { deactivate }
98
145
>
@@ -104,7 +151,7 @@ function HeroContent({data}) {
104
151
) ;
105
152
}
106
153
107
- export default function Hero ( { book} ) {
154
+ export default function Hero ( { book} : HeroProps ) : React . ReactElement | null {
108
155
const [ slug , title ] = useBookInfo ( book ) ;
109
156
110
157
if ( ! slug ) {
@@ -118,4 +165,4 @@ export default function Hero({book}) {
118
165
</ div >
119
166
</ div >
120
167
) ;
121
- }
168
+ }
0 commit comments