import { React, classnames } from '@gravityforms/libraries';
import { useId } from '@gravityforms/react-utils';
import { spacerClasses } from '@gravityforms/utils';
import FileUpload from '../../elements/FileUpload';
import Droplist from '../Droplist';
import { generateComplementaryGradient } from './utils';
const { forwardRef } = React;
/**
* @module Banner
* @description Renders a banner component with optional file upload.
*
* @since 5.6.0
*
* @param {React.ReactNode|React.ReactNode[]} [children] - React element children
* @param {Record<string, any>} [customAttributes] - Custom attributes for the component
* @param {string|string[]|Record<string, boolean>} [customClasses] - Custom classes for the component
* @param {Record<string, any>} [droplistAttributes] - Custom attributes for the droplist component
* @param {string|string[]|Record<string, boolean>} [droplistClasses] - Custom classes for the droplist component
* @param {Record<string, any>} [fileUploadAttributes] - Custom attributes for the file upload component
* @param {boolean} [hasActions=false] - Whether to show the actions droplist
* @param {boolean} [hasUpload=false] - Whether to show the file upload
* @param {string} [height=''] - The height of the component
* @param {Record<string, any>} [i18n] - The i18n strings for the component
* @param {string} [id=''] - The ID of the component
* @param {string} [imageFile=''] - The image file for the component
* @param {string} [noImageGradient=''] - The gradient for the component
* @param {string} [noImageGradientColor=''] - The gradient color for the component
* @param {object} [noImageGradientLayout] - The optional gradient layout for the component
* @param {Record<string, any>} [removeButtonAttributes] - Custom attributes for the remove button
* @param {Record<string, any>} [selectButtonAttributes] - Custom attributes for the select button
* @param {string|number|string[]|Record<string, any>} [spacing=''] - The spacing for the component
* @param {Record<string, any>} [uploadButtonAttributes] - Custom attributes for the upload button
* @param {React.RefObject<HTMLElement>|null} ref - Ref to the component
*
* @return {JSX.Element} The banner component.
*
* @example
* import Banner from '@gravityforms/components/react/admin/modules/Banner';
*
* return (
* <Banner>
* { 'children' }
* </Banner>
* );
*
*/
const Banner = forwardRef(
(
{
children = null,
customAttributes = {},
customClasses = [],
droplistAttributes = {},
droplistClasses = [],
fileUploadAttributes = {},
hasActions = false,
hasUpload = false,
height = '',
i18n = {},
id: idProp = '',
imageFile = '',
noImageGradient = '',
noImageGradientColor = '',
noImageGradientLayout = null,
removeButtonAttributes = {},
selectButtonAttributes = {},
spacing = '',
uploadButtonAttributes = {},
},
ref
) => {
const id = useId( idProp );
const style = {};
// Apply image background if provided
if ( ! hasUpload && imageFile ) {
style.backgroundImage = `url(${ imageFile })`;
}
// Apply height if provided
if ( height ) {
style.height = height;
}
// Apply gradient or background color
if ( ! imageFile ) {
if ( noImageGradientColor ) {
style.backgroundColor = noImageGradientColor;
// Generate complementary gradient if no predefined gradient is set
if ( ! noImageGradient ) {
style.backgroundImage = generateComplementaryGradient( noImageGradientColor, noImageGradientLayout );
style.backgroundBlendMode = 'normal';
}
}
}
const bannerProps = {
className: classnames( {
'gform-banner': true,
'gform-banner--has-image': imageFile.length > 0,
[ `gform-gradient--${ noImageGradient }` ]: ( ( ! hasUpload && ! imageFile ) || hasUpload ) && noImageGradient.length > 0,
...spacerClasses( spacing ),
}, customClasses ),
ref,
style,
...customAttributes,
};
const fileUploadProps = {
fileURL: imageFile,
...fileUploadAttributes,
};
const listItems = [
{
key: 'upload',
props: {
element: 'button',
iconBefore: 'upload-file',
iconPrefix: 'gravity-component-icon',
label: i18n?.upload || '',
...uploadButtonAttributes,
},
},
{
key: 'select',
props: {
element: 'button',
iconBefore: 'photograph',
iconPrefix: 'gravity-component-icon',
label: i18n?.select || '',
...selectButtonAttributes,
},
},
];
if ( imageFile ) {
listItems.push( {
key: 'remove',
props: {
element: 'button',
iconBefore: 'trash',
iconPrefix: 'gravity-component-icon',
label: i18n?.remove || '',
...removeButtonAttributes,
},
} );
}
const droplistProps = {
align: 'right',
closeOnClick: true,
customClasses: classnames(
[ 'gform-banner__droplist' ],
droplistClasses || [],
),
listItems,
width: 192,
...droplistAttributes,
triggerAttributes: {
ariaId: `${ id }-droplist-aria-labelledby`,
ariaText: '',
iconPosition: 'leading',
iconPrefix: 'gravity-component-icon',
icon: 'camera-plus',
id: `${ id }-droplist-trigger`,
label: ( imageFile ? i18n?.triggerHasImage : i18n?.triggerNoImage ) || '',
size: 'size-height-s',
...( droplistAttributes?.triggerAttributes || {} ),
},
};
return (
<div { ...bannerProps }>
{ hasUpload && <FileUpload { ...fileUploadProps } /> }
{ hasActions && <Droplist { ...droplistProps } /> }
{ children }
</div>
);
}
);
Banner.displayName = 'Banner';
export default Banner;