From 487010943aea12d335d34a0ff364049571003b50 Mon Sep 17 00:00:00 2001
From: Seth Hill <53914-sethhill@users.noreply.drupalcode.org>
Date: Sun, 18 Aug 2024 21:02:44 +0000
Subject: [PATCH] Issue #3465076 by woldtwerk, sethhill: use es6 as default and
 rename to .js

---
 js/builder-form.es6.js     |  29 --
 js/builder-form.js         |  41 +--
 js/builder.es6.js          | 609 -------------------------------------
 js/builder.js              | 586 +++++++++++++++++++++++------------
 js/component-form.es6.js   |  16 -
 js/component-form.js       |  20 +-
 js/component-list.es6.js   |  20 --
 js/component-list.js       |  26 +-
 layout_paragraphs.info.yml |   2 +-
 9 files changed, 442 insertions(+), 907 deletions(-)
 delete mode 100644 js/builder-form.es6.js
 delete mode 100644 js/builder.es6.js
 delete mode 100644 js/component-form.es6.js
 delete mode 100644 js/component-list.es6.js

diff --git a/js/builder-form.es6.js b/js/builder-form.es6.js
deleted file mode 100644
index 916cf7e..0000000
--- a/js/builder-form.es6.js
+++ /dev/null
@@ -1,29 +0,0 @@
-(($, Drupal, once) => {
-  // Updates the "Close" button label when a layout is changed.
-  Drupal.behaviors.layoutParagraphsBuilderForm = {
-    attach: function attach(context) {
-      // Prevent nested frontend editors from being activated at the same time.
-      $('.lpb-enable__wrapper').removeClass('hidden');
-      $('[data-lpb-form-id]').each((i, e) => {
-        const p = $(e).parents('[data-lpb-id]').toArray().pop();
-        const parent = p || e;
-        $('.lpb-enable__wrapper', parent).addClass('hidden');
-      });
-
-      // Update the "Close" button to say "Cancel" when any changes are made.
-      const events = [
-        'lpb-component:insert.lpb',
-        'lpb-component:update.lpb',
-        'lpb-component:move.lpb',
-        'lpb-component:drop.lpb',
-      ].join(' ');
-      $(once('lpb-builder-form', '[data-lpb-id]', context))
-        .on(events, (e) => {
-          $(e.currentTarget)
-            .closest('[data-lpb-form-id]')
-            .find('[data-drupal-selector="edit-close"]')
-            .val(Drupal.t('Cancel'));
-        });
-    },
-  };
-})(jQuery, Drupal, once);
diff --git a/js/builder-form.js b/js/builder-form.js
index 8d36cbc..916cf7e 100644
--- a/js/builder-form.js
+++ b/js/builder-form.js
@@ -1,24 +1,29 @@
-/**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-"use strict";
-
-(function ($, Drupal, once) {
+(($, Drupal, once) => {
+  // Updates the "Close" button label when a layout is changed.
   Drupal.behaviors.layoutParagraphsBuilderForm = {
     attach: function attach(context) {
+      // Prevent nested frontend editors from being activated at the same time.
       $('.lpb-enable__wrapper').removeClass('hidden');
-      $('[data-lpb-form-id]').each(function (i, e) {
-        var p = $(e).parents('[data-lpb-id]').toArray().pop();
-        var parent = p || e;
+      $('[data-lpb-form-id]').each((i, e) => {
+        const p = $(e).parents('[data-lpb-id]').toArray().pop();
+        const parent = p || e;
         $('.lpb-enable__wrapper', parent).addClass('hidden');
       });
-      var events = ['lpb-component:insert.lpb', 'lpb-component:update.lpb', 'lpb-component:move.lpb', 'lpb-component:drop.lpb'].join(' ');
-      $(once('lpb-builder-form', '[data-lpb-id]', context)).on(events, function (e) {
-        $(e.currentTarget).closest('[data-lpb-form-id]').find('[data-drupal-selector="edit-close"]').val(Drupal.t('Cancel'));
-      });
-    }
+
+      // Update the "Close" button to say "Cancel" when any changes are made.
+      const events = [
+        'lpb-component:insert.lpb',
+        'lpb-component:update.lpb',
+        'lpb-component:move.lpb',
+        'lpb-component:drop.lpb',
+      ].join(' ');
+      $(once('lpb-builder-form', '[data-lpb-id]', context))
+        .on(events, (e) => {
+          $(e.currentTarget)
+            .closest('[data-lpb-form-id]')
+            .find('[data-drupal-selector="edit-close"]')
+            .val(Drupal.t('Cancel'));
+        });
+    },
   };
-})(jQuery, Drupal, once);
\ No newline at end of file
+})(jQuery, Drupal, once);
diff --git a/js/builder.es6.js b/js/builder.es6.js
deleted file mode 100644
index be38b63..0000000
--- a/js/builder.es6.js
+++ /dev/null
@@ -1,609 +0,0 @@
-(($, Drupal, debounce, dragula, once) => {
-  const idAttr = 'data-lpb-id';
-
-  /**
-   * Attaches UI elements to $container.
-   * @param {jQuery} $container
-   *   The container.
-   * @param {Object} settings
-   *   The settings object.
-   */
-  function attachUiElements($container, settings) {
-    const id = $container.attr('data-lpb-ui-id');
-    const lpbBuilderSettings = settings.lpBuilder || {};
-    const uiElements = lpbBuilderSettings.uiElements || {};
-    const containerUiElements = uiElements[id] || [];
-    Object.values(containerUiElements).forEach((uiElement) => {
-      const { element, method } = uiElement;
-      $container[method]($(element).addClass('js-lpb-ui'));
-    });
-  }
-
-  /**
-   * Repositions open dialogs when their height changes to exceed viewport.
-   *
-   * The height of an open dialog will change based on its contents and can
-   * cause a dialog to grow taller than the current window viewport, making
-   * it impossible to reach parts of the content (for example, submit buttons).
-   * Repositioning the dialog fixes the issue.
-   * @see https://www.drupal.org/project/layout_paragraphs/issues/3252978
-   * @see https://stackoverflow.com/questions/5456298/refresh-jquery-ui-dialog-position
-   *
-   * @param {Number} intervalId
-   *   The interval id.
-   */
-  function repositionDialog(intervalId) {
-    const $dialogs = $('.lpb-dialog');
-    if ($dialogs.length === 0) {
-      clearInterval(intervalId);
-      return;
-    }
-    $dialogs.each((i, dialog) => {
-      const bounding = dialog.getBoundingClientRect();
-      const viewPortHeight =
-        window.innerHeight || document.documentElement.clientHeight;
-      if (bounding.bottom > viewPortHeight) {
-        const $dialog = $('.ui-dialog-content', dialog);
-        const height = viewPortHeight - 200;
-        $dialog.dialog('option', 'height', height);
-        $dialog.css('overscroll-behavior', 'contain');
-
-        if ($dialog.data('lpOriginalHeight') !== height) {
-          $dialog.data('lpOriginalHeight', height);
-          const bounding = dialog.getBoundingClientRect();
-          const viewPortHeight = window.innerHeight || document.documentElement.clientHeight;
-          if (bounding.bottom > viewPortHeight) {
-            const pos = $dialog.dialog('option', 'position');
-            $dialog.dialog('option', 'position', pos);
-          }
-        }
-      }
-    });
-  }
-
-  /**
-   * Makes an ajax request to reorder all items in the layout.
-   * This function is debounced below and not called directly.
-   * @param {jQuery} $element The builder element.
-   */
-  function doReorderComponents($element) {
-    const id = $element.attr(idAttr);
-    const order = $('.js-lpb-component', $element)
-      .get()
-      .map((item) => {
-        const $item = $(item);
-        return {
-          uuid: $item.attr('data-uuid'),
-          parentUuid:
-            $item.parents('.js-lpb-component').first().attr('data-uuid') ||
-            null,
-          region:
-            $item.parents('.js-lpb-region').first().attr('data-region') || null,
-        };
-      });
-    Drupal.ajax({
-      url: `${drupalSettings.path.baseUrl}${drupalSettings.path.pathPrefix}layout-paragraphs-builder/${id}/reorder`,
-      submit: {
-        components: JSON.stringify(order),
-      },
-      error: () => {
-        // Fail silently to prevent console errors.
-      },
-    }).execute();
-  }
-
-  const reorderComponents = debounce(doReorderComponents);
-
-  /**
-   * Returns a list of errors for the attempted move, or an empty array if there are no errors.
-   * @param {Element} settings The builder settings.
-   * @param {Element} el The element being moved.
-   * @param {Element} target The destination
-   * @param {Element} source The source
-   * @param {Element} sibling The next sibling element
-   * @return {Array} An array of errors.
-   */
-  function moveErrors(settings, el, target, source, sibling) {
-    return Drupal._lpbMoveErrors
-      .map((validator) =>
-        validator.apply(null, [settings, el, target, source, sibling]),
-      )
-      .filter((errors) => errors !== false && errors !== undefined);
-  }
-
-  /**
-   * Updates move buttons to reflect current state.
-   * @param {jQuery} $element The builder element.
-   */
-  function updateMoveButtons($element) {
-    const lpbBuilderElements = Array.from($element[0].querySelectorAll('.js-lpb-component-list, .js-lpb-region'));
-    const lpbBuilderComponent = lpbBuilderElements.filter(el => el.querySelector('.js-lpb-component'));
-
-    $element[0].querySelectorAll('.lpb-up, .lpb-down').forEach((el) => {
-      // Set the tabindex of the up and down arrows to 0.
-      el.setAttribute('tabindex', '0');
-    });
-
-    lpbBuilderComponent.forEach((el) => {
-      const components = Array.from(el.children).filter(n => n.classList.contains('js-lpb-component'));
-
-      // Set the tabindex of the first component's up arrow to -1.
-      components[0].querySelector('.lpb-up')?.setAttribute('tabindex', '-1');
-
-      // Set the tabindex of the last component's down arrow to -1.
-      components[components.length - 1].querySelector('.lpb-down')?.setAttribute('tabindex', '-1');
-    });
-  }
-
-  /**
-   * Hides the add content button in regions that contain components.
-   * @param {jQuery} $element The builder element.
-   */
-  function hideEmptyRegionButtons($element) {
-    $element.find('.js-lpb-region').each((i, e) => {
-      const $e = $(e);
-      if ($e.find('.js-lpb-component').length === 0) {
-        $e.find('.lpb-btn--add.center').css('display', 'block');
-      } else {
-        $e.find('.lpb-btn--add.center').css('display', 'none');
-      }
-    });
-  }
-
-  /**
-   * Updates the UI based on currently state.
-   * @param {jQuery} $element The builder element.
-   */
-  function updateUi($element) {
-    reorderComponents($element);
-    updateMoveButtons($element);
-    hideEmptyRegionButtons($element);
-  }
-
-  /**
-   * Moves a component up or down within a simple list of components.
-   * @param {jQuery} $moveItem The item to move.
-   * @param {int} direction 1 (down) or -1 (up).
-   * @return {void}
-   */
-  function move($moveItem, direction) {
-    const $sibling =
-      direction === 1
-        ? $moveItem.nextAll('.js-lpb-component').first()
-        : $moveItem.prevAll('.js-lpb-component').first();
-
-    const method = direction === 1 ? 'after' : 'before';
-    const { scrollY } = window;
-    const destScroll = scrollY + $sibling.outerHeight() * direction;
-
-    if ($sibling.length === 0) {
-      return false;
-    }
-
-    // Determine if the move should be animated horizontally or vertically.
-    const animateProp = $sibling[0].getBoundingClientRect().top == $moveItem[0].getBoundingClientRect().top
-      ? 'translateX'
-      : 'translateY';
-    // Determine the dimension property to use for the animation.
-    const dimmensionProp = animateProp === 'translateX' ? 'offsetWidth' : 'offsetHeight';
-    // Determine the distance to move the sibling and the item.
-    const siblingDest = $moveItem[0][dimmensionProp] * direction * -1;
-    const itemDest = $sibling[0][dimmensionProp] * direction;
-    const distance = Math.abs(Math.max(siblingDest, itemDest));
-    const duration  = distance * .25;
-    const siblingKeyframes = [
-      { transform: `${animateProp}(0)` },
-      { transform: `${animateProp}(${siblingDest}px)` },
-    ];
-    const itemKeyframes = [
-      { transform: `${animateProp}(0)` },
-      { transform: `${animateProp}(${itemDest}px)` },
-    ];
-    const timing = {
-      duration,
-      iterations: 1
-    }
-    const anim1 = $moveItem[0].animate(itemKeyframes, timing);
-    anim1.onfinish = () => {
-      $moveItem.css({ transform: 'none' });
-      $sibling.css({ transform: 'none' });
-      $sibling[method]($moveItem);
-      $moveItem
-        .closest(`[${idAttr}]`)
-        .trigger('lpb-component:move', [$moveItem.attr('data-uuid')]);
-    };
-    $sibling[0].animate(siblingKeyframes, timing);
-    if (animateProp === 'translateY') {
-      window.scrollTo({
-        top: destScroll,
-        behavior: 'smooth',
-      });
-    }
-  }
-
-  /**
-   * Moves the focused component up or down the DOM to the next valid position
-   * when an arrow key is pressed. Unlike move(), nav()can fully navigate
-   * components to any valid position in an entire layout.
-   * @param {jQuery} $item The jQuery item to move.
-   * @param {int} dir The direction to move (1 == down, -1 == up).
-   * @param {Object} settings The builder ui settings.
-   */
-  function nav($item, dir, settings) {
-    const $element = $item.closest(`[${idAttr}]`);
-    $item.addClass('lpb-active-item');
-    // Add shims as target elements.
-    if (dir === -1) {
-      $(
-        '.js-lpb-region .lpb-btn--add.center, .lpb-layout:not(.lpb-active-item)',
-        $element,
-      ).before('<div class="lpb-shim"></div>');
-    } else if (dir === 1) {
-      $('.js-lpb-region', $element).prepend('<div class="lpb-shim"></div>');
-      $('.lpb-layout:not(.lpb-active-item)', $element).after(
-        '<div class="lpb-shim"></div>',
-      );
-    }
-    // Build a list of possible targets, or move destinations.
-    const targets = $('.js-lpb-component, .lpb-shim', $element)
-      .toArray()
-      // Remove child components from possible targets.
-      .filter((i) => !$.contains($item[0], i))
-      // Remove layout elements that are not self from possible targets.
-      .filter(
-        (i) => i.className.indexOf('lpb-layout') === -1 || i === $item[0],
-      );
-    const currentElement = $item[0];
-    let pos = targets.indexOf(currentElement);
-    // Check to see if the next position is allowed by calling the 'accepts' callback.
-    while (
-      targets[pos + dir] !== undefined &&
-      moveErrors(
-        settings,
-        $item[0],
-        targets[pos + dir].parentNode,
-        null,
-        $item.next().length ? $item.next()[0] : null,
-      ).length > 0
-    ) {
-      pos += dir;
-    }
-    if (targets[pos + dir] !== undefined) {
-      // Move after or before the target based on direction.
-      $(targets[pos + dir])[dir === 1 ? 'after' : 'before']($item);
-    }
-    // Remove the shims and save the order.
-    $('.lpb-shim', $element).remove();
-    $item.removeClass('lpb-active-item').focus();
-    $item
-      .closest(`[${idAttr}]`)
-      .trigger('lpb-component:move', [$item.attr('data-uuid')]);
-  }
-
-  function startNav($item) {
-    const $msg = $(
-      `<div id="lpb-navigating-msg" class="lpb-tooltiptext lpb-tooltiptext--visible js-lpb-tooltiptext">${Drupal.t(
-        'Use arrow keys to move. Press Return or Tab when finished.',
-      )}</div>`,
-    );
-    $item
-      .closest('.lp-builder')
-      .addClass('is-navigating')
-      .find('.is-navigating')
-      .removeClass('is-navigating');
-    $item
-      .attr('aria-describedby', 'lpb-navigating-msg')
-      .addClass('is-navigating')
-      .prepend($msg);
-    $item.before('<div class="lpb-navigating-placeholder"></div>');
-  }
-
-  function stopNav($item) {
-    $item
-      .removeClass('is-navigating')
-      .attr('aria-describedby', '')
-      .find('.js-lpb-tooltiptext')
-      .remove();
-    $item
-      .closest(`[${idAttr}]`)
-      .removeClass('is-navigating')
-      .find('.lpb-navigating-placeholder')
-      .remove();
-  }
-
-  function cancelNav($item) {
-    const $builder = $item.closest(`[${idAttr}]`);
-    $builder.find('.lpb-navigating-placeholder').replaceWith($item);
-    updateUi($builder);
-    stopNav($item);
-  }
-
-  /**
-   * Prevents user from navigating away and accidentally loosing changes.
-   * @param {jQuery} $element The jQuery layout paragraphs builder object.
-   */
-  function preventLostChanges($element) {
-    // Add class "is_changed" when the builder is edited.
-    const events = [
-      'lpb-component:insert.lpb',
-      'lpb-component:update.lpb',
-      'lpb-component:move.lpb',
-      'lpb-component:drop.lpb',
-    ].join(' ');
-    $element.on(events, (e) => {
-      $(e.currentTarget).addClass('is_changed');
-    });
-    window.addEventListener('beforeunload', (e) => {
-      if ($(`.is_changed[${idAttr}]`).length) {
-        e.preventDefault();
-        e.returnValue = '';
-      }
-    });
-    $('.form-actions')
-      .find('input[type="submit"], a')
-      .click(() => {
-        $element.removeClass('is_changed');
-      });
-  }
-
-  /**
-   * Attaches event listeners/handlers for builder ui.
-   * @param {jQuery} $element The layout paragraphs builder object.
-   * @param {Object} settings The builder settings.
-   */
-  function attachEventListeners($element, settings) {
-    preventLostChanges($element);
-    $element.on('click.lp-builder', '.lpb-up', (e) => {
-      move($(e.target).closest('.js-lpb-component'), -1);
-      return false;
-    });
-    $element.on('click.lp-builder', '.lpb-down', (e) => {
-      move($(e.target).closest('.js-lpb-component'), 1);
-      return false;
-    });
-    $element.on('click.lp-builder', '.js-lpb-component', (e) => {
-      $(e.currentTarget).focus();
-    });
-    $element.on('click.lp-builder', '.lpb-drag', (e) => {
-      const $btn = $(e.currentTarget);
-      startNav($btn.closest('.js-lpb-component'));
-    });
-    $(document).off('keydown');
-    $(document).on('keydown', (e) => {
-      const $item = $('.js-lpb-component.is-navigating');
-      if ($item.length) {
-        switch (e.code) {
-          case 'ArrowUp':
-          case 'ArrowLeft':
-            nav($item, -1, settings);
-            break;
-          case 'ArrowDown':
-          case 'ArrowRight':
-            nav($item, 1, settings);
-            break;
-          case 'Enter':
-          case 'Tab':
-            stopNav($item);
-            break;
-          case 'Escape':
-            cancelNav($item);
-            break;
-          default:
-            break;
-        }
-      }
-    });
-  }
-
-  function initDragAndDrop($element, settings) {
-    const containers = once('is-dragula-enabled', '.js-lpb-component-list, .js-lpb-region', $element[0]);
-    const drake = dragula(
-      containers,
-      {
-        accepts: (el, target, source, sibling) =>
-          moveErrors(settings, el, target, source, sibling).length === 0,
-        moves(el, source, handle) {
-          const $handle = $(handle);
-          if ($handle.closest('.lpb-drag').length) {
-            return true;
-          }
-          if ($handle.closest('.lpb-controls').length) {
-            return false;
-          }
-          return true;
-        },
-      },
-    );
-    drake.on('drop', (el) => {
-      const $el = $(el);
-      if ($el.prev().is('a')) {
-        $el.insertBefore($el.prev());
-      }
-      $element.trigger('lpb-component:drop', [$el.attr('data-uuid')]);
-    });
-    drake.on('drag', (el) => {
-      $element.addClass('is-dragging');
-      if (el.className.indexOf('lpb-layout') > -1) {
-        $element.addClass('is-dragging-layout');
-      } else {
-        $element.addClass('is-dragging-item');
-      }
-      $element.trigger('lpb-component:drag', [$(el).attr('data-uuid')]);
-    });
-    drake.on('dragend', () => {
-      $element
-        .removeClass('is-dragging')
-        .removeClass('is-dragging-layout')
-        .removeClass('is-dragging-item');
-    });
-    drake.on('over', (el, container) => {
-      $(container).addClass('drag-target');
-    });
-    drake.on('out', (el, container) => {
-      $(container).removeClass('drag-target');
-    });
-    return drake;
-  }
-
-  // An array of move error callback functions.
-  Drupal._lpbMoveErrors = [];
-  /**
-   * Registers a move validation function.
-   * @param {Function} f The validator function.
-   */
-  Drupal.registerLpbMoveError = (f) => {
-    Drupal._lpbMoveErrors.push(f);
-  };
-  // Checks nesting depth.
-  Drupal.registerLpbMoveError((settings, el, target) => {
-    if (
-      el.classList.contains('lpb-layout') &&
-      $(target).parents('.lpb-layout').length > settings.nesting_depth
-    ) {
-      return Drupal.t('Exceeds nesting depth of @depth.', {
-        '@depth': settings.nesting_depth,
-      });
-    }
-  });
-  // If layout is required, prevents component from being placed outside a layout.
-  Drupal.registerLpbMoveError((settings, el, target) => {
-    if (settings.require_layouts) {
-      if (
-        el.classList.contains('js-lpb-component') &&
-        !el.classList.contains('lpb-layout') &&
-        !target.classList.contains('js-lpb-region')
-      ) {
-        return Drupal.t('Components must be added inside sections.');
-      }
-    }
-  });
-  Drupal.AjaxCommands.prototype.LayoutParagraphsEventCommand = (
-    ajax,
-    response,
-  ) => {
-    const { layoutId, componentUuid, eventName } = response;
-    const $element = $(`[data-lpb-id="${layoutId}"]`);
-    $element.trigger(`lpb-${eventName}`, [componentUuid]);
-  };
-
-  /*
-   * Moves the main form action buttons into the jQuery modal button pane.
-   * @param {jQuery} context
-   *  The context to search for dialog buttons.
-   * @return {void}
-   */
-  function updateDialogButtons(context) {
-    // Determine if this context is from within dialog content.
-    const $lpDialog = $(context).closest('.ui-dialog-content');
-
-    if (!$lpDialog) {
-      return;
-    }
-
-    const buttons = [];
-    const $buttons = $lpDialog.find('.layout-paragraphs-component-form > .form-actions input[type=submit], .layout-paragraphs-component-form > .form-actions a.button');
-
-    if ($buttons.length === 0) {
-      return;
-    }
-
-    $buttons.each((_i, el) => {
-      const $originalButton = $(el).css({ display: 'none' });
-      buttons.push({
-        text: $originalButton.html() || $originalButton.attr('value'),
-        class: $originalButton.attr('class'),
-        click(e) {
-          // If the original button is an anchor tag, triggering the "click"
-          // event will not simulate a click. Use the click method instead.
-          if ($originalButton.is('a')) {
-            $originalButton[0].click();
-          } else {
-            $originalButton
-              .trigger('mousedown')
-              .trigger('mouseup')
-              .trigger('click');
-            e.preventDefault();
-          }
-        },
-      });
-    });
-
-    $lpDialog.dialog('option', 'buttons', buttons);
-  }
-
-  Drupal.behaviors.layoutParagraphsBuilder = {
-    attach: function attach(context, settings) {
-      // Add UI elements to the builder, each component, and each region.
-      const jsUiElements = once('lpb-ui-elements', '[data-has-js-ui-element]');
-      jsUiElements.forEach((el) => {
-        attachUiElements($(el), settings);
-      });
-
-      // Listen to relevant events and update UI.
-      once('lpb-events', '[data-lpb-id]').forEach((el) => {
-        $(el).on('lpb-builder:init.lpb lpb-component:insert.lpb lpb-component:update.lpb lpb-component:move.lpb lpb-component:drop.lpb lpb-component:delete.lpb', (e) => {
-          const $element = $(e.currentTarget);
-          updateUi($element);
-        });
-      });
-
-      // Initialize the editor drag and drop ui.
-      once('lpb-enabled', '[data-lpb-id].has-components').forEach((el) => {
-        const $element = $(el);
-        const id = $element.attr(idAttr);
-        const lpbSettings = settings.lpBuilder[id];
-        // Attach event listeners and init dragula just once.
-        $element.data('drake', initDragAndDrop($element, lpbSettings));
-        attachEventListeners($element, lpbSettings);
-        $element.trigger('lpb-builder:init');
-      });
-
-      // Add new containers to the dragula instance.
-      once('is-dragula-enabled', '.js-lpb-region').forEach((c) => {
-        const builderElement = c.closest('[data-lpb-id]');
-        const drake = $(builderElement).data('drake');
-        drake.containers.push(c);
-      });
-
-      // If UI elements have been attached to the DOM, we need to attach behaviors.
-      if (jsUiElements.length) {
-        Drupal.attachBehaviors(context, settings);
-      }
-
-      // Moves dialog buttons into the jQuery modal button pane.
-      updateDialogButtons(context);
-    },
-  };
-
-  // Move the main form action buttons into the jQuery modal button pane.
-  // By default, dialog.ajax.js moves all form action buttons into the button
-  // pane -- which can have unintended consequences. We suppress that option
-  // by setting drupalAutoButtons to false, but then manually move _only_ the
-  // main form action buttons into the jQuery button pane.
-  // @see https://www.drupal.org/project/layout_paragraphs/issues/3191418
-  // @see https://www.drupal.org/project/layout_paragraphs/issues/3216981
-
-  // Repositions open dialogs.
-  // @see https://www.drupal.org/project/layout_paragraphs/issues/3252978
-  // @see https://stackoverflow.com/questions/5456298/refresh-jquery-ui-dialog-position
-
-  let lpDialogInterval;
-
-  const handleAfterDialogCreate = (event, dialog, $dialog) => {
-    const $element = $dialog || jQuery(event.target);
-    if ($element.attr('id').startsWith('lpb-dialog-')) {
-      updateDialogButtons($element);
-      clearInterval(lpDialogInterval);
-      lpDialogInterval = setInterval(
-        repositionDialog.bind(null, lpDialogInterval),
-        500
-      );
-    }
-  };
-  if (typeof DrupalDialogEvent === 'undefined') {
-    $(window).on('dialog:aftercreate', handleAfterDialogCreate);
-  } else {
-    window.addEventListener('dialog:aftercreate', handleAfterDialogCreate);
-  }
-
-})(jQuery, Drupal, Drupal.debounce, dragula, once);
diff --git a/js/builder.js b/js/builder.js
index ef597fc..be38b63 100644
--- a/js/builder.js
+++ b/js/builder.js
@@ -1,96 +1,147 @@
-/**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-"use strict";
-
-(function ($, Drupal, debounce, dragula, once) {
-  var idAttr = 'data-lpb-id';
+(($, Drupal, debounce, dragula, once) => {
+  const idAttr = 'data-lpb-id';
+
+  /**
+   * Attaches UI elements to $container.
+   * @param {jQuery} $container
+   *   The container.
+   * @param {Object} settings
+   *   The settings object.
+   */
   function attachUiElements($container, settings) {
-    var id = $container.attr('data-lpb-ui-id');
-    var lpbBuilderSettings = settings.lpBuilder || {};
-    var uiElements = lpbBuilderSettings.uiElements || {};
-    var containerUiElements = uiElements[id] || [];
-    Object.values(containerUiElements).forEach(function (uiElement) {
-      var element = uiElement.element,
-        method = uiElement.method;
+    const id = $container.attr('data-lpb-ui-id');
+    const lpbBuilderSettings = settings.lpBuilder || {};
+    const uiElements = lpbBuilderSettings.uiElements || {};
+    const containerUiElements = uiElements[id] || [];
+    Object.values(containerUiElements).forEach((uiElement) => {
+      const { element, method } = uiElement;
       $container[method]($(element).addClass('js-lpb-ui'));
     });
   }
+
+  /**
+   * Repositions open dialogs when their height changes to exceed viewport.
+   *
+   * The height of an open dialog will change based on its contents and can
+   * cause a dialog to grow taller than the current window viewport, making
+   * it impossible to reach parts of the content (for example, submit buttons).
+   * Repositioning the dialog fixes the issue.
+   * @see https://www.drupal.org/project/layout_paragraphs/issues/3252978
+   * @see https://stackoverflow.com/questions/5456298/refresh-jquery-ui-dialog-position
+   *
+   * @param {Number} intervalId
+   *   The interval id.
+   */
   function repositionDialog(intervalId) {
-    var $dialogs = $('.lpb-dialog');
+    const $dialogs = $('.lpb-dialog');
     if ($dialogs.length === 0) {
       clearInterval(intervalId);
       return;
     }
-    $dialogs.each(function (i, dialog) {
-      var bounding = dialog.getBoundingClientRect();
-      var viewPortHeight = window.innerHeight || document.documentElement.clientHeight;
+    $dialogs.each((i, dialog) => {
+      const bounding = dialog.getBoundingClientRect();
+      const viewPortHeight =
+        window.innerHeight || document.documentElement.clientHeight;
       if (bounding.bottom > viewPortHeight) {
-        var $dialog = $('.ui-dialog-content', dialog);
-        var height = viewPortHeight - 200;
+        const $dialog = $('.ui-dialog-content', dialog);
+        const height = viewPortHeight - 200;
         $dialog.dialog('option', 'height', height);
         $dialog.css('overscroll-behavior', 'contain');
+
         if ($dialog.data('lpOriginalHeight') !== height) {
           $dialog.data('lpOriginalHeight', height);
-          var _bounding = dialog.getBoundingClientRect();
-          var _viewPortHeight = window.innerHeight || document.documentElement.clientHeight;
-          if (_bounding.bottom > _viewPortHeight) {
-            var pos = $dialog.dialog('option', 'position');
+          const bounding = dialog.getBoundingClientRect();
+          const viewPortHeight = window.innerHeight || document.documentElement.clientHeight;
+          if (bounding.bottom > viewPortHeight) {
+            const pos = $dialog.dialog('option', 'position');
             $dialog.dialog('option', 'position', pos);
           }
         }
       }
     });
   }
+
+  /**
+   * Makes an ajax request to reorder all items in the layout.
+   * This function is debounced below and not called directly.
+   * @param {jQuery} $element The builder element.
+   */
   function doReorderComponents($element) {
-    var id = $element.attr(idAttr);
-    var order = $('.js-lpb-component', $element).get().map(function (item) {
-      var $item = $(item);
-      return {
-        uuid: $item.attr('data-uuid'),
-        parentUuid: $item.parents('.js-lpb-component').first().attr('data-uuid') || null,
-        region: $item.parents('.js-lpb-region').first().attr('data-region') || null
-      };
-    });
+    const id = $element.attr(idAttr);
+    const order = $('.js-lpb-component', $element)
+      .get()
+      .map((item) => {
+        const $item = $(item);
+        return {
+          uuid: $item.attr('data-uuid'),
+          parentUuid:
+            $item.parents('.js-lpb-component').first().attr('data-uuid') ||
+            null,
+          region:
+            $item.parents('.js-lpb-region').first().attr('data-region') || null,
+        };
+      });
     Drupal.ajax({
-      url: "".concat(drupalSettings.path.baseUrl).concat(drupalSettings.path.pathPrefix, "layout-paragraphs-builder/").concat(id, "/reorder"),
+      url: `${drupalSettings.path.baseUrl}${drupalSettings.path.pathPrefix}layout-paragraphs-builder/${id}/reorder`,
       submit: {
-        components: JSON.stringify(order)
+        components: JSON.stringify(order),
+      },
+      error: () => {
+        // Fail silently to prevent console errors.
       },
-      error: function error() {}
     }).execute();
   }
-  var reorderComponents = debounce(doReorderComponents);
+
+  const reorderComponents = debounce(doReorderComponents);
+
+  /**
+   * Returns a list of errors for the attempted move, or an empty array if there are no errors.
+   * @param {Element} settings The builder settings.
+   * @param {Element} el The element being moved.
+   * @param {Element} target The destination
+   * @param {Element} source The source
+   * @param {Element} sibling The next sibling element
+   * @return {Array} An array of errors.
+   */
   function moveErrors(settings, el, target, source, sibling) {
-    return Drupal._lpbMoveErrors.map(function (validator) {
-      return validator.apply(null, [settings, el, target, source, sibling]);
-    }).filter(function (errors) {
-      return errors !== false && errors !== undefined;
-    });
+    return Drupal._lpbMoveErrors
+      .map((validator) =>
+        validator.apply(null, [settings, el, target, source, sibling]),
+      )
+      .filter((errors) => errors !== false && errors !== undefined);
   }
+
+  /**
+   * Updates move buttons to reflect current state.
+   * @param {jQuery} $element The builder element.
+   */
   function updateMoveButtons($element) {
-    var lpbBuilderElements = Array.from($element[0].querySelectorAll('.js-lpb-component-list, .js-lpb-region'));
-    var lpbBuilderComponent = lpbBuilderElements.filter(function (el) {
-      return el.querySelector('.js-lpb-component');
-    });
-    $element[0].querySelectorAll('.lpb-up, .lpb-down').forEach(function (el) {
+    const lpbBuilderElements = Array.from($element[0].querySelectorAll('.js-lpb-component-list, .js-lpb-region'));
+    const lpbBuilderComponent = lpbBuilderElements.filter(el => el.querySelector('.js-lpb-component'));
+
+    $element[0].querySelectorAll('.lpb-up, .lpb-down').forEach((el) => {
+      // Set the tabindex of the up and down arrows to 0.
       el.setAttribute('tabindex', '0');
     });
-    lpbBuilderComponent.forEach(function (el) {
-      var _components$0$querySe, _components$querySele;
-      var components = Array.from(el.children).filter(function (n) {
-        return n.classList.contains('js-lpb-component');
-      });
-      (_components$0$querySe = components[0].querySelector('.lpb-up')) === null || _components$0$querySe === void 0 || _components$0$querySe.setAttribute('tabindex', '-1');
-      (_components$querySele = components[components.length - 1].querySelector('.lpb-down')) === null || _components$querySele === void 0 || _components$querySele.setAttribute('tabindex', '-1');
+
+    lpbBuilderComponent.forEach((el) => {
+      const components = Array.from(el.children).filter(n => n.classList.contains('js-lpb-component'));
+
+      // Set the tabindex of the first component's up arrow to -1.
+      components[0].querySelector('.lpb-up')?.setAttribute('tabindex', '-1');
+
+      // Set the tabindex of the last component's down arrow to -1.
+      components[components.length - 1].querySelector('.lpb-down')?.setAttribute('tabindex', '-1');
     });
   }
+
+  /**
+   * Hides the add content button in regions that contain components.
+   * @param {jQuery} $element The builder element.
+   */
   function hideEmptyRegionButtons($element) {
-    $element.find('.js-lpb-region').each(function (i, e) {
-      var $e = $(e);
+    $element.find('.js-lpb-region').each((i, e) => {
+      const $e = $(e);
       if ($e.find('.js-lpb-component').length === 0) {
         $e.find('.lpb-btn--add.center').css('display', 'block');
       } else {
@@ -98,136 +149,228 @@
       }
     });
   }
+
+  /**
+   * Updates the UI based on currently state.
+   * @param {jQuery} $element The builder element.
+   */
   function updateUi($element) {
     reorderComponents($element);
     updateMoveButtons($element);
     hideEmptyRegionButtons($element);
   }
+
+  /**
+   * Moves a component up or down within a simple list of components.
+   * @param {jQuery} $moveItem The item to move.
+   * @param {int} direction 1 (down) or -1 (up).
+   * @return {void}
+   */
   function move($moveItem, direction) {
-    var $sibling = direction === 1 ? $moveItem.nextAll('.js-lpb-component').first() : $moveItem.prevAll('.js-lpb-component').first();
-    var method = direction === 1 ? 'after' : 'before';
-    var _window = window,
-      scrollY = _window.scrollY;
-    var destScroll = scrollY + $sibling.outerHeight() * direction;
+    const $sibling =
+      direction === 1
+        ? $moveItem.nextAll('.js-lpb-component').first()
+        : $moveItem.prevAll('.js-lpb-component').first();
+
+    const method = direction === 1 ? 'after' : 'before';
+    const { scrollY } = window;
+    const destScroll = scrollY + $sibling.outerHeight() * direction;
+
     if ($sibling.length === 0) {
       return false;
     }
-    var animateProp = $sibling[0].getBoundingClientRect().top == $moveItem[0].getBoundingClientRect().top ? 'translateX' : 'translateY';
-    var dimmensionProp = animateProp === 'translateX' ? 'offsetWidth' : 'offsetHeight';
-    var siblingDest = $moveItem[0][dimmensionProp] * direction * -1;
-    var itemDest = $sibling[0][dimmensionProp] * direction;
-    var distance = Math.abs(Math.max(siblingDest, itemDest));
-    var duration = distance * .25;
-    var siblingKeyframes = [{
-      transform: "".concat(animateProp, "(0)")
-    }, {
-      transform: "".concat(animateProp, "(").concat(siblingDest, "px)")
-    }];
-    var itemKeyframes = [{
-      transform: "".concat(animateProp, "(0)")
-    }, {
-      transform: "".concat(animateProp, "(").concat(itemDest, "px)")
-    }];
-    var timing = {
-      duration: duration,
+
+    // Determine if the move should be animated horizontally or vertically.
+    const animateProp = $sibling[0].getBoundingClientRect().top == $moveItem[0].getBoundingClientRect().top
+      ? 'translateX'
+      : 'translateY';
+    // Determine the dimension property to use for the animation.
+    const dimmensionProp = animateProp === 'translateX' ? 'offsetWidth' : 'offsetHeight';
+    // Determine the distance to move the sibling and the item.
+    const siblingDest = $moveItem[0][dimmensionProp] * direction * -1;
+    const itemDest = $sibling[0][dimmensionProp] * direction;
+    const distance = Math.abs(Math.max(siblingDest, itemDest));
+    const duration  = distance * .25;
+    const siblingKeyframes = [
+      { transform: `${animateProp}(0)` },
+      { transform: `${animateProp}(${siblingDest}px)` },
+    ];
+    const itemKeyframes = [
+      { transform: `${animateProp}(0)` },
+      { transform: `${animateProp}(${itemDest}px)` },
+    ];
+    const timing = {
+      duration,
       iterations: 1
-    };
-    var anim1 = $moveItem[0].animate(itemKeyframes, timing);
-    anim1.onfinish = function () {
-      $moveItem.css({
-        transform: 'none'
-      });
-      $sibling.css({
-        transform: 'none'
-      });
+    }
+    const anim1 = $moveItem[0].animate(itemKeyframes, timing);
+    anim1.onfinish = () => {
+      $moveItem.css({ transform: 'none' });
+      $sibling.css({ transform: 'none' });
       $sibling[method]($moveItem);
-      $moveItem.closest("[".concat(idAttr, "]")).trigger('lpb-component:move', [$moveItem.attr('data-uuid')]);
+      $moveItem
+        .closest(`[${idAttr}]`)
+        .trigger('lpb-component:move', [$moveItem.attr('data-uuid')]);
     };
     $sibling[0].animate(siblingKeyframes, timing);
     if (animateProp === 'translateY') {
       window.scrollTo({
         top: destScroll,
-        behavior: 'smooth'
+        behavior: 'smooth',
       });
     }
   }
+
+  /**
+   * Moves the focused component up or down the DOM to the next valid position
+   * when an arrow key is pressed. Unlike move(), nav()can fully navigate
+   * components to any valid position in an entire layout.
+   * @param {jQuery} $item The jQuery item to move.
+   * @param {int} dir The direction to move (1 == down, -1 == up).
+   * @param {Object} settings The builder ui settings.
+   */
   function nav($item, dir, settings) {
-    var $element = $item.closest("[".concat(idAttr, "]"));
+    const $element = $item.closest(`[${idAttr}]`);
     $item.addClass('lpb-active-item');
+    // Add shims as target elements.
     if (dir === -1) {
-      $('.js-lpb-region .lpb-btn--add.center, .lpb-layout:not(.lpb-active-item)', $element).before('<div class="lpb-shim"></div>');
+      $(
+        '.js-lpb-region .lpb-btn--add.center, .lpb-layout:not(.lpb-active-item)',
+        $element,
+      ).before('<div class="lpb-shim"></div>');
     } else if (dir === 1) {
       $('.js-lpb-region', $element).prepend('<div class="lpb-shim"></div>');
-      $('.lpb-layout:not(.lpb-active-item)', $element).after('<div class="lpb-shim"></div>');
+      $('.lpb-layout:not(.lpb-active-item)', $element).after(
+        '<div class="lpb-shim"></div>',
+      );
     }
-    var targets = $('.js-lpb-component, .lpb-shim', $element).toArray().filter(function (i) {
-      return !$.contains($item[0], i);
-    }).filter(function (i) {
-      return i.className.indexOf('lpb-layout') === -1 || i === $item[0];
-    });
-    var currentElement = $item[0];
-    var pos = targets.indexOf(currentElement);
-    while (targets[pos + dir] !== undefined && moveErrors(settings, $item[0], targets[pos + dir].parentNode, null, $item.next().length ? $item.next()[0] : null).length > 0) {
+    // Build a list of possible targets, or move destinations.
+    const targets = $('.js-lpb-component, .lpb-shim', $element)
+      .toArray()
+      // Remove child components from possible targets.
+      .filter((i) => !$.contains($item[0], i))
+      // Remove layout elements that are not self from possible targets.
+      .filter(
+        (i) => i.className.indexOf('lpb-layout') === -1 || i === $item[0],
+      );
+    const currentElement = $item[0];
+    let pos = targets.indexOf(currentElement);
+    // Check to see if the next position is allowed by calling the 'accepts' callback.
+    while (
+      targets[pos + dir] !== undefined &&
+      moveErrors(
+        settings,
+        $item[0],
+        targets[pos + dir].parentNode,
+        null,
+        $item.next().length ? $item.next()[0] : null,
+      ).length > 0
+    ) {
       pos += dir;
     }
     if (targets[pos + dir] !== undefined) {
+      // Move after or before the target based on direction.
       $(targets[pos + dir])[dir === 1 ? 'after' : 'before']($item);
     }
+    // Remove the shims and save the order.
     $('.lpb-shim', $element).remove();
     $item.removeClass('lpb-active-item').focus();
-    $item.closest("[".concat(idAttr, "]")).trigger('lpb-component:move', [$item.attr('data-uuid')]);
+    $item
+      .closest(`[${idAttr}]`)
+      .trigger('lpb-component:move', [$item.attr('data-uuid')]);
   }
+
   function startNav($item) {
-    var $msg = $("<div id=\"lpb-navigating-msg\" class=\"lpb-tooltiptext lpb-tooltiptext--visible js-lpb-tooltiptext\">".concat(Drupal.t('Use arrow keys to move. Press Return or Tab when finished.'), "</div>"));
-    $item.closest('.lp-builder').addClass('is-navigating').find('.is-navigating').removeClass('is-navigating');
-    $item.attr('aria-describedby', 'lpb-navigating-msg').addClass('is-navigating').prepend($msg);
+    const $msg = $(
+      `<div id="lpb-navigating-msg" class="lpb-tooltiptext lpb-tooltiptext--visible js-lpb-tooltiptext">${Drupal.t(
+        'Use arrow keys to move. Press Return or Tab when finished.',
+      )}</div>`,
+    );
+    $item
+      .closest('.lp-builder')
+      .addClass('is-navigating')
+      .find('.is-navigating')
+      .removeClass('is-navigating');
+    $item
+      .attr('aria-describedby', 'lpb-navigating-msg')
+      .addClass('is-navigating')
+      .prepend($msg);
     $item.before('<div class="lpb-navigating-placeholder"></div>');
   }
+
   function stopNav($item) {
-    $item.removeClass('is-navigating').attr('aria-describedby', '').find('.js-lpb-tooltiptext').remove();
-    $item.closest("[".concat(idAttr, "]")).removeClass('is-navigating').find('.lpb-navigating-placeholder').remove();
+    $item
+      .removeClass('is-navigating')
+      .attr('aria-describedby', '')
+      .find('.js-lpb-tooltiptext')
+      .remove();
+    $item
+      .closest(`[${idAttr}]`)
+      .removeClass('is-navigating')
+      .find('.lpb-navigating-placeholder')
+      .remove();
   }
+
   function cancelNav($item) {
-    var $builder = $item.closest("[".concat(idAttr, "]"));
+    const $builder = $item.closest(`[${idAttr}]`);
     $builder.find('.lpb-navigating-placeholder').replaceWith($item);
     updateUi($builder);
     stopNav($item);
   }
+
+  /**
+   * Prevents user from navigating away and accidentally loosing changes.
+   * @param {jQuery} $element The jQuery layout paragraphs builder object.
+   */
   function preventLostChanges($element) {
-    var events = ['lpb-component:insert.lpb', 'lpb-component:update.lpb', 'lpb-component:move.lpb', 'lpb-component:drop.lpb'].join(' ');
-    $element.on(events, function (e) {
+    // Add class "is_changed" when the builder is edited.
+    const events = [
+      'lpb-component:insert.lpb',
+      'lpb-component:update.lpb',
+      'lpb-component:move.lpb',
+      'lpb-component:drop.lpb',
+    ].join(' ');
+    $element.on(events, (e) => {
       $(e.currentTarget).addClass('is_changed');
     });
-    window.addEventListener('beforeunload', function (e) {
-      if ($(".is_changed[".concat(idAttr, "]")).length) {
+    window.addEventListener('beforeunload', (e) => {
+      if ($(`.is_changed[${idAttr}]`).length) {
         e.preventDefault();
         e.returnValue = '';
       }
     });
-    $('.form-actions').find('input[type="submit"], a').click(function () {
-      $element.removeClass('is_changed');
-    });
+    $('.form-actions')
+      .find('input[type="submit"], a')
+      .click(() => {
+        $element.removeClass('is_changed');
+      });
   }
+
+  /**
+   * Attaches event listeners/handlers for builder ui.
+   * @param {jQuery} $element The layout paragraphs builder object.
+   * @param {Object} settings The builder settings.
+   */
   function attachEventListeners($element, settings) {
     preventLostChanges($element);
-    $element.on('click.lp-builder', '.lpb-up', function (e) {
+    $element.on('click.lp-builder', '.lpb-up', (e) => {
       move($(e.target).closest('.js-lpb-component'), -1);
       return false;
     });
-    $element.on('click.lp-builder', '.lpb-down', function (e) {
+    $element.on('click.lp-builder', '.lpb-down', (e) => {
       move($(e.target).closest('.js-lpb-component'), 1);
       return false;
     });
-    $element.on('click.lp-builder', '.js-lpb-component', function (e) {
+    $element.on('click.lp-builder', '.js-lpb-component', (e) => {
       $(e.currentTarget).focus();
     });
-    $element.on('click.lp-builder', '.lpb-drag', function (e) {
-      var $btn = $(e.currentTarget);
+    $element.on('click.lp-builder', '.lpb-drag', (e) => {
+      const $btn = $(e.currentTarget);
       startNav($btn.closest('.js-lpb-component'));
     });
     $(document).off('keydown');
-    $(document).on('keydown', function (e) {
-      var $item = $('.js-lpb-component.is-navigating');
+    $(document).on('keydown', (e) => {
+      const $item = $('.js-lpb-component.is-navigating');
       if ($item.length) {
         switch (e.code) {
           case 'ArrowUp':
@@ -251,31 +394,34 @@
       }
     });
   }
+
   function initDragAndDrop($element, settings) {
-    var containers = once('is-dragula-enabled', '.js-lpb-component-list, .js-lpb-region', $element[0]);
-    var drake = dragula(containers, {
-      accepts: function accepts(el, target, source, sibling) {
-        return moveErrors(settings, el, target, source, sibling).length === 0;
-      },
-      moves: function moves(el, source, handle) {
-        var $handle = $(handle);
-        if ($handle.closest('.lpb-drag').length) {
+    const containers = once('is-dragula-enabled', '.js-lpb-component-list, .js-lpb-region', $element[0]);
+    const drake = dragula(
+      containers,
+      {
+        accepts: (el, target, source, sibling) =>
+          moveErrors(settings, el, target, source, sibling).length === 0,
+        moves(el, source, handle) {
+          const $handle = $(handle);
+          if ($handle.closest('.lpb-drag').length) {
+            return true;
+          }
+          if ($handle.closest('.lpb-controls').length) {
+            return false;
+          }
           return true;
-        }
-        if ($handle.closest('.lpb-controls').length) {
-          return false;
-        }
-        return true;
-      }
-    });
-    drake.on('drop', function (el) {
-      var $el = $(el);
+        },
+      },
+    );
+    drake.on('drop', (el) => {
+      const $el = $(el);
       if ($el.prev().is('a')) {
         $el.insertBefore($el.prev());
       }
       $element.trigger('lpb-component:drop', [$el.attr('data-uuid')]);
     });
-    drake.on('drag', function (el) {
+    drake.on('drag', (el) => {
       $element.addClass('is-dragging');
       if (el.className.indexOf('lpb-layout') > -1) {
         $element.addClass('is-dragging-layout');
@@ -284,109 +430,174 @@
       }
       $element.trigger('lpb-component:drag', [$(el).attr('data-uuid')]);
     });
-    drake.on('dragend', function () {
-      $element.removeClass('is-dragging').removeClass('is-dragging-layout').removeClass('is-dragging-item');
+    drake.on('dragend', () => {
+      $element
+        .removeClass('is-dragging')
+        .removeClass('is-dragging-layout')
+        .removeClass('is-dragging-item');
     });
-    drake.on('over', function (el, container) {
+    drake.on('over', (el, container) => {
       $(container).addClass('drag-target');
     });
-    drake.on('out', function (el, container) {
+    drake.on('out', (el, container) => {
       $(container).removeClass('drag-target');
     });
     return drake;
   }
+
+  // An array of move error callback functions.
   Drupal._lpbMoveErrors = [];
-  Drupal.registerLpbMoveError = function (f) {
+  /**
+   * Registers a move validation function.
+   * @param {Function} f The validator function.
+   */
+  Drupal.registerLpbMoveError = (f) => {
     Drupal._lpbMoveErrors.push(f);
   };
-  Drupal.registerLpbMoveError(function (settings, el, target) {
-    if (el.classList.contains('lpb-layout') && $(target).parents('.lpb-layout').length > settings.nesting_depth) {
+  // Checks nesting depth.
+  Drupal.registerLpbMoveError((settings, el, target) => {
+    if (
+      el.classList.contains('lpb-layout') &&
+      $(target).parents('.lpb-layout').length > settings.nesting_depth
+    ) {
       return Drupal.t('Exceeds nesting depth of @depth.', {
-        '@depth': settings.nesting_depth
+        '@depth': settings.nesting_depth,
       });
     }
   });
-  Drupal.registerLpbMoveError(function (settings, el, target) {
+  // If layout is required, prevents component from being placed outside a layout.
+  Drupal.registerLpbMoveError((settings, el, target) => {
     if (settings.require_layouts) {
-      if (el.classList.contains('js-lpb-component') && !el.classList.contains('lpb-layout') && !target.classList.contains('js-lpb-region')) {
+      if (
+        el.classList.contains('js-lpb-component') &&
+        !el.classList.contains('lpb-layout') &&
+        !target.classList.contains('js-lpb-region')
+      ) {
         return Drupal.t('Components must be added inside sections.');
       }
     }
   });
-  Drupal.AjaxCommands.prototype.LayoutParagraphsEventCommand = function (ajax, response) {
-    var layoutId = response.layoutId,
-      componentUuid = response.componentUuid,
-      eventName = response.eventName;
-    var $element = $("[data-lpb-id=\"".concat(layoutId, "\"]"));
-    $element.trigger("lpb-".concat(eventName), [componentUuid]);
+  Drupal.AjaxCommands.prototype.LayoutParagraphsEventCommand = (
+    ajax,
+    response,
+  ) => {
+    const { layoutId, componentUuid, eventName } = response;
+    const $element = $(`[data-lpb-id="${layoutId}"]`);
+    $element.trigger(`lpb-${eventName}`, [componentUuid]);
   };
+
+  /*
+   * Moves the main form action buttons into the jQuery modal button pane.
+   * @param {jQuery} context
+   *  The context to search for dialog buttons.
+   * @return {void}
+   */
   function updateDialogButtons(context) {
-    var $lpDialog = $(context).closest('.ui-dialog-content');
+    // Determine if this context is from within dialog content.
+    const $lpDialog = $(context).closest('.ui-dialog-content');
+
     if (!$lpDialog) {
       return;
     }
-    var buttons = [];
-    var $buttons = $lpDialog.find('.layout-paragraphs-component-form > .form-actions input[type=submit], .layout-paragraphs-component-form > .form-actions a.button');
+
+    const buttons = [];
+    const $buttons = $lpDialog.find('.layout-paragraphs-component-form > .form-actions input[type=submit], .layout-paragraphs-component-form > .form-actions a.button');
+
     if ($buttons.length === 0) {
       return;
     }
-    $buttons.each(function (_i, el) {
-      var $originalButton = $(el).css({
-        display: 'none'
-      });
+
+    $buttons.each((_i, el) => {
+      const $originalButton = $(el).css({ display: 'none' });
       buttons.push({
         text: $originalButton.html() || $originalButton.attr('value'),
         class: $originalButton.attr('class'),
-        click: function click(e) {
+        click(e) {
+          // If the original button is an anchor tag, triggering the "click"
+          // event will not simulate a click. Use the click method instead.
           if ($originalButton.is('a')) {
             $originalButton[0].click();
           } else {
-            $originalButton.trigger('mousedown').trigger('mouseup').trigger('click');
+            $originalButton
+              .trigger('mousedown')
+              .trigger('mouseup')
+              .trigger('click');
             e.preventDefault();
           }
-        }
+        },
       });
     });
+
     $lpDialog.dialog('option', 'buttons', buttons);
   }
+
   Drupal.behaviors.layoutParagraphsBuilder = {
     attach: function attach(context, settings) {
-      var jsUiElements = once('lpb-ui-elements', '[data-has-js-ui-element]');
-      jsUiElements.forEach(function (el) {
+      // Add UI elements to the builder, each component, and each region.
+      const jsUiElements = once('lpb-ui-elements', '[data-has-js-ui-element]');
+      jsUiElements.forEach((el) => {
         attachUiElements($(el), settings);
       });
-      once('lpb-events', '[data-lpb-id]').forEach(function (el) {
-        $(el).on('lpb-builder:init.lpb lpb-component:insert.lpb lpb-component:update.lpb lpb-component:move.lpb lpb-component:drop.lpb lpb-component:delete.lpb', function (e) {
-          var $element = $(e.currentTarget);
+
+      // Listen to relevant events and update UI.
+      once('lpb-events', '[data-lpb-id]').forEach((el) => {
+        $(el).on('lpb-builder:init.lpb lpb-component:insert.lpb lpb-component:update.lpb lpb-component:move.lpb lpb-component:drop.lpb lpb-component:delete.lpb', (e) => {
+          const $element = $(e.currentTarget);
           updateUi($element);
         });
       });
-      once('lpb-enabled', '[data-lpb-id].has-components').forEach(function (el) {
-        var $element = $(el);
-        var id = $element.attr(idAttr);
-        var lpbSettings = settings.lpBuilder[id];
+
+      // Initialize the editor drag and drop ui.
+      once('lpb-enabled', '[data-lpb-id].has-components').forEach((el) => {
+        const $element = $(el);
+        const id = $element.attr(idAttr);
+        const lpbSettings = settings.lpBuilder[id];
+        // Attach event listeners and init dragula just once.
         $element.data('drake', initDragAndDrop($element, lpbSettings));
         attachEventListeners($element, lpbSettings);
         $element.trigger('lpb-builder:init');
       });
-      once('is-dragula-enabled', '.js-lpb-region').forEach(function (c) {
-        var builderElement = c.closest('[data-lpb-id]');
-        var drake = $(builderElement).data('drake');
+
+      // Add new containers to the dragula instance.
+      once('is-dragula-enabled', '.js-lpb-region').forEach((c) => {
+        const builderElement = c.closest('[data-lpb-id]');
+        const drake = $(builderElement).data('drake');
         drake.containers.push(c);
       });
+
+      // If UI elements have been attached to the DOM, we need to attach behaviors.
       if (jsUiElements.length) {
         Drupal.attachBehaviors(context, settings);
       }
+
+      // Moves dialog buttons into the jQuery modal button pane.
       updateDialogButtons(context);
-    }
+    },
   };
-  var lpDialogInterval;
-  var handleAfterDialogCreate = function handleAfterDialogCreate(event, dialog, $dialog) {
-    var $element = $dialog || jQuery(event.target);
+
+  // Move the main form action buttons into the jQuery modal button pane.
+  // By default, dialog.ajax.js moves all form action buttons into the button
+  // pane -- which can have unintended consequences. We suppress that option
+  // by setting drupalAutoButtons to false, but then manually move _only_ the
+  // main form action buttons into the jQuery button pane.
+  // @see https://www.drupal.org/project/layout_paragraphs/issues/3191418
+  // @see https://www.drupal.org/project/layout_paragraphs/issues/3216981
+
+  // Repositions open dialogs.
+  // @see https://www.drupal.org/project/layout_paragraphs/issues/3252978
+  // @see https://stackoverflow.com/questions/5456298/refresh-jquery-ui-dialog-position
+
+  let lpDialogInterval;
+
+  const handleAfterDialogCreate = (event, dialog, $dialog) => {
+    const $element = $dialog || jQuery(event.target);
     if ($element.attr('id').startsWith('lpb-dialog-')) {
       updateDialogButtons($element);
       clearInterval(lpDialogInterval);
-      lpDialogInterval = setInterval(repositionDialog.bind(null, lpDialogInterval), 500);
+      lpDialogInterval = setInterval(
+        repositionDialog.bind(null, lpDialogInterval),
+        500
+      );
     }
   };
   if (typeof DrupalDialogEvent === 'undefined') {
@@ -394,4 +605,5 @@
   } else {
     window.addEventListener('dialog:aftercreate', handleAfterDialogCreate);
   }
-})(jQuery, Drupal, Drupal.debounce, dragula, once);
\ No newline at end of file
+
+})(jQuery, Drupal, Drupal.debounce, dragula, once);
diff --git a/js/component-form.es6.js b/js/component-form.es6.js
deleted file mode 100644
index a1a2dac..0000000
--- a/js/component-form.es6.js
+++ /dev/null
@@ -1,16 +0,0 @@
-(function ($, Drupal) {
-  Drupal.behaviors.layoutParagraphsComponentForm = {
-    attach: function attach(context) {
-      // The layout selection element uses AJAX to load the layout config form.
-      // We need to disable the save button while waiting for the AJAX request,
-      // to prevent race UI condition.
-      // @see https://www.drupal.org/project/layout_paragraphs/issues/3265669
-      $('[name="layout_paragraphs[layout]"]').on('change', (e) => {
-        $('.lpb-btn--save').prop('disabled', e.currentTarget.disabled);
-      });
-      // Re-enable the component form save button when the behavior reattaches,
-      // which will happen once the AJAX request completes.
-      $('.lpb-btn--save').prop('disabled', false);
-    }
-  }
-})(jQuery, Drupal);
diff --git a/js/component-form.js b/js/component-form.js
index 8dc94e8..a1a2dac 100644
--- a/js/component-form.js
+++ b/js/component-form.js
@@ -1,18 +1,16 @@
-/**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-"use strict";
-
 (function ($, Drupal) {
   Drupal.behaviors.layoutParagraphsComponentForm = {
     attach: function attach(context) {
-      $('[name="layout_paragraphs[layout]"]').on('change', function (e) {
+      // The layout selection element uses AJAX to load the layout config form.
+      // We need to disable the save button while waiting for the AJAX request,
+      // to prevent race UI condition.
+      // @see https://www.drupal.org/project/layout_paragraphs/issues/3265669
+      $('[name="layout_paragraphs[layout]"]').on('change', (e) => {
         $('.lpb-btn--save').prop('disabled', e.currentTarget.disabled);
       });
+      // Re-enable the component form save button when the behavior reattaches,
+      // which will happen once the AJAX request completes.
       $('.lpb-btn--save').prop('disabled', false);
     }
-  };
-})(jQuery, Drupal);
\ No newline at end of file
+  }
+})(jQuery, Drupal);
diff --git a/js/component-list.es6.js b/js/component-list.es6.js
deleted file mode 100644
index c0e2d6f..0000000
--- a/js/component-list.es6.js
+++ /dev/null
@@ -1,20 +0,0 @@
-(($, Drupal) => {
-  Drupal.behaviors.layoutParagraphsComponentList = {
-    attach: function attach(context) {
-      $('.lpb-component-list-search-input', context).keyup((e) => {
-        const v = e.currentTarget.value;
-        const pattern = new RegExp(v, 'i');
-        const $list = $(e.currentTarget)
-          .closest('.lpb-component-list')
-          .find('.lpb-component-list__item');
-        $list.each((i, item) => {
-          if (pattern.test(item.innerText)) {
-            item.removeAttribute('style');
-          } else {
-            item.style.display = 'none';
-          }
-        });
-      });
-    },
-  };
-})(jQuery, Drupal);
diff --git a/js/component-list.js b/js/component-list.js
index f46a48f..c0e2d6f 100644
--- a/js/component-list.js
+++ b/js/component-list.js
@@ -1,19 +1,13 @@
-/**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
-"use strict";
-
-(function ($, Drupal) {
+(($, Drupal) => {
   Drupal.behaviors.layoutParagraphsComponentList = {
     attach: function attach(context) {
-      $('.lpb-component-list-search-input', context).keyup(function (e) {
-        var v = e.currentTarget.value;
-        var pattern = new RegExp(v, 'i');
-        var $list = $(e.currentTarget).closest('.lpb-component-list').find('.lpb-component-list__item');
-        $list.each(function (i, item) {
+      $('.lpb-component-list-search-input', context).keyup((e) => {
+        const v = e.currentTarget.value;
+        const pattern = new RegExp(v, 'i');
+        const $list = $(e.currentTarget)
+          .closest('.lpb-component-list')
+          .find('.lpb-component-list__item');
+        $list.each((i, item) => {
           if (pattern.test(item.innerText)) {
             item.removeAttribute('style');
           } else {
@@ -21,6 +15,6 @@
           }
         });
       });
-    }
+    },
   };
-})(jQuery, Drupal);
\ No newline at end of file
+})(jQuery, Drupal);
diff --git a/layout_paragraphs.info.yml b/layout_paragraphs.info.yml
index 56142e3..9e8754b 100644
--- a/layout_paragraphs.info.yml
+++ b/layout_paragraphs.info.yml
@@ -1,7 +1,7 @@
 name: 'Layout Paragraphs'
 type: module
 description: 'Field widget and formatter for using layouts with paragraph fields.'
-core_version_requirement: ^9.2 || ^10 || ^11
+core_version_requirement: ^10 || ^11
 package: 'Paragraphs'
 configure: layout_paragraphs.label_settings
 dependencies:
-- 
GitLab