@@ -14,6 +14,7 @@ export interface BannerPluginConfig {
1414 position ?: 'top' | 'bottom' ;
1515 dismissable ?: boolean ;
1616 zIndex ?: number ;
17+ pushDown ?: string ; // CSS selector of element to push down (add margin-top)
1718 } ;
1819}
1920
@@ -33,7 +34,23 @@ export interface BannerPlugin {
3334 * import { createInstance } from '@prosdevlab/experience-sdk';
3435 * import { bannerPlugin } from '@prosdevlab/experience-sdk-plugins';
3536 *
36- * const sdk = createInstance({ banner: { position: 'top', dismissable: true } });
37+ * // Basic usage (banner overlays at top)
38+ * const sdk = createInstance({
39+ * banner: {
40+ * position: 'top',
41+ * dismissable: true
42+ * }
43+ * });
44+ * sdk.use(bannerPlugin);
45+ *
46+ * // With pushDown (pushes navigation down instead of overlaying)
47+ * const sdk = createInstance({
48+ * banner: {
49+ * position: 'top',
50+ * dismissable: true,
51+ * pushDown: 'header' // CSS selector of element to push down
52+ * }
53+ * });
3754 * sdk.use(bannerPlugin);
3855 * ```
3956 */
@@ -426,6 +443,49 @@ export const bannerPlugin: PluginFunction = (plugin, instance, config) => {
426443 return banner ;
427444 }
428445
446+ /**
447+ * Apply pushDown margin to target element
448+ */
449+ function applyPushDown ( banner : HTMLElement , position : 'top' | 'bottom' ) : void {
450+ const pushDownSelector = config . get ( 'banner.pushDown' ) ;
451+
452+ if ( ! pushDownSelector || position !== 'top' ) {
453+ return ; // Only push down for top banners
454+ }
455+
456+ const targetElement = document . querySelector ( pushDownSelector ) ;
457+ if ( ! targetElement || ! ( targetElement instanceof HTMLElement ) ) {
458+ return ;
459+ }
460+
461+ // Get banner height
462+ const height = banner . offsetHeight ;
463+
464+ // Apply margin-top with transition
465+ targetElement . style . transition = 'margin-top 0.3s ease' ;
466+ targetElement . style . marginTop = `${ height } px` ;
467+ }
468+
469+ /**
470+ * Remove pushDown margin from target element
471+ */
472+ function removePushDown ( ) : void {
473+ const pushDownSelector = config . get ( 'banner.pushDown' ) ;
474+
475+ if ( ! pushDownSelector ) {
476+ return ;
477+ }
478+
479+ const targetElement = document . querySelector ( pushDownSelector ) ;
480+ if ( ! targetElement || ! ( targetElement instanceof HTMLElement ) ) {
481+ return ;
482+ }
483+
484+ // Remove margin-top with transition
485+ targetElement . style . transition = 'margin-top 0.3s ease' ;
486+ targetElement . style . marginTop = '0' ;
487+ }
488+
429489 /**
430490 * Show a banner experience
431491 */
@@ -444,6 +504,11 @@ export const bannerPlugin: PluginFunction = (plugin, instance, config) => {
444504 document . body . appendChild ( banner ) ;
445505 activeBanners . set ( experience . id , banner ) ;
446506
507+ // Apply pushDown to target element if configured
508+ const content = experience . content as BannerContent ;
509+ const position = content . position ?? config . get ( 'banner.position' ) ?? 'top' ;
510+ applyPushDown ( banner , position ) ;
511+
447512 instance . emit ( 'experiences:shown' , {
448513 experienceId : experience . id ,
449514 type : 'banner' ,
@@ -462,6 +527,11 @@ export const bannerPlugin: PluginFunction = (plugin, instance, config) => {
462527 banner . parentNode . removeChild ( banner ) ;
463528 }
464529 activeBanners . delete ( experienceId ) ;
530+
531+ // Remove pushDown if no more banners
532+ if ( activeBanners . size === 0 ) {
533+ removePushDown ( ) ;
534+ }
465535 } else {
466536 // Remove all banners
467537 for ( const [ id , banner ] of activeBanners . entries ( ) ) {
@@ -470,6 +540,9 @@ export const bannerPlugin: PluginFunction = (plugin, instance, config) => {
470540 }
471541 activeBanners . delete ( id ) ;
472542 }
543+
544+ // Remove pushDown
545+ removePushDown ( ) ;
473546 }
474547 }
475548
0 commit comments