1
1
/*
2
- * Copyright 2024 Google LLC
2
+ * Copyright 2025 Google LLC
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
19
19
*/
20
20
import { store , getContext , getElement } from '@wordpress/interactivity' ;
21
21
22
+ interface StoryDef {
23
+ href : string ;
24
+ title : string | null ;
25
+ posterImage : string | null ;
26
+ idx : number ;
27
+ distance : number ;
28
+ storyContentLoaded : boolean ;
29
+ desktopAspectRatio : number | null ;
30
+ }
31
+
32
+ interface AmpStoryPlayerElement extends HTMLElement {
33
+ getStories : ( ) => StoryDef [ ] ;
34
+ play : ( ) => void ;
35
+ pause : ( ) => void ;
36
+ rewind : ( ) => void ;
37
+ mute : ( ) => void ;
38
+ show : ( href : string ) => void ;
39
+ }
40
+
41
+ interface AmpStoryPlayerNavigationEvent extends Event {
42
+ detail : {
43
+ index : number ;
44
+ remaining : number ;
45
+ } ;
46
+ }
47
+
48
+ type State = {
49
+ lightboxElement : HTMLElement | null ;
50
+ player : null | AmpStoryPlayerElement ;
51
+ stories : StoryDef [ ] ;
52
+ instanceId : string | null ;
53
+ currentLocation : string | null ;
54
+ } ;
55
+
56
+ type BlockContext = {
57
+ instanceId : string ;
58
+ } ;
59
+
60
+ function runWithViewTransition ( f : ( ) => void ) {
61
+ if ( ! document . startViewTransition ) {
62
+ f ( ) ;
63
+ } else {
64
+ document . startViewTransition ( ( ) => f ( ) ) ;
65
+ }
66
+ }
67
+
22
68
const { state, actions } = store ( 'web-stories-block' , {
23
69
state : {
24
70
lightboxElement : null ,
25
71
player : null ,
26
- stories : null ,
72
+ stories : [ ] ,
27
73
instanceId : null ,
28
74
currentLocation : null ,
29
- } ,
75
+ } as State ,
30
76
actions : {
31
- storyContentReady : ( storyObject , callback , maxRetries = 5 ) => {
77
+ storyContentReady : (
78
+ storyObject : StoryDef ,
79
+ callback : ( ) => void ,
80
+ maxRetries = 5
81
+ ) => {
32
82
const stateIntervalObj = setInterval ( ( ) => {
33
83
if ( storyObject . storyContentLoaded === true ) {
34
84
window . clearInterval ( stateIntervalObj ) ;
@@ -52,44 +102,56 @@ const { state, actions } = store('web-stories-block', {
52
102
player . pause ( ) ;
53
103
player . mute ( ) ;
54
104
55
- lightboxElement . classList . toggle ( 'show' ) ;
105
+ lightboxElement ? .classList . toggle ( 'show' ) ;
56
106
document . body . classList . toggle ( 'web-stories-lightbox-open' ) ;
57
107
} ,
58
- open : ( event ) => {
108
+ open : ( event : Event ) => {
59
109
event . preventDefault ( ) ;
60
- const { ref : card } = getElement ( ) ;
61
- const context = JSON . parse ( getContext ( ) . replaceAll ( "'" , '' ) ) ;
110
+ const context = getContext < BlockContext > ( ) ;
62
111
const lightboxElement =
63
112
document . querySelector (
64
113
`.ws-lightbox-${ context . instanceId } .web-stories-list__lightbox`
65
114
) ||
66
115
document . querySelector (
67
- `.ws-lightbox-${ context . instanceId } .web-stories-singleton__lightbox`
116
+ `.ws-lightbox-singleton- ${ context . instanceId } .web-stories-singleton__lightbox`
68
117
) ;
69
- const player = lightboxElement . querySelector ( 'amp-story-player' ) ;
118
+
119
+ if ( ! lightboxElement ) {
120
+ return ;
121
+ }
122
+
123
+ const player = lightboxElement . querySelector (
124
+ 'amp-story-player'
125
+ ) as unknown as AmpStoryPlayerElement ;
70
126
const stories = player . getStories ( ) ;
71
127
72
- state . lightboxElement = lightboxElement ;
128
+ state . lightboxElement = lightboxElement as HTMLElement ;
73
129
state . player = player ;
74
130
state . stories = stories ;
75
131
state . instanceId = context . instanceId ;
76
132
state . currentLocation = location . href ;
77
133
134
+ const { ref : card } = getElement ( ) ;
135
+
78
136
const storyObject = stories . find (
79
- ( story ) => story . href === card . querySelector ( 'a' ) . href
137
+ ( story ) => story . href === card ? .querySelector ( 'a' ) ? .href
80
138
) ;
81
139
82
- player . show ( storyObject . href ) ;
83
- player . play ( ) ;
140
+ if ( storyObject ) {
141
+ player . show ( storyObject . href ) ;
142
+ player . play ( ) ;
84
143
85
- actions . storyContentReady ( storyObject , ( ) => {
86
- history . pushState ( { } , '' , storyObject . href ) ;
87
- } ) ;
144
+ actions . storyContentReady ( storyObject , ( ) => {
145
+ history . pushState ( { } , '' , storyObject . href ) ;
146
+ } ) ;
147
+ }
88
148
89
- lightboxElement . classList . toggle ( 'show' ) ;
90
- document . body . classList . toggle ( 'web-stories-lightbox-open' ) ;
149
+ runWithViewTransition ( ( ) => {
150
+ lightboxElement . classList . toggle ( 'show' ) ;
151
+ document . body . classList . toggle ( 'web-stories-lightbox-open' ) ;
152
+ } ) ;
91
153
} ,
92
- navigation : ( event ) => {
154
+ navigation : ( event : AmpStoryPlayerNavigationEvent ) => {
93
155
const storyObject = state . stories [ event . detail . index ] ;
94
156
if ( storyObject && storyObject . href !== document . location . href ) {
95
157
actions . storyContentReady ( storyObject , ( ) => {
@@ -100,20 +162,20 @@ const { state, actions } = store('web-stories-block', {
100
162
onPopstate : ( ) => {
101
163
const lightboxElement = state . lightboxElement ;
102
164
const player = state . player ;
103
- const isLightboxOpen = lightboxElement . classList . contains ( 'show' ) ;
165
+ const isLightboxOpen = lightboxElement ? .classList . contains ( 'show' ) ;
104
166
105
167
const storyObject = state . stories . find (
106
168
( story ) => story . href === document . location . href
107
169
) ;
108
170
109
171
if ( storyObject ) {
110
172
if ( ! isLightboxOpen ) {
111
- lightboxElement . classList . toggle ( 'show' ) ;
173
+ lightboxElement ? .classList . toggle ( 'show' ) ;
112
174
document . body . classList . toggle ( 'web-stories-lightbox-open' ) ;
113
- player . play ( ) ;
175
+ player ? .play ( ) ;
114
176
}
115
177
116
- player . show ( storyObject . href ) ;
178
+ player ? .show ( storyObject . href ) ;
117
179
} else if ( isLightboxOpen ) {
118
180
actions . close ( ) ;
119
181
}
0 commit comments