@@ -15,6 +15,8 @@ interface State {
1515//It interfaces with the parent window via CrossOriginInterface.js (COI)
1616class ScrollNavigationBar extends StreamlitComponentBase < State > {
1717 public state = { activeAnchorId : "" } ;
18+ private disable_scroll : boolean = false ;
19+ private mounted = false ;
1820
1921 // Send message to COI
2022 postMessage ( COI_method : string ,
@@ -23,38 +25,37 @@ class ScrollNavigationBar extends StreamlitComponentBase<State> {
2325 anchor_ids ?:string [ ] ;
2426 auto_update_anchor ?: boolean
2527 styles ?: { [ key : string ] : CSSProperties }
26- } ) : void {
28+ disable_scroll ?: boolean
29+ } ) : boolean {
2730 const { key } = this . props . args ;
2831 if ( key == null || typeof key !== "string" ) {
2932 throw new Error ( "Invalid key: key must be a string." ) ;
3033 }
34+ window . parent . postMessage ( { COI_method, key, ...data } , "*" ) ;
3135
32- const { anchor_id , anchor_ids , styles } = data || { } ;
33- window . parent . postMessage ( { COI_method , key , anchor_id , anchor_ids , styles } , "*" ) ;
36+ console . debug ( "postMessage from " , key , ": " , COI_method , data ) ;
37+ return true ;
3438 }
3539
3640
3741 postRegister ( auto_update_anchor :boolean ) : void {
3842 this . postMessage ( "register" , { auto_update_anchor } ) ;
39- console . debug ( "postRegister" ) ;
4043 }
41- postUpdateStyles ( styles :{ [ key :string ] : CSSProperties } ) : void {
42- this . postMessage ( "updateStyles" , { styles} ) ;
43- console . debug ( "postUpdateStyles" , styles ) ;
44+ postUpdateConfig ( ) : void {
45+ let styles = this . styles ;
46+ let disable_scroll = this . disable_scroll ;
47+ this . postMessage ( "updateConfig" , { styles, disable_scroll} ) ;
4448 }
4549 postScroll ( anchor_id : string ) : void {
4650 this . postMessage ( "scroll" , { anchor_id } ) ;
47- console . debug ( "postScroll" , anchor_id ) ;
4851 }
4952 postTrackAnchors ( anchor_ids : string [ ] ) : void {
5053 this . postMessage ( "trackAnchors" , { anchor_ids } ) ;
51- console . debug ( "postTrackAnchors" , anchor_ids ) ;
5254 }
5355 postUpdateActiveAnchor ( anchor_id : string ) : void {
5456 const { auto_update_anchor } = this . getCleanedArgs ( ) ;
5557 if ( auto_update_anchor )
5658 this . postMessage ( "updateActiveAnchor" , { anchor_id } ) ;
57- console . debug ( "postUpdateActiveAnchor" , anchor_id , "; autoupdate" , auto_update_anchor ) ;
5859 }
5960
6061 // Handle menu item click
@@ -71,13 +72,15 @@ class ScrollNavigationBar extends StreamlitComponentBase<State> {
7172 } ;
7273
7374 public componentDidMount ( ) : void {
74- const { anchor_ids, auto_update_anchor} = this . getCleanedArgs ( ) ;
75+ const { anchor_ids, auto_update_anchor, disable_scroll } = this . getCleanedArgs ( ) ;
7576 const initialAnchorId = anchor_ids [ 0 ] ;
7677
78+ this . disable_scroll = disable_scroll ;
79+
7780 // Register component
7881 this . postRegister ( auto_update_anchor ) ;
7982 // Send styles to COI
80- this . postUpdateStyles ( this . styles ) ;
83+ this . postUpdateConfig ( ) ;
8184 // Tell COI to track anchors for visibility
8285 this . postTrackAnchors ( anchor_ids ) ;
8386 // Set initial active anchor for component and COI
@@ -88,6 +91,8 @@ class ScrollNavigationBar extends StreamlitComponentBase<State> {
8891
8992 //Send component value to streamlit
9093 Streamlit . setComponentValue ( initialAnchorId ) ;
94+
95+ this . mounted = true ;
9196 }
9297
9398 componentDidUpdate ( ) : void {
@@ -128,8 +133,18 @@ class ScrollNavigationBar extends StreamlitComponentBase<State> {
128133 }
129134 }
130135
131- private getCleanedArgs ( ) {
132- let { key, anchor_ids, anchor_labels, anchor_icons, force_anchor, orientation, override_styles, auto_update_anchor} = this . props . args ;
136+ private getCleanedArgs ( ) : {
137+ anchor_ids : string [ ] ,
138+ anchor_labels : string [ ] ,
139+ anchor_icons : string [ ] ,
140+ force_anchor : string ,
141+ key : string ,
142+ orientation : string ,
143+ override_styles : { [ key : string ] : CSSProperties } ,
144+ auto_update_anchor : boolean ,
145+ disable_scroll : boolean }
146+ {
147+ let { key, anchor_ids, anchor_labels, anchor_icons, force_anchor, orientation, override_styles, auto_update_anchor, disable_scroll} = this . props . args ;
133148 //key is required
134149 if ( key == null || typeof key !== "string" ) {
135150 throw new Error ( "Invalid key: key must be a string." ) ;
@@ -203,7 +218,18 @@ class ScrollNavigationBar extends StreamlitComponentBase<State> {
203218 }
204219 }
205220
206- return { anchor_ids, anchor_labels, anchor_icons, force_anchor, key, orientation, override_styles, auto_update_anchor } ;
221+ //disable_scroll is an optional boolean
222+ //If not provided, default to false
223+ //If provided, it must be a boolean
224+ if ( disable_scroll == null ) {
225+ disable_scroll = false ;
226+ } else {
227+ if ( typeof disable_scroll !== "boolean" ) {
228+ throw new Error ( "Invalid disable_scroll: disable_scroll must be a boolean." ) ;
229+ }
230+ }
231+
232+ return { anchor_ids, anchor_labels, anchor_icons, force_anchor, key, orientation, override_styles, auto_update_anchor, disable_scroll} ;
207233 }
208234
209235 static getBiName ( icon : string ) {
@@ -268,30 +294,39 @@ class ScrollNavigationBar extends StreamlitComponentBase<State> {
268294
269295 // Render sidebar with dynamic orientation handling
270296 public render = ( ) : ReactNode => {
271- const { orientation, override_styles } = this . getCleanedArgs ( ) ;
272-
273- // Deep merge override_styles into styles
274- const mergeDeep = ( target : any , source : any ) => {
275- let changed = false ;
276- for ( const key in source ) {
277- if ( source [ key ] instanceof Object && key in target ) {
278- const { changed : childChanged } = mergeDeep ( target [ key ] , source [ key ] ) ;
279- if ( childChanged ) {
280- changed = true ;
281- }
282- } else {
283- if ( target [ key ] !== source [ key ] ) {
284- target [ key ] = source [ key ] ;
285- changed = true ;
297+ const { orientation, override_styles, disable_scroll} = this . getCleanedArgs ( ) ;
298+
299+ if ( this . mounted ) {
300+ // Deep merge override_styles into styles
301+ const mergeDeep = ( target : any , source : any ) => {
302+ let changed = false ;
303+ for ( const key in source ) {
304+ if ( source [ key ] instanceof Object && key in target ) {
305+ const { changed : childChanged } = mergeDeep ( target [ key ] , source [ key ] ) ;
306+ if ( childChanged ) {
307+ changed = true ;
308+ }
309+ } else {
310+ if ( target [ key ] !== source [ key ] ) {
311+ target [ key ] = source [ key ] ;
312+ changed = true ;
313+ }
286314 }
287315 }
316+ return { result : target , changed } ;
317+ } ;
318+ let { changed } = mergeDeep ( this . styles , override_styles ) ;
319+
320+ // Update disable_scroll if it has changed
321+ if ( disable_scroll !== this . disable_scroll ) {
322+ this . disable_scroll = disable_scroll ;
323+ changed = true ;
324+ }
325+
326+ //Communicate new styles and other config to COI
327+ if ( changed ) {
328+ this . postUpdateConfig ( )
288329 }
289- return { result : target , changed } ;
290- } ;
291- const { changed } = mergeDeep ( this . styles , override_styles ) ;
292- //Communicate new styles to COI
293- if ( changed ) {
294- this . postUpdateStyles ( this . styles ) ;
295330 }
296331
297332 // Adjust layout direction based on orientation
0 commit comments