Call To Action

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Read More

Lorem ipsum dolor sit amet consectetur. Donec sagittis morbi est lacinia gravida a eget. Aenean eget sed vel velit sed natoque. Dolor nunc mauris nec mauris. Vulputate cursus a congue sagittis non volutpat non dictumst vitae.

Read More

ButtonSettings.js

import {
  __experimentalToolsPanelItem as ToolsPanelItem,
  __experimentalToolsPanel as ToolsPanel,
  ToggleControl,
  PanelBody,
  RangeControl,
  SelectControl,
  TextControl,
  __experimentalBoxControl as BoxControl,
  __experimentalBorderControl as BorderControl,
} from "@wordpress/components";
import {
  __experimentalFontAppearanceControl as FontAppearanceControl,
  __experimentalLetterSpacingControl as LetterSpacingControl,
  FontSizePicker,
  __experimentalTextTransformControl as TextTransformControl,
  PanelColorSettings,
  __experimentalPanelColorGradientSettings as PanelColorGradientSettings,
  __experimentalTextDecorationControl as TextDecorationControl,
  __experimentalFontFamilyControl as FontFamilyControl,
  useSettings,
} from "@wordpress/block-editor";
import { __ } from "@wordpress/i18n";

const ButtonSettings = ({ attributes, setAttributes }) => {
  const {
    typography,
    padding,
    border,
    showButton,
    buttonLink,
    target,
    borderRadius,
    showBorder,
    borderStyle,
    bgColor,
    textColor,
    display,
    btnAlign,
    textAlign,
    width,
    fontFamily,
  } = attributes;

  /**
   * Reset typography
   */
  const resetAll = () => {
    setAttributes({ typography: {} });
  };

  // Get theme settings
  const [fontFamilies] = useSettings("typography.fontFamilies.theme") || [];
  const [colors] = useSettings("color.palette") || [];

  return (
    <PanelBody title={__("Button Settings", "WLC")}>
      <ToggleControl
        checked={!!showButton}
        label={__("Show Button", "WLC")}
        onChange={() => setAttributes({ showButton: !showButton })}
      />
      {showButton && (
        <>
          <TextControl
            label={__("Button Link", "WLC")}
            value={buttonLink}
            onChange={(value) => setAttributes({ buttonLink: value })}
          />
          <SelectControl
            label={__("Target", "WLC")}
            value={target}
            options={[
              { label: __("Self (default)", "WLC"), value: "_self" },
              { label: __("Blank (new tab)", "WLC"), value: "_blank" },
            ]}
            onChange={(value) => setAttributes({ target: value })}
          />
          <SelectControl
            label={__("Display", "WLC")}
            value={display}
            options={[
              { label: __("Inline (default)", "WLC"), value: "inline" },
              { label: __("Block", "WLC"), value: "block" },
              { label: __("Flex", "WLC"), value: "flex" },
              { label: __("Inline-Block", "WLC"), value: "inline-block" },
              { label: __("Inline-Flex", "WLC"), value: "inline-flex" },
              { label: __("None", "WLC"), value: "none" },
            ]}
            onChange={(value) => setAttributes({ display: value })}
          />
          <SelectControl
            label={__("Width", "WLC")}
            value={width}
            options={[
              { label: __("Auto", "WLC"), value: "auto" },
              { label: __("100%", "WLC"), value: "100%" },
              { label: __("50%", "WLC"), value: "50%" },
              { label: __("25%", "WLC"), value: "25%" },
              { label: __("Fit Content", "WLC"), value: "fit-content" },
            ]}
            onChange={(value) => setAttributes({ width: value })}
          />
          <SelectControl
            label={__("Button Align", "WLC")}
            value={btnAlign}
            options={[
              { label: __("Left", "WLC"), value: "left" },
              { label: __("Center", "WLC"), value: "center" },
              { label: __("Right", "WLC"), value: "right" },
            ]}
            onChange={(value) => setAttributes({ btnAlign: value })}
          />
          <SelectControl
            label={__("Justify Content(For Flex)", "WLC")}
            value={textAlign}
            options={[
              { label: __("Left", "WLC"), value: "flex-start" },
              { label: __("Center", "WLC"), value: "center" },
              { label: __("Right", "WLC"), value: "flex-end" },
            ]}
            onChange={(value) => setAttributes({ textAlign: value })}
          />
          <FontFamilyControl
            label={__("Font Family", "WLC")}
            fontFamilies={fontFamilies}
            value={fontFamily}
            onChange={(value) => setAttributes({ fontFamily: value })}
          />
          <ToolsPanel label={__("Typography", "WLC")} resetAll={resetAll}>
            <ToolsPanelItem
              hasValue={() => !!typography.fontSize}
              label={__("Font Size", "WLC")}
              onDeselect={() =>
                setAttributes({ typography: { ...typography, fontSize: null } })
              }
            >
              <FontSizePicker
                value={typography.fontSize}
                onChange={(value) =>
                  setAttributes({
                    typography: { ...typography, fontSize: value },
                  })
                }
              />
            </ToolsPanelItem>
            <ToolsPanelItem
              hasValue={() => !!typography.textDecoration}
              label={__("Text Decoration", "WLC")}
              onDeselect={() =>
                setAttributes({
                  typography: { ...typography, textDecoration: null },
                })
              }
            >
              <TextDecorationControl
                value={typography.textDecoration}
                onChange={(value) =>
                  setAttributes({
                    typography: { ...typography, textDecoration: value },
                  })
                }
              />
            </ToolsPanelItem>
            <ToolsPanelItem
              hasValue={() => !!typography.textTransform}
              label={__("Text Transform", "WLC")}
              onDeselect={() =>
                setAttributes({
                  typography: { ...typography, textTransform: null },
                })
              }
            >
              <TextTransformControl
                value={typography.textTransform}
                onChange={(value) =>
                  setAttributes({
                    typography: { ...typography, textTransform: value },
                  })
                }
              />
            </ToolsPanelItem>
            <ToolsPanelItem
              hasValue={() => !!typography.textTransform}
              label={__("Letter Spacing", "WLC")}
              onDeselect={() =>
                setAttributes({
                  typography: { ...typography, textTransform: null },
                })
              }
            >
              <LetterSpacingControl
                value={typography.letterSpacing}
                onChange={(value) =>
                  setAttributes({
                    typography: { ...typography, letterSpacing: value },
                  })
                }
              />
            </ToolsPanelItem>
            <ToolsPanelItem
              hasValue={() => !!typography.appearance}
              label={__("Appearance", "WLC")}
              onDeselect={() =>
                setAttributes({
                  typography: { ...typography, appearance: null },
                })
              }
            >
              <FontAppearanceControl
                value={{ ...typography.appearance }}
                onChange={(value) =>
                  setAttributes({
                    typography: { ...typography, appearance: value },
                  })
                }
              />
            </ToolsPanelItem>
          </ToolsPanel>
          <BoxControl
            label={__("Padding", "WLC")}
            splitOnAxis
            values={padding}
            onChange={(nextValues) => setAttributes({ padding: nextValues })}
          />
          <PanelColorSettings
            title={__("Color", "WLC")}
            initialOpen={true}
            colorSettings={[
              {
                value: textColor,
                onChange: (value) => setAttributes({ textColor: value }),
                label: __("Select a Text Color", "WLC"),
              },
              {
                value: bgColor,
                onChange: (value) => setAttributes({ bgColor: value }),
                label: __("Select a Background Color", "WLC"),
              },
            ]}
          />
          <PanelColorGradientSettings
            title={__("Background Gradient", "WLC")}
            settings={[
              {
                gradientValue: bgColor,
                gradients: [
                  {
                    name: "Vivid cyan blue to vivid purple",
                    gradient:
                      "linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%)",
                    slug: "vivid-cyan-blue-to-vivid-purple",
                  },
                  {
                    name: "Light green cyan to vivid green cyan",
                    gradient:
                      "linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%)",
                    slug: "light-green-cyan-to-vivid-green-cyan",
                  },
                  {
                    name: "Luminous vivid amber to luminous vivid orange",
                    gradient:
                      "linear-gradient(135deg,rgba(252,185,0,1) 0%,rgba(255,105,0,1) 100%)",
                    slug: "luminous-vivid-amber-to-luminous-vivid-orange",
                  },
                ],
                label: __("Choose a Gradient", "WLC"),
                onGradientChange: (newValue) =>
                  setAttributes({ bgColor: newValue }),
              },
            ]}
          />
          <ToggleControl
            checked={!!showBorder}
            label={__("Border", "WLC")}
            onChange={() => setAttributes({ showBorder: !showBorder })}
          />
          {showBorder && (
            <>
              <BorderControl
                enableStyle={false}
                label={__("Border", "WLC")}
                colors={colors}
                onChange={(value) => setAttributes({ border: value })}
                value={border}
              />
              <SelectControl
                label={__("Border Style", "WLC")}
                value={borderStyle}
                options={[
                  { label: __("Solid", "WLC"), value: "solid" },
                  { label: __("Dashed", "WLC"), value: "dashed" },
                  { label: __("Dotted", "WLC"), value: "dotted" },
                  { label: __("Double", "WLC"), value: "double" },
                  { label: __("Groove", "WLC"), value: "groove" },
                  { label: __("Ridge", "WLC"), value: "ridge" },
                  { label: __("Inset", "WLC"), value: "inset" },
                  { label: __("Outset", "WLC"), value: "outset" },
                ]}
                onChange={(value) => setAttributes({ borderStyle: value })}
              />
              <RangeControl
                label={__("Border Radius (px)", "WLC")}
                value={borderRadius}
                onChange={(value) => setAttributes({ borderRadius: value })}
                min={0}
                max={100}
                step={1}
                initialPosition={0}
                allowReset={true}
                resetFallbackValue={0}
              />
            </>
          )}
        </>
      )}
    </PanelBody>
  );
};

export default ButtonSettings;

ButtonSettingsAnimations.js

import {
  PanelBody,
  ToggleControl,
  SelectControl,
  RangeControl,
} from "@wordpress/components";
import { __ } from "@wordpress/i18n";
import { useEffect } from "@wordpress/element";

const ButtonSettingsAnimations = ({ attributes, setAttributes, btnRef }) => {
  const { animation } = attributes;

  const animationList = [
    {
      label: __("Bounce", "WLC"),
      value: "bounce",
    },
    {
      label: __("Spin", "WLC"),
      value: "spin",
    },
    {
      label: __("Pulse", "WLC"),
      value: "pulse",
    },
    {
      label: __("Ping", "WLC"),
      value: "ping",
    },
    {
      label: __("Scale 75%", "WLC"),
      value: "transform-scale-75",
    },
    {
      label: __("Scale 125%", "WLC"),
      value: "transform-scale-125",
    },
    {
      label: __("Shadow", "WLC"),
      value: "shadows",
    },
    {
      label: __("Pulse Size", "WLC"),
      value: "pulse_size",
    },
  ];

  /**
   * Make animation work in editor
   *
   * Execute when hoverActive is changed
   */
  useEffect(() => {
    const onMouseEnter = () => {
      btnRef.current.classList.add("animated");
    };

    const onMouseLeave = () => {
      btnRef.current.classList.remove("animated");
    };

    if (animation.hoverActive) {
      // Add event listeners to the button
      btnRef.current.addEventListener("mouseenter", onMouseEnter);
      btnRef.current.addEventListener("mouseleave", onMouseLeave);

      // Clean up
      return () => {
        btnRef.current.removeEventListener("mouseenter", onMouseEnter);
        btnRef.current.removeEventListener("mouseleave", onMouseLeave);
      };
    } else {
      // Remove event listeners when not in hover mode
      btnRef.current.removeEventListener("mouseenter", onMouseEnter);
      btnRef.current.removeEventListener("mouseleave", onMouseLeave);
    }
  }, [animation.hoverActive]);

  /**
   * Add animation class if infinite animation is set
   *
   * Execute when infiniteActive is changed
   * and
   * Execute when animation.name is changed
   */
  useEffect(() => {
    if (animation.infiniteActive) {
      btnRef.current.classList.add("animated");
    } else {
      btnRef.current.classList.remove("animated");
    }
  }, [animation.infiniteActive, animation.name]);

  /**
   * Change hoverActive state
   *
   * hoverActive and infiniteActive are mutually exclusive
   * When infiniteActive is set to true, changing infiniteActive to false
   */
  const onHoverActiveChange = () => {
    if (animation.hoverActive) {
      setAttributes({ animation: { ...animation, hoverActive: false } });
    } else {
      if (animation.infiniteActive) {
        setAttributes({
          animation: { ...animation, infiniteActive: false, hoverActive: true },
        });
      } else {
        setAttributes({ animation: { ...animation, hoverActive: true } });
      }
    }
  };

  /**
   * Change infiniteActive state
   *
   * hoverActive and infiniteActive are mutually exclusive
   * When hoverActive is set to true, changing hoverActive to false
   */
  const onInfiniteActiveChange = () => {
    if (animation.infiniteActive) {
      setAttributes({ animation: { ...animation, infiniteActive: false } });
    } else {
      if (animation.hoverActive) {
        setAttributes({
          animation: { ...animation, hoverActive: false, infiniteActive: true },
        });
      } else {
        setAttributes({ animation: { ...animation, infiniteActive: true } });
      }
    }
  };

  return (
    <PanelBody title={__("Button Settings (Animations)", "WLC")}>
      <ToggleControl
        checked={!!animation.hoverActive}
        label={__("Hover Active", "WLC")}
        onChange={onHoverActiveChange}
      />
      <ToggleControl
        checked={!!animation.infiniteActive}
        label={__("Infinite Active", "WLC")}
        onChange={onInfiniteActiveChange}
      />
      {(animation.hoverActive || animation.infiniteActive) && (
        <>
          <SelectControl
            label={__("Animation", "WLC")}
            value={animation.name}
            options={animationList}
            onChange={(value) =>
              setAttributes({ animation: { ...animation, name: value } })
            }
          />
          <RangeControl
            label={__("Animation Duration (s)", "WLC")}
            value={animation.duration}
            min={0.1}
            max={10}
            step={0.1}
            initialPosition={1}
            onChange={(value) =>
              setAttributes({ animation: { ...animation, duration: value } })
            }
          />
        </>
      )}
    </PanelBody>
  );
};

export default ButtonSettingsAnimations;

ButtonSettingsHover.js

import {
  PanelBody,
  ToggleControl,
  SelectControl,
  __experimentalBorderControl as BorderControl,
} from "@wordpress/components";
import {
  PanelColorSettings,
  __experimentalPanelColorGradientSettings as PanelColorGradientSettings,
  useSettings,
} from "@wordpress/block-editor";
import { __ } from "@wordpress/i18n";

const ButtonSettingsHover = ({ attributes, setAttributes }) => {
  const { hover, showBorder, hoverActive } = attributes;

  // Get theme color palette settings
  const [colors] = useSettings("color.palette") || [];

  return (
    <PanelBody title={__("Button Settings (Hover)", "WLC")}>
      <ToggleControl
        checked={!!hoverActive}
        label={__("Active", "WLC")}
        onChange={() => setAttributes({ hoverActive: !hoverActive })}
      />
      <PanelColorSettings
        title={__("Color", "WLC")}
        initialOpen={true}
        colorSettings={[
          {
            value: hover.textColor,
            onChange: (value) =>
              setAttributes({ hover: { ...hover, textColor: value } }),
            label: __("Text Color", "WLC"),
          },
          {
            value: hover.bgColor,
            onChange: (value) =>
              setAttributes({ hover: { ...hover, bgColor: value } }),
            label: __("Background Color", "WLC"),
          },
        ]}
      />
      <PanelColorGradientSettings
        title={__("Background Gradient", "WLC")}
        settings={[
          {
            gradientValue: hover.bgColor,
            gradients: [
              {
                name: "Vivid cyan blue to vivid purple",
                gradient:
                  "linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%)",
                slug: "vivid-cyan-blue-to-vivid-purple",
              },
              {
                name: "Light green cyan to vivid green cyan",
                gradient:
                  "linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%)",
                slug: "light-green-cyan-to-vivid-green-cyan",
              },
              {
                name: "Luminous vivid amber to luminous vivid orange",
                gradient:
                  "linear-gradient(135deg,rgba(252,185,0,1) 0%,rgba(255,105,0,1) 100%)",
                slug: "luminous-vivid-amber-to-luminous-vivid-orange",
              },
            ],
            label: __("Choose a Gradient", "WLC"),
            onGradientChange: (newValue) =>
              setAttributes({ hover: { ...hover, bgColor: newValue } }),
          },
        ]}
      />
      {showBorder && (
        <>
          <BorderControl
            enableStyle={false}
            label={__("Border", "WLC")}
            colors={colors}
            onChange={(value) =>
              setAttributes({ hover: { ...hover, border: value } })
            }
            value={hover.border}
          />
          <SelectControl
            label={__("Border Style", "WLC")}
            value={hover.borderStyle}
            options={[
              { label: __("Solid", "WLC"), value: "solid" },
              { label: __("Dashed", "WLC"), value: "dashed" },
              { label: __("Dotted", "WLC"), value: "dotted" },
              { label: __("Double", "WLC"), value: "double" },
              { label: __("Groove", "WLC"), value: "groove" },
              { label: __("Ridge", "WLC"), value: "ridge" },
              { label: __("Inset", "WLC"), value: "inset" },
              { label: __("Outset", "WLC"), value: "outset" },
            ]}
            onChange={(value) =>
              setAttributes({ hover: { ...hover, borderStyle: value } })
            }
          />
        </>
      )}
    </PanelBody>
  );
};

export default ButtonSettingsHover;

block.json

{
  "$schema": "https://schemas.wp.org/trunk/block.json",
  "apiVersion": 3,
  "name": "wlc/cta",
  "title": " Call To Action",
  "category": "theme",
  "icon": "smiley",
  "description": "Call To Action",
  "keywords": ["cta", "call to action"],
  "supports": {
    "anchor": true,
    "align": true,
    "spacing": {
      "margin": ["vertical"],
      "padding": true
    },
    "renaming": true
  },
  "attributes": {
    "showButton": {
      "type": "boolean",
      "default": true
    },
    "buttonText": {
      "type": "string",
      "default": "CTA"
    },
    "buttonLink": {
      "type": "string",
      "default": "#"
    },
    "target": {
      "type": "string"
    },
    "borderRadius": {
      "type": "integer",
      "default": 25
    },
    "showBorder": {
      "type": "boolean",
      "default": true
    },
    "borderStyle": {
      "type": "string",
      "default": "ridge"
    },
    "bgColor": {
      "type": "string",
      "default": "linear-gradient(135deg, rgb(252, 185, 0) 0%, rgb(255, 105, 0) 100%)"
    },
    "textColor": {
      "type": "string",
      "default": "rgb(219, 0, 47)"
    },
    "border": {
      "type": "object",
      "default": {
        "width": "18px",
        "color": "rgb(209, 0, 0)"
      }
    },
    "padding": {
      "type": "object",
      "default": {
        "top": 0,
        "right": "4rem",
        "bottom": 0,
        "left": "4rem"
      }
    },
    "typography": {
      "type": "object",
      "default": {
        "fontSize": "6rem",
        "appearance": {
          "fontStyle": "normal",
          "fontWeight": "700"
        },
        "textTransform": "uppercase",
        "letterSpacing": "7px",
        "textDecoration": "none"
      }
    },
    "display": {
      "enum": [
        "inline",
        "block",
        "flex",
        "inline-block",
        "inline-flex",
        "none"
      ],
      "default": "flex"
    },
    "btnAlign": {
      "enum": ["left", "center", "right"],
      "default": "center"
    },
    "textAlign": {
      "enum": ["flex-start", "center", "flex-end"],
      "default": "center"
    },
    "width": {
      "enum": ["auto", "100%", "50%", "25%", "fit-content"],
      "default": "fit-content"
    },
    "hover": {
      "type": "object",
      "default": {
        "textColor": "#600015",
        "bgColor": "linear-gradient(279deg,rgba(252,185,0,1) 0%,rgba(255,105,0,1) 100%)",
        "border": {
          "color": "#e90303",
          "width": "18px"
        },
        "borderStyle": "inset"
      }
    },
    "hoverActive": {
      "type": "boolean",
      "default": true
    },
    "animation": {
      "type": "object",
      "default": {
        "hoverActive": false,
        "infiniteActive": true,
        "name": "bounce",
        "delay": 0,
        "duration": 1
      }
    },
    "fontFamily": {
      "type": "string"
    }
  },
  "version": "1.0.0",
  "textdomain": "WLC",
  "editorScript": "file:./index.js",
  "style": "file:./style-index.css",
  "viewScript": "file:./view.js"
}

edit.js

import { __ } from "@wordpress/i18n";
import { useBlockProps, RichText, InspectorControls, InnerBlocks } from "@wordpress/block-editor";
import ButtonSettings from "./ButtonSettings";
import ButtonSettingsHover from "./ButtonSettingsHover";
import ButtonSettingsAnimations from "./ButtonSettingsAnimations";
import { useRef } from "@wordpress/element";

const edit = ({ attributes, setAttributes }) => {
  const {
    typography,
    padding,
    border,
    showButton,
    buttonText,
    buttonLink,
    target,
    borderRadius,
    showBorder,
    borderStyle,
    bgColor,
    textColor,
    display,
    btnAlign,
    textAlign,
    width,
    hover,
    hoverActive,
    animation,
  } = attributes;

  let btnClass = "wlc-cta__button";

  const ref = useRef(null);

  const blockProps = useBlockProps({ className: "wlc-cta" });

  // Prepare border styles
  const borderStyles =
    showBorder && border && border.width && parseInt(border.width) > 0
      ? {
          borderColor: `${border.color}`,
          borderStyle: `${borderStyle}`,
          borderWidth: `${border.width}`,
        }
      : {};
  const borderRadiusStyles = showBorder ? { borderRadius: `${borderRadius}px` } : {};

  const hoverStyles = {};

  // Prepare hover styles
  if (hover && hoverActive) {
    if (hover.textColor) {
      hoverStyles["--wlc-cta-button-hover-text"] = hover.textColor;
    }
    if (hover.bgColor) {
      hoverStyles["--wlc-cta-button-hover-bg"] = hover.bgColor;
    }
    if (hover.border) {
      hoverStyles["--wlc-cta-button-hover-border-color"] = hover.border.color;
      hoverStyles["--wlc-cta-button-hover-border-width"] = hover.border.width;
      hoverStyles["--wlc-cta-button-hover-border-style"] = hover.borderStyle;
    }
  } else {
    hoverStyles["--wlc-cta-button-hover-text"] = textColor;
    hoverStyles["--wlc-cta-button-hover-bg"] = bgColor;
    hoverStyles["--wlc-cta-button-hover-border-color"] = borderStyles.borderColor;
    hoverStyles["--wlc-cta-button-hover-border-width"] = borderStyles.borderWidth;
    hoverStyles["--wlc-cta-button-hover-border-style"] = borderStyles.borderStyle;
  }

  // Remove styles if border is not shown
  if (!showBorder) {
    hoverStyles["--wlc-cta-button-hover-border-style"] = "none";
  }

  // Add animation class if animation is set
  if (animation.name) {
    btnClass += " " + animation.name;
  }

  // Add hover off class if hover is not active
  if (!animation.hoverActive) {
    btnClass += " hover-off";
  }

  // Template for inner blocks
  const template = [
    [
      "core/group",
      {
        className: "container",
        layout: { type: "flex", flexWrap: "nowrap" },
        align: "wide",
      },
      [
        [
          "core/group",
          { layout: { type: "default" } },
          [
            [
              "core/heading",
              {
                level: 2,
                placeholder: __("Heading", "movant"),
                content: "CALL TO ACTION",
                textAlign: "center",
              },
            ],
            [
              "core/paragraph",
              {
                placeholder: __("Paragraph", "movant"),
                fontSize: "text-lg",
                content:
                  "Lorem ipsum dolor sit amet consectetur. Donec sagittis morbi est lacinia gravida a eget. Aenean eget sed vel velit sed natoque. Dolor nunc mauris nec mauris. Vulputate cursus a congue sagittis non volutpat non dictumst vitae.",
              },
            ],
          ],
        ],
      ],
    ],
  ];

  return (
    <>
      <InspectorControls>
        <ButtonSettings attributes={attributes} setAttributes={setAttributes} />
        {showButton && (
          <>
            <ButtonSettingsHover attributes={attributes} setAttributes={setAttributes} />
            <ButtonSettingsAnimations attributes={attributes} setAttributes={setAttributes} btnRef={ref} />
          </>
        )}
      </InspectorControls>
      <section {...blockProps}>
        <InnerBlocks template={template} templateLock={"all"} />
        {showButton && (
          <a
            ref={ref}
            onClick={(e) => e.preventDefault()}
            className={btnClass}
            rel="noopener"
            href={buttonLink}
            target={target}
            style={{
              padding: `${padding.top} ${padding.right} ${padding.bottom} ${padding.left}`,
              borderColor: borderStyles.borderColor,
              borderStyle: borderStyles.borderStyle,
              borderWidth: borderStyles.borderWidth,
              ...borderRadiusStyles,
              background: bgColor,
              color: textColor,
              fontSize: typography.fontSize,
              fontWeight: typography.fontWeight,
              textTransform: typography.textTransform,
              letterSpacing: typography.letterSpacing,
              textDecoration: typography.textDecoration,
              ...typography.appearance,
              display: display,
              justifySelf: btnAlign,
              width: width,
              ...hoverStyles,
              justifyContent: textAlign,
              animationDuration: animation.duration + "s",
            }}
          >
            <RichText
              allowedFormats={[]}
              tagName="span"
              placeholder={__("Type text...", "WLC")}
              className="wlc-cta__button-text"
              value={buttonText}
              onChange={(value) => setAttributes({ buttonText: value })}
            />
          </a>
        )}
      </section>
    </>
  );
};

export default edit;

index.js

import { registerBlockType } from "@wordpress/blocks";
import metadata from './block.json';
import save from "./save";
import edit from './edit';
import './style.scss';

registerBlockType(metadata, {
  edit: edit,
  save: save,
});

save.js

import { useBlockProps, RichText, InnerBlocks } from "@wordpress/block-editor";

const save = ({ attributes }) => {
  const {
    typography,
    padding,
    border,
    showButton,
    buttonText,
    buttonLink,
    target,
    borderRadius,
    showBorder,
    borderStyle,
    bgColor,
    textColor,
    display,
    btnAlign,
    textAlign,
    width,
    hover,
    hoverActive,
    animation,
  } = attributes;

  let btnClass = "wlc-cta__button";

  const blockProps = useBlockProps.save({ className: "wlc-cta" });

  // Prepare border styles
  const borderStyles =
    showBorder && border && border.width && parseInt(border.width) > 0
      ? {
          borderColor: `${border.color}`,
          borderStyle: `${borderStyle}`,
          borderWidth: `${border.width}`,
        }
      : {};
  const borderRadiusStyles = showBorder ? { borderRadius: `${borderRadius}px` } : {};

  const hoverStyles = {};

  // Prepare hover styles
  if (hover && hoverActive) {
    if (hover.textColor) {
      hoverStyles["--wlc-cta-button-hover-text"] = hover.textColor;
    }
    if (hover.bgColor) {
      hoverStyles["--wlc-cta-button-hover-bg"] = hover.bgColor;
    }
    if (hover.border) {
      hoverStyles["--wlc-cta-button-hover-border-color"] = hover.border.color;
      hoverStyles["--wlc-cta-button-hover-border-width"] = hover.border.width;
      hoverStyles["--wlc-cta-button-hover-border-style"] = hover.borderStyle;
    }
  } else {
    hoverStyles["--wlc-cta-button-hover-text"] = textColor;
    hoverStyles["--wlc-cta-button-hover-bg"] = bgColor;
    hoverStyles["--wlc-cta-button-hover-border-color"] = borderStyles.borderColor;
    hoverStyles["--wlc-cta-button-hover-border-width"] = borderStyles.borderWidth;
    hoverStyles["--wlc-cta-button-hover-border-style"] = borderStyles.borderStyle;
  }

  // Remove styles if border is not shown
  if (!showBorder) {
    hoverStyles["--wlc-cta-button-hover-border-style"] = "none";
  }

  if (animation.name) {
    btnClass += " " + animation.name;
  }

  if (!animation.hoverActive) {
    btnClass += " hover-off";
  }

  if (animation.infiniteActive) {
    btnClass += " animated";
  }

  return (
    <section {...blockProps}>
      <InnerBlocks.Content />
      {showButton && (
        <a
          className={btnClass}
          rel="noopener"
          href={buttonLink}
          target={target}
          style={{
            padding: `${padding.top} ${padding.right} ${padding.bottom} ${padding.left}`,
            borderColor: borderStyles.borderColor,
            borderStyle: borderStyles.borderStyle,
            borderWidth: borderStyles.borderWidth,
            ...borderRadiusStyles,
            background: bgColor,
            color: textColor,
            fontSize: typography.fontSize,
            fontWeight: typography.fontWeight,
            textTransform: typography.textTransform,
            letterSpacing: typography.letterSpacing,
            textDecoration: typography.textDecoration,
            ...typography.appearance,
            display: display,
            justifySelf: btnAlign,
            width: width,
            ...hoverStyles,
            justifyContent: textAlign,
            animationDuration: animation.duration + "s",
          }}
        >
          <RichText.Content tagName="span" className="wlc-cta__button-text" value={buttonText} />
        </a>
      )}
    </section>
  );
};

export default save;

style.scss

.wlc-cta {
  @apply grid;

  &__button {
    @apply transition-all;

    &:hover,
    &:active,
    &:focus {
      @apply text-[var(--wlc-cta-button-hover-text)] #{!important};
      @apply border-[color:var(--wlc-cta-button-hover-border-color)] border-[line-width:var(--wlc-cta-button-hover-border-width)] #{!important};
      border-style: var(--wlc-cta-button-hover-border-style) !important;
      background: var(--wlc-cta-button-hover-bg) !important;
    }

    &.animated {
      &.bounce {
        @apply animate-bounce;
      }

      &.spin {
        @apply animate-spin;
      }

      &.pulse {
        @apply animate-pulse;
      }

      &.ping {
        @apply animate-ping;
      }

      &.transform-scale-75 {
        @apply scale-75;
      }

      &.transform-scale-125 {
        @apply scale-125;
      }

      &.shadows {
        @apply shadow-lg;
      }

      &.pulse_size {
        @apply animate-pulse_size;
      }
    }
  }
}

view.js

document.addEventListener("DOMContentLoaded", function () {
  // Get the buttons without the .hover-off class
  const btns = document.querySelectorAll(".wlc-cta__button:not(.hover-off)");

  // Add event listeners to the buttons
  // .animated class is added on mouseenter and removed on mouseleave
  // .animated class is required for animations to work
  btns.forEach((element) => {
    const onMouseEnter = () => {
      element.classList.add("animated");
    };

    const onMouseLeave = () => {
      element.classList.remove("animated");
    };

    element.addEventListener("mouseenter", onMouseEnter);
    element.addEventListener("mouseleave", onMouseLeave);
  });
});