/**
* External dependencies
*/
import { css } from '@nelio/popups/css';
import { addClass, isHTMLElement } from '@nelio/popups/utils';
import type {
BorderSettings,
CssSizeUnit,
Popup,
ShadowSettings,
} from '@nelio/popups/types';
/**
* Internal dependencies
*/
import { VisiblePopup } from '../types';
import { vh, vw } from './pure-functions';
export function renderPopup( popup: Popup ): HTMLElement {
const overlay = makePopupOverlay( popup );
const popupBox = makePopupBox( popup );
const wrapper = document.createElement( 'div' );
addClass( 'wrapper', wrapper );
addClass( `wrapper-${ popup.id }`, wrapper );
wrapper.appendChild( overlay );
wrapper.appendChild( popupBox );
return wrapper;
}
export function renderCloseButton( vp: VisiblePopup ): void {
const { el, popup } = vp;
const box = el.querySelector( '.nelio-popup-js-popup' );
if ( ! isHTMLElement( box ) ) {
return;
}
addCloseButton( popup, box );
}
// =======
// HELPERS
// =======
function makePopupBox( popup: Popup ): HTMLElement {
const positioner = document.createElement( 'div' );
positioner.style.zIndex = `${ popup.config.display.zIndex }`;
addClass( 'positioner', positioner );
addClass( 'js-positioner', positioner );
const box = document.createElement( 'div' );
addClass( box );
addClass( 'js-popup', box );
addClass( `${ popup.id }`, box );
const content = getPopupContent( popup.id );
// Connect elements.
positioner.appendChild( box );
box.appendChild( content );
// Style box
setPopupLocation( popup, positioner );
setPopupSize( popup, box );
setPopupStyle( popup, box );
setPopupMargin( popup, box );
setPopupPadding( popup, box );
return positioner;
}
function getPopupContent( id: number ): HTMLElement {
const container =
document.getElementById( `nelio-popup-content-${ id }` ) ||
document.createElement( 'div' );
addClass( 'content', container );
container.classList.remove( 'nelio-invisible-popup-wrapper' );
return container;
}
function makePopupOverlay( popup: Popup ): HTMLElement {
const settings = popup.config.overlay;
const overlay = document.createElement( 'div' );
if ( ! settings.isEnabled ) {
return overlay;
}
addClass( 'overlay', overlay );
addClass( 'js-overlay', overlay );
overlay.style.backgroundColor = settings.color;
overlay.style.zIndex = `${ popup.config.display.zIndex }`;
return overlay;
}
function setPopupLocation( popup: Popup, box: HTMLElement ): void {
const location = getLocation( popup );
box.classList.add( css( location ) );
}
function setPopupSize( popup: Popup, box: HTMLElement ): void {
const { size } = popup.config;
if ( 'auto' === size.type ) {
addClass( `size--is-${ size.type }-${ size.value }`, box );
} else {
addClass( `size--is-${ size.type }`, box );
}
if ( 'custom' !== size.type ) {
return;
}
const { width, height: heightSettings } = size;
box.style.width = vw( width );
if ( 'custom-height' === heightSettings.type ) {
const { isContentScrollable, value: height } = heightSettings;
box.style.height = vh( height );
box.style.overflowY = isContentScrollable ? 'auto' : 'hidden';
}
}
function setPopupMargin( popup: Popup, box: HTMLElement ): void {
const { margin: m, padding: p } = popup.config.spacing;
const { border: b } = popup.config.wrapper;
const border = b.isEnabled ? vw( b.width ) : '0px';
const hm = `${ vw( m.left ) } - ${ vw( m.right ) }`;
const vm = `${ vh( m.top ) } - ${ vh( m.bottom ) }`;
const hp = `${ vw( p.left ) } - ${ vw( p.right ) }`;
const vp = `${ vh( p.top ) } - ${ vh( p.bottom ) }`;
const bw = `calc(2 * ${ border })`;
box.style.maxWidth = `calc(100vw - ${ hm } - ${ hp } - ${ bw })`;
box.style.maxHeight = `calc(100vh - ${ vm } - ${ vp } - ${ bw })`;
box.style.marginTop = vh( m.top );
box.style.marginBottom = vh( m.bottom );
box.style.marginLeft = vw( m.left );
box.style.marginRight = vw( m.right );
}
function setPopupPadding( popup: Popup, el: HTMLElement ) {
const { padding } = popup.config.spacing;
const { top: t, bottom: b, left: l, right: r } = padding;
el.style.paddingTop = vh( t );
el.style.paddingBottom = vh( b );
el.style.paddingLeft = vw( l );
el.style.paddingRight = vw( r );
}
function setPopupStyle( popup: Popup, box: HTMLElement ): void {
const { wrapper: settings } = popup.config;
setBorderStyle( settings.border, box );
addShadow( settings.shadow, box );
}
function setBorderStyle( settings: BorderSettings, box: HTMLElement ): void {
if ( ! settings.isEnabled ) {
return;
}
const color = settings.color;
const radius = vw( settings.radius );
const width = vw( settings.width );
box.style.border = `${ width } solid ${ color }`;
box.style.borderRadius = radius;
}
function addCloseButton( popup: Popup, box: HTMLElement ): void {
const { closeButton: settings } = popup.config.wrapper;
if ( ! settings.isEnabled ) {
return;
}
const button = document.createElement( 'button' );
addClass( 'close-button', button );
addClass( `close-button--is-${ settings.position }`, button );
addClass( 'js-close', button );
if ( settings.icon.startsWith( 'dashicons' ) ) {
const icon = document.createElement( 'span' );
icon.innerHTML = getIcon( settings.icon, settings.size );
icon.style.display = 'flex';
addClass( 'close-button-icon', icon );
button.appendChild( icon );
}
if ( settings.label ) {
const label = document.createElement( 'span' );
label.textContent = settings.label;
addClass( 'close-button-label', label );
button.appendChild( label );
}
button.style.background = settings.backgroundColor;
button.style.color = settings.color;
button.style.opacity = '0';
button.style.transition = 'opacity 100ms ease-in-out';
box.appendChild( button );
setTimeout( () => {
button.style.opacity = '1';
}, settings.delayInMillis );
}
export function getIcon( icon: string, size: CssSizeUnit ): string {
switch ( icon ) {
case 'dashicons-dismiss':
return ``;
case 'dashicons-no':
return ``;
case 'dashicons-no-alt':
return ``;
case 'dashicons-remove':
return ``;
case 'dashicons-minus':
return ``;
}
return '';
}
function addShadow( settings: ShadowSettings, box: HTMLElement ): void {
if ( ! settings.isEnabled ) {
return;
}
const color = settings.color;
const offsetX = vw( settings.offsetX );
const offsetY = vh( settings.offsetY );
const blur = vw( settings.blur );
box.style.boxShadow = `${ offsetX } ${ offsetY } ${ blur } ${ color }`;
}
function getLocation( popup: Popup ) {
const { location } = popup.config;
switch ( location ) {
case 'top-left':
return {
top: '0',
left: '0',
transform: 'scale(1)',
};
case 'top':
return {
top: '0',
left: '50vw',
transform: 'translate(-50%, 0) scale(1)',
};
case 'top-right':
return {
top: '0',
right: '0',
transform: 'scale(1)',
};
case 'left':
return {
top: '50vh',
left: '0',
transform: 'translate(0, -50%) scale(1)',
};
case 'center':
return {
top: '50vh',
left: '50vw',
transform: 'translate(-50%, -50%) scale(1)',
};
case 'right':
return {
top: '50vh',
right: '0',
transform: 'translate(0, -50%) scale(1)',
};
case 'bottom-left':
return {
bottom: '0',
left: '0',
transform: 'scale(1)',
};
case 'bottom':
return {
bottom: '0',
left: '50vw',
transform: 'translate(-50%, 0) scale(1)',
};
case 'bottom-right':
return {
bottom: '0',
right: '0',
transform: 'scale(1)',
};
}
}