diff --git a/assets/css/instant-results.css b/assets/css/instant-results.css
new file mode 100644
index 0000000000..497fb56ec1
--- /dev/null
+++ b/assets/css/instant-results.css
@@ -0,0 +1,27 @@
+@import "instant-results/utilities.css";
+@import "instant-results/input.css";
+@import "instant-results/modal.css";
+@import "instant-results/options-list.css";
+@import "instant-results/page.css";
+@import "instant-results/panel.css";
+@import "instant-results/pagination.css";
+@import "instant-results/range-slider.css";
+@import "instant-results/result.css";
+@import "instant-results/results.css";
+@import "instant-results/sidebar.css";
+@import "instant-results/sidebar-toggle.css";
+@import "instant-results/sort.css";
+@import "instant-results/toolbar.css";
+
+:root {
+ --ep-search-background-color: #fff;
+ --ep-search-alternate-background-color: #efefef;
+ --ep-search-border-color: #dfdfdf;
+ --ep-search-range-thumb-size: 1.625em;
+ --ep-search-range-track-size: 0.75em;
+
+ @media ( min-width: 768px ) {
+ --ep-search-range-thumb-size: 1.25em;
+ --ep-search-range-track-size: 0.5em;
+ }
+}
diff --git a/assets/css/instant-results/input.css b/assets/css/instant-results/input.css
new file mode 100644
index 0000000000..1b527edd71
--- /dev/null
+++ b/assets/css/instant-results/input.css
@@ -0,0 +1,5 @@
+.ep-search-input {
+ font-size: 1.25em;
+ margin: 0 !important;
+ width: 100%;
+}
diff --git a/assets/css/instant-results/modal.css b/assets/css/instant-results/modal.css
new file mode 100644
index 0000000000..081dfffc0a
--- /dev/null
+++ b/assets/css/instant-results/modal.css
@@ -0,0 +1,60 @@
+.has-ep-search-modal {
+ overflow: hidden;
+}
+
+.ep-search-modal {
+ --ep-search-modal-focus-within: 0;
+ background-color: rgba(43, 46, 56, 0.9);
+ bottom: 0;
+ display: flex;
+ left: 0;
+ position: fixed;
+ right: 0;
+ top: 0;
+ z-index: 9999;
+
+ @nest .rtl & {
+ direction: rtl;
+ text-align: right;
+ }
+
+ @nest .admin-bar & {
+ top: 32px;
+
+ @media ( max-width: 782px ) {
+ top: 46px;
+ }
+ }
+
+ &[aria-hidden="true"] {
+ display: none;
+ }
+
+ &:focus-within {
+ --ep-search-modal-focus-within: 1;
+ }
+}
+
+.ep-search-modal__content {
+ background-color: var(--ep-search-background-color);
+ bottom: 0;
+ display: flex;
+ flex-direction: column;
+ left: 0;
+ position: absolute;
+ right: 0;
+ top: 0;
+
+ @media ( min-width: 768px ) {
+ bottom: 1em;
+ margin: 0 auto;
+ max-width: calc(100% - 2em);
+ top: 1em;
+ width: 80em;
+ }
+}
+
+.ep-search-modal__close {
+ align-self: flex-end;
+ padding: 1em !important;
+}
diff --git a/assets/css/instant-results/options-list.css b/assets/css/instant-results/options-list.css
new file mode 100644
index 0000000000..0624818948
--- /dev/null
+++ b/assets/css/instant-results/options-list.css
@@ -0,0 +1,17 @@
+.ep-search-options-list {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+
+.ep-search-options-list__item {
+ margin: 0.5em 0;
+
+ &::before {
+ content: none;
+ }
+}
+
+.ep-search-options-list__sub-menu {
+ padding-left: 1em;
+}
diff --git a/assets/css/instant-results/page.css b/assets/css/instant-results/page.css
new file mode 100644
index 0000000000..5fba4e1877
--- /dev/null
+++ b/assets/css/instant-results/page.css
@@ -0,0 +1,39 @@
+.ep-search-page {
+ display: flex;
+ flex-direction: column;
+ flex-grow: 2;
+ margin: 0;
+ overflow-y: auto;
+ transition: opacity 300ms ease-out;
+ width: 100%;
+
+ @media ( min-width: 768px ) {
+ overflow: hidden;
+ }
+
+ & *,
+ & *::before,
+ & *::after {
+ box-sizing: border-box;
+ }
+
+ &.is-loading {
+ opacity: 0.5;
+ }
+}
+
+.ep-search-page__header,
+.ep-search-page__tools,
+.ep-search-page__body {
+ padding: 0 1em;
+}
+
+.ep-search-page__body {
+
+ @media ( min-width: 768px ) {
+ align-items: flex-start;
+ display: flex;
+ flex-grow: 2;
+ overflow: hidden;
+ }
+}
diff --git a/assets/css/instant-results/pagination.css b/assets/css/instant-results/pagination.css
new file mode 100644
index 0000000000..c0eb1b2bfa
--- /dev/null
+++ b/assets/css/instant-results/pagination.css
@@ -0,0 +1,19 @@
+.ep-search-pagination {
+ align-items: center;
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr;
+ margin-top: auto;
+ text-align: center;
+
+ @nest .rtl & {
+ direction: rtl;
+ }
+}
+
+.ep-search-pagination__next {
+ justify-self: end;
+}
+
+.ep-search-pagination__previous {
+ justify-self: start;
+}
diff --git a/assets/css/instant-results/panel.css b/assets/css/instant-results/panel.css
new file mode 100644
index 0000000000..cfa0620f19
--- /dev/null
+++ b/assets/css/instant-results/panel.css
@@ -0,0 +1,27 @@
+.ep-search-panel {
+ border: 1px solid var(--ep-search-border-color);
+ margin: 0;
+ padding: 0;
+
+ @nest .ep-search-panel + & {
+ border-top-width: 0;
+ }
+}
+
+.ep-search-panel__heading {
+ font-size: inherit;
+ margin: 0;
+}
+
+.ep-search-panel__button {
+ padding: 1em !important;
+ width: 100% !important;
+}
+
+.ep-search-panel__content {
+ padding: 0 1em 1em 1em;
+
+ &[aria-hidden="true"] {
+ display: none;
+ }
+}
diff --git a/assets/css/instant-results/range-slider.css b/assets/css/instant-results/range-slider.css
new file mode 100644
index 0000000000..c224807d2b
--- /dev/null
+++ b/assets/css/instant-results/range-slider.css
@@ -0,0 +1,26 @@
+.ep-search-range-slider {
+ align-items: center;
+ display: flex;
+ margin: 0.5em 0;
+ min-height: var(--ep-search-range-thumb-size);
+}
+
+.ep-search-range-slider__track {
+ background: var(--ep-search-alternate-background-color);
+ border-radius: calc(var(--ep-search-range-track-size) / 2);
+ height: var(--ep-search-range-track-size);
+}
+
+.ep-search-range-slider__track-1 {
+ background-color: currentColor;
+}
+
+.ep-search-range-slider__thumb {
+ background-color: currentColor;
+ border-radius: calc(var(--ep-search-range-thumb-size) / 2);
+ box-shadow:
+ inset 0 0 0 calc(var(--ep-search-range-thumb-size) / 10) currentColor,
+ inset 0 0 0 calc((var(--ep-search-range-thumb-size) - var(--ep-search-range-track-size)) / 2) var(--ep-search-background-color);
+ height: var(--ep-search-range-thumb-size);
+ width: var(--ep-search-range-thumb-size);
+}
diff --git a/assets/css/instant-results/result.css b/assets/css/instant-results/result.css
new file mode 100644
index 0000000000..cce353b0e1
--- /dev/null
+++ b/assets/css/instant-results/result.css
@@ -0,0 +1,89 @@
+.ep-search-result {
+ align-items: flex-start;
+ display: grid;
+ grid-gap: 0.5em;
+ grid-template-areas:
+ "header"
+ "footer";
+ grid-template-rows: auto 1fr;
+
+ @media ( min-width: 768px ) {
+ grid-gap: 1em;
+ grid-template-areas:
+ "header"
+ "description"
+ "footer";
+ grid-template-rows: auto auto 1fr;
+ }
+}
+
+.ep-search-result--has-thumbnail {
+ grid-template-areas:
+ "thumbnail header"
+ "thumbnail footer";
+ grid-template-columns: min(300px, 34%) auto;
+
+ @media ( min-width: 768px ) {
+ grid-template-areas:
+ "thumbnail header"
+ "thumbnail description"
+ "thumbnail footer";
+ }
+}
+
+.ep-search-result__thumbnail {
+ display: block;
+ grid-area: thumbnail;
+
+ & img {
+ display: block;
+ margin: 0;
+ width: 100%;
+ }
+}
+
+.ep-search-result__header {
+ display: grid;
+ grid-area: header;
+ grid-gap: 0.5em;
+ grid-template-columns: auto;
+ justify-items: start;
+}
+
+.ep-search-result__title {
+ font-size: 1em;
+ margin: 0;
+
+ @media ( min-width: 768px ) {
+ font-size: 1.25em;
+ }
+}
+
+.ep-search-result__type {
+ background-color: var(--ep-search-alternate-background-color);
+ border-radius: 0.25em;
+ display: inline-block;
+ font-size: 0.875em;
+ line-height: 1.5;
+ padding: 0 0.25em;
+ vertical-align: text-bottom;
+}
+
+.ep-search-result__description {
+ display: none;
+ font-size: 0.875em;
+ grid-area: description;
+ margin: 0;
+
+ @media ( min-width: 768px ) {
+ display: block;
+ font-size: 1em;
+ }
+}
+
+.ep-search-result__footer {
+ display: grid;
+ grid-area: footer;
+ grid-gap: 0.5em;
+ justify-items: start;
+}
diff --git a/assets/css/instant-results/results.css b/assets/css/instant-results/results.css
new file mode 100644
index 0000000000..eb3dc3c7a5
--- /dev/null
+++ b/assets/css/instant-results/results.css
@@ -0,0 +1,30 @@
+.ep-search-results {
+ display: grid;
+ grid-gap: 2em;
+ grid-template-columns: 100%;
+ grid-template-rows: max-content;
+ padding: 0 0 1em 0;
+ width: 100%;
+
+ @media ( min-width: 768px ) {
+ height: 100%;
+ overflow-y: auto;
+ padding: 0 1em 1em 1em;
+ }
+}
+
+.ep-search-results__header {
+ align-items: center;
+ display: flex;
+ gap: 1em;
+ justify-content: space-between;
+}
+
+.ep-search-results__title {
+ font-size: 1.25em;
+ margin: 0 !important;
+
+ @media ( min-width: 768px ) {
+ font-size: 1.5em;
+ }
+}
diff --git a/assets/css/instant-results/sidebar-toggle.css b/assets/css/instant-results/sidebar-toggle.css
new file mode 100644
index 0000000000..10c32003c7
--- /dev/null
+++ b/assets/css/instant-results/sidebar-toggle.css
@@ -0,0 +1,7 @@
+.ep-search-sidebar-toggle {
+ width: 100%;
+
+ @media ( min-width: 768px ) {
+ display: none;
+ }
+}
diff --git a/assets/css/instant-results/sidebar.css b/assets/css/instant-results/sidebar.css
new file mode 100644
index 0000000000..c3d225375f
--- /dev/null
+++ b/assets/css/instant-results/sidebar.css
@@ -0,0 +1,15 @@
+.ep-search-sidebar {
+ display: none;
+ margin-bottom: 2em;
+
+ &.is-open {
+ display: block;
+ }
+
+ @media ( min-width: 768px ) {
+ display: block;
+ max-height: calc(100% - 1em);
+ min-width: 25%;
+ overflow-y: auto;
+ }
+}
diff --git a/assets/css/instant-results/sort.css b/assets/css/instant-results/sort.css
new file mode 100644
index 0000000000..be9e085b4c
--- /dev/null
+++ b/assets/css/instant-results/sort.css
@@ -0,0 +1,24 @@
+.ep-search-sort {
+ flex-shrink: 0;
+ gap: 0.5em;
+ margin: 0;
+
+ @nest .ep-search-results & {
+ display: none;
+
+ @media ( min-width: 768px ) {
+ align-items: center;
+ display: flex;
+ }
+ }
+
+ @nest .ep-search-sidebar & {
+ display: flex;
+ flex-direction: column;
+ margin-bottom: 1em;
+
+ @media ( min-width: 768px ) {
+ display: none;
+ }
+ }
+}
diff --git a/assets/css/instant-results/toolbar.css b/assets/css/instant-results/toolbar.css
new file mode 100644
index 0000000000..ced39b1d6f
--- /dev/null
+++ b/assets/css/instant-results/toolbar.css
@@ -0,0 +1,11 @@
+.ep-search-toolbar {
+ align-items: start;
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.25em;
+ margin: 1em 0;
+
+ @media ( min-width: 768px ) {
+ align-items: center;
+ }
+}
diff --git a/assets/css/instant-results/utilities.css b/assets/css/instant-results/utilities.css
new file mode 100644
index 0000000000..38d36749a9
--- /dev/null
+++ b/assets/css/instant-results/utilities.css
@@ -0,0 +1,47 @@
+.ep-search-reset-button {
+ font: inherit !important;
+ height: auto !important;
+ letter-spacing: inherit !important;
+ line-height: 1 !important;
+ margin: 0 !important;
+ padding: 0 !important;
+ text-align: inherit !important;
+ text-transform: inherit !important;
+ width: auto !important;
+
+ &,
+ &:focus,
+ &:hover {
+ background: transparent !important;
+ border: none !important;
+ box-shadow: none !important;
+ color: inherit !important;
+ cursor: default !important;
+ }
+
+ &:focus {
+ outline: medium auto Highlight !important;
+ outline: medium auto -webkit-focus-ring-color !important;
+ outline-offset: 0 !important;
+ }
+}
+
+.ep-search-small-button {
+ font-size: 0.875em !important;
+ height: auto !important;
+ line-height: 1 !important;
+ padding: 0.5em !important;
+}
+
+.ep-search-icon-button {
+ align-items: center;
+ display: flex;
+ justify-content: space-between;
+
+ & svg {
+ fill: currentColor;
+ flex-shrink: 0;
+ height: 1em;
+ width: 1em;
+ }
+}
diff --git a/assets/js/dashboard.js b/assets/js/dashboard.js
index 5fb1f8257a..9cdea70adb 100644
--- a/assets/js/dashboard.js
+++ b/assets/js/dashboard.js
@@ -1,4 +1,6 @@
/* eslint-disable camelcase, no-use-before-define */
+import jQuery from 'jquery';
+
const { ajaxurl, epDash } = window;
const $features = jQuery(document.getElementsByClassName('ep-features'));
diff --git a/assets/js/instant-results/admin/components/facet-selector.js b/assets/js/instant-results/admin/components/facet-selector.js
new file mode 100644
index 0000000000..026d80eb11
--- /dev/null
+++ b/assets/js/instant-results/admin/components/facet-selector.js
@@ -0,0 +1,81 @@
+/**
+ * WordPress dependencies.
+ */
+import { FormTokenField } from '@wordpress/components';
+import { useMemo, useState, WPElement } from '@wordpress/element';
+import { __ } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies.
+ */
+import { facets } from '../config';
+
+/**
+ * Facet selector component.
+ *
+ * @param {Object} props Props.
+ * @param {string} props.defaultValue Default value.
+ * @return {WPElement} Element.
+ */
+export default ({ defaultValue, ...props }) => {
+ const defaultValues = defaultValue.split(',');
+ const [selectedFacets, setSelectedFacets] = useState(defaultValues);
+
+ /**
+ * Get the label for a facet from the facet key.
+ *
+ * @param {string} key Facet key.
+ * @return {string} Facet label.
+ */
+ const getLabelFromKey = (key) => {
+ return facets[key]?.label;
+ };
+
+ /**
+ * Get the key for a facet from the facet label.
+ *
+ * @param {string} label Facet label.
+ * @return {string} Facet key.
+ */
+ const getKeyFromLabel = (label) => {
+ return Object.keys(facets).find((key) => {
+ return label === facets[key].label;
+ });
+ };
+
+ /**
+ * Suggestions for the token field.
+ */
+ const suggestions = useMemo(() => Object.keys(facets).map(getLabelFromKey).filter(Boolean), []);
+
+ /**
+ * Values for the token field.
+ */
+ const value = useMemo(
+ () => selectedFacets.map(getLabelFromKey).filter(Boolean),
+ [selectedFacets],
+ );
+
+ /**
+ * Handle change to token field.
+ *
+ * @param {Array} tokens Selected tokens.
+ */
+ const onChange = (tokens) => {
+ setSelectedFacets(tokens.map(getKeyFromLabel).filter(Boolean));
+ };
+
+ return (
+ <>
+
+
+ >
+ );
+};
diff --git a/assets/js/instant-results/admin/config.js b/assets/js/instant-results/admin/config.js
new file mode 100644
index 0000000000..ba3d3fb311
--- /dev/null
+++ b/assets/js/instant-results/admin/config.js
@@ -0,0 +1,6 @@
+/**
+ * Window dependencies.
+ */
+const { facets } = window.epInstantResultsAdmin;
+
+export { facets };
diff --git a/assets/js/instant-results/admin/index.js b/assets/js/instant-results/admin/index.js
new file mode 100644
index 0000000000..f3c7c8e95e
--- /dev/null
+++ b/assets/js/instant-results/admin/index.js
@@ -0,0 +1,31 @@
+/**
+ * WordPress dependencies.
+ */
+import { render } from '@wordpress/element';
+
+/**
+ * Internal dependences.
+ */
+import FacetSelector from './components/facet-selector';
+
+// eslint-disable-next-line @wordpress/no-global-event-listener
+document.addEventListener('DOMContentLoaded', () => {
+ const input = document.getElementById('feature_instant_results_facets');
+
+ const {
+ className,
+ dataset: { fieldName },
+ id,
+ value,
+ } = input;
+
+ render(
+ ,
+ input.parentElement,
+ );
+});
diff --git a/assets/js/instant-results/components/common/checkbox-list.js b/assets/js/instant-results/components/common/checkbox-list.js
new file mode 100644
index 0000000000..6eecb38412
--- /dev/null
+++ b/assets/js/instant-results/components/common/checkbox-list.js
@@ -0,0 +1,246 @@
+/**
+ * WordPress dependencies.
+ */
+import { Fragment, useRef, useState, WPElement } from '@wordpress/element';
+import { __, _n, sprintf } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies.
+ */
+import Checkbox from './checkbox';
+import SmallButton from './small-button';
+
+/**
+ * Checkbox list component.
+ *
+ * @typedef {Object} Option
+ * @property {number} count Number associated with option.
+ * @property {string} id Option ID.
+ * @property {string} label Option label.
+ * @property {number} order Option order.
+ * @property {string} parent Parent option value.
+ * @property {any} value Option value.
+ *
+ * @param {Object} props Component props.
+ * @param {boolean} props.disabled Whether the checkboxes should be disabled.
+ * @param {boolean} props.label List label.
+ * @param {Function} props.onChange Checkbox change event callback function.
+ * @param {Option[]} props.options Checkbox options.
+ * @param {string} props.selected Selected values.
+ * @param {string} props.sortBy How to sort options.
+ * @return {WPElement} A React element.
+ */
+export default ({ disabled, label, options, onChange, selected, sortBy }) => {
+ /**
+ * Outermost list element.
+ */
+ const listEl = useRef(null);
+
+ /**
+ * Whether all items are displayed and a setter.
+ */
+ const [showAll, setShowAll] = useState(false);
+
+ /**
+ * Reducer to group options by parent.
+ *
+ * @param {Object} items Options grouped by parent.
+ * @param {Option} option Option details.
+ * @param {string} option.parent Option parent value.
+ * @return {Object} Options grouped by parent.
+ */
+ const reduceOptionsByParent = (items, { parent, ...option }) => {
+ // eslint-disable-next-line eqeqeq
+ if (parent != false) {
+ items[parent] = items[parent] || [];
+ items[parent].push(option);
+ }
+
+ return items;
+ };
+
+ /**
+ * Options grouped by parent value.
+ */
+ const childOptions = options.reduce(reduceOptionsByParent, {});
+
+ /**
+ * Reducer to group top level options. Top level options are options
+ * with a parent of '0' or without a parent.
+ *
+ * @param {Array} items Options without a parent.
+ * @param {Option} option Option details.
+ * @param {string} option.parent Option parent value.
+ * @return {Object} Options without a parent.
+ */
+ const reduceTopLevelOptions = (items, { parent, ...option }) => {
+ // eslint-disable-next-line eqeqeq
+ if (parent == false || parent === '0') {
+ items.push(option);
+ }
+
+ return items;
+ };
+
+ /**
+ * Top level options.
+ */
+ const topLevelOptions = options.reduce(reduceTopLevelOptions, []);
+
+ /**
+ * How many options should be displayed by default.
+ */
+ const optionsLimit = options.length > 8 ? 5 : 8;
+
+ /**
+ * How many options have been displayed.
+ *
+ * Incremented each time an item is displayed. Used to limit the number of
+ * items displayed by default until the show more button is pressed.
+ */
+ let optionsShown = 0;
+
+ /**
+ * Handle checkbox change event.
+ *
+ * @param {Event} event Change event.
+ */
+ const onCheck = (event) => {
+ const { checked, value } = event.target;
+
+ let values = checked ? [...selected, value] : selected.filter((v) => v !== value);
+
+ /* Only send selected values that are in the available options. */
+ values = values.filter((v) => options.some((o) => o.value === v));
+
+ onChange(values);
+ };
+
+ /**
+ * Render an option.
+ *
+ * @param {Option} option Option.
+ * @return {WPElement} Render function.
+ */
+ const displayOption = ({ id, label, value }) => {
+ const children = childOptions[value];
+
+ if (!showAll && optionsShown >= optionsLimit) {
+ return ;
+ }
+
+ const option = (
+
+
+
+ {children && (showAll || optionsShown < optionsLimit) && (
+
+ {
+ /* eslint-disable-next-line no-use-before-define */
+ displayOptions(children)
+ }
+
+ )}
+
+ );
+
+ optionsShown++;
+
+ return option;
+ };
+
+ /**
+ * Sort option callback.
+ *
+ * @param {Option} a First option to compare.
+ * @param {Option} b second option to compare.
+ * @return {number} Comparison number.
+ */
+ const sortOptions = (a, b) => {
+ let comparison = 0;
+
+ if (sortBy === 'count') {
+ comparison = b.count - a.count;
+ }
+
+ if (sortBy === 'name' || comparison === 0) {
+ comparison = a.label.localeCompare(b.label);
+ }
+
+ return comparison;
+ };
+
+ /**
+ * Render a list of options.
+ *
+ * @param {Option[]} options Options to display.
+ * @return {WPElement[]} Array of elements.
+ */
+ const displayOptions = (options) => {
+ return options.splice(0).sort(sortOptions).map(displayOption);
+ };
+
+ /**
+ * Handle clicking the show more/fewer button.
+ *
+ * @return {void}
+ */
+ const onToggleShowAll = () => {
+ setShowAll(!showAll);
+
+ listEl.current.focus();
+ };
+
+ /**
+ * Show all button component.
+ *
+ * @return {WPElement} Element.
+ */
+ const ShowAllButton = () =>
+ options.length > optionsLimit && (
+
+ {showAll
+ ? __('Show fewer options', 'elasticpress')
+ : sprintf(
+ /* translators: %d: Number of additional options available. */
+ _n(
+ 'Show %d more option',
+ 'Show %d more options',
+ options.length - optionsLimit,
+ 'elasticpress',
+ ),
+ options.length - optionsLimit,
+ )}
+
+ );
+
+ return (
+ <>
+ {options.length > 0 && (
+
+ {
+ /* Display top level options and their children. */
+ displayOptions(topLevelOptions)
+ }
+ {
+ /* Display remaining orphaned options. */
+ Object.values(childOptions).map(displayOptions)
+ }
+
+ )}
+
+ >
+ );
+};
diff --git a/assets/js/instant-results/components/common/checkbox.js b/assets/js/instant-results/components/common/checkbox.js
new file mode 100644
index 0000000000..c9f2da6598
--- /dev/null
+++ b/assets/js/instant-results/components/common/checkbox.js
@@ -0,0 +1,24 @@
+/**
+ * WordPress dependencies.
+ */
+import { WPElement } from '@wordpress/element';
+
+/**
+ * Checkbox component.
+ *
+ * @param {Option} props Component props.
+ * @param {string} props.id Checkbox ID.
+ * @param {string} props.label Checkbox label.
+ *
+ * @return {WPElement} Component element.
+ */
+export default ({ id, label, ...props }) => {
+ return (
+
+
+
+
+ );
+};
diff --git a/assets/js/instant-results/components/common/image.js b/assets/js/instant-results/components/common/image.js
new file mode 100644
index 0000000000..6e0765ac28
--- /dev/null
+++ b/assets/js/instant-results/components/common/image.js
@@ -0,0 +1,15 @@
+/**
+ * WordPress dependencies.
+ */
+import { WPElement } from '@wordpress/element';
+
+/**
+ * Image component.
+ *
+ * @param {Option} props Component props.
+ *
+ * @return {WPElement} Component element.
+ */
+export default ({ alt, height, ID, src, width, ...props }) => {
+ return
;
+};
diff --git a/assets/js/instant-results/components/common/modal.js b/assets/js/instant-results/components/common/modal.js
new file mode 100644
index 0000000000..179d579b57
--- /dev/null
+++ b/assets/js/instant-results/components/common/modal.js
@@ -0,0 +1,106 @@
+/**
+ * External dependencies.
+ */
+import FocusTrap from 'focus-trap-react';
+
+/**
+ * WordPress dependencies.
+ */
+import { forwardRef, useCallback, useEffect, useRef, WPElement } from '@wordpress/element';
+import { closeSmall, Icon } from '@wordpress/icons';
+import { __ } from '@wordpress/i18n';
+
+/**
+ * Modal components.
+ *
+ * @param {Object} props Component props.
+ * @param {WPElement} props.children Component children.
+ * @param {boolean} props.isOpen Whether the modal is open.
+ * @param {Function} props.onClose Callback to run when modal is closed.
+ * @param {Object} ref Ref.
+ * @return {WPElement} React element.
+ */
+const Modal = ({ children, isOpen, onClose, ...props }, ref) => {
+ /**
+ * Reference to close button element.
+ */
+ const closeRef = useRef(null);
+
+ /**
+ * Handle key down.
+ *
+ * @param {Event} event Keydown event.
+ */
+ const onKeyDown = useCallback(
+ (event) => {
+ if (event.key === 'Escape' || event.key === 'Esc') {
+ onClose();
+ }
+ },
+ [onClose],
+ );
+
+ /**
+ * Handle binding events to outside DOM elements.
+ *
+ * @return {Function} Clean up function that removes events.
+ */
+ const handleEvents = () => {
+ const { current: modalEl } = ref;
+
+ modalEl.ownerDocument.body.addEventListener('keydown', onKeyDown);
+
+ return () => {
+ modalEl.ownerDocument.body.removeEventListener('keydown', onKeyDown);
+ };
+ };
+
+ /**
+ * Handle the model being opened or closed.
+ *
+ * Adds a class to the body element to allow controlling scrolling.
+ */
+ const handleOpen = () => {
+ const { current: modalEl } = ref;
+
+ if (isOpen) {
+ modalEl.ownerDocument.body.classList.add('has-ep-search-modal');
+ closeRef.current.focus();
+ } else {
+ modalEl.ownerDocument.body.classList.remove('has-ep-search-modal');
+ }
+ };
+
+ useEffect(handleEvents, [onKeyDown, ref]);
+ useEffect(handleOpen, [isOpen, ref]);
+
+ return (
+
+ {isOpen && (
+
+
+
+ {children}
+
+
+ )}
+
+ );
+};
+
+export default forwardRef(Modal);
diff --git a/assets/js/instant-results/components/common/panel.js b/assets/js/instant-results/components/common/panel.js
new file mode 100644
index 0000000000..7d80f301f1
--- /dev/null
+++ b/assets/js/instant-results/components/common/panel.js
@@ -0,0 +1,44 @@
+/**
+ * WordPress dependencies.
+ */
+import { useState, WPElement } from '@wordpress/element';
+import { chevronDown, chevronUp, Icon } from '@wordpress/icons';
+
+/**
+ * Facet wrapper component.
+ *
+ * @param {Object} props Component props.
+ * @param {WPElement} props.children Component children.
+ * @param {boolean} props.defaultIsOpen Whether the panel is open by default.
+ * @param {string} props.label Facet label.
+ * @return {WPElement} Component element.
+ */
+export default ({ children, defaultIsOpen, label }) => {
+ const [isOpen, setIsOpen] = useState(defaultIsOpen);
+
+ /**
+ * Handle click event on the header.
+ */
+ const onClick = () => {
+ setIsOpen(!isOpen);
+ };
+
+ return (
+
+
+
+
+
+ {children(isOpen)}
+
+
+ );
+};
diff --git a/assets/js/instant-results/components/common/range-slider.js b/assets/js/instant-results/components/common/range-slider.js
new file mode 100644
index 0000000000..540332c01b
--- /dev/null
+++ b/assets/js/instant-results/components/common/range-slider.js
@@ -0,0 +1,28 @@
+/**
+ * External dependencies.
+ */
+import ReactSlider from 'react-slider';
+
+/**
+ * WordPress dependencies.
+ */
+import { WPElement } from '@wordpress/element';
+
+/**
+ * Range slider component.
+ *
+ * @param {Object} props Props.
+ * @return {WPElement} Element.
+ */
+export default ({ ...props }) => {
+ return (
+
+ );
+};
diff --git a/assets/js/instant-results/components/common/small-button.js b/assets/js/instant-results/components/common/small-button.js
new file mode 100644
index 0000000000..c870952dd5
--- /dev/null
+++ b/assets/js/instant-results/components/common/small-button.js
@@ -0,0 +1,15 @@
+/**
+ * Small button component.
+ *
+ * @param {Object} props Props.
+ * @param {WPElement} props.children Children.
+ * @param {string} props.className Class attribute.
+ * @return {WPElement} Element.
+ */
+export default ({ children, className, ...props }) => {
+ return (
+
+ );
+};
diff --git a/assets/js/instant-results/components/common/star-rating.js b/assets/js/instant-results/components/common/star-rating.js
new file mode 100644
index 0000000000..6ae5bc990e
--- /dev/null
+++ b/assets/js/instant-results/components/common/star-rating.js
@@ -0,0 +1,29 @@
+/**
+ * WordPress dependencies.
+ */
+import { __, sprintf } from '@wordpress/i18n';
+
+/**
+ * Star rating component.
+ *
+ * @param {Option} props Component props.
+ * @param {string} props.rating Rating.
+ *
+ * @return {WPElement} Component element.
+ */
+export default ({ rating }) => {
+ const label = sprintf(
+ /* translators: %1$f Rating. %2$d Max rating. */
+ __('Rated %1$f out of %2$d', 'elasticpress'),
+ rating,
+ 5,
+ );
+
+ return (
+
+ );
+};
diff --git a/assets/js/instant-results/components/facets/facet.js b/assets/js/instant-results/components/facets/facet.js
new file mode 100644
index 0000000000..30141d554d
--- /dev/null
+++ b/assets/js/instant-results/components/facets/facet.js
@@ -0,0 +1,38 @@
+/**
+ * WordPress dependencies.
+ */
+import { WPElement } from '@wordpress/element';
+
+/**
+ * Internal dependencies.
+ */
+import PostTypeFacet from './post-type-facet';
+import PriceRangeFacet from './price-range-facet';
+import TaxonomyTermsFacet from './taxonomy-terms-facet';
+
+/**
+ * Facet component.
+ *
+ * @param {Object} props Props.
+ * @param {number} props.index Facet index.
+ * @param {string} props.name Facet name.
+ * @param {string} props.label Facet label.
+ * @param {'post_type'|'price_range'|'taxonomy'} props.type Facet type.
+ * @return {WPElement} Component element.
+ */
+export default ({ index, label, name, type }) => {
+ const defaultIsOpen = index < 2;
+
+ switch (type) {
+ case 'post_type':
+ return ;
+ case 'price_range':
+ return ;
+ case 'taxonomy':
+ return (
+
+ );
+ default:
+ return <>>;
+ }
+};
diff --git a/assets/js/instant-results/components/facets/post-type-facet.js b/assets/js/instant-results/components/facets/post-type-facet.js
new file mode 100644
index 0000000000..1b68064b8d
--- /dev/null
+++ b/assets/js/instant-results/components/facets/post-type-facet.js
@@ -0,0 +1,114 @@
+/**
+ * WordPress dependencies.
+ */
+import { useCallback, useContext, useMemo, WPElement } from '@wordpress/element';
+import { __ } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies.
+ */
+import { postTypeLabels } from '../../config';
+import Context from '../../context';
+import Panel from '../common/panel';
+import CheckboxList from '../common/checkbox-list';
+import { ActiveContraint } from '../tools/active-constraints';
+
+/**
+ * Post type facet component.
+ *
+ * @param {Object} props Props.
+ * @param {boolean} props.defaultIsOpen Whether the panel is open by default.
+ * @param {string} props.label Facet label.
+ * @return {WPElement} Component element.
+ */
+export default ({ defaultIsOpen, label }) => {
+ const {
+ state: {
+ isLoading,
+ postTypes: selectedPostTypes = [],
+ postTypesAggregation: { post_types: { buckets = [] } = {} } = {},
+ },
+ dispatch,
+ } = useContext(Context);
+
+ /**
+ * Create list of filter options from aggregation buckets.
+ *
+ * @param {Array} options List of options.
+ * @param {Object} bucket Aggregation bucket.
+ * @param {string} bucket.key Aggregation key.
+ * @param {number} index Bucket index.
+ * @return {Array} Array of options.
+ */
+ const reduceOptions = useCallback(
+ (options, { key }, index) => {
+ if (!Object.prototype.hasOwnProperty.call(postTypeLabels, key)) {
+ return options;
+ }
+
+ options.push({
+ checked: selectedPostTypes.includes(key),
+ id: `ep-search-post-type-${key}`,
+ label: postTypeLabels[key],
+ order: index,
+ value: key,
+ });
+
+ return options;
+ },
+ [selectedPostTypes],
+ );
+
+ /**
+ * Reduce buckets to options.
+ */
+ const options = useMemo(() => buckets.reduce(reduceOptions, []), [buckets, reduceOptions]);
+
+ /**
+ * Handle checkbox change event.
+ *
+ * @param {string[]} postTypes Selected post types.
+ */
+ const onChange = (postTypes) => {
+ dispatch({ type: 'SET_POST_TYPES', payload: postTypes });
+ };
+
+ /**
+ * Handle clearing a post type.
+ *
+ * @param {string} postType Post type being cleared.
+ */
+ const onClear = (postType) => {
+ const postTypes = [...selectedPostTypes];
+
+ postTypes.splice(postTypes.indexOf(postType), 1);
+
+ dispatch({ type: 'SET_POST_TYPES', payload: postTypes });
+ };
+
+ return (
+ options.length > 0 && (
+
+ {() => (
+ <>
+
+
+ {selectedPostTypes.map((value) => (
+ onClear(value)}
+ />
+ ))}
+ >
+ )}
+
+ )
+ );
+};
diff --git a/assets/js/instant-results/components/facets/price-range-facet.js b/assets/js/instant-results/components/facets/price-range-facet.js
new file mode 100644
index 0000000000..de526cbda9
--- /dev/null
+++ b/assets/js/instant-results/components/facets/price-range-facet.js
@@ -0,0 +1,145 @@
+/**
+ * WordPress dependencies.
+ */
+import { useContext, useLayoutEffect, useState, WPElement } from '@wordpress/element';
+import { __, sprintf } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies.
+ */
+import Context from '../../context';
+import { formatPrice } from '../../functions';
+import Panel from '../common/panel';
+import RangeSlider from '../common/range-slider';
+import { ActiveContraint } from '../tools/active-constraints';
+
+/**
+ * Price range facet.
+ *
+ * @param {Object} props Props.
+ * @param {boolean} props.defaultIsOpen Whether the panel is open by default.
+ * @param {string} props.label Facet label.
+ * @return {WPElement} Component element.
+ */
+export default ({ defaultIsOpen, label }) => {
+ const {
+ state: {
+ isLoading,
+ priceRangeAggregations: {
+ max_price: { value: maxAgg = null } = {},
+ min_price: { value: minAgg = null } = {},
+ } = {},
+ priceRange: [minArg = null, maxArg = null],
+ },
+ dispatch,
+ } = useContext(Context);
+
+ /**
+ * Minimum and maximum possible values.
+ */
+ const max = Math.ceil(maxAgg);
+ const min = Math.floor(minAgg);
+
+ /**
+ * Current minimum and maximum values.
+ */
+ const [currentMaxValue, setCurrentMaxValue] = useState(0);
+ const [currentMinValue, setCurrentMinValue] = useState(0);
+
+ /**
+ * Current minimum and maximum prices, formatted.
+ */
+ const currentMaxPrice = formatPrice(currentMaxValue, { maximumFractionDigits: 0 });
+ const currentMinPrice = formatPrice(currentMinValue, { maximumFractionDigits: 0 });
+
+ /**
+ * Applied minimum and maximum values.
+ */
+ const maxValue = maxArg || max;
+ const minValue = minArg || min;
+
+ /**
+ * Applied minimum and maximum prices, formatted.
+ */
+ const maxPrice = formatPrice(maxValue, { maximumFractionDigits: 0 });
+ const minPrice = formatPrice(minValue, { maximumFractionDigits: 0 });
+
+ /**
+ * Handle completed slider change.
+ *
+ * @param {number[]} values Lowest and highest values.
+ */
+ const onAfterChange = (values) => {
+ dispatch({ type: 'SET_PRICE_RANGE', payload: values });
+ };
+
+ /**
+ * Handle slider changes as they're made.
+ *
+ * @param {number[]} values Lowest and highest values.
+ */
+ const onChange = ([min, max]) => {
+ setCurrentMinValue(min);
+ setCurrentMaxValue(max);
+ };
+
+ /**
+ * Handle clearing the filter.
+ */
+ const onClear = () => {
+ dispatch({ type: 'SET_PRICE_RANGE', payload: [] });
+ };
+
+ /**
+ * Effects.
+ */
+ useLayoutEffect(() => {
+ const currentMaxValue = Math.min(max, maxValue);
+ const currentMinValue = Math.max(min, minValue);
+
+ setCurrentMaxValue(currentMaxValue);
+ setCurrentMinValue(currentMinValue);
+ }, [min, max, minValue, maxValue]);
+
+ return (
+ maxAgg !== null &&
+ minAgg !== null && (
+
+ {(isOpen) => (
+ <>
+
+
+ {isOpen && (
+
+ )}
+
+
+
+ {currentMinPrice} — {currentMaxPrice}
+
+
+
+ {maxArg !== null && minArg !== null && (
+
+ )}
+ >
+ )}
+
+ )
+ );
+};
diff --git a/assets/js/instant-results/components/facets/search-term-facet.js b/assets/js/instant-results/components/facets/search-term-facet.js
new file mode 100644
index 0000000000..f28516e09a
--- /dev/null
+++ b/assets/js/instant-results/components/facets/search-term-facet.js
@@ -0,0 +1,64 @@
+/**
+ * WordPress dependencies.
+ */
+import { useContext, WPElement } from '@wordpress/element';
+import { __, sprintf } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies.
+ */
+import Context from '../../context';
+import { ActiveContraint } from '../tools/active-constraints';
+
+/**
+ * Search field component.
+ *
+ * @return {WPElement} Component element.
+ */
+export default () => {
+ const {
+ state: {
+ args: { search },
+ searchedTerm,
+ },
+ dispatch,
+ } = useContext(Context);
+
+ /**
+ * Handle input changes.
+ *
+ * @param {Event} event Change event.
+ */
+ const onChange = (event) => {
+ dispatch({ type: 'SET_SEARCH_TERM', payload: event.target.value });
+ };
+
+ /**
+ * Handle clearing.
+ */
+ const onClear = () => {
+ dispatch({ type: 'SET_SEARCH_TERM', payload: '' });
+ };
+
+ return (
+ <>
+
+ {searchedTerm && (
+
+ )}
+ >
+ );
+};
diff --git a/assets/js/instant-results/components/facets/taxonomy-terms-facet.js b/assets/js/instant-results/components/facets/taxonomy-terms-facet.js
new file mode 100644
index 0000000000..e265edec41
--- /dev/null
+++ b/assets/js/instant-results/components/facets/taxonomy-terms-facet.js
@@ -0,0 +1,142 @@
+/**
+ * WordPress dependencies.
+ */
+import { useCallback, useContext, useMemo, WPElement } from '@wordpress/element';
+import { __, sprintf } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies.
+ */
+import Context from '../../context';
+import Panel from '../common/panel';
+import CheckboxList from '../common/checkbox-list';
+import { ActiveContraint } from '../tools/active-constraints';
+
+/**
+ * Taxonomy filter component.
+ *
+ * @param {Object} props Components props.
+ * @param {boolean} props.defaultIsOpen Whether the panel is open by default.
+ * @param {string} props.label Facet label.
+ * @param {string} props.taxonomy Facet taxonomy.
+ * @return {WPElement} Component element.
+ */
+export default ({ defaultIsOpen, label, taxonomy }) => {
+ const {
+ state: {
+ isLoading,
+ taxonomyTerms: { [taxonomy]: selectedTerms = [] },
+ taxonomyTermsAggregations: {
+ [taxonomy]: { taxonomy_terms: { buckets = [] } = {} } = {},
+ } = {},
+ },
+ dispatch,
+ } = useContext(Context);
+
+ /**
+ * Create list of filter options from aggregation buckets.
+ *
+ * @param {Array} options List of options.
+ * @param {Object} bucket Aggregation bucket.
+ * @param {string} bucket.key Aggregation key.
+ * @return {Array} Array of options.
+ */
+ const reduceOptions = useCallback(
+ (options, { key }) => {
+ const { name, parent, term_id, term_order } = JSON.parse(key);
+
+ options.push({
+ checked: selectedTerms.includes(term_id),
+ id: `ep-search-${taxonomy}-${term_id}`,
+ label: name,
+ parent: parent.toString(),
+ order: term_order,
+ value: term_id.toString(),
+ });
+
+ return options;
+ },
+ [selectedTerms, taxonomy],
+ );
+
+ /**
+ * Reduce buckets to options.
+ */
+ const options = useMemo(() => buckets.reduce(reduceOptions, []), [buckets, reduceOptions]);
+
+ /**
+ * Reduce options to labels.
+ *
+ * @param {Object} labels List of options.
+ * @param {Object} bucket Aggregation bucket.
+ * @param {string} bucket.key Aggregation key.
+ * @return {Object} Options and their labels.
+ */
+ const reduceLabels = useCallback((labels, { label, value }) => {
+ labels[value] = label;
+
+ return labels;
+ }, []);
+
+ /**
+ * Reduce buckets to labels.
+ */
+ const labels = options.reduce(reduceLabels, {});
+
+ /**
+ * Handle checkbox change event.
+ *
+ * @param {string[]} terms Selected terms.
+ */
+ const onChange = (terms) => {
+ dispatch({ type: 'SET_TAXONOMY_TERMS', payload: { taxonomy, terms } });
+ };
+
+ /**
+ * Handle clearing a term.
+ *
+ * @param {string} term Term being cleared.
+ */
+ const onClear = (term) => {
+ const terms = [...selectedTerms];
+
+ terms.splice(terms.indexOf(term), 1);
+
+ dispatch({ type: 'SET_TAXONOMY_TERMS', payload: { taxonomy, terms } });
+ };
+
+ return (
+ options.length > 0 && (
+
+ {(isOpen) => (
+ <>
+ {isOpen && (
+
+ )}
+
+ {selectedTerms.map(
+ (value) =>
+ labels?.[value] && (
+ onClear(value)}
+ />
+ ),
+ )}
+ >
+ )}
+
+ )
+ );
+};
diff --git a/assets/js/instant-results/components/layout.js b/assets/js/instant-results/components/layout.js
new file mode 100644
index 0000000000..6384563a2c
--- /dev/null
+++ b/assets/js/instant-results/components/layout.js
@@ -0,0 +1,55 @@
+/**
+ * WordPress dependencies.
+ */
+import { useContext, WPElement } from '@wordpress/element';
+
+/**
+ * Internal dependencies.
+ */
+import { facets } from '../config';
+import Context from '../context';
+import Facet from './facets/facet';
+import SearchTermFacet from './facets/search-term-facet';
+import Results from './layout/results';
+import Sidebar from './layout/sidebar';
+import Toolbar from './layout/toolbar';
+import ActiveConstraints from './tools/active-constraints';
+import ClearConstraints from './tools/clear-constraints';
+import SidebarToggle from './tools/sidebar-toggle';
+import Sort from './tools/sort';
+
+/**
+ * Search dialog.
+ *
+ * @return {WPElement} Component element.
+ */
+export default () => {
+ const {
+ state: { isLoading, isSidebarOpen },
+ } = useContext(Context);
+
+ return (
+
+
+
+
+
+
+ {facets.map(({ name, label, type }, index) => (
+
+ ))}
+
+
+
+
+
+ );
+};
diff --git a/assets/js/instant-results/components/layout/results.js b/assets/js/instant-results/components/layout/results.js
new file mode 100644
index 0000000000..a30cce559c
--- /dev/null
+++ b/assets/js/instant-results/components/layout/results.js
@@ -0,0 +1,93 @@
+/**
+ * Internal depenencies.
+ */
+import { useContext, useEffect, useRef, WPElement } from '@wordpress/element';
+import { _n, sprintf } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies.
+ */
+import Context from '../../context';
+import Pagination from '../results/pagination';
+import Result from '../results/result';
+import Sort from '../tools/sort';
+
+/**
+ * Search results component.
+ *
+ * @return {WPElement} Component element.
+ */
+export default () => {
+ const {
+ state: {
+ args: { offset, per_page },
+ searchResults,
+ searchedTerm,
+ totalResults,
+ },
+ dispatch,
+ } = useContext(Context);
+
+ const headingRef = useRef();
+
+ /**
+ * Handle clicking next.
+ */
+ const onNext = () => {
+ dispatch({ type: 'NEXT_PAGE' });
+ };
+
+ /**
+ * Handle clicking previous.
+ */
+ const onPrevious = () => {
+ dispatch({ type: 'PREVIOUS_PAGE' });
+ };
+
+ /**
+ * Effects.
+ */
+ useEffect(() => {
+ headingRef.current.scrollIntoView({ behavior: 'smooth' });
+ }, [offset]);
+
+ return (
+
+
+
+ {searchedTerm
+ ? sprintf(
+ /* translators: %1$d: results count. %2$s: Search term. */
+ _n(
+ '%1$d result for “%2$s“',
+ '%1$d results for “%2$s“',
+ totalResults,
+ 'elasticpress',
+ ),
+ totalResults,
+ searchedTerm,
+ )
+ : sprintf(
+ /* translators: %d: results count. */
+ _n('%d result', '%d results', totalResults, 'elasticpress'),
+ totalResults,
+ )}
+
+
+
+
+
+ {searchResults.map((hit) => (
+
+ ))}
+
+
+
+ );
+};
diff --git a/assets/js/instant-results/components/layout/sidebar.js b/assets/js/instant-results/components/layout/sidebar.js
new file mode 100644
index 0000000000..e2b6cc4ef0
--- /dev/null
+++ b/assets/js/instant-results/components/layout/sidebar.js
@@ -0,0 +1,26 @@
+/**
+ * WordPress dependencies.
+ */
+import { useContext, WPElement } from '@wordpress/element';
+
+/**
+ * Internal dependencies.
+ */
+import Context from '../../context';
+
+/**
+ * Search field component.
+ *
+ * @param {Object} props Props.
+ * @param {WPElement} props.children Children.
+ * @return {WPElement} Element.
+ */
+export default ({ children }) => {
+ const {
+ state: { isSidebarOpen },
+ } = useContext(Context);
+
+ return (
+
+ );
+};
diff --git a/assets/js/instant-results/components/layout/toolbar.js b/assets/js/instant-results/components/layout/toolbar.js
new file mode 100644
index 0000000000..7be536ec7b
--- /dev/null
+++ b/assets/js/instant-results/components/layout/toolbar.js
@@ -0,0 +1,15 @@
+/**
+ * WordPress dependencies.
+ */
+import { WPElement } from '@wordpress/element';
+
+/**
+ * Search field component.
+ *
+ * @param {Object} props Props.
+ * @param {WPElement} props.children Children.
+ * @return {WPElement} Element.
+ */
+export default ({ children }) => {
+ return {children}
;
+};
diff --git a/assets/js/instant-results/components/results/pagination.js b/assets/js/instant-results/components/results/pagination.js
new file mode 100644
index 0000000000..44ebbd562b
--- /dev/null
+++ b/assets/js/instant-results/components/results/pagination.js
@@ -0,0 +1,75 @@
+/**
+ * WordPress dependencies.
+ */
+import { __, sprintf } from '@wordpress/i18n';
+
+/**
+ * Search results component.
+ *
+ * @param {Object} props Props.
+ * @param {number} props.offset Current items offset.
+ * @param {Function} props.onNext Next button handler.
+ * @param {Function} props.onPrevious Previous button handler.
+ * @param {number} props.perPage Items per page.
+ * @param {number} props.total Total number of items.
+ * @return {WPElement} Element.
+ */
+export default ({ offset, onNext, onPrevious, perPage, total }) => {
+ /**
+ * Current page number.
+ */
+ const currentPage = (offset + perPage) / perPage;
+
+ /**
+ * Whether there are more pages.
+ */
+ const nextIsAvailable = total > offset + perPage;
+
+ /**
+ * Whether the are previous pages.
+ */
+ const previousIsAvailable = offset > 0;
+
+ /**
+ * Total pages.
+ */
+ const totalPages = Math.ceil(total / perPage);
+
+ return (
+
+ );
+};
diff --git a/assets/js/instant-results/components/results/result.js b/assets/js/instant-results/components/results/result.js
new file mode 100644
index 0000000000..96ec38cfb4
--- /dev/null
+++ b/assets/js/instant-results/components/results/result.js
@@ -0,0 +1,80 @@
+/**
+ * WordPress dependencies.
+ */
+import { WPElement } from '@wordpress/element';
+
+/**
+ * Internal dependencies.
+ */
+import { postTypeLabels, isWooCommerce } from '../../config';
+import StarRating from '../common/star-rating';
+import Image from '../common/image';
+
+const { gmdateI18n } = wp.date;
+
+/**
+ * Search result.
+ *
+ * @param {Object} props Component props.
+ * @param {Object} props.hit Elasticsearch hit.
+ * @return {WPElement} Component element.
+ */
+export default ({ hit }) => {
+ const {
+ highlight: { post_title: resultTitle, post_content_plain: resultContent = [] },
+ _source: {
+ meta: { _wc_average_rating: [{ value: resultRating = 0 } = {}] = [] },
+ post_date_gmt: resultDateGmt,
+ permalink: resultPermalink,
+ post_type: resultPostType,
+ price_html: priceHtml,
+ thumbnail: resultThumbnail = false,
+ },
+ } = hit;
+
+ const postTypeLabel = postTypeLabels?.[resultPostType];
+
+ return (
+
+ {resultThumbnail && (
+
+
+
+ )}
+
+
+ {postTypeLabel && {postTypeLabel}}
+
+
+ {/* eslint-disable-next-line jsx-a11y/control-has-associated-label */}
+
+
+
+ {isWooCommerce && priceHtml && (
+ // eslint-disable-next-line react/no-danger
+
+ )}
+
+
+ {resultContent.length > 0 && (
+
+ )}
+
+
+
+ );
+};
diff --git a/assets/js/instant-results/components/tools/active-constraints.js b/assets/js/instant-results/components/tools/active-constraints.js
new file mode 100644
index 0000000000..cf8f88c4cb
--- /dev/null
+++ b/assets/js/instant-results/components/tools/active-constraints.js
@@ -0,0 +1,53 @@
+/**
+ * WordPress dependencies.
+ */
+import { createSlotFill } from '@wordpress/components';
+import { WPElement } from '@wordpress/element';
+import { closeSmall, Icon } from '@wordpress/icons';
+import { __, sprintf } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies.
+ */
+import SmallButton from '../common/small-button';
+
+/**
+ * Create SlotFill.
+ */
+const { Fill, Slot } = createSlotFill('ActiveContraints');
+
+/**
+ * Active filter component.
+ *
+ * @param {Object} props Props.
+ * @param {string} props.label Constraint label.
+ * @param {Function} props.onClick Click handler.
+ * @return {WPElement} Element.
+ */
+export const ActiveContraint = ({ label, onClick }) => {
+ return (
+
+
+
+ {label}
+
+
+ );
+};
+
+/**
+ * Active constraints component.
+ *
+ * @return {WPElement} Element.
+ */
+export default () => {
+ return {(fills) => fills};
+};
diff --git a/assets/js/instant-results/components/tools/clear-constraints.js b/assets/js/instant-results/components/tools/clear-constraints.js
new file mode 100644
index 0000000000..f4127dd946
--- /dev/null
+++ b/assets/js/instant-results/components/tools/clear-constraints.js
@@ -0,0 +1,53 @@
+/**
+ * WordPress dependencies.
+ */
+import { useContext, useMemo, WPElement } from '@wordpress/element';
+import { __ } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies.
+ */
+import Context from '../../context';
+import SmallButton from '../common/small-button';
+
+/**
+ * Active constraints component.
+ *
+ * @return {WPElement} Element.
+ */
+export default () => {
+ const {
+ state: { postTypes, priceRange, taxonomyTerms },
+ dispatch,
+ } = useContext(Context);
+
+ /**
+ * Return whether there are active filters.
+ *
+ * @return {boolean} Whether there are active filters.
+ */
+ const hasFilters = useMemo(() => {
+ const [minPrice, maxPrice] = priceRange;
+
+ const hasPostTypes = postTypes.length > 0;
+ const hasPriceRange = Boolean(minPrice || maxPrice);
+ const hasTaxonomyTerms = Object.values(taxonomyTerms).some((terms) => terms.length > 0);
+
+ return hasPostTypes || hasPriceRange || hasTaxonomyTerms;
+ }, [postTypes, priceRange, taxonomyTerms]);
+
+ /**
+ * Handle clicking button.
+ *
+ * @return {void}
+ */
+ const onClick = () => {
+ dispatch({ type: 'CLEAR_FILTERS' });
+ };
+
+ return (
+ hasFilters && (
+ {__('Clear filters', 'elasticpress')}
+ )
+ );
+};
diff --git a/assets/js/instant-results/components/tools/sidebar-toggle.js b/assets/js/instant-results/components/tools/sidebar-toggle.js
new file mode 100644
index 0000000000..0d8aa2c9c2
--- /dev/null
+++ b/assets/js/instant-results/components/tools/sidebar-toggle.js
@@ -0,0 +1,45 @@
+/**
+ * WordPress deendencies.
+ */
+import { useContext, WPElement } from '@wordpress/element';
+import { chevronDown, chevronUp, Icon } from '@wordpress/icons';
+import { __ } from '@wordpress/i18n';
+
+/**
+ * Internal deendencies.
+ */
+import Context from '../../context';
+
+/**
+ * Open sidebar component.
+ *
+ * @return {WPElement} Element.
+ */
+export default () => {
+ const {
+ state: { isSidebarOpen },
+ dispatch,
+ } = useContext(Context);
+
+ /**
+ * Handle click.
+ */
+ const onClick = () => {
+ dispatch({ type: 'TOGGLE_SIDEBAR' });
+ };
+
+ return (
+
+ );
+};
diff --git a/assets/js/instant-results/components/tools/sort.js b/assets/js/instant-results/components/tools/sort.js
new file mode 100644
index 0000000000..ca36074a26
--- /dev/null
+++ b/assets/js/instant-results/components/tools/sort.js
@@ -0,0 +1,63 @@
+/**
+ * WordPress deendencies.
+ */
+import { useContext, useMemo, WPElement } from '@wordpress/element';
+import { __ } from '@wordpress/i18n';
+
+/**
+ * Internal deendencies.
+ */
+import { sortOptions } from '../../config';
+import Context from '../../context';
+
+/**
+ * Search results component.
+ *
+ * @return {WPElement} Component element.
+ */
+export default () => {
+ const {
+ state: {
+ args: { orderby, order },
+ },
+ dispatch,
+ } = useContext(Context);
+
+ /**
+ * The key for the current sorting option.
+ */
+ const currentOption = useMemo(() => {
+ return Object.keys(sortOptions).find((key) => {
+ return sortOptions[key].orderby === orderby && sortOptions[key].order === order;
+ });
+ }, [orderby, order]);
+
+ /**
+ * Handle sorting option change.
+ *
+ * @param {Event} event Change event.
+ */
+ const onChange = (event) => {
+ const { orderby, order } = sortOptions[event.target.value];
+
+ dispatch({ type: 'SORT_RESULTS', payload: { orderby, order } });
+ };
+
+ return (
+
+ );
+};
diff --git a/assets/js/instant-results/config.js b/assets/js/instant-results/config.js
new file mode 100644
index 0000000000..5b6aa6ce23
--- /dev/null
+++ b/assets/js/instant-results/config.js
@@ -0,0 +1,71 @@
+/**
+ * WordPress dependencies.
+ */
+import { __ } from '@wordpress/i18n';
+
+/**
+ * Window dependencies.
+ */
+const {
+ apiEndpoint,
+ apiHost,
+ currencyCode,
+ facets,
+ highlightTag,
+ isWooCommerce,
+ matchType,
+ postTypeLabels,
+ taxonomyLabels,
+} = window.epInstantResults;
+
+/**
+ * Sorting options configuration.
+ */
+const sortOptions = {
+ relevance_desc: {
+ name: __('Most relevant', 'elasticpress'),
+ orderby: 'relevance',
+ order: 'desc',
+ currencyCode,
+ },
+ date_desc: {
+ name: __('Date, newest to oldest', 'elasticpress'),
+ orderby: 'date',
+ order: 'desc',
+ },
+ date_asc: {
+ name: __('Date, oldest to newest', 'elasticpress'),
+ orderby: 'date',
+ order: 'asc',
+ },
+};
+
+/**
+ * Sort by price is only available for WooCommerce.
+ */
+if (isWooCommerce) {
+ sortOptions.price_desc = {
+ name: __('Price, highest to lowest', 'elasticpress'),
+ orderby: 'price',
+ order: 'desc',
+ };
+
+ sortOptions.price_asc = {
+ name: __('Price, lowest to highest', 'elasticpress'),
+ orderby: 'price',
+ order: 'asc',
+ };
+}
+
+export {
+ apiEndpoint,
+ apiHost,
+ currencyCode,
+ facets,
+ highlightTag,
+ isWooCommerce,
+ matchType,
+ postTypeLabels,
+ sortOptions,
+ taxonomyLabels,
+};
diff --git a/assets/js/instant-results/context.js b/assets/js/instant-results/context.js
new file mode 100644
index 0000000000..05f9cf53a2
--- /dev/null
+++ b/assets/js/instant-results/context.js
@@ -0,0 +1,6 @@
+/**
+ * Internal dependencies.
+ */
+import { createContext } from '@wordpress/element';
+
+export default createContext();
diff --git a/assets/js/instant-results/functions.js b/assets/js/instant-results/functions.js
new file mode 100644
index 0000000000..1500c2dea6
--- /dev/null
+++ b/assets/js/instant-results/functions.js
@@ -0,0 +1,100 @@
+/**
+ * Internal deendencies.
+ */
+import { currencyCode } from './config';
+
+/**
+ * Set API request args for post type.
+ *
+ * @param {string[]} postTypes Post types.
+ * @return {Object} Price range args.
+ */
+export const getArgsFromPostTypes = (postTypes) => {
+ const args = {};
+
+ if (postTypes.length > 0) {
+ args.post_type = postTypes;
+ }
+
+ return args;
+};
+
+/**
+ * Set API request args for a price range.
+ *
+ * @param {number} min Minimum price.
+ * @param {number} max Maximum price.
+ * @return {Object} Request args.
+ */
+export const getArgsFromPriceRange = (min, max) => {
+ const args = {};
+
+ if (min) {
+ args.min_price = min;
+ }
+
+ if (max) {
+ args.max_price = max;
+ }
+
+ return args;
+};
+
+/**
+ * Set API request args for taxonomy terms.
+ *
+ * @param {Object[]} taxonomyTerms Taxonomies and their terms.
+ * @return {Object} Request args.
+ */
+export const getArgsFromTaxonomyTerms = (taxonomyTerms) => {
+ return Object.entries(taxonomyTerms).reduce((args, [taxonomy, terms]) => {
+ const param = `tax-${taxonomy}`;
+
+ if (terms.length > 0) {
+ args[param] = terms.join(',');
+ }
+
+ return args;
+ }, {});
+};
+
+/**
+ * Format a number as a price.
+ *
+ * @param {number} number Number to format.
+ * @param {Object} options Formatter options.
+ * @return {string} Formatted number.
+ */
+export const formatPrice = (number, options) => {
+ const format = new Intl.NumberFormat(navigator.language, {
+ style: 'currency',
+ currency: currencyCode,
+ currencyDisplay: 'narrowSymbol',
+ ...options,
+ });
+
+ return format.format(number);
+};
+
+/**
+ * Get query parameters for an API request from the state.
+ *
+ * @param {Object} state State.
+ * @return {URLSearchParams} URLSearchParams instance.
+ */
+export const getURLParamsFromState = (state) => {
+ const { args, postTypes, priceRange, taxonomyTerms } = state;
+
+ const postTypeParam = getArgsFromPostTypes(postTypes);
+ const priceRangeParams = getArgsFromPriceRange(...priceRange);
+ const taxonomyTermsParams = getArgsFromTaxonomyTerms(taxonomyTerms);
+
+ const init = {
+ ...args,
+ ...postTypeParam,
+ ...priceRangeParams,
+ ...taxonomyTermsParams,
+ };
+
+ return new URLSearchParams(init);
+};
diff --git a/assets/js/instant-results/hooks.js b/assets/js/instant-results/hooks.js
new file mode 100644
index 0000000000..801d32cc84
--- /dev/null
+++ b/assets/js/instant-results/hooks.js
@@ -0,0 +1,70 @@
+import { useCallback, useRef } from '@wordpress/element';
+import { apiEndpoint, apiHost } from './config';
+
+/**
+ * Get debounced version of a function that only runs a given ammount of time
+ * after the last time it was run.
+ *
+ * @param {Function} callback Function to debounce.
+ * @param {number} delay Milliseconds to delay.
+ * @return {Function} Debounced function.
+ */
+export const useDebounce = (callback, delay) => {
+ const timeout = useRef(null);
+
+ return useCallback(
+ (...args) => {
+ window.clearTimeout(timeout.current);
+
+ timeout.current = window.setTimeout(() => {
+ callback(...args);
+ }, delay);
+ },
+ [callback, delay],
+ );
+};
+
+/**
+ * Get a callback function for retrieving search results.
+ *
+ * @return {Function} Memoized callback function for retrieving search results.
+ */
+export const useGetResults = () => {
+ const abort = useRef(new AbortController());
+ const request = useRef(null);
+
+ /**
+ * Get new search results from the API.
+ *
+ * @param {URLSearchParams} urlParams Query arguments.
+ * @return {Promise} Request promise.
+ */
+ const getResults = async (urlParams) => {
+ const url = `${apiHost}${apiEndpoint}?${urlParams.toString()}`;
+
+ abort.current.abort();
+ abort.current = new AbortController();
+
+ request.current = fetch(url, {
+ signal: abort.current.signal,
+ headers: {
+ Accept: 'application/json',
+ },
+ })
+ .then((response) => {
+ return response.json();
+ })
+ .catch((error) => {
+ if (error?.name !== 'AbortError' && !request.current) {
+ throw error;
+ }
+ })
+ .finally(() => {
+ request.current = null;
+ });
+
+ return request.current;
+ };
+
+ return useCallback(getResults, []);
+};
diff --git a/assets/js/instant-results/index.js b/assets/js/instant-results/index.js
new file mode 100644
index 0000000000..fac481f892
--- /dev/null
+++ b/assets/js/instant-results/index.js
@@ -0,0 +1,203 @@
+/**
+ * WordPress dependencies.
+ */
+import { SlotFillProvider } from '@wordpress/components';
+import { render, useCallback, useEffect, useReducer, useRef, WPElement } from '@wordpress/element';
+import { __ } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies.
+ */
+import Context from './context';
+import { getURLParamsFromState } from './functions';
+import { useDebounce, useGetResults } from './hooks';
+import { reducer, initialArg } from './reducer';
+import Layout from './components/layout';
+import Modal from './components/common/modal';
+
+/**
+ * component.
+ *
+ * @return {WPElement} Element.
+ */
+const App = () => {
+ const getResults = useGetResults();
+ const [state, dispatch] = useReducer(reducer, initialArg);
+ const inputRef = useRef();
+ const modalRef = useRef();
+ const stateRef = useRef(state);
+
+ stateRef.current = state;
+
+ /**
+ * Close the modal.
+ */
+ const openModal = useCallback(() => {
+ dispatch({ type: 'OPEN_MODAL' });
+ }, []);
+
+ /**
+ * Close the modal.
+ */
+ const closeModal = useCallback(() => {
+ dispatch({ type: 'CLOSE_MODAL' });
+ inputRef.current.focus();
+ }, []);
+
+ /**
+ * Start loading.
+ */
+ const startLoading = useCallback(() => {
+ dispatch({ type: 'START_LOADING' });
+ }, []);
+
+ /**
+ * Finish loading.
+ */
+ const finishLoading = useCallback(() => {
+ dispatch({ type: 'FINISH_LOADING' });
+ }, []);
+
+ /**
+ * Update search results.
+ *
+ * @param {Object} response Search results.
+ */
+ const updateResults = useCallback((response) => {
+ if (response) {
+ dispatch({ type: 'NEW_SEARCH_RESULTS', payload: response });
+ }
+ }, []);
+
+ /**
+ * Perform a search.
+ */
+ const doSearch = useCallback(async () => {
+ const urlParams = getURLParamsFromState(stateRef.current);
+
+ startLoading();
+
+ const response = await getResults(urlParams);
+
+ updateResults(response);
+
+ finishLoading();
+ }, [finishLoading, getResults, startLoading, updateResults]);
+
+ /**
+ * Debounced search function.
+ */
+ const doSearchDebounced = useDebounce(doSearch, 250);
+
+ /**
+ * Handle escape key press.
+ *
+ * @param {Event} event Key down event.
+ */
+ const onEscape = useCallback(
+ (event) => {
+ if (event.key === 'Escape') {
+ closeModal();
+ }
+ },
+ [closeModal],
+ );
+
+ /**
+ * Handle submitting the search form.
+ *
+ * @param {Event} event Input event.
+ */
+ const onSubmit = useCallback(
+ (event) => {
+ event.preventDefault();
+
+ inputRef.current = event.target.s;
+
+ dispatch({ type: 'SET_SEARCH_TERM', payload: event.target.s.value });
+
+ openModal();
+ },
+ [openModal],
+ );
+
+ /**
+ * Handle changes to search parameters.
+ */
+ const handleChanges = () => {
+ const {
+ args: { search },
+ isOpen,
+ searchedTerm,
+ } = stateRef.current;
+
+ if (!isOpen) {
+ return;
+ }
+
+ if (search !== searchedTerm) {
+ doSearchDebounced();
+ } else {
+ doSearch();
+ }
+ };
+
+ /**
+ * Bind events to outside elements.
+ *
+ * @return {Function} A cleanup function that unbinds the events.
+ */
+ const handleEvents = () => {
+ const inputs = document.querySelectorAll('form input[type="search"');
+ const modal = modalRef.current;
+
+ inputs.forEach((input) => {
+ input.form.addEventListener('submit', onSubmit);
+ });
+
+ modal.ownerDocument.body.addEventListener('keydown', onEscape);
+
+ return () => {
+ inputs.forEach((input) => {
+ input.form.removeEventListener('submit', onSubmit);
+ });
+
+ modal.ownerDocument.body.removeEventListener('keydown', onEscape);
+ };
+ };
+
+ /**
+ * Effects.
+ */
+ useEffect(handleEvents, [onEscape, onSubmit]);
+ useEffect(handleChanges, [
+ doSearch,
+ doSearchDebounced,
+ state.args,
+ state.args.orderby,
+ state.args.order,
+ state.args.offset,
+ state.args.search,
+ state.isOpen,
+ state.postTypes,
+ state.priceRange,
+ state.taxonomyTerms,
+ ]);
+
+ return (
+
+
+
+
+
+
+
+ );
+};
+
+render(, document.getElementById('ep-instant-results'));
diff --git a/assets/js/instant-results/reducer.js b/assets/js/instant-results/reducer.js
new file mode 100644
index 0000000000..7c95cc4153
--- /dev/null
+++ b/assets/js/instant-results/reducer.js
@@ -0,0 +1,157 @@
+/**
+ * Internal dependencies.
+ */
+import { highlightTag, matchType } from './config';
+
+/**
+ * Initial state.
+ */
+export const initialArg = {
+ args: {
+ highlight: highlightTag,
+ offset: 0,
+ orderby: 'relevance',
+ order: 'desc',
+ per_page: 6,
+ relation: matchType === 'all' ? 'and' : 'or',
+ search: '',
+ elasticpress: '1',
+ },
+ isLoading: false,
+ isOpen: false,
+ isSidebarOpen: false,
+ poppingState: false,
+ postTypes: [],
+ postTypesAggregation: {},
+ priceRange: [],
+ priceRangeAggregations: {},
+ searchResults: [],
+ searchedTerm: '',
+ taxonomyTerms: {},
+ taxonomyTermsAggregations: {},
+ totalResults: 0,
+};
+
+/**
+ * Reducer function for handling state changes.
+ *
+ * @param {Object} state The current state.
+ * @param {Object} action Action data.
+ * @param {string} action.type The action name.
+ * @param {Object} action.payload New state data from the action.
+ * @return {Object} Updated state.
+ */
+export const reducer = (state, { type, payload }) => {
+ const newState = { ...state };
+
+ switch (type) {
+ case 'CLEAR_FILTERS': {
+ newState.postTypes = [];
+ newState.priceRange = [];
+ newState.taxonomyTerms = {};
+ break;
+ }
+ case 'POP_STATE': {
+ newState.args = payload.args;
+ newState.isOpen = payload.isOpen;
+ newState.poppingState = true;
+ newState.postTypes = payload.postTypes;
+ newState.priceRange = payload.priceRange;
+ newState.taxonomyTerms = payload.taxonomyTerms;
+ break;
+ }
+ case 'SET_SEARCH_TERM': {
+ newState.args.offset = 0;
+ newState.args.search = payload;
+
+ if (payload) {
+ newState.postTypes = [];
+ newState.priceRange = [];
+ newState.taxonomyTerms = {};
+ }
+
+ break;
+ }
+ case 'SET_POST_TYPES': {
+ newState.args.offset = 0;
+ newState.postTypes = payload;
+ break;
+ }
+ case 'SET_PRICE_RANGE': {
+ newState.args.offset = 0;
+ newState.priceRange = payload;
+ break;
+ }
+ case 'SET_TAXONOMY_TERMS': {
+ const newTaxonomyTerms = { ...newState.taxonomyTerms };
+
+ newTaxonomyTerms[payload.taxonomy] = payload.terms;
+ newState.args.offset = 0;
+ newState.taxonomyTerms = newTaxonomyTerms;
+ break;
+ }
+ case 'SORT_RESULTS': {
+ newState.args.offset = 0;
+ newState.args.order = payload.order;
+ newState.args.orderby = payload.orderby;
+ break;
+ }
+ case 'NEW_SEARCH_RESULTS': {
+ const {
+ hits: { hits, total },
+ aggregations: {
+ post_type: postTypesAggregation,
+ price_range: priceRangeAggregation,
+ ...taxonomyTermsAggregations
+ } = {},
+ } = payload;
+
+ /**
+ * Total number of items.
+ */
+ const totalNumber = typeof total === 'number' ? total : total.value;
+
+ newState.poppingState = false;
+ newState.postTypesAggregation = postTypesAggregation;
+ newState.priceRangeAggregations = priceRangeAggregation;
+ newState.searchResults = hits;
+ newState.searchedTerm = newState.args.search;
+ newState.taxonomyTermsAggregations = taxonomyTermsAggregations;
+ newState.totalResults = totalNumber;
+
+ break;
+ }
+ case 'NEXT_PAGE': {
+ newState.args.offset += newState.args.per_page;
+ break;
+ }
+ case 'PREVIOUS_PAGE': {
+ newState.args.offset = Math.max(newState.args.offset - newState.args.per_page, 0);
+ break;
+ }
+ case 'START_LOADING': {
+ newState.isLoading = true;
+ break;
+ }
+ case 'FINISH_LOADING': {
+ newState.isLoading = false;
+ break;
+ }
+ case 'TOGGLE_SIDEBAR': {
+ newState.isSidebarOpen = !state.isSidebarOpen;
+ break;
+ }
+ case 'OPEN_MODAL': {
+ newState.isOpen = true;
+ break;
+ }
+ case 'CLOSE_MODAL': {
+ newState.isOpen = false;
+ break;
+ }
+ default:
+ break;
+ }
+
+ return newState;
+};
diff --git a/assets/js/notice.js b/assets/js/notice.js
index 772d25263c..035d9c57cc 100644
--- a/assets/js/notice.js
+++ b/assets/js/notice.js
@@ -1,3 +1,5 @@
+import jQuery from 'jquery';
+
const { epAdmin, ajaxurl } = window;
jQuery('.notice').on('click', '.notice-dismiss', (event) => {
diff --git a/assets/js/sites-admin.js b/assets/js/sites-admin.js
index dac812865f..746427b673 100644
--- a/assets/js/sites-admin.js
+++ b/assets/js/sites-admin.js
@@ -1,3 +1,5 @@
+import jQuery from 'jquery';
+
const { epsa } = window;
// eslint-disable-next-line @wordpress/no-global-event-listener
diff --git a/assets/js/weighting.js b/assets/js/weighting.js
index b73fdb01dd..732f5bad65 100644
--- a/assets/js/weighting.js
+++ b/assets/js/weighting.js
@@ -1,3 +1,5 @@
+import jQuery from 'jquery';
+
jQuery('.weighting-settings input[type=range]').on('input', function () {
const el = jQuery(this);
diff --git a/dist/css/autosuggest-styles.min.asset.php b/dist/css/autosuggest-styles.min.asset.php
new file mode 100644
index 0000000000..8715299f0d
--- /dev/null
+++ b/dist/css/autosuggest-styles.min.asset.php
@@ -0,0 +1 @@
+ array(), 'version' => '73e372e29a839749702d1458418c1f9b');
\ No newline at end of file
diff --git a/dist/css/autosuggest-styles.min.css b/dist/css/autosuggest-styles.min.css
index 74dbbca92f..4453af2f30 100644
--- a/dist/css/autosuggest-styles.min.css
+++ b/dist/css/autosuggest-styles.min.css
@@ -1 +1 @@
-.ep-autosuggest-container{position:relative}.ep-autosuggest-container .ep-autosuggest{background:#fff;border:1px solid #ccc;-webkit-box-shadow:0 2px 4px rgba(0,0,0,.2);box-shadow:0 2px 4px rgba(0,0,0,.2);display:none;position:absolute;width:100%;z-index:200}.ep-autosuggest-container .ep-autosuggest>ul{list-style:none;margin:0!important}.ep-autosuggest-container .ep-autosuggest>ul>li{font-family:sans-serif}.ep-autosuggest-container .ep-autosuggest>ul>li>a.autosuggest-link{color:#000;cursor:pointer;display:block;padding:2px 10px}.ep-autosuggest-container .ep-autosuggest>ul>li>a.autosuggest-link:active,.ep-autosuggest-container .ep-autosuggest>ul>li>a.autosuggest-link:hover,.ep-autosuggest-container .selected{background-color:#eee;text-decoration:none}
+.ep-autosuggest-container{position:relative}.ep-autosuggest-container .ep-autosuggest{background:#fff;border:1px solid #ccc;-webkit-box-shadow:0 2px 4px rgba(0,0,0,.2);box-shadow:0 2px 4px rgba(0,0,0,.2);display:none;position:absolute;width:100%;z-index:200}.ep-autosuggest-container .ep-autosuggest>ul{list-style:none;margin:0!important}.ep-autosuggest-container .ep-autosuggest>ul>li{font-family:sans-serif}.ep-autosuggest-container .ep-autosuggest>ul>li>a.autosuggest-link{color:#000;cursor:pointer;display:block;padding:2px 10px}.ep-autosuggest-container .ep-autosuggest>ul>li>a.autosuggest-link:active,.ep-autosuggest-container .ep-autosuggest>ul>li>a.autosuggest-link:hover{background-color:#eee;text-decoration:none}.ep-autosuggest-container .selected{background-color:#eee;text-decoration:none}
diff --git a/dist/css/comments-styles.min.asset.php b/dist/css/comments-styles.min.asset.php
new file mode 100644
index 0000000000..118b83fef3
--- /dev/null
+++ b/dist/css/comments-styles.min.asset.php
@@ -0,0 +1 @@
+ array(), 'version' => 'db2d0dc74c9edb3b118473615470b5eb');
\ No newline at end of file
diff --git a/dist/css/dashboard-styles.min.asset.php b/dist/css/dashboard-styles.min.asset.php
new file mode 100644
index 0000000000..2eec3fe212
--- /dev/null
+++ b/dist/css/dashboard-styles.min.asset.php
@@ -0,0 +1 @@
+ array(), 'version' => '966cdf5a54291a6c47713b86805cbe18');
\ No newline at end of file
diff --git a/dist/css/dashboard-styles.min.css b/dist/css/dashboard-styles.min.css
index cafa1f5583..cc0a2da000 100644
--- a/dist/css/dashboard-styles.min.css
+++ b/dist/css/dashboard-styles.min.css
@@ -1 +1 @@
-:root{--statusOk:#6aa000;--statusWarning:#e3e600;--statusError:red}.wrap .notice,.wrap>h2{position:relative;z-index:2}.wrap h1{font-size:23px;font-weight:400;line-height:29px;margin:0;padding:9px 0 4px}.wrap h2{color:#888;line-height:1.75;margin:.5em 0 .75em}#wpbody #update-nag,#wpbody .update-nag{margin-bottom:20px;margin-left:-20px;margin-top:0;width:100%}h2.ep-list-features{display:none}.ep-header-menu{background-color:#fff;border-bottom:2px solid #ddd;margin-left:-20px;padding-bottom:5px;padding-left:20px;padding-right:20px;padding-top:5px;position:relative;z-index:2}.ep-header-menu:after{clear:both;content:" ";display:block}.ep-header-menu img{float:left}.ep-header-menu .icons{display:inline-block;float:right;height:39px;line-height:39px;padding-right:3px}.ep-header-menu .icons a{color:inherit;cursor:pointer;font-size:27px;margin-left:8px;position:relative;top:-3px;vertical-align:middle}.ep-header-menu .icons .dashicons-admin-generic,.ep-header-menu .icons .dashicons-controls-pause,.ep-header-menu .icons .dashicons-controls-play,.ep-header-menu .icons .dashicons-no,.ep-header-menu .icons .dashicons-update{font-size:30px;top:1px}.ep-header-menu .cancel-sync,.ep-header-menu .pause-sync,.ep-header-menu .resume-sync{display:none}.ep-header-menu .sync-status{bottom:-1px;color:#666;display:none;font-style:italic;margin-right:8px;position:relative;vertical-align:middle}.ep-header-menu .progress-bar{background-color:#d84440;bottom:0;height:5px;left:0;margin-bottom:-5px;position:absolute}.ep-header-menu .icons .dashicons-admin-generic,.ep-header-menu .icons .dashicons-update{display:inline}.ep-features{overflow:auto}.error-overlay.cant-connect,.error-overlay.syncing{background-color:#fff;bottom:0;content:" ";display:block;left:0;opacity:.6;position:fixed;right:0;top:46px;z-index:1}@media (min-width:880px){.error-overlay,.error-overlay.cant-connect,.error-overlay.syncing{left:10pc;top:2pc}}.ep-feature .postbox{margin-bottom:0}.ep-feature .postbox .hndle{cursor:inherit}.ep-feature .postbox .hndle .settings-button{background-color:#efefef;border-radius:4px;color:inherit;cursor:pointer;display:inline-block;float:right;font-size:13px;margin-top:-4px;padding:4px 7px;padding-left:23px;position:relative}.ep-feature .settings-button:before{color:#72777c;content:"\f140";display:inline-block;font:400 19px/1 dashicons;left:1px;padding:0 5px 0 0;position:absolute;top:4px;vertical-align:middle}.ep-feature .settings-button:after{border-radius:50%;content:" ";display:inline-block;height:8px;margin-left:10px;margin-top:-2px;vertical-align:middle;width:8px}.feature-requirements-status-2.ep-feature .postbox .hndle .settings-button:after{background-color:transparent;border:1px solid red;border:1px solid var(--statusError)}.feature-requirements-status-2.ep-feature .settings .requirements-status-notice{border-color:red;border-color:var(--statusError)}.feature-requirements-status-1.ep-feature .postbox .hndle .settings-button:after{background-color:transparent;border:1px solid #e3e600;border:1px solid var(--statusWarning)}.feature-requirements-status-1.ep-feature.feature-active .postbox .hndle .settings-button:after{background-color:#e3e600;background-color:var(--statusWarning)}.feature-requirements-status-1.ep-feature .settings .requirements-status-notice{border-color:#e3e600;border-color:var(--statusWarning)}.feature-requirements-status-0.ep-feature .postbox .hndle .settings-button:after{background-color:transparent;border:1px solid #6aa000;border:1px solid var(--statusOk)}.feature-requirements-status-0.ep-feature.feature-active .postbox .hndle .settings-button:after{background-color:#6aa000;background-color:var(--statusOk)}.feature-requirements-status-0.ep-feature .settings .requirements-status-notice{border-color:#6aa000;border-color:var(--statusOk)}.ep-feature{margin-bottom:20px;position:relative;vertical-align:top}.ep-feature.saving .action-wrap:before{-webkit-animation:load8 1.1s linear infinite;animation:load8 1.1s linear infinite;border-bottom:5px solid #ccc;border-left:5px solid #999;border-radius:50%;border-right:5px solid #ccc;border-top:5px solid #ccc;content:" ";display:inline-block;font-size:7px;height:8px;margin-right:1.4em;position:relative;text-indent:-9999em;top:4px;-webkit-transform:translateZ(0);transform:translateZ(0);vertical-align:middle;width:8px}.ep-feature .description,.ep-feature .settings{margin-bottom:0;text-align:left}.ep-feature .settings{display:none;overflow:auto}.ep-feature .settings h3{font-size:inherit;font-weight:700;margin-top:0}.ep-feature.show-settings .settings{display:block}.ep-feature.show-settings .description{display:none}.ep-feature.show-settings .settings-button:before{content:"\f142"}.ep-feature .settings .requirements-status-notice{background-color:#efefef;border-left:4px solid #6aa000;border-left:4px solid var(--statusOk);margin-bottom:10px;padding:8px 9pt}.ep-feature .settings .action-wrap{clear:both;padding-top:15px;text-align:right;vertical-align:middle}.ep-feature .settings .action-wrap a{cursor:pointer;display:inline-block}.ep-feature .settings .action-wrap .no-dash-sync{color:#aaa;display:none;line-height:27px;padding-right:8px}.ep-feature .settings .action-wrap a.disabled{cursor:default}.ep-feature .settings .action-wrap .cancel{margin-right:6px;margin-top:4px}.ep-feature.dash-sync-disabled .settings .action-wrap .no-dash-sync{display:inline}.ep-feature .settings .field{clear:both;overflow:visible;overflow:initial;padding-top:15px}.ep-feature .settings .field:first-child{padding-top:0}.ep-feature .settings .field label{display:inline-block;margin:.25em 0 .5em}.ep-feature .settings .field div{padding-top:5px}.ep-feature .settings .field .field-name,.ep-feature .settings .field>label{-webkit-box-sizing:border-box;box-sizing:border-box;display:block;float:left;padding-right:1.5em;width:25%}.ep-feature .settings .field .input-wrap{display:block;float:right;width:75%}.ep-feature .settings .field .field-description{color:#666;font-style:italic;margin-bottom:0;margin-top:4px}.ep-feature .settings .field .disabled{color:#bbb}.ep-feature .settings .field .disabled input{cursor:default}.ep-feature .long{display:none}.ep-feature .long p:last-child{margin-bottom:0}.ep-feature.show-full .long{display:block}.ep-feature .collapse,.ep-feature .learn-more{cursor:pointer}.ep-feature.show-full .learn-more{display:none}.ep-feature .learn-more:after{content:"\f140"}.ep-feature .collapse:after,.ep-feature .learn-more:after{font-family:dashicons;font-size:1.5em;position:relative;top:-.07em;vertical-align:middle}.ep-feature .collapse:after{content:"\f142"}.intro h2{line-height:1.2;padding:9px 0 4px 0}.intro h1{color:#626262;font-weight:600;margin:.5em 0 2em;text-align:center}.intro-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;padding-left:10%;padding-right:10%;text-align:center}.intro-box{width:33%}.intro-container a{font-weight:700}.intro-container h2{color:#626262;height:8%}.intro-container p{max-width:300px}.intro-container-success{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;text-align:center}.intro-container-success p{margin-top:23px;padding:0 35% 0 35%}@media (max-width:880px){.intro-container-success p{margin-top:23px;padding:0 26%}}.ep-config-success span{font-size:6em;padding-right:75px}.setup-complete{font-size:2em;width:100%}.setup-complete,.setup-complete h2{margin-top:0;padding-top:0}.ep-copy-text{padding:0 15% 0 15%}@media (max-width:880px){.intro-box{width:auto}.ep-copy-text{padding:0 9% 0 9%}}.ep-circle{border-radius:50%;color:#fff;display:inline-block;font-size:1pc;font-weight:400;height:6em;line-height:2.8em;margin:0 1em;position:relative;text-align:center;width:6em}.ep-circle p{border:0;font-size:50px;font-weight:700;line-height:.5em;margin:0}.red-ep-circle{background-color:#d73c38;color:#fff}.ep-middle-circle:after{background:#d4d4d4;content:"";height:.2em;left:-14em;position:absolute;top:2.9em;width:34em;z-index:-1}@media (max-width:1270px){.ep-middle-circle:after{left:-8em;width:21.9em}}@media (min-width:880px){.wrap h1{line-height:1.75}}.white-ep-circle{background:#fff;color:#626262}.wrap.intro{margin-bottom:30px;margin-top:30px;overflow:auto}.wrap.intro .error,.wrap.intro .is-dismissible,.wrap.intro .notice,.wrap.intro .updated{display:none!important}.features-screenshot{display:none}.setup-message{clear:both;padding:2em 0;text-align:center}.setup-message .setup-button{background-color:#e63e3b;border-radius:10px;-webkit-box-shadow:1px 1px 3px 1px rgba(0,0,0,.25);box-shadow:1px 1px 3px 1px rgba(0,0,0,.25);color:#fff;display:inline-block;margin:0 .75em;padding:1em 1.5em;text-decoration:none}.setup-message .setup-button:hover{background-color:#b93431;color:#ffe8ed}.setup-message .setup-button-primary{background-color:#fff;color:#d84440}.weighting-settings .postbox{max-width:650px}.weighting-settings .postbox,.weighting-settings .postbox *{-webkit-box-sizing:border-box;box-sizing:border-box}.weighting-settings .postbox h2.hndle{color:#444;cursor:inherit}.weighting-settings fieldset{padding:10px}.weighting-settings fieldset legend{float:left;position:relative;top:5px;width:75pt}.weighting-settings fieldset p{display:inline-block;float:left;margin:0}.weighting-settings .field-group{margin:10px 0 0}.weighting-settings .field-group h3{font-size:1em;margin:10px}.weighting-settings .fields>fieldset:nth-of-type(odd){background:#f9f9f9}.weighting-settings .searchable{display:inline-block;width:90pt}.weighting-settings .weighting{-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex}.weighting-settings .weighting label{margin-right:10px;min-width:5pc}.weighting-settings input[type=range]{-webkit-appearance:none;background:transparent;display:inline-block;height:1em;margin:0;vertical-align:middle;width:200px}.weighting-settings input[type=range]:focus{outline:none}.weighting-settings input[type=range]:disabled{opacity:.5;pointer-events:none}.weighting-settings input[type=range]::-webkit-slider-runnable-track{background:#ddd;border:0 solid #000;border-radius:1px;-webkit-box-shadow:0 0 0 #000;box-shadow:0 0 0 #000;cursor:pointer;height:3px;width:100%}.weighting-settings input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;background:#1e8cbe;border:1px solid #1e8cbe;border-radius:25px;-webkit-box-shadow:0 0 0 #000;box-shadow:0 0 0 #000;cursor:pointer;height:14px;margin-top:-6px;width:14px}.weighting-settings input[type=range]:focus::-webkit-slider-runnable-track{background:#ddd}.weighting-settings input[type=range]:focus::-webkit-slider-thumb{background:#fff!important}.weighting-settings input[type=range]::-moz-range-track{background:#1e8cbe;border:0 solid #000;border-radius:1px;box-shadow:0 0 0 #000;cursor:pointer;height:3px;width:100%}.weighting-settings input[type=range]::-moz-range-thumb{background:#1e8cbe;border:1px solid #1e8cbe;border-radius:25px;box-shadow:0 0 0 #000;cursor:pointer;height:14px;width:14px}.weighting-settings input[type=range]::-ms-track{background:transparent;border-color:transparent;color:transparent;cursor:pointer;height:3px;width:100%}.weighting-settings input[type=range]::-ms-fill-lower,.weighting-settings input[type=range]::-ms-fill-upper{background:#1e8cbe;border:0 solid #000;border-radius:2px;box-shadow:0 0 0 #000}.weighting-settings input[type=range]::-ms-thumb{background:#a1d0ff;border:1px solid #1e8cbe;border-radius:25px;box-shadow:0 0 0 #000;cursor:pointer;height:14px;margin-top:1px;width:14px}.weighting-settings input[type=range]:focus::-ms-fill-lower,.weighting-settings input[type=range]:focus::-ms-fill-upper{background:#1e8cbe}.ep-feature-search .wp-color-result.button{margin-bottom:10px}.ep-feature.ep-feature-search .settings .wp-picker-input-wrap>label{margin-right:10px;margin-top:0}.ep-feature.ep-feature-search .settings.wp-picker-input-wrap label{-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex}.ep-feature.ep-feature-search .settings .wp-picker-open+.wp-picker-input-wrap{display:-webkit-box;display:-ms-flexbox;display:flex}@-webkit-keyframes load8{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes load8{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@media (min-width:880px){.intro .left{float:left;width:30%}.features-screenshot{display:block;float:right;height:auto;margin:0 auto;max-width:750pt;width:70%}.ep-features .left{float:left;padding-right:10px}.ep-features .left,.ep-features .right{-webkit-box-sizing:border-box;box-sizing:border-box;display:block;width:50%}.ep-features .right{float:right;padding-left:10px}.ep-feature .feature-message{display:inline-block;float:left;padding:0;padding-top:.5em;vertical-align:middle}}.wrap h2.nav-tab-wrapper.ep-credentials-tabs{border-bottom:1px solid #ccc}.ep-credentials input[type=text]{min-width:250px}h2 .nav-tab.ep-credentials-tab{cursor:pointer;margin-bottom:-1px}.ep-credentials-tab.nav-tab-active{border-bottom-color:#f1f1f1}.ep-credentials-tab img,.ep-credentials-tab span{display:inline-block;vertical-align:middle}.ep-credentials fieldset{border-bottom:1px solid #ccc;border-left:1px solid #ccc;border-right:1px solid #ccc;margin:0;padding:0 1rem}.ep-credentials fieldset.predefined{border-top:1px solid #ccc}.ep-settings .description{font-size:.75rem;font-style:italic}@media (min-width:880px){.ep-credentials{display:inline-block}.ep-credentials .form-table{width:auto}.ep-credentials .form-table td{padding-left:0}}.ep-flex-container{-ms-flex-wrap:wrap;flex-wrap:wrap}.ep-flex-container,.ep-flex-container-nowrap{display:-webkit-box;display:-ms-flexbox;display:flex;width:100%}.stats-list{margin-right:0;width:100%}@media (min-width:1270px){.stats-list{background-color:#fff;margin-right:28px;width:37%}}.stats-queries{background-color:#fff;width:100%}@media (min-width:1270px){.stats-queries{width:60%}}.stats-list-th span:last-of-type{border-radius:4px;color:inherit;cursor:pointer;display:inline-block;float:right;font-size:13px;margin-top:-4px;padding:4px 7px;padding-left:23px;position:relative}.status-circle{float:right;text-transform:capitalize}.status-circle:after{border-radius:50%;content:" ";display:inline-block;height:8px;margin-left:10px;margin-top:-2px;vertical-align:middle;width:8px}.green-status{color:#6aa000;color:var(--statusOk)}.yellow-status{color:#e3e600;color:var(--statusWarning)}.red-status{color:red;color:var(--statusError)}.green-status:after{background-color:#6aa000;background-color:var(--statusOk)}.yellow-status:after{background-color:#e3e600;background-color:var(--statusWarning)}.red-status:after{background-color:red;background-color:var(--statusError)}.doc-chart{margin-right:0;width:100%}@media (min-width:880px){.doc-chart{margin-right:24px;width:48%}}@media (min-width:1270px){.doc-chart{margin-right:28px;width:50%}}.ep-qchart-container{margin:0 auto;width:90%}@media (min-width:880px){.ep-qchart-container{width:48%}}@media (min-width:1270px){.ep-qchart-container{margin:0 auto;width:50%}}.inside-totals{padding:0 9pt 9pt}.ep-totals{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;width:100%}@media (min-width:880px){.ep-totals{width:48%}}@media (min-width:1270px){.ep-totals{width:47%}}.ep-totals .ep-flex-container{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;margin-bottom:auto;margin-top:auto}@media (min-width:1270px){.ep-totals .ep-flex-container{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}}.ep-totals-column{-webkit-box-sizing:border-box;box-sizing:border-box;text-align:center;width:100%}@media (min-width:1270px){.ep-totals-column{width:50%}}p.ep-totals-title{font-weight:bolder;margin-top:28px}p.ep-totals-data{font-size:3em;margin-top:22px}
+:root{--statusOk:#6aa000;--statusWarning:#e3e600;--statusError:red}.wrap .notice,.wrap>h2{position:relative;z-index:2}.wrap h1{font-size:23px;font-weight:400;line-height:29px;margin:0;padding:9px 0 4px}.wrap h2{color:#888;line-height:1.75;margin:.5em 0 .75em}#wpbody #update-nag,#wpbody .update-nag{margin-bottom:20px;margin-left:-20px;margin-top:0;width:100%}h2.ep-list-features{display:none}.ep-header-menu{background-color:#fff;border-bottom:2px solid #ddd;margin-left:-20px;padding-bottom:5px;padding-left:20px;padding-right:20px;padding-top:5px;position:relative;z-index:2}.ep-header-menu:after{clear:both;content:" ";display:block}.ep-header-menu img{float:left}.ep-header-menu .icons{display:inline-block;float:right;height:39px;line-height:39px;padding-right:3px}.ep-header-menu .icons a{color:inherit;cursor:pointer;font-size:27px;margin-left:8px;position:relative;top:-3px;vertical-align:middle}.ep-header-menu .icons .dashicons-admin-generic,.ep-header-menu .icons .dashicons-controls-pause,.ep-header-menu .icons .dashicons-controls-play,.ep-header-menu .icons .dashicons-no,.ep-header-menu .icons .dashicons-update{font-size:30px;top:1px}.ep-header-menu .cancel-sync,.ep-header-menu .pause-sync,.ep-header-menu .resume-sync{display:none}.ep-header-menu .sync-status{bottom:-1px;color:#666;display:none;font-style:italic;margin-right:8px;position:relative;vertical-align:middle}.ep-header-menu .progress-bar{background-color:#d84440;bottom:0;height:5px;left:0;margin-bottom:-5px;position:absolute}.ep-header-menu .icons .dashicons-admin-generic,.ep-header-menu .icons .dashicons-update{display:inline}.ep-features{overflow:auto}.error-overlay.cant-connect,.error-overlay.syncing{background-color:#fff;bottom:0;content:" ";display:block;left:0;opacity:.6;position:fixed;right:0;top:46px;z-index:1}@media (min-width:880px){.error-overlay,.error-overlay.cant-connect,.error-overlay.syncing{left:10pc;top:2pc}}.ep-feature .postbox{margin-bottom:0}.ep-feature .postbox .hndle{cursor:inherit}.ep-feature .postbox .hndle .settings-button{background-color:#efefef;border-radius:4px;color:inherit;cursor:pointer;display:inline-block;float:right;font-size:13px;margin-top:-4px;padding:4px 7px;padding-left:23px;position:relative}.ep-feature .settings-button:before{color:#72777c;content:"\f140";display:inline-block;font:400 19px/1 dashicons;left:1px;padding:0 5px 0 0;position:absolute;top:4px;vertical-align:middle}.ep-feature .settings-button:after{border-radius:50%;content:" ";display:inline-block;height:8px;margin-left:10px;margin-top:-2px;vertical-align:middle;width:8px}.feature-requirements-status-2.ep-feature .postbox .hndle .settings-button:after{background-color:transparent;border:1px solid #f00;border:1px solid var(--statusError)}.feature-requirements-status-2.ep-feature .settings .requirements-status-notice{border-color:#f00;border-color:var(--statusError)}.feature-requirements-status-1.ep-feature .postbox .hndle .settings-button:after{background-color:transparent;border:1px solid #e3e600;border:1px solid var(--statusWarning)}.feature-requirements-status-1.ep-feature.feature-active .postbox .hndle .settings-button:after{background-color:#e3e600;background-color:var(--statusWarning)}.feature-requirements-status-1.ep-feature .settings .requirements-status-notice{border-color:#e3e600;border-color:var(--statusWarning)}.feature-requirements-status-0.ep-feature .postbox .hndle .settings-button:after{background-color:transparent;border:1px solid #6aa000;border:1px solid var(--statusOk)}.feature-requirements-status-0.ep-feature.feature-active .postbox .hndle .settings-button:after{background-color:#6aa000;background-color:var(--statusOk)}.feature-requirements-status-0.ep-feature .settings .requirements-status-notice{border-color:#6aa000;border-color:var(--statusOk)}.ep-feature{margin-bottom:20px;position:relative;vertical-align:top}.ep-feature.saving .action-wrap:before{-webkit-animation:load8 1.1s linear infinite;animation:load8 1.1s linear infinite;border-bottom:5px solid #ccc;border-left:5px solid #999;border-radius:50%;border-right:5px solid #ccc;border-top:5px solid #ccc;content:" ";display:inline-block;font-size:7px;height:8px;margin-right:1.4em;position:relative;text-indent:-9999em;top:4px;-webkit-transform:translateZ(0);transform:translateZ(0);vertical-align:middle;width:8px}.ep-feature .description,.ep-feature .settings{margin-bottom:0;text-align:left}.ep-feature .settings{display:none;overflow:auto}.ep-feature .settings h3{font-size:inherit;font-weight:700;margin-top:0}.ep-feature.show-settings .settings{display:block}.ep-feature.show-settings .description{display:none}.ep-feature.show-settings .settings-button:before{content:"\f142"}.ep-feature .settings .requirements-status-notice{background-color:#efefef;border-left:4px solid #6aa000;border-left:4px solid var(--statusOk);margin-bottom:10px;padding:8px 9pt}.ep-feature .settings .action-wrap{clear:both;padding-top:15px;text-align:right;vertical-align:middle}.ep-feature .settings .action-wrap a{cursor:pointer;display:inline-block}.ep-feature .settings .action-wrap .no-dash-sync{color:#aaa;display:none;line-height:27px;padding-right:8px}.ep-feature .settings .action-wrap a.disabled{cursor:default}.ep-feature .settings .action-wrap .cancel{margin-right:6px;margin-top:4px}.ep-feature.dash-sync-disabled .settings .action-wrap .no-dash-sync{display:inline}.ep-feature .settings .field{clear:both;overflow:visible;overflow:initial;padding-top:15px}.ep-feature .settings .field:first-child{padding-top:0}.ep-feature .settings .field label{display:inline-block;margin:.25em 0 .5em}.ep-feature .settings .field div{padding-top:5px}.ep-feature .settings .field .field-name,.ep-feature .settings .field>label{-webkit-box-sizing:border-box;box-sizing:border-box;display:block;float:left;padding-right:1.5em;width:25%}.ep-feature .settings .field .input-wrap{display:block;float:right;width:75%}.ep-feature .settings .field .field-description{color:#666;font-style:italic;margin-bottom:0;margin-top:4px}.ep-feature .settings .field .disabled{color:#bbb}.ep-feature .settings .field .disabled input{cursor:default}.ep-feature .long{display:none}.ep-feature .long p:last-child{margin-bottom:0}.ep-feature.show-full .long{display:block}.ep-feature .collapse,.ep-feature .learn-more{cursor:pointer}.ep-feature.show-full .learn-more{display:none}.ep-feature .learn-more:after{content:"\f140";font-family:dashicons;font-size:1.5em;position:relative;top:-.07em;vertical-align:middle}.ep-feature .collapse:after{content:"\f142";font-family:dashicons;font-size:1.5em;position:relative;top:-.07em;vertical-align:middle}.intro h2{line-height:1.2;padding:9px 0 4px 0}.intro h1{color:#626262;font-weight:600;margin:.5em 0 2em;text-align:center}.intro-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;padding-left:10%;padding-right:10%;text-align:center}.intro-box{width:33%}.intro-container a{font-weight:700}.intro-container h2{color:#626262;height:8%}.intro-container p{max-width:300px}.intro-container-success{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;text-align:center}.intro-container-success p{margin-top:23px;padding:0 35% 0 35%}@media (max-width:880px){.intro-container-success p{margin-top:23px;padding:0 26%}}.ep-config-success span{font-size:6em;padding-right:75px}.setup-complete{font-size:2em;margin-top:0;padding-top:0;width:100%}.setup-complete h2{margin-top:0;padding-top:0}.ep-copy-text{padding:0 15% 0 15%}@media (max-width:880px){.intro-box{width:auto}.ep-copy-text{padding:0 9% 0 9%}}.ep-circle{border-radius:50%;color:#fff;display:inline-block;font-size:1pc;font-weight:400;height:6em;line-height:2.8em;margin:0 1em;position:relative;text-align:center;width:6em}.ep-circle p{border:0;font-size:50px;font-weight:700;line-height:.5em;margin:0}.red-ep-circle{background-color:#d73c38;color:#fff}.ep-middle-circle:after{background:#d4d4d4;content:"";height:.2em;left:-14em;position:absolute;top:2.9em;width:34em;z-index:-1}@media (max-width:1270px){.ep-middle-circle:after{left:-8em;width:21.9em}}@media (min-width:880px){.wrap h1{line-height:1.75}}.white-ep-circle{background:#fff;color:#626262}.wrap.intro{margin-bottom:30px;margin-top:30px;overflow:auto}.wrap.intro .error,.wrap.intro .is-dismissible,.wrap.intro .notice,.wrap.intro .updated{display:none!important}.features-screenshot{display:none}.setup-message{clear:both;padding:2em 0;text-align:center}.setup-message .setup-button{background-color:#e63e3b;border-radius:10px;-webkit-box-shadow:1px 1px 3px 1px rgba(0,0,0,.25);box-shadow:1px 1px 3px 1px rgba(0,0,0,.25);color:#fff;display:inline-block;margin:0 .75em;padding:1em 1.5em;text-decoration:none}.setup-message .setup-button:hover{background-color:#b93431;color:#ffe8ed}.setup-message .setup-button-primary{background-color:#fff;color:#d84440}.weighting-settings .postbox{-webkit-box-sizing:border-box;box-sizing:border-box;max-width:650px}.weighting-settings .postbox *{-webkit-box-sizing:border-box;box-sizing:border-box}.weighting-settings .postbox h2.hndle{color:#444;cursor:inherit}.weighting-settings fieldset{padding:10px}.weighting-settings fieldset legend{float:left;position:relative;top:5px;width:75pt}.weighting-settings fieldset p{display:inline-block;float:left;margin:0}.weighting-settings .field-group{margin:10px 0 0}.weighting-settings .field-group h3{font-size:1em;margin:10px}.weighting-settings .fields>fieldset:nth-of-type(odd){background:#f9f9f9}.weighting-settings .searchable{display:inline-block;width:90pt}.weighting-settings .weighting{-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex}.weighting-settings .weighting label{margin-right:10px;min-width:5pc}.weighting-settings input[type=range]{-webkit-appearance:none;background:transparent;display:inline-block;height:1em;margin:0;vertical-align:middle;width:200px}.weighting-settings input[type=range]:focus{outline:none}.weighting-settings input[type=range]:disabled{opacity:.5;pointer-events:none}.weighting-settings input[type=range]::-webkit-slider-runnable-track{background:#ddd;border:0 solid #000;border-radius:1px;-webkit-box-shadow:0 0 0 #000;box-shadow:0 0 0 #000;cursor:pointer;height:3px;width:100%}.weighting-settings input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;background:#1e8cbe;border:1px solid #1e8cbe;border-radius:25px;-webkit-box-shadow:0 0 0 #000;box-shadow:0 0 0 #000;cursor:pointer;height:14px;margin-top:-6px;width:14px}.weighting-settings input[type=range]:focus::-webkit-slider-runnable-track{background:#ddd}.weighting-settings input[type=range]:focus::-webkit-slider-thumb{background:#fff!important}.weighting-settings input[type=range]::-moz-range-track{background:#1e8cbe;border:0 solid #000;border-radius:1px;box-shadow:0 0 0 #000;cursor:pointer;height:3px;width:100%}.weighting-settings input[type=range]::-moz-range-thumb{background:#1e8cbe;border:1px solid #1e8cbe;border-radius:25px;box-shadow:0 0 0 #000;cursor:pointer;height:14px;width:14px}.weighting-settings input[type=range]::-ms-track{background:transparent;border-color:transparent;color:transparent;cursor:pointer;height:3px;width:100%}.weighting-settings input[type=range]::-ms-fill-lower{background:#1e8cbe;border:0 solid #000;border-radius:2px;box-shadow:0 0 0 #000}.weighting-settings input[type=range]::-ms-fill-upper{background:#1e8cbe;border:0 solid #000;border-radius:2px;box-shadow:0 0 0 #000}.weighting-settings input[type=range]::-ms-thumb{background:#a1d0ff;border:1px solid #1e8cbe;border-radius:25px;box-shadow:0 0 0 #000;cursor:pointer;height:14px;margin-top:1px;width:14px}.weighting-settings input[type=range]:focus::-ms-fill-lower{background:#1e8cbe}.weighting-settings input[type=range]:focus::-ms-fill-upper{background:#1e8cbe}.ep-feature-search .wp-color-result.button{margin-bottom:10px}.ep-feature.ep-feature-search .settings .wp-picker-input-wrap>label{margin-right:10px;margin-top:0}.ep-feature.ep-feature-search .settings.wp-picker-input-wrap label{-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex}.ep-feature.ep-feature-search .settings .wp-picker-open+.wp-picker-input-wrap{display:-webkit-box;display:-ms-flexbox;display:flex}@-webkit-keyframes load8{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes load8{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@media (min-width:880px){.intro .left{float:left;width:30%}.features-screenshot{display:block;float:right;height:auto;margin:0 auto;max-width:750pt;width:70%}.ep-features .left{-webkit-box-sizing:border-box;box-sizing:border-box;display:block;float:left;padding-right:10px;width:50%}.ep-features .right{-webkit-box-sizing:border-box;box-sizing:border-box;display:block;float:right;padding-left:10px;width:50%}.ep-feature .feature-message{display:inline-block;float:left;padding:0;padding-top:.5em;vertical-align:middle}}.wrap h2.nav-tab-wrapper.ep-credentials-tabs{border-bottom:1px solid #ccc}.ep-credentials input[type=text]{min-width:250px}h2 .nav-tab.ep-credentials-tab{cursor:pointer;margin-bottom:-1px}.ep-credentials-tab.nav-tab-active{border-bottom-color:#f1f1f1}.ep-credentials-tab img,.ep-credentials-tab span{display:inline-block;vertical-align:middle}.ep-credentials fieldset{border-bottom:1px solid #ccc;border-left:1px solid #ccc;border-right:1px solid #ccc;margin:0;padding:0 1rem}.ep-credentials fieldset.predefined{border-top:1px solid #ccc}.ep-settings .description{font-size:.75rem;font-style:italic}@media (min-width:880px){.ep-credentials{display:inline-block}.ep-credentials .form-table{width:auto}.ep-credentials .form-table td{padding-left:0}}.ep-flex-container{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;width:100%}.ep-flex-container-nowrap{display:-webkit-box;display:-ms-flexbox;display:flex;width:100%}.stats-list{margin-right:0;width:100%}@media (min-width:1270px){.stats-list{background-color:#fff;margin-right:28px;width:37%}}.stats-queries{background-color:#fff;width:100%}@media (min-width:1270px){.stats-queries{width:60%}}.stats-list-th span:last-of-type{border-radius:4px;color:inherit;cursor:pointer;display:inline-block;float:right;font-size:13px;margin-top:-4px;padding:4px 7px;padding-left:23px;position:relative}.status-circle{float:right;text-transform:capitalize}.status-circle:after{border-radius:50%;content:" ";display:inline-block;height:8px;margin-left:10px;margin-top:-2px;vertical-align:middle;width:8px}.green-status{color:#6aa000;color:var(--statusOk)}.yellow-status{color:#e3e600;color:var(--statusWarning)}.red-status{color:#f00;color:var(--statusError)}.green-status:after{background-color:#6aa000;background-color:var(--statusOk)}.yellow-status:after{background-color:#e3e600;background-color:var(--statusWarning)}.red-status:after{background-color:#f00;background-color:var(--statusError)}.doc-chart{margin-right:0;width:100%}@media (min-width:880px){.doc-chart{margin-right:24px;width:48%}}@media (min-width:1270px){.doc-chart{margin-right:28px;width:50%}}.ep-qchart-container{margin:0 auto;width:90%}@media (min-width:880px){.ep-qchart-container{width:48%}}@media (min-width:1270px){.ep-qchart-container{margin:0 auto;width:50%}}.inside-totals{padding:0 9pt 9pt}.ep-totals{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;width:100%}@media (min-width:880px){.ep-totals{width:48%}}@media (min-width:1270px){.ep-totals{width:47%}}.ep-totals .ep-flex-container{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;margin-bottom:auto;margin-top:auto}@media (min-width:1270px){.ep-totals .ep-flex-container{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}}.ep-totals-column{-webkit-box-sizing:border-box;box-sizing:border-box;text-align:center;width:100%}@media (min-width:1270px){.ep-totals-column{width:50%}}p.ep-totals-title{font-weight:bolder;margin-top:28px}p.ep-totals-data{font-size:3em;margin-top:22px}
diff --git a/dist/css/facets-admin-styles.min.asset.php b/dist/css/facets-admin-styles.min.asset.php
new file mode 100644
index 0000000000..20d8091eba
--- /dev/null
+++ b/dist/css/facets-admin-styles.min.asset.php
@@ -0,0 +1 @@
+ array(), 'version' => '62b4efb5a1eb12c5c0913abc1339cb6d');
\ No newline at end of file
diff --git a/dist/css/facets-styles.min.asset.php b/dist/css/facets-styles.min.asset.php
new file mode 100644
index 0000000000..36fb5c1f45
--- /dev/null
+++ b/dist/css/facets-styles.min.asset.php
@@ -0,0 +1 @@
+ array(), 'version' => '673f67e087d92e2427870d8f576671b4');
\ No newline at end of file
diff --git a/dist/css/facets-styles.min.css b/dist/css/facets-styles.min.css
index c5dfbee479..a344dbae9b 100644
--- a/dist/css/facets-styles.min.css
+++ b/dist/css/facets-styles.min.css
@@ -1 +1 @@
-.widget_ep-facet input[type=search]{margin-bottom:1rem}.widget_ep-facet .searchable .inner{max-height:20em;overflow:scroll}.widget_ep-facet .term.hide{display:none}.widget_ep-facet .empty-term{opacity:.5;position:relative}.widget_ep-facet .empty-term:after{bottom:0;content:" ";display:block;left:0;position:absolute;right:0;top:0;width:100%;z-index:2}.widget_ep-facet .level-1{padding-left:20px}.widget_ep-facet .level-2{padding-left:40px}.widget_ep-facet .level-3{padding-left:60px}.widget_ep-facet .level-4{padding-left:5pc}.widget_ep-facet .level-5{padding-left:75pt}.widget_ep-facet input[disabled]{cursor:pointer;opacity:1}.widget_ep-facet .term a{position:relative}.ep-checkbox,.widget_ep-facet .term a{-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex}.ep-checkbox{background-color:#eee;-ms-flex-negative:0;flex-shrink:0;height:1em;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;margin-right:.25em;width:1em}.ep-checkbox:after{border:solid #fff;border-width:0 .125em .125em 0;content:"";display:none;height:.5em;-webkit-transform:rotate(45deg);transform:rotate(45deg);width:.25em}.ep-checkbox.checked{background-color:#5e5e5e}.ep-checkbox.checked:after{display:block}.widget_ep-facet .term a:hover .ep-checkbox{background-color:#ccc}
+.widget_ep-facet input[type=search]{margin-bottom:1rem}.widget_ep-facet .searchable .inner{max-height:20em;overflow:scroll}.widget_ep-facet .term.hide{display:none}.widget_ep-facet .empty-term{opacity:.5;position:relative}.widget_ep-facet .empty-term:after{bottom:0;content:" ";display:block;left:0;position:absolute;right:0;top:0;width:100%;z-index:2}.widget_ep-facet .level-1{padding-left:20px}.widget_ep-facet .level-2{padding-left:40px}.widget_ep-facet .level-3{padding-left:60px}.widget_ep-facet .level-4{padding-left:5pc}.widget_ep-facet .level-5{padding-left:75pt}.widget_ep-facet input[disabled]{cursor:pointer;opacity:1}.widget_ep-facet .term a{-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex;position:relative}.ep-checkbox{-webkit-box-align:center;-ms-flex-align:center;align-items:center;background-color:#eee;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-negative:0;flex-shrink:0;height:1em;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;margin-right:.25em;width:1em}.ep-checkbox:after{border:solid #fff;border-width:0 .125em .125em 0;content:"";display:none;height:.5em;-webkit-transform:rotate(45deg);transform:rotate(45deg);width:.25em}.ep-checkbox.checked{background-color:#5e5e5e}.ep-checkbox.checked:after{display:block}.widget_ep-facet .term a:hover .ep-checkbox{background-color:#ccc}
diff --git a/dist/css/highlighting-styles.min.asset.php b/dist/css/highlighting-styles.min.asset.php
new file mode 100644
index 0000000000..fd90c77303
--- /dev/null
+++ b/dist/css/highlighting-styles.min.asset.php
@@ -0,0 +1 @@
+ array(), 'version' => '60d6246eadb2aaaf679e2a0632fa6f9c');
\ No newline at end of file
diff --git a/dist/css/instant-results-styles.min.asset.php b/dist/css/instant-results-styles.min.asset.php
new file mode 100644
index 0000000000..c2d81158e2
--- /dev/null
+++ b/dist/css/instant-results-styles.min.asset.php
@@ -0,0 +1 @@
+ array(), 'version' => '33115981671556b65a81c3a4ec06ab07');
\ No newline at end of file
diff --git a/dist/css/instant-results-styles.min.css b/dist/css/instant-results-styles.min.css
new file mode 100644
index 0000000000..d22dcdba14
--- /dev/null
+++ b/dist/css/instant-results-styles.min.css
@@ -0,0 +1 @@
+.ep-search-reset-button{font:inherit!important;height:auto!important;letter-spacing:inherit!important;line-height:1!important;margin:0!important;padding:0!important;text-align:inherit!important;text-transform:inherit!important;width:auto!important}.ep-search-reset-button,.ep-search-reset-button:focus,.ep-search-reset-button:hover{background:transparent!important;border:none!important;-webkit-box-shadow:none!important;box-shadow:none!important;color:inherit!important;cursor:default!important}.ep-search-reset-button:focus{outline:medium auto Highlight!important;outline:medium auto -webkit-focus-ring-color!important;outline-offset:0!important}.ep-search-small-button{font-size:.875em!important;height:auto!important;line-height:1!important;padding:.5em!important}.ep-search-icon-button{-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.ep-search-icon-button svg{fill:currentColor;-ms-flex-negative:0;flex-shrink:0;height:1em;width:1em}.ep-search-input{font-size:1.25em;margin:0!important;width:100%}.has-ep-search-modal{overflow:hidden}.ep-search-modal{--ep-search-modal-focus-within:0;background-color:rgba(43,46,56,.9);bottom:0;display:-webkit-box;display:-ms-flexbox;display:flex;left:0;position:fixed;right:0;top:0;z-index:9999}.rtl .ep-search-modal{direction:rtl;text-align:right}.admin-bar .ep-search-modal{top:2pc}@media (max-width:782px){.admin-bar .ep-search-modal{top:46px}}.ep-search-modal[aria-hidden=true]{display:none}.ep-search-modal[focus-within]{--ep-search-modal-focus-within:1}.ep-search-modal:focus-within{--ep-search-modal-focus-within:1}.ep-search-modal__content{background-color:#fff;background-color:var(--ep-search-background-color);bottom:0;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;left:0;position:absolute;right:0;top:0}@media (min-width:768px){.ep-search-modal__content{bottom:1em;margin:0 auto;max-width:calc(100% - 2em);top:1em;width:80em}}.ep-search-modal__close{-ms-flex-item-align:end;align-self:flex-end;padding:1em!important}.ep-search-options-list{list-style:none;margin:0;padding:0}.ep-search-options-list__item{margin:.5em 0}.ep-search-options-list__item:before{content:none}.ep-search-options-list__sub-menu{padding-left:1em}.ep-search-page{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-flex:2;-ms-flex-positive:2;flex-grow:2;margin:0;overflow-y:auto;-webkit-transition:opacity .3s ease-out;transition:opacity .3s ease-out;width:100%}@media (min-width:768px){.ep-search-page{overflow:hidden}}.ep-search-page *,.ep-search-page :after,.ep-search-page :before{-webkit-box-sizing:border-box;box-sizing:border-box}.ep-search-page.is-loading{opacity:.5}.ep-search-page__body,.ep-search-page__header,.ep-search-page__tools{padding:0 1em}@media (min-width:768px){.ep-search-page__body{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:2;-ms-flex-positive:2;flex-grow:2;overflow:hidden}}.ep-search-panel{border:1px solid #dfdfdf;border:1px solid var(--ep-search-border-color);margin:0;padding:0}.ep-search-panel + .ep-search-panel{border-top-width:0}.ep-search-panel__heading{font-size:inherit;margin:0}.ep-search-panel__button{padding:1em!important;width:100%!important}.ep-search-panel__content{padding:0 1em 1em 1em}.ep-search-panel__content[aria-hidden=true]{display:none}.ep-search-pagination{-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-ms-grid;display:grid;-ms-grid-columns:1fr 1fr 1fr;grid-template-columns:1fr 1fr 1fr;margin-top:auto;text-align:center}.rtl .ep-search-pagination{direction:rtl}.ep-search-pagination__next{-ms-grid-column-align:end;justify-self:end}.ep-search-pagination__previous{-ms-grid-column-align:start;justify-self:start}.ep-search-range-slider{-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex;margin:.5em 0;min-height:1.625em;min-height:var(--ep-search-range-thumb-size)}.ep-search-range-slider__track{background:#efefef;background:var(--ep-search-alternate-background-color);border-radius:calc(0.75em/2);border-radius:calc(var(--ep-search-range-track-size)/2);height:0.75em;height:var(--ep-search-range-track-size)}.ep-search-range-slider__track-1{background-color:currentColor}.ep-search-range-slider__thumb{background-color:currentColor;border-radius:calc(1.625em/2);border-radius:calc(var(--ep-search-range-thumb-size)/2);-webkit-box-shadow:inset 0 0 0 calc(1.625em/10) currentColor,inset 0 0 0 calc(1.625em/2 - 0.75em/2) #fff;box-shadow:inset 0 0 0 calc(1.625em/10) currentColor,inset 0 0 0 calc(1.625em/2 - 0.75em/2) #fff;-webkit-box-shadow:inset 0 0 0 calc(var(--ep-search-range-thumb-size)/10) currentColor,inset 0 0 0 calc(var(--ep-search-range-thumb-size)/2 - var(--ep-search-range-track-size)/2) var(--ep-search-background-color);box-shadow:inset 0 0 0 calc(var(--ep-search-range-thumb-size)/10) currentColor,inset 0 0 0 calc(var(--ep-search-range-thumb-size)/2 - var(--ep-search-range-track-size)/2) var(--ep-search-background-color);height:1.625em;height:var(--ep-search-range-thumb-size);width:1.625em;width:var(--ep-search-range-thumb-size)}.ep-search-result{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start;display:-ms-grid;display:grid;grid-gap:.5em;grid-template-areas:"header" "footer";-ms-grid-rows:auto .5em 1fr;grid-template-rows:auto 1fr}@media (min-width:768px){.ep-search-result{grid-gap:1em;grid-template-areas:"header" "description" "footer";-ms-grid-rows:auto 1em auto 1em 1fr;grid-template-rows:auto auto 1fr}}.ep-search-result--has-thumbnail{grid-template-areas:"thumbnail header" "thumbnail footer";-ms-grid-columns:min(300px,34%) auto;grid-template-columns:min(300px,34%) auto}@media (min-width:768px){.ep-search-result--has-thumbnail{grid-template-areas:"thumbnail header" "thumbnail description" "thumbnail footer"}}.ep-search-result__thumbnail{-ms-grid-row:1;-ms-grid-row-span:2;-ms-grid-column:1;display:block;grid-area:thumbnail}.ep-search-result__thumbnail img{display:block;margin:0;width:100%}.ep-search-result__header{-ms-grid-row:1;-ms-grid-column:1;display:-ms-grid;display:grid;grid-area:header;grid-gap:.5em;-ms-grid-columns:auto;grid-template-columns:auto;justify-items:start}.ep-search-result--has-thumbnail > .ep-search-result__header{-ms-grid-row:1;-ms-grid-column:2}.ep-search-result__title{font-size:1em;margin:0}@media (min-width:768px){.ep-search-result__title{font-size:1.25em}}.ep-search-result__type{background-color:#efefef;background-color:var(--ep-search-alternate-background-color);border-radius:.25em;display:inline-block;font-size:.875em;line-height:1.5;padding:0 .25em;vertical-align:text-bottom}.ep-search-result__description{display:none;font-size:.875em;grid-area:description;margin:0}@media (min-width:768px){.ep-search-result__description{display:block;font-size:1em}}.ep-search-result__footer{-ms-grid-row:3;-ms-grid-column:1;display:-ms-grid;display:grid;grid-area:footer;grid-gap:.5em;justify-items:start}.ep-search-result--has-thumbnail > .ep-search-result__footer{-ms-grid-row:2;-ms-grid-column:2}@media (min-width:768px){.ep-search-result__thumbnail{-ms-grid-row:1;-ms-grid-row-span:3;-ms-grid-column:1}.ep-search-result__header{-ms-grid-row:1;-ms-grid-column:1}.ep-search-result--has-thumbnail > .ep-search-result__header{-ms-grid-row:1;-ms-grid-column:2}.ep-search-result__description{-ms-grid-row:3;-ms-grid-column:1}.ep-search-result__description{-ms-grid-row:2;-ms-grid-column:2}.ep-search-result__footer{-ms-grid-row:5;-ms-grid-column:1}.ep-search-result--has-thumbnail > .ep-search-result__footer{-ms-grid-row:3;-ms-grid-column:2}}.ep-search-results{display:-ms-grid;display:grid;grid-gap:2em;-ms-grid-columns:100%;grid-template-columns:100%;-ms-grid-rows:-webkit-max-content;-ms-grid-rows:max-content;grid-template-rows:-webkit-max-content;grid-template-rows:max-content;padding:0 0 1em 0;width:100%}@media (min-width:768px){.ep-search-results{height:100%;overflow-y:auto;padding:0 1em 1em 1em}}.ep-search-results__header{-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex;gap:1em;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.ep-search-results__title{font-size:1.25em;margin:0!important}@media (min-width:768px){.ep-search-results__title{font-size:1.5em}}.ep-search-sidebar{display:none;margin-bottom:2em}.ep-search-sidebar.is-open{display:block}@media (min-width:768px){.ep-search-sidebar{display:block;max-height:calc(100% - 1em);min-width:25%;overflow-y:auto}}.ep-search-sidebar-toggle{width:100%}@media (min-width:768px){.ep-search-sidebar-toggle{display:none}}.ep-search-sort{-ms-flex-negative:0;flex-shrink:0;gap:.5em;margin:0}.ep-search-results .ep-search-sort{display:none}@media (min-width:768px){.ep-search-results .ep-search-sort{-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex}}.ep-search-sidebar .ep-search-sort{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;margin-bottom:1em}@media (min-width:768px){.ep-search-sidebar .ep-search-sort{display:none}}.ep-search-toolbar{-webkit-box-align:start;-ms-flex-align:start;align-items:start;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;gap:.25em;margin:1em 0}@media (min-width:768px){.ep-search-toolbar{-webkit-box-align:center;-ms-flex-align:center;align-items:center}}:root{--ep-search-background-color:#fff;--ep-search-alternate-background-color:#efefef;--ep-search-border-color:#dfdfdf;--ep-search-range-thumb-size:1.625em;--ep-search-range-track-size:0.75em}@media (min-width:768px){:root{--ep-search-range-thumb-size:1.25em;--ep-search-range-track-size:0.5em}}
diff --git a/dist/css/ordering-styles.min.asset.php b/dist/css/ordering-styles.min.asset.php
new file mode 100644
index 0000000000..115faa2a8e
--- /dev/null
+++ b/dist/css/ordering-styles.min.asset.php
@@ -0,0 +1 @@
+ array(), 'version' => '23718efa0dc239df4fb35aca3d9b5015');
\ No newline at end of file
diff --git a/dist/css/ordering-styles.min.css b/dist/css/ordering-styles.min.css
index fa5543f4f0..5ba9a2ca0d 100644
--- a/dist/css/ordering-styles.min.css
+++ b/dist/css/ordering-styles.min.css
@@ -1 +1 @@
-#ep-ordering{border-left-width:0;border-right-width:0}#ep-ordering .inside{background-color:#f1f1f1;margin:0;padding:0}#ep-ordering .loading,#ep-ordering .pointer-search,#ep-ordering .pointers{background-color:#fff;border-left:1px solid #eee;border-right:1px solid #eee}#ep-ordering .new-post{background:#fff;padding:0 1em}#ep-ordering .loading{padding:1em}#ep-ordering .loading .spinner{float:left;margin-left:0;margin-top:0}#ep-ordering .pointer-type{border:2px solid #0073aa;border-radius:2px;color:#0073aa;display:inline-block;font-size:.75em;font-weight:700;margin-right:8px;padding:1px 2px}#ep-ordering .pointers .pointer,#ep-ordering .pointers .post{padding:1em}#ep-ordering .pointers .pointer:nth-child(odd),#ep-ordering .pointers .post:nth-child(odd){background-color:#f9f9f9}#ep-ordering .pointers .title{color:#0073aa}#ep-ordering .pointers .pointer-actions{float:right}#ep-ordering .pointers .pointer-actions .handle{cursor:move}#ep-ordering .pointers .pointer-actions .delete-pointer{margin-left:10px}#ep-ordering .pointers .next-page-notice{background-color:#fdeeca;padding:1em 0;text-align:center}#ep-ordering .legend{background:#fff;border-bottom:1px solid #eee;padding:1em 0;text-align:center}#ep-ordering .legend-item{display:inline-block;font-size:.875em;font-style:italic;margin:0 .5em}#ep-ordering .pointer-search{margin-top:2em}#ep-ordering .pointer-search .no-results{padding:1em}#ep-ordering .pointer-search .section-title{border-bottom:1px solid #eee;border-top:1px solid #eee;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.04);box-shadow:0 1px 1px rgba(0,0,0,.04);font-weight:700}#ep-ordering .pointer-search .search-wrapper{padding:1em 0}#ep-ordering .pointer-search .input-wrap{padding:0 1em}#ep-ordering .pointer-search .search-pointers{font-size:18px;height:1.7em;line-height:100%;padding:3px 8px}#ep-ordering .pointer-search .pointer-results{padding:1em 0 0}#ep-ordering .pointer-search .pointer-result{padding:10px 2em}#ep-ordering .pointer-search .pointer-result .dashicons{float:right}#ep-ordering .pointer-search .pointer-result:hover{background-color:#f9f9f9}#ep-ordering .add-pointer,#ep-ordering .delete-pointer{cursor:pointer}
+#ep-ordering{border-left-width:0;border-right-width:0}#ep-ordering .inside{background-color:#f1f1f1;margin:0;padding:0}#ep-ordering .loading,#ep-ordering .pointer-search,#ep-ordering .pointers{background-color:#fff;border-left:1px solid #eee;border-right:1px solid #eee}#ep-ordering .new-post{background:#fff;padding:0 1em}#ep-ordering .loading{padding:1em}#ep-ordering .loading .spinner{float:left;margin-left:0;margin-top:0}#ep-ordering .pointer-type{border:2px solid #0073aa;border-radius:2px;color:#0073aa;display:inline-block;font-size:.75em;font-weight:700;margin-right:8px;padding:1px 2px}#ep-ordering .pointers .pointer,#ep-ordering .pointers .post{padding:1em}:is(#ep-ordering .pointers .pointer,#ep-ordering .pointers .post):nth-child(odd){background-color:#f9f9f9}#ep-ordering .pointers .title{color:#0073aa}#ep-ordering .pointers .pointer-actions{float:right}#ep-ordering .pointers .pointer-actions .handle{cursor:move}#ep-ordering .pointers .pointer-actions .delete-pointer{margin-left:10px}#ep-ordering .pointers .next-page-notice{background-color:#fdeeca;padding:1em 0;text-align:center}#ep-ordering .legend{background:#fff;border-bottom:1px solid #eee;padding:1em 0;text-align:center}#ep-ordering .legend-item{display:inline-block;font-size:.875em;font-style:italic;margin:0 .5em}#ep-ordering .pointer-search{margin-top:2em}#ep-ordering .pointer-search .no-results{padding:1em}#ep-ordering .pointer-search .section-title{border-bottom:1px solid #eee;border-top:1px solid #eee;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.04);box-shadow:0 1px 1px rgba(0,0,0,.04);font-weight:700}#ep-ordering .pointer-search .search-wrapper{padding:1em 0}#ep-ordering .pointer-search .input-wrap{padding:0 1em}#ep-ordering .pointer-search .search-pointers{font-size:18px;height:1.7em;line-height:100%;padding:3px 8px}#ep-ordering .pointer-search .pointer-results{padding:1em 0 0}#ep-ordering .pointer-search .pointer-result{padding:10px 2em}#ep-ordering .pointer-search .pointer-result .dashicons{float:right}#ep-ordering .pointer-search .pointer-result:hover{background-color:#f9f9f9}#ep-ordering .add-pointer,#ep-ordering .delete-pointer{cursor:pointer}
diff --git a/dist/css/related-posts-block-styles.min.asset.php b/dist/css/related-posts-block-styles.min.asset.php
new file mode 100644
index 0000000000..17d52b084d
--- /dev/null
+++ b/dist/css/related-posts-block-styles.min.asset.php
@@ -0,0 +1 @@
+ array(), 'version' => '74d31a9a3be6b9a141a51036c6921e11');
\ No newline at end of file
diff --git a/dist/css/sites-admin-styles.min.asset.php b/dist/css/sites-admin-styles.min.asset.php
new file mode 100644
index 0000000000..1121c6418e
--- /dev/null
+++ b/dist/css/sites-admin-styles.min.asset.php
@@ -0,0 +1 @@
+ array(), 'version' => 'b2e47e66474a3b20e3524480ba479c1e');
\ No newline at end of file
diff --git a/dist/css/sites-admin-styles.min.css b/dist/css/sites-admin-styles.min.css
index ca1a2e0f08..e497315b46 100644
--- a/dist/css/sites-admin-styles.min.css
+++ b/dist/css/sites-admin-styles.min.css
@@ -1 +1 @@
-.switch{display:inline-block;height:34px;position:relative;width:60px}.switch input{height:0;opacity:0;width:0}.slider{background-color:#ccc;bottom:0;cursor:pointer;left:0;right:0;top:0}.slider,.slider:before{position:absolute;-webkit-transition:.4s;transition:.4s}.slider:before{background-color:#fff;bottom:4px;content:"";height:26px;left:4px;width:26px}input:checked+.slider{background-color:#2196f3}input:focus+.slider{-webkit-box-shadow:0 0 1px #2196f3;box-shadow:0 0 1px #2196f3}input:checked+.slider:before{-webkit-transform:translateX(26px);transform:translateX(26px)}.slider.round{border-radius:34px}.slider.round:before{border-radius:50%}.switch-label{padding-left:20px;padding-top:20px}
+.switch{display:inline-block;height:34px;position:relative;width:60px}.switch input{height:0;opacity:0;width:0}.slider{background-color:#ccc;bottom:0;cursor:pointer;left:0;position:absolute;right:0;top:0;-webkit-transition:.4s;transition:.4s}.slider:before{background-color:#fff;bottom:4px;content:"";height:26px;left:4px;position:absolute;-webkit-transition:.4s;transition:.4s;width:26px}input:checked+.slider{background-color:#2196f3}input:focus+.slider{-webkit-box-shadow:0 0 1px #2196f3;box-shadow:0 0 1px #2196f3}input:checked+.slider:before{-webkit-transform:translateX(26px);transform:translateX(26px)}.slider.round{border-radius:34px}.slider.round:before{border-radius:50%}.switch-label{padding-left:20px;padding-top:20px}
diff --git a/dist/css/sync-styles.min.asset.php b/dist/css/sync-styles.min.asset.php
new file mode 100644
index 0000000000..7038a5e2ae
--- /dev/null
+++ b/dist/css/sync-styles.min.asset.php
@@ -0,0 +1 @@
+ array(), 'version' => 'a8e686d31cee10fff438081cc49ed675');
\ No newline at end of file
diff --git a/dist/css/synonyms-styles.min.asset.php b/dist/css/synonyms-styles.min.asset.php
new file mode 100644
index 0000000000..3fee7937b9
--- /dev/null
+++ b/dist/css/synonyms-styles.min.asset.php
@@ -0,0 +1 @@
+ array(), 'version' => 'd6ec0a74dda1170df5ae372c70a7d786');
\ No newline at end of file
diff --git a/dist/css/synonyms-styles.min.css b/dist/css/synonyms-styles.min.css
index 8804833902..faa122429c 100644
--- a/dist/css/synonyms-styles.min.css
+++ b/dist/css/synonyms-styles.min.css
@@ -1 +1 @@
-#synonym-root .page-title-action{margin-left:10px}#synonym-root .postbox .hndle{cursor:default}#synonym-root h2{color:#23282d}.synonym-alternatives-editor,.synonym-set-editor{display:-webkit-box;display:-ms-flexbox;display:flex}.synonym-alternatives-editor>.postbox,.synonym-set-editor>.postbox{width:100%}.synonym-alternatives-editor .synonym-alternative-editor,.synonym-alternatives-editor>.postbox>.hndle,.synonym-set-editor .synonym-alternative-editor,.synonym-set-editor>.postbox>.hndle{display:-webkit-box;display:-ms-flexbox;display:flex}.synonym-alternatives-editor .ep-synonyms__linked-multi-input,.synonym-set-editor .ep-synonyms__linked-multi-input{-webkit-box-flex:1;-ms-flex:1;flex:1;margin-bottom:.5em}.synonym-alternatives-editor .ep-synonyms__input,.synonym-set-editor .ep-synonyms__input{border:1px solid #ccc;margin-bottom:.5em;margin-right:1em;width:10em}.synonym-alternatives-editor .synonym-alternatives__primary-heading,.synonym-set-editor .synonym-alternatives__primary-heading{width:11em}.synonym-alternatives-editor .synonym-alternatives__input-heading,.synonym-set-editor .synonym-alternatives__input-heading{-webkit-box-flex:1;-ms-flex:1;flex:1}.synonym-alternatives-editor .ep-synonyms__linked-multi-input input:focus,.synonym-set-editor .ep-synonyms__linked-multi-input input:focus{-webkit-box-shadow:none;box-shadow:none}.synonym-alternatives-editor.invalid input,.synonym-set-editor.invalid input{border-color:#a00}.synonym-alternative-editor,.synonym-set-editor{margin-top:.625em}button.synonym__remove{background-color:transparent;border:none;color:#a00;cursor:pointer;margin:-8px 0 0 10px;padding:0}button.synonym__remove .dashicons-dismiss{margin:-2px 2px 0 0}.synonym__validation:before{content:"";-ms-flex-preferred-size:100%;flex-basis:100%;height:0}.synonym-solr-editor__validation p,.synonym__validation{color:#a00;font-style:italic}.synonym__validation{margin:0 0 .625em .5em}.synonym-btn-group button.button{margin-right:.625em}
+#synonym-root .page-title-action{margin-left:10px}#synonym-root .postbox .hndle{cursor:default}#synonym-root h2{color:#23282d}.synonym-alternatives-editor,.synonym-set-editor{display:-webkit-box;display:-ms-flexbox;display:flex}:is(.synonym-alternatives-editor,.synonym-set-editor)>.postbox{width:100%}:is(.synonym-alternatives-editor,.synonym-set-editor)>.postbox>.hndle{display:-webkit-box;display:-ms-flexbox;display:flex}:is(.synonym-alternatives-editor,.synonym-set-editor) .synonym-alternative-editor{display:-webkit-box;display:-ms-flexbox;display:flex}:is(.synonym-alternatives-editor,.synonym-set-editor) .ep-synonyms__linked-multi-input{-webkit-box-flex:1;-ms-flex:1;flex:1;margin-bottom:.5em}:is(.synonym-alternatives-editor,.synonym-set-editor) .ep-synonyms__input{border:1px solid #ccc;margin-bottom:.5em;margin-right:1em;width:10em}:is(.synonym-alternatives-editor,.synonym-set-editor) .synonym-alternatives__primary-heading{width:11em}:is(.synonym-alternatives-editor,.synonym-set-editor) .synonym-alternatives__input-heading{-webkit-box-flex:1;-ms-flex:1;flex:1}:is(.synonym-alternatives-editor,.synonym-set-editor) .ep-synonyms__linked-multi-input input:focus{-webkit-box-shadow:none;box-shadow:none}:is(.synonym-alternatives-editor,.synonym-set-editor).invalid input{border-color:#a00}.synonym-alternative-editor,.synonym-set-editor{margin-top:.625em}button.synonym__remove{background-color:transparent;border:none;color:#a00;cursor:pointer;margin:-8px 0 0 10px;padding:0}button.synonym__remove .dashicons-dismiss{margin:-2px 2px 0 0}.synonym__validation:before{content:"";-ms-flex-preferred-size:100%;flex-basis:100%;height:0}.synonym-solr-editor__validation p,.synonym__validation{color:#a00;font-style:italic}.synonym__validation{margin:0 0 .625em .5em}.synonym-btn-group button.button{margin-right:.625em}
diff --git a/dist/js/autosuggest-script.min.asset.php b/dist/js/autosuggest-script.min.asset.php
new file mode 100644
index 0000000000..ff95831e43
--- /dev/null
+++ b/dist/js/autosuggest-script.min.asset.php
@@ -0,0 +1 @@
+ array('wp-polyfill'), 'version' => '457c836b9c89e0c1b7a117c190465da1');
\ No newline at end of file
diff --git a/dist/js/autosuggest-script.min.js b/dist/js/autosuggest-script.min.js
index 54503a0f4b..444a732a64 100644
--- a/dist/js/autosuggest-script.min.js
+++ b/dist/js/autosuggest-script.min.js
@@ -1 +1 @@
-!function(){var t={9662:function(t,e,r){var n=r(614),o=r(6330);t.exports=function(t){if(n(t))return t;throw TypeError(o(t)+" is not a function")}},9483:function(t,e,r){var n=r(4411),o=r(6330);t.exports=function(t){if(n(t))return t;throw TypeError(o(t)+" is not a constructor")}},6077:function(t,e,r){var n=r(614);t.exports=function(t){if("object"===typeof t||n(t))return t;throw TypeError("Can't set "+String(t)+" as a prototype")}},1223:function(t,e,r){var n=r(5112),o=r(30),i=r(3070),a=n("unscopables"),c=Array.prototype;void 0==c[a]&&i.f(c,a,{configurable:!0,value:o(null)}),t.exports=function(t){c[a][t]=!0}},1530:function(t,e,r){"use strict";var n=r(8710).charAt;t.exports=function(t,e,r){return e+(r?n(t,e).length:1)}},5787:function(t){t.exports=function(t,e,r){if(t instanceof e)return t;throw TypeError("Incorrect "+(r?r+" ":"")+"invocation")}},9670:function(t,e,r){var n=r(111);t.exports=function(t){if(n(t))return t;throw TypeError(String(t)+" is not an object")}},8533:function(t,e,r){"use strict";var n=r(2092).forEach,o=r(9341)("forEach");t.exports=o?[].forEach:function(t){return n(this,t,arguments.length>1?arguments[1]:void 0)}},8457:function(t,e,r){"use strict";var n=r(9974),o=r(7908),i=r(3411),a=r(7659),c=r(4411),u=r(7466),s=r(6135),f=r(8554),l=r(1246);t.exports=function(t){var e=o(t),r=c(this),p=arguments.length,h=p>1?arguments[1]:void 0,d=void 0!==h;d&&(h=n(h,p>2?arguments[2]:void 0,2));var v,y,g,m,b,x,w=l(e),E=0;if(!w||this==Array&&a(w))for(v=u(e.length),y=r?new this(v):Array(v);v>E;E++)x=d?h(e[E],E):e[E],s(y,E,x);else for(b=(m=f(e,w)).next,y=r?new this:[];!(g=b.call(m)).done;E++)x=d?i(m,h,[g.value,E],!0):g.value,s(y,E,x);return y.length=E,y}},1318:function(t,e,r){var n=r(5656),o=r(7466),i=r(1400),a=function(t){return function(e,r,a){var c,u=n(e),s=o(u.length),f=i(a,s);if(t&&r!=r){for(;s>f;)if((c=u[f++])!=c)return!0}else for(;s>f;f++)if((t||f in u)&&u[f]===r)return t||f||0;return!t&&-1}};t.exports={includes:a(!0),indexOf:a(!1)}},2092:function(t,e,r){var n=r(9974),o=r(8361),i=r(7908),a=r(7466),c=r(5417),u=[].push,s=function(t){var e=1==t,r=2==t,s=3==t,f=4==t,l=6==t,p=7==t,h=5==t||l;return function(d,v,y,g){for(var m,b,x=i(d),w=o(x),E=n(v,y,3),S=a(w.length),O=0,A=g||c,T=e?A(d,S):r||p?A(d,0):void 0;S>O;O++)if((h||O in w)&&(b=E(m=w[O],O,x),t))if(e)T[O]=b;else if(b)switch(t){case 3:return!0;case 5:return m;case 6:return O;case 2:u.call(T,m)}else switch(t){case 4:return!1;case 7:u.call(T,m)}return l?-1:s||f?f:T}};t.exports={forEach:s(0),map:s(1),filter:s(2),some:s(3),every:s(4),find:s(5),findIndex:s(6),filterReject:s(7)}},1194:function(t,e,r){var n=r(7293),o=r(5112),i=r(7392),a=o("species");t.exports=function(t){return i>=51||!n((function(){var e=[];return(e.constructor={})[a]=function(){return{foo:1}},1!==e[t](Boolean).foo}))}},9341:function(t,e,r){"use strict";var n=r(7293);t.exports=function(t,e){var r=[][t];return!!r&&n((function(){r.call(null,e||function(){throw 1},1)}))}},4362:function(t){var e=Math.floor,r=function(t,i){var a=t.length,c=e(a/2);return a<8?n(t,i):o(r(t.slice(0,c),i),r(t.slice(c),i),i)},n=function(t,e){for(var r,n,o=t.length,i=1;i0;)t[n]=t[--n];n!==i++&&(t[n]=r)}return t},o=function(t,e,r){for(var n=t.length,o=e.length,i=0,a=0,c=[];i=74)&&(n=a.match(/Chrome\/(\d+)/))&&(o=n[1]),t.exports=o&&+o},8008:function(t,e,r){var n=r(8113).match(/AppleWebKit\/(\d+)\./);t.exports=!!n&&+n[1]},748:function(t){t.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},2109:function(t,e,r){var n=r(7854),o=r(1236).f,i=r(8880),a=r(1320),c=r(3505),u=r(9920),s=r(4705);t.exports=function(t,e){var r,f,l,p,h,d=t.target,v=t.global,y=t.stat;if(r=v?n:y?n[d]||c(d,{}):(n[d]||{}).prototype)for(f in e){if(p=e[f],l=t.noTargetGet?(h=o(r,f))&&h.value:r[f],!s(v?f:d+(y?".":"#")+f,t.forced)&&void 0!==l){if(typeof p===typeof l)continue;u(p,l)}(t.sham||l&&l.sham)&&i(p,"sham",!0),a(r,f,p,t)}}},7293:function(t){t.exports=function(t){try{return!!t()}catch(t){return!0}}},7007:function(t,e,r){"use strict";r(4916);var n=r(1320),o=r(2261),i=r(7293),a=r(5112),c=r(8880),u=a("species"),s=RegExp.prototype;t.exports=function(t,e,r,f){var l=a(t),p=!i((function(){var e={};return e[l]=function(){return 7},7!=""[t](e)})),h=p&&!i((function(){var e=!1,r=/a/;return"split"===t&&((r={}).constructor={},r.constructor[u]=function(){return r},r.flags="",r[l]=/./[l]),r.exec=function(){return e=!0,null},r[l](""),!e}));if(!p||!h||r){var d=/./[l],v=e(l,""[t],(function(t,e,r,n,i){var a=e.exec;return a===o||a===s.exec?p&&!i?{done:!0,value:d.call(e,r,n)}:{done:!0,value:t.call(r,e,n)}:{done:!1}}));n(String.prototype,t,v[0]),n(s,l,v[1])}f&&c(s[l],"sham",!0)}},9974:function(t,e,r){var n=r(9662);t.exports=function(t,e,r){if(n(t),void 0===e)return t;switch(r){case 0:return function(){return t.call(e)};case 1:return function(r){return t.call(e,r)};case 2:return function(r,n){return t.call(e,r,n)};case 3:return function(r,n,o){return t.call(e,r,n,o)}}return function(){return t.apply(e,arguments)}}},6530:function(t,e,r){var n=r(9781),o=r(6656),i=Function.prototype,a=n&&Object.getOwnPropertyDescriptor,c=o(i,"name"),u=c&&"something"===function(){}.name,s=c&&(!n||n&&a(i,"name").configurable);t.exports={EXISTS:c,PROPER:u,CONFIGURABLE:s}},5005:function(t,e,r){var n=r(7854),o=r(614),i=function(t){return o(t)?t:void 0};t.exports=function(t,e){return arguments.length<2?i(n[t]):n[t]&&n[t][e]}},1246:function(t,e,r){var n=r(648),o=r(8173),i=r(7497),a=r(5112)("iterator");t.exports=function(t){if(void 0!=t)return o(t,a)||o(t,"@@iterator")||i[n(t)]}},8554:function(t,e,r){var n=r(9662),o=r(9670),i=r(1246);t.exports=function(t,e){var r=arguments.length<2?i(t):e;if(n(r))return o(r.call(t));throw TypeError(String(t)+" is not iterable")}},8173:function(t,e,r){var n=r(9662);t.exports=function(t,e){var r=t[e];return null==r?void 0:n(r)}},647:function(t,e,r){var n=r(7908),o=Math.floor,i="".replace,a=/\$([$&'`]|\d{1,2}|<[^>]*>)/g,c=/\$([$&'`]|\d{1,2})/g;t.exports=function(t,e,r,u,s,f){var l=r+t.length,p=u.length,h=c;return void 0!==s&&(s=n(s),h=a),i.call(f,h,(function(n,i){var a;switch(i.charAt(0)){case"$":return"$";case"&":return t;case"`":return e.slice(0,r);case"'":return e.slice(l);case"<":a=s[i.slice(1,-1)];break;default:var c=+i;if(0===c)return n;if(c>p){var f=o(c/10);return 0===f?n:f<=p?void 0===u[f-1]?i.charAt(1):u[f-1]+i.charAt(1):n}a=u[c-1]}return void 0===a?"":a}))}},7854:function(t,e,r){var n=function(t){return t&&t.Math==Math&&t};t.exports=n("object"==typeof globalThis&&globalThis)||n("object"==typeof window&&window)||n("object"==typeof self&&self)||n("object"==typeof r.g&&r.g)||function(){return this}()||Function("return this")()},6656:function(t,e,r){var n=r(7908),o={}.hasOwnProperty;t.exports=Object.hasOwn||function(t,e){return o.call(n(t),e)}},3501:function(t){t.exports={}},842:function(t,e,r){var n=r(7854);t.exports=function(t,e){var r=n.console;r&&r.error&&(1===arguments.length?r.error(t):r.error(t,e))}},490:function(t,e,r){var n=r(5005);t.exports=n("document","documentElement")},4664:function(t,e,r){var n=r(9781),o=r(7293),i=r(317);t.exports=!n&&!o((function(){return 7!=Object.defineProperty(i("div"),"a",{get:function(){return 7}}).a}))},8361:function(t,e,r){var n=r(7293),o=r(4326),i="".split;t.exports=n((function(){return!Object("z").propertyIsEnumerable(0)}))?function(t){return"String"==o(t)?i.call(t,""):Object(t)}:Object},9587:function(t,e,r){var n=r(614),o=r(111),i=r(7674);t.exports=function(t,e,r){var a,c;return i&&n(a=e.constructor)&&a!==r&&o(c=a.prototype)&&c!==r.prototype&&i(t,c),t}},2788:function(t,e,r){var n=r(614),o=r(5465),i=Function.toString;n(o.inspectSource)||(o.inspectSource=function(t){return i.call(t)}),t.exports=o.inspectSource},9909:function(t,e,r){var n,o,i,a=r(8536),c=r(7854),u=r(111),s=r(8880),f=r(6656),l=r(5465),p=r(6200),h=r(3501),d="Object already initialized",v=c.WeakMap;if(a||l.state){var y=l.state||(l.state=new v),g=y.get,m=y.has,b=y.set;n=function(t,e){if(m.call(y,t))throw new TypeError(d);return e.facade=t,b.call(y,t,e),e},o=function(t){return g.call(y,t)||{}},i=function(t){return m.call(y,t)}}else{var x=p("state");h[x]=!0,n=function(t,e){if(f(t,x))throw new TypeError(d);return e.facade=t,s(t,x,e),e},o=function(t){return f(t,x)?t[x]:{}},i=function(t){return f(t,x)}}t.exports={set:n,get:o,has:i,enforce:function(t){return i(t)?o(t):n(t,{})},getterFor:function(t){return function(e){var r;if(!u(e)||(r=o(e)).type!==t)throw TypeError("Incompatible receiver, "+t+" required");return r}}}},7659:function(t,e,r){var n=r(5112),o=r(7497),i=n("iterator"),a=Array.prototype;t.exports=function(t){return void 0!==t&&(o.Array===t||a[i]===t)}},3157:function(t,e,r){var n=r(4326);t.exports=Array.isArray||function(t){return"Array"==n(t)}},614:function(t){t.exports=function(t){return"function"===typeof t}},4411:function(t,e,r){var n=r(7293),o=r(614),i=r(648),a=r(5005),c=r(2788),u=[],s=a("Reflect","construct"),f=/^\s*(?:class|function)\b/,l=f.exec,p=!f.exec((function(){})),h=function(t){if(!o(t))return!1;try{return s(Object,u,t),!0}catch(t){return!1}};t.exports=!s||n((function(){var t;return h(h.call)||!h(Object)||!h((function(){t=!0}))||t}))?function(t){if(!o(t))return!1;switch(i(t)){case"AsyncFunction":case"GeneratorFunction":case"AsyncGeneratorFunction":return!1}return p||!!l.call(f,c(t))}:h},4705:function(t,e,r){var n=r(7293),o=r(614),i=/#|\.prototype\./,a=function(t,e){var r=u[c(t)];return r==f||r!=s&&(o(e)?n(e):!!e)},c=a.normalize=function(t){return String(t).replace(i,".").toLowerCase()},u=a.data={},s=a.NATIVE="N",f=a.POLYFILL="P";t.exports=a},111:function(t,e,r){var n=r(614);t.exports=function(t){return"object"===typeof t?null!==t:n(t)}},1913:function(t){t.exports=!1},7850:function(t,e,r){var n=r(111),o=r(4326),i=r(5112)("match");t.exports=function(t){var e;return n(t)&&(void 0!==(e=t[i])?!!e:"RegExp"==o(t))}},2190:function(t,e,r){var n=r(614),o=r(5005),i=r(3307);t.exports=i?function(t){return"symbol"==typeof t}:function(t){var e=o("Symbol");return n(e)&&Object(t)instanceof e}},408:function(t,e,r){var n=r(9670),o=r(7659),i=r(7466),a=r(9974),c=r(8554),u=r(1246),s=r(9212),f=function(t,e){this.stopped=t,this.result=e};t.exports=function(t,e,r){var l,p,h,d,v,y,g,m=r&&r.that,b=!(!r||!r.AS_ENTRIES),x=!(!r||!r.IS_ITERATOR),w=!(!r||!r.INTERRUPTED),E=a(e,m,1+b+w),S=function(t){return l&&s(l,"normal",t),new f(!0,t)},O=function(t){return b?(n(t),w?E(t[0],t[1],S):E(t[0],t[1])):w?E(t,S):E(t)};if(x)l=t;else{if(!(p=u(t)))throw TypeError(String(t)+" is not iterable");if(o(p)){for(h=0,d=i(t.length);d>h;h++)if((v=O(t[h]))&&v instanceof f)return v;return new f(!1)}l=c(t,p)}for(y=l.next;!(g=y.call(l)).done;){try{v=O(g.value)}catch(t){s(l,"throw",t)}if("object"==typeof v&&v&&v instanceof f)return v}return new f(!1)}},9212:function(t,e,r){var n=r(9670),o=r(8173);t.exports=function(t,e,r){var i,a;n(t);try{if(!(i=o(t,"return"))){if("throw"===e)throw r;return r}i=i.call(t)}catch(t){a=!0,i=t}if("throw"===e)throw r;if(a)throw i;return n(i),r}},3383:function(t,e,r){"use strict";var n,o,i,a=r(7293),c=r(614),u=r(30),s=r(9518),f=r(1320),l=r(5112),p=r(1913),h=l("iterator"),d=!1;[].keys&&("next"in(i=[].keys())?(o=s(s(i)))!==Object.prototype&&(n=o):d=!0),void 0==n||a((function(){var t={};return n[h].call(t)!==t}))?n={}:p&&(n=u(n)),c(n[h])||f(n,h,(function(){return this})),t.exports={IteratorPrototype:n,BUGGY_SAFARI_ITERATORS:d}},7497:function(t){t.exports={}},5948:function(t,e,r){var n,o,i,a,c,u,s,f,l=r(7854),p=r(1236).f,h=r(261).set,d=r(6833),v=r(1528),y=r(1036),g=r(5268),m=l.MutationObserver||l.WebKitMutationObserver,b=l.document,x=l.process,w=l.Promise,E=p(l,"queueMicrotask"),S=E&&E.value;S||(n=function(){var t,e;for(g&&(t=x.domain)&&t.exit();o;){e=o.fn,o=o.next;try{e()}catch(t){throw o?a():i=void 0,t}}i=void 0,t&&t.enter()},d||g||y||!m||!b?!v&&w&&w.resolve?((s=w.resolve(void 0)).constructor=w,f=s.then,a=function(){f.call(s,n)}):a=g?function(){x.nextTick(n)}:function(){h.call(l,n)}:(c=!0,u=b.createTextNode(""),new m(n).observe(u,{characterData:!0}),a=function(){u.data=c=!c})),t.exports=S||function(t){var e={fn:t,next:void 0};i&&(i.next=e),o||(o=e,a()),i=e}},3366:function(t,e,r){var n=r(7854);t.exports=n.Promise},133:function(t,e,r){var n=r(7392),o=r(7293);t.exports=!!Object.getOwnPropertySymbols&&!o((function(){var t=Symbol();return!String(t)||!(Object(t)instanceof Symbol)||!Symbol.sham&&n&&n<41}))},8536:function(t,e,r){var n=r(7854),o=r(614),i=r(2788),a=n.WeakMap;t.exports=o(a)&&/native code/.test(i(a))},8523:function(t,e,r){"use strict";var n=r(9662),o=function(t){var e,r;this.promise=new t((function(t,n){if(void 0!==e||void 0!==r)throw TypeError("Bad Promise constructor");e=t,r=n})),this.resolve=n(e),this.reject=n(r)};t.exports.f=function(t){return new o(t)}},3929:function(t,e,r){var n=r(7850);t.exports=function(t){if(n(t))throw TypeError("The method doesn't accept regular expressions");return t}},30:function(t,e,r){var n,o=r(9670),i=r(6048),a=r(748),c=r(3501),u=r(490),s=r(317),f=r(6200),l=f("IE_PROTO"),p=function(){},h=function(t){return"