diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js
index 38282a0ca..813605be1 100644
--- a/website/docusaurus.config.js
+++ b/website/docusaurus.config.js
@@ -205,6 +205,7 @@ const siteConfig = {
// end_config_example
plugins: [
'./src/plugins/support-symlinks',
+ ...fbContent({internal: [], external: [require.resolve('docusaurus-lunr-search')]}),
[
require.resolve('@docusaurus/plugin-content-pages'),
{
diff --git a/website/package.json b/website/package.json
index 60d651b0e..63aa74ee9 100644
--- a/website/package.json
+++ b/website/package.json
@@ -4,6 +4,9 @@
"start": "yarn copy-schema && yarn generate-plugin-docs && yarn build:style-guide && docusaurus start --port 3001",
"build": "yarn copy-schema && yarn generate-plugin-docs && yarn build:style-guide && docusaurus build",
"publish-gh-pages": "docusaurus deploy",
+ "clear": "docusaurus clear",
+ "clean": "docusaurus clear",
+ "swizzle": "docusaurus swizzle",
"write-translations": "docusaurus write-translations",
"version": "docusaurus version",
"rename-version": "docusaurus rename-version",
@@ -19,7 +22,8 @@
"@emotion/styled": "^11.10.6",
"@types/fs-extra": "^11.0.1",
"antd": "^4.23.4",
- "docusaurus-plugin-internaldocs-fb": "1.9.1",
+ "docusaurus-plugin-internaldocs-fb": "1.13.0",
+ "docusaurus-lunr-search": "^2.3.2",
"file-cli": "^1.2.0",
"flipper-plugin": "^0.183.0",
"fs-extra": "^11.1.0",
@@ -32,7 +36,6 @@
"typescript": "^4.9.5",
"yarn-audit-fix": "^9.3.9"
},
- "dependencies": {},
"resolutions": {
"kind-of": "6.0.3",
"chokidar": "^3.1.5",
diff --git a/website/src/theme/SearchBar/DocSearch.js b/website/src/theme/SearchBar/DocSearch.js
new file mode 100644
index 000000000..e98a46c2f
--- /dev/null
+++ b/website/src/theme/SearchBar/DocSearch.js
@@ -0,0 +1,304 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+import Hogan from "hogan.js";
+import LunrSearchAdapter from "./lunar-search";
+import autocomplete from "autocomplete.js";
+import templates from "./templates";
+import utils from "./utils";
+import $ from "autocomplete.js/zepto";
+
+class DocSearch {
+ constructor({
+ searchDocs,
+ searchIndex,
+ inputSelector,
+ debug = false,
+ baseUrl = '/',
+ queryDataCallback = null,
+ autocompleteOptions = {
+ debug: false,
+ hint: false,
+ autoselect: true
+ },
+ transformData = false,
+ queryHook = false,
+ handleSelected = false,
+ enhancedSearchInput = false,
+ layout = "collumns"
+ }) {
+ this.input = DocSearch.getInputFromSelector(inputSelector);
+ this.queryDataCallback = queryDataCallback || null;
+ const autocompleteOptionsDebug =
+ autocompleteOptions && autocompleteOptions.debug
+ ? autocompleteOptions.debug
+ : false;
+ // eslint-disable-next-line no-param-reassign
+ autocompleteOptions.debug = debug || autocompleteOptionsDebug;
+ this.autocompleteOptions = autocompleteOptions;
+ this.autocompleteOptions.cssClasses =
+ this.autocompleteOptions.cssClasses || {};
+ this.autocompleteOptions.cssClasses.prefix =
+ this.autocompleteOptions.cssClasses.prefix || "ds";
+ const inputAriaLabel =
+ this.input &&
+ typeof this.input.attr === "function" &&
+ this.input.attr("aria-label");
+ this.autocompleteOptions.ariaLabel =
+ this.autocompleteOptions.ariaLabel || inputAriaLabel || "search input";
+
+ this.isSimpleLayout = layout === "simple";
+
+ this.client = new LunrSearchAdapter(searchDocs, searchIndex, baseUrl);
+
+ if (enhancedSearchInput) {
+ this.input = DocSearch.injectSearchBox(this.input);
+ }
+ this.autocomplete = autocomplete(this.input, autocompleteOptions, [
+ {
+ source: this.getAutocompleteSource(transformData, queryHook),
+ templates: {
+ suggestion: DocSearch.getSuggestionTemplate(this.isSimpleLayout),
+ footer: templates.footer,
+ empty: DocSearch.getEmptyTemplate()
+ }
+ }
+ ]);
+
+ const customHandleSelected = handleSelected;
+ this.handleSelected = customHandleSelected || this.handleSelected;
+
+ // We prevent default link clicking if a custom handleSelected is defined
+ if (customHandleSelected) {
+ $(".algolia-autocomplete").on("click", ".ds-suggestions a", event => {
+ event.preventDefault();
+ });
+ }
+
+ this.autocomplete.on(
+ "autocomplete:selected",
+ this.handleSelected.bind(null, this.autocomplete.autocomplete)
+ );
+
+ this.autocomplete.on(
+ "autocomplete:shown",
+ this.handleShown.bind(null, this.input)
+ );
+
+ if (enhancedSearchInput) {
+ DocSearch.bindSearchBoxEvent();
+ }
+ }
+
+ static injectSearchBox(input) {
+ input.before(templates.searchBox);
+ const newInput = input
+ .prev()
+ .prev()
+ .find("input");
+ input.remove();
+ return newInput;
+ }
+
+ static bindSearchBoxEvent() {
+ $('.searchbox [type="reset"]').on("click", function () {
+ $("input#docsearch").focus();
+ $(this).addClass("hide");
+ autocomplete.autocomplete.setVal("");
+ });
+
+ $("input#docsearch").on("keyup", () => {
+ const searchbox = document.querySelector("input#docsearch");
+ const reset = document.querySelector('.searchbox [type="reset"]');
+ reset.className = "searchbox__reset";
+ if (searchbox.value.length === 0) {
+ reset.className += " hide";
+ }
+ });
+ }
+
+ /**
+ * Returns the matching input from a CSS selector, null if none matches
+ * @function getInputFromSelector
+ * @param {string} selector CSS selector that matches the search
+ * input of the page
+ * @returns {void}
+ */
+ static getInputFromSelector(selector) {
+ const input = $(selector).filter("input");
+ return input.length ? $(input[0]) : null;
+ }
+
+ /**
+ * Returns the `source` method to be passed to autocomplete.js. It will query
+ * the Algolia index and call the callbacks with the formatted hits.
+ * @function getAutocompleteSource
+ * @param {function} transformData An optional function to transform the hits
+ * @param {function} queryHook An optional function to transform the query
+ * @returns {function} Method to be passed as the `source` option of
+ * autocomplete
+ */
+ getAutocompleteSource(transformData, queryHook) {
+ return (query, callback) => {
+ if (queryHook) {
+ // eslint-disable-next-line no-param-reassign
+ query = queryHook(query) || query;
+ }
+ this.client.search(query).then(hits => {
+ if (
+ this.queryDataCallback &&
+ typeof this.queryDataCallback == "function"
+ ) {
+ this.queryDataCallback(hits);
+ }
+ if (transformData) {
+ hits = transformData(hits) || hits;
+ }
+ callback(DocSearch.formatHits(hits));
+ });
+ };
+ }
+
+ // Given a list of hits returned by the API, will reformat them to be used in
+ // a Hogan template
+ static formatHits(receivedHits) {
+ const clonedHits = utils.deepClone(receivedHits);
+ const hits = clonedHits.map(hit => {
+ if (hit._highlightResult) {
+ // eslint-disable-next-line no-param-reassign
+ hit._highlightResult = utils.mergeKeyWithParent(
+ hit._highlightResult,
+ "hierarchy"
+ );
+ }
+ return utils.mergeKeyWithParent(hit, "hierarchy");
+ });
+
+ // Group hits by category / subcategory
+ let groupedHits = utils.groupBy(hits, "lvl0");
+ $.each(groupedHits, (level, collection) => {
+ const groupedHitsByLvl1 = utils.groupBy(collection, "lvl1");
+ const flattenedHits = utils.flattenAndFlagFirst(
+ groupedHitsByLvl1,
+ "isSubCategoryHeader"
+ );
+ groupedHits[level] = flattenedHits;
+ });
+ groupedHits = utils.flattenAndFlagFirst(groupedHits, "isCategoryHeader");
+
+ // Translate hits into smaller objects to be send to the template
+ return groupedHits.map(hit => {
+ const url = DocSearch.formatURL(hit);
+ const category = utils.getHighlightedValue(hit, "lvl0");
+ const subcategory = utils.getHighlightedValue(hit, "lvl1") || category;
+ const displayTitle = utils
+ .compact([
+ utils.getHighlightedValue(hit, "lvl2") || subcategory,
+ utils.getHighlightedValue(hit, "lvl3"),
+ utils.getHighlightedValue(hit, "lvl4"),
+ utils.getHighlightedValue(hit, "lvl5"),
+ utils.getHighlightedValue(hit, "lvl6")
+ ])
+ .join(
+ ''
+ );
+ const text = utils.getSnippetedValue(hit, "content");
+ const isTextOrSubcategoryNonEmpty =
+ (subcategory && subcategory !== "") ||
+ (displayTitle && displayTitle !== "");
+ const isLvl1EmptyOrDuplicate =
+ !subcategory || subcategory === "" || subcategory === category;
+ const isLvl2 =
+ displayTitle && displayTitle !== "" && displayTitle !== subcategory;
+ const isLvl1 =
+ !isLvl2 &&
+ (subcategory && subcategory !== "" && subcategory !== category);
+ const isLvl0 = !isLvl1 && !isLvl2;
+
+ return {
+ isLvl0,
+ isLvl1,
+ isLvl2,
+ isLvl1EmptyOrDuplicate,
+ isCategoryHeader: hit.isCategoryHeader,
+ isSubCategoryHeader: hit.isSubCategoryHeader,
+ isTextOrSubcategoryNonEmpty,
+ category,
+ subcategory,
+ title: displayTitle,
+ text,
+ url
+ };
+ });
+ }
+
+ static formatURL(hit) {
+ const { url, anchor } = hit;
+ if (url) {
+ const containsAnchor = url.indexOf("#") !== -1;
+ if (containsAnchor) return url;
+ else if (anchor) return `${hit.url}#${hit.anchor}`;
+ return url;
+ } else if (anchor) return `#${hit.anchor}`;
+ /* eslint-disable */
+ console.warn("no anchor nor url for : ", JSON.stringify(hit));
+ /* eslint-enable */
+ return null;
+ }
+
+ static getEmptyTemplate() {
+ return args => Hogan.compile(templates.empty).render(args);
+ }
+
+ static getSuggestionTemplate(isSimpleLayout) {
+ const stringTemplate = isSimpleLayout
+ ? templates.suggestionSimple
+ : templates.suggestion;
+ const template = Hogan.compile(stringTemplate);
+ return suggestion => template.render(suggestion);
+ }
+
+ handleSelected(input, event, suggestion, datasetNumber, context = {}) {
+ // Do nothing if click on the suggestion, as it's already a , the
+ // browser will take care of it. This allow Ctrl-Clicking on results and not
+ // having the main window being redirected as well
+ if (context.selectionMethod === "click") {
+ return;
+ }
+
+ input.setVal("");
+ window.location.assign(suggestion.url);
+ }
+
+ handleShown(input) {
+ const middleOfInput = input.offset().left + input.width() / 2;
+ let middleOfWindow = $(document).width() / 2;
+
+ if (isNaN(middleOfWindow)) {
+ middleOfWindow = 900;
+ }
+
+ const alignClass =
+ middleOfInput - middleOfWindow >= 0
+ ? "algolia-autocomplete-right"
+ : "algolia-autocomplete-left";
+ const otherAlignClass =
+ middleOfInput - middleOfWindow < 0
+ ? "algolia-autocomplete-right"
+ : "algolia-autocomplete-left";
+ const autocompleteWrapper = $(".algolia-autocomplete");
+ if (!autocompleteWrapper.hasClass(alignClass)) {
+ autocompleteWrapper.addClass(alignClass);
+ }
+
+ if (autocompleteWrapper.hasClass(otherAlignClass)) {
+ autocompleteWrapper.removeClass(otherAlignClass);
+ }
+ }
+}
+
+export default DocSearch;
diff --git a/website/src/theme/SearchBar/algolia.css b/website/src/theme/SearchBar/algolia.css
new file mode 100644
index 000000000..eeb7def15
--- /dev/null
+++ b/website/src/theme/SearchBar/algolia.css
@@ -0,0 +1,533 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+/* Bottom border of each suggestion */
+.algolia-docsearch-suggestion {
+ border-bottom-color: #3a3dd1;
+}
+/* Main category headers */
+.algolia-docsearch-suggestion--category-header {
+ background-color: #4b54de;
+}
+/* Highlighted search terms */
+.algolia-docsearch-suggestion--highlight {
+ color: #3a33d1;
+}
+/* Highligted search terms in the main category headers */
+.algolia-docsearch-suggestion--category-header
+ .algolia-docsearch-suggestion--highlight {
+ background-color: #4d47d5;
+}
+/* Currently selected suggestion */
+.aa-cursor .algolia-docsearch-suggestion--content {
+ color: #272296;
+}
+.aa-cursor .algolia-docsearch-suggestion {
+ background: #ebebfb;
+}
+
+/* For bigger screens, when displaying results in two columns */
+@media (min-width: 768px) {
+ /* Bottom border of each suggestion */
+ .algolia-docsearch-suggestion {
+ border-bottom-color: #7671df;
+ }
+ /* Left column, with secondary category header */
+ .algolia-docsearch-suggestion--subcategory-column {
+ border-right-color: #7671df;
+ color: #4e4726;
+ }
+}
+
+.searchbox {
+ display: inline-block;
+ position: relative;
+ width: 200px;
+ height: 32px !important;
+ white-space: nowrap;
+ box-sizing: border-box;
+ visibility: visible !important;
+}
+
+.searchbox .algolia-autocomplete {
+ display: block;
+ width: 100%;
+ height: 100%;
+}
+
+.searchbox__wrapper {
+ width: 100%;
+ height: 100%;
+ z-index: 999;
+ position: relative;
+}
+
+.searchbox__input {
+ display: inline-block;
+ box-sizing: border-box;
+ -webkit-transition: box-shadow 0.4s ease, background 0.4s ease;
+ transition: box-shadow 0.4s ease, background 0.4s ease;
+ border: 0;
+ border-radius: 16px;
+ box-shadow: inset 0 0 0 1px #cccccc;
+ background: #ffffff !important;
+ padding: 0;
+ padding-right: 26px;
+ padding-left: 32px;
+ width: 100%;
+ height: 100%;
+ vertical-align: middle;
+ white-space: normal;
+ font-size: 12px;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+}
+
+.searchbox__input::-webkit-search-decoration,
+.searchbox__input::-webkit-search-cancel-button,
+.searchbox__input::-webkit-search-results-button,
+.searchbox__input::-webkit-search-results-decoration {
+ display: none;
+}
+
+.searchbox__input:hover {
+ box-shadow: inset 0 0 0 1px #b3b3b3;
+}
+
+.searchbox__input:focus,
+.searchbox__input:active {
+ outline: 0;
+ box-shadow: inset 0 0 0 1px #aaaaaa;
+ background: #ffffff;
+}
+
+.searchbox__input::-webkit-input-placeholder {
+ color: #aaaaaa;
+}
+
+.searchbox__input::-moz-placeholder {
+ color: #aaaaaa;
+}
+
+.searchbox__input:-ms-input-placeholder {
+ color: #aaaaaa;
+}
+
+.searchbox__input::placeholder {
+ color: #aaaaaa;
+}
+
+.searchbox__submit {
+ position: absolute;
+ top: 0;
+ margin: 0;
+ border: 0;
+ border-radius: 16px 0 0 16px;
+ background-color: rgba(69, 142, 225, 0);
+ padding: 0;
+ width: 32px;
+ height: 100%;
+ vertical-align: middle;
+ text-align: center;
+ font-size: inherit;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ right: inherit;
+ left: 0;
+}
+
+.searchbox__submit::before {
+ display: inline-block;
+ margin-right: -4px;
+ height: 100%;
+ vertical-align: middle;
+ content: '';
+}
+
+.searchbox__submit:hover,
+.searchbox__submit:active {
+ cursor: pointer;
+}
+
+.searchbox__submit:focus {
+ outline: 0;
+}
+
+.searchbox__submit svg {
+ width: 14px;
+ height: 14px;
+ vertical-align: middle;
+ fill: #6d7e96;
+}
+
+.searchbox__reset {
+ display: block;
+ position: absolute;
+ top: 8px;
+ right: 8px;
+ margin: 0;
+ border: 0;
+ background: none;
+ cursor: pointer;
+ padding: 0;
+ font-size: inherit;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ fill: rgba(0, 0, 0, 0.5);
+}
+
+.searchbox__reset.hide {
+ display: none;
+}
+
+.searchbox__reset:focus {
+ outline: 0;
+}
+
+.searchbox__reset svg {
+ display: block;
+ margin: 4px;
+ width: 8px;
+ height: 8px;
+}
+
+.searchbox__input:valid ~ .searchbox__reset {
+ display: block;
+ -webkit-animation-name: sbx-reset-in;
+ animation-name: sbx-reset-in;
+ -webkit-animation-duration: 0.15s;
+ animation-duration: 0.15s;
+}
+
+@-webkit-keyframes sbx-reset-in {
+ 0% {
+ -webkit-transform: translate3d(-20%, 0, 0);
+ transform: translate3d(-20%, 0, 0);
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: none;
+ transform: none;
+ opacity: 1;
+ }
+}
+
+@keyframes sbx-reset-in {
+ 0% {
+ -webkit-transform: translate3d(-20%, 0, 0);
+ transform: translate3d(-20%, 0, 0);
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: none;
+ transform: none;
+ opacity: 1;
+ }
+}
+
+.algolia-autocomplete .ds-dropdown-menu:before {
+ display: block;
+ position: absolute;
+ content: '';
+ width: 14px;
+ height: 14px;
+ background: #373940;
+ z-index: 1000;
+ top: -7px;
+ border-top: 1px solid #373940;
+ border-right: 1px solid #373940;
+ -webkit-transform: rotate(-45deg);
+ transform: rotate(-45deg);
+ border-radius: 2px;
+}
+
+.algolia-autocomplete .ds-dropdown-menu {
+ box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.2), 0 2px 3px 0 rgba(0, 0, 0, 0.1);
+}
+
+@media (min-width: 601px) {
+ .algolia-autocomplete.algolia-autocomplete-right .ds-dropdown-menu {
+ right: 0 !important;
+ left: inherit !important;
+ }
+
+ .algolia-autocomplete.algolia-autocomplete-right .ds-dropdown-menu:before {
+ right: 48px;
+ }
+
+ .algolia-autocomplete .ds-dropdown-menu {
+ position: relative;
+ top: -6px;
+ border-radius: 4px;
+ margin: 6px 0 0;
+ padding: 0;
+ text-align: left;
+ height: auto;
+ position: relative;
+ background: transparent;
+ border: none;
+ z-index: 999;
+ max-width: 600px;
+ min-width: 500px;
+ }
+}
+
+@media (max-width: 600px) {
+ .algolia-autocomplete .ds-dropdown-menu {
+ z-index: 100;
+ position: fixed !important;
+ top: 50px !important;
+ left: auto !important;
+ right: 1rem !important;
+ width: 600px;
+ max-width: calc(100% - 2rem);
+ max-height: calc(100% - 5rem);
+ display: block;
+ }
+
+ .algolia-autocomplete .ds-dropdown-menu:before {
+ right: 6rem;
+ }
+}
+
+.algolia-autocomplete .ds-dropdown-menu .ds-suggestions {
+ position: relative;
+ z-index: 1000;
+}
+
+.algolia-autocomplete .ds-dropdown-menu .ds-suggestion {
+ cursor: pointer;
+}
+
+.algolia-autocomplete .ds-dropdown-menu [class^='ds-dataset-'] {
+ position: relative;
+ border-radius: 4px;
+ overflow: auto;
+ padding: 0;
+ background: #ffffff;
+}
+
+.algolia-autocomplete .ds-dropdown-menu * {
+ box-sizing: border-box;
+}
+
+.algolia-autocomplete .algolia-docsearch-suggestion {
+ display: block;
+ position: relative;
+ padding: 0;
+ overflow: hidden;
+ text-decoration: none;
+}
+
+.algolia-autocomplete .ds-cursor .algolia-docsearch-suggestion--wrapper {
+ background: #f1f1f1;
+ box-shadow: inset -2px 0 0 #61dafb;
+}
+
+.algolia-autocomplete .algolia-docsearch-suggestion--highlight {
+ background: #ffe564;
+ padding: 0.1em 0.05em;
+}
+
+.algolia-autocomplete
+ .algolia-docsearch-suggestion--category-header
+ .algolia-docsearch-suggestion--category-header-lvl0
+ .algolia-docsearch-suggestion--highlight,
+.algolia-autocomplete
+ .algolia-docsearch-suggestion--category-header
+ .algolia-docsearch-suggestion--category-header-lvl1
+ .algolia-docsearch-suggestion--highlight {
+ color: inherit;
+ background: inherit;
+}
+
+.algolia-autocomplete
+ .algolia-docsearch-suggestion--text
+ .algolia-docsearch-suggestion--highlight {
+ padding: 0 0 1px;
+ background: inherit;
+ box-shadow: inset 0 -2px 0 0 rgba(69, 142, 225, 0.8);
+ color: inherit;
+}
+
+.algolia-autocomplete .algolia-docsearch-suggestion--content {
+ display: block;
+ float: right;
+ width: 70%;
+ position: relative;
+ padding: 5.33333px 0 5.33333px 10.66667px;
+ cursor: pointer;
+}
+
+.algolia-autocomplete .algolia-docsearch-suggestion--content:before {
+ content: '';
+ position: absolute;
+ display: block;
+ top: 0;
+ height: 100%;
+ width: 1px;
+ background: #ececec;
+ left: -1px;
+}
+
+.algolia-autocomplete .algolia-docsearch-suggestion--category-header {
+ position: relative;
+ display: none;
+ font-size: 14px;
+ letter-spacing: 0.08em;
+ font-weight: 700;
+ background-color: #373940;
+ text-transform: uppercase;
+ color: #fff;
+ margin: 0;
+ padding: 5px 8px;
+}
+
+.algolia-autocomplete .algolia-docsearch-suggestion--wrapper {
+ background-color: #fff;
+ width: 100%;
+ float: left;
+ padding: 8px 0 0 0;
+}
+
+.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column {
+ float: left;
+ width: 30%;
+ display: none;
+ padding-left: 0;
+ text-align: right;
+ position: relative;
+ padding: 5.33333px 10.66667px;
+ color: #777;
+ font-size: 0.9em;
+ word-wrap: break-word;
+}
+
+.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column:before {
+ content: '';
+ position: absolute;
+ display: block;
+ top: 0;
+ height: 100%;
+ width: 1px;
+ background: #ececec;
+ right: 0;
+}
+
+.algolia-autocomplete
+ .algolia-docsearch-suggestion.algolia-docsearch-suggestion__main
+ .algolia-docsearch-suggestion--category-header,
+.algolia-autocomplete
+ .algolia-docsearch-suggestion.algolia-docsearch-suggestion__secondary {
+ display: block;
+}
+
+.algolia-autocomplete
+ .algolia-docsearch-suggestion--subcategory-column
+ .algolia-docsearch-suggestion--highlight {
+ background-color: inherit;
+ color: inherit;
+}
+
+.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-inline {
+ display: none;
+}
+
+.algolia-autocomplete .algolia-docsearch-suggestion--title {
+ margin-bottom: 4px;
+ color: #02060c;
+ font-size: 0.9em;
+ font-weight: bold;
+}
+
+.algolia-autocomplete .algolia-docsearch-suggestion--text {
+ display: block;
+ line-height: 1.2em;
+ font-size: 0.85em;
+ color: #63676d;
+ padding-right: 2px;
+}
+
+.algolia-autocomplete .algolia-docsearch-suggestion--no-results {
+ width: 100%;
+ padding: 8px 0;
+ text-align: center;
+ font-size: 1.2em;
+ background-color: #373940;
+ margin-top: -8px;
+}
+
+.algolia-autocomplete
+ .algolia-docsearch-suggestion--no-results
+ .algolia-docsearch-suggestion--text {
+ color: #ffffff;
+ margin-top: 4px;
+}
+
+.algolia-autocomplete .algolia-docsearch-suggestion--no-results::before {
+ display: none;
+}
+
+.algolia-autocomplete .algolia-docsearch-suggestion code {
+ padding: 1px 5px;
+ font-size: 90%;
+ border: none;
+ color: #222222;
+ background-color: #ebebeb;
+ border-radius: 3px;
+ font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
+ monospace;
+}
+
+.algolia-autocomplete
+ .algolia-docsearch-suggestion
+ code
+ .algolia-docsearch-suggestion--highlight {
+ background: none;
+}
+
+.algolia-autocomplete
+ .algolia-docsearch-suggestion.algolia-docsearch-suggestion__main
+ .algolia-docsearch-suggestion--category-header {
+ color: white;
+ display: block;
+}
+
+.algolia-autocomplete
+ .algolia-docsearch-suggestion.algolia-docsearch-suggestion__secondary
+ .algolia-docsearch-suggestion--subcategory-column {
+ display: block;
+}
+
+.algolia-autocomplete .algolia-docsearch-footer {
+ background-color: #fff;
+ width: 100%;
+ height: 30px;
+ z-index: 2000;
+ float: right;
+ font-size: 0;
+ line-height: 0;
+}
+
+.algolia-autocomplete .algolia-docsearch-footer--logo {
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 130 18'%3E%3Cdefs%3E%3ClinearGradient id='a' x1='-36.87%25' x2='129.43%25' y1='134.94%25' y2='-27.7%25'%3E%3Cstop stop-color='%252300AEFF' offset='0%25'/%3E%3Cstop stop-color='%25233369E7' offset='100%25'/%3E%3C/linearGradient%3E%3C/defs%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cpath fill='url(%2523a)' d='M59.4.02h13.3a2.37 2.37 0 0 1 2.38 2.37V15.6a2.37 2.37 0 0 1-2.38 2.36H59.4a2.37 2.37 0 0 1-2.38-2.36V2.38A2.37 2.37 0 0 1 59.4.02z'/%3E%3Cpath fill='%2523FFF' d='M66.26 4.56c-2.82 0-5.1 2.27-5.1 5.08 0 2.8 2.28 5.07 5.1 5.07 2.8 0 5.1-2.26 5.1-5.07 0-2.8-2.28-5.07-5.1-5.07zm0 8.65c-2 0-3.6-1.6-3.6-3.56 0-1.97 1.6-3.58 3.6-3.58 1.98 0 3.6 1.6 3.6 3.58a3.58 3.58 0 0 1-3.6 3.57zm0-6.4v2.66c0 .07.08.13.15.1l2.4-1.24c.04-.02.06-.1.03-.14a2.96 2.96 0 0 0-2.46-1.5c-.06 0-.1.05-.1.1zm-3.33-1.96l-.3-.3a.78.78 0 0 0-1.12 0l-.36.36a.77.77 0 0 0 0 1.1l.3.3c.05.05.13.04.17 0 .2-.25.4-.5.6-.7.23-.23.46-.43.7-.6.07-.04.07-.1.03-.16zm5-.8V3.4a.78.78 0 0 0-.78-.78h-1.83a.78.78 0 0 0-.78.78v.63c0 .07.06.12.14.1a5.74 5.74 0 0 1 1.58-.22c.52 0 1.04.07 1.54.2a.1.1 0 0 0 .13-.1z'/%3E%3Cpath fill='%2523182359' d='M102.16 13.76c0 1.46-.37 2.52-1.12 3.2-.75.67-1.9 1-3.44 1-.56 0-1.74-.1-2.67-.3l.34-1.7c.78.17 1.82.2 2.36.2.86 0 1.48-.16 1.84-.5.37-.36.55-.88.55-1.57v-.35a6.37 6.37 0 0 1-.84.3 4.15 4.15 0 0 1-1.2.17 4.5 4.5 0 0 1-1.6-.28 3.38 3.38 0 0 1-1.26-.82 3.74 3.74 0 0 1-.8-1.35c-.2-.54-.3-1.5-.3-2.2 0-.67.1-1.5.3-2.06a3.92 3.92 0 0 1 .9-1.43 4.12 4.12 0 0 1 1.45-.92 5.3 5.3 0 0 1 1.94-.37c.7 0 1.35.1 1.97.2a15.86 15.86 0 0 1 1.6.33v8.46zm-5.95-4.2c0 .9.2 1.88.6 2.3.4.4.9.62 1.53.62.34 0 .66-.05.96-.15a2.75 2.75 0 0 0 .73-.33V6.7a8.53 8.53 0 0 0-1.42-.17c-.76-.02-1.36.3-1.77.8-.4.5-.62 1.4-.62 2.23zm16.13 0c0 .72-.1 1.26-.32 1.85a4.4 4.4 0 0 1-.9 1.53c-.38.42-.85.75-1.4.98-.54.24-1.4.37-1.8.37-.43 0-1.27-.13-1.8-.36a4.1 4.1 0 0 1-1.4-.97 4.5 4.5 0 0 1-.92-1.52 5.04 5.04 0 0 1-.33-1.84c0-.72.1-1.4.32-2 .22-.6.53-1.1.92-1.5.4-.43.86-.75 1.4-.98a4.55 4.55 0 0 1 1.78-.34 4.7 4.7 0 0 1 1.8.34c.54.23 1 .55 1.4.97.38.42.68.92.9 1.5.23.6.35 1.3.35 2zm-2.2 0c0-.92-.2-1.7-.6-2.22-.38-.54-.94-.8-1.64-.8-.72 0-1.27.26-1.67.8-.4.54-.58 1.3-.58 2.22 0 .93.2 1.56.6 2.1.38.54.94.8 1.64.8s1.25-.26 1.65-.8c.4-.55.6-1.17.6-2.1zm6.97 4.7c-3.5.02-3.5-2.8-3.5-3.27L113.57.92l2.15-.34v10c0 .25 0 1.87 1.37 1.88v1.8zm3.77 0h-2.15v-9.2l2.15-.33v9.54zM119.8 3.74c.7 0 1.3-.58 1.3-1.3 0-.7-.58-1.3-1.3-1.3-.73 0-1.3.6-1.3 1.3 0 .72.58 1.3 1.3 1.3zm6.43 1c.7 0 1.3.1 1.78.27.5.18.88.42 1.17.73.28.3.5.74.6 1.18.13.46.2.95.2 1.5v5.47a25.24 25.24 0 0 1-1.5.25c-.67.1-1.42.15-2.25.15a6.83 6.83 0 0 1-1.52-.16 3.2 3.2 0 0 1-1.18-.5 2.46 2.46 0 0 1-.76-.9c-.18-.37-.27-.9-.27-1.44 0-.52.1-.85.3-1.2.2-.37.48-.67.83-.9a3.6 3.6 0 0 1 1.23-.5 7.07 7.07 0 0 1 2.2-.1l.83.16v-.35c0-.25-.03-.48-.1-.7a1.5 1.5 0 0 0-.3-.58c-.15-.18-.34-.3-.58-.4a2.54 2.54 0 0 0-.92-.17c-.5 0-.94.06-1.35.13-.4.08-.75.16-1 .25l-.27-1.74c.27-.1.67-.18 1.2-.28a9.34 9.34 0 0 1 1.65-.14zm.18 7.74c.66 0 1.15-.04 1.5-.1V10.2a5.1 5.1 0 0 0-2-.1c-.23.03-.45.1-.64.2a1.17 1.17 0 0 0-.47.38c-.13.17-.18.26-.18.52 0 .5.17.8.5.98.32.2.74.3 1.3.3zM84.1 4.8c.72 0 1.3.08 1.8.26.48.17.87.42 1.15.73.3.3.5.72.6 1.17.14.45.2.94.2 1.47v5.48a25.24 25.24 0 0 1-1.5.26c-.67.1-1.42.14-2.25.14a6.83 6.83 0 0 1-1.52-.16 3.2 3.2 0 0 1-1.18-.5 2.46 2.46 0 0 1-.76-.9c-.18-.38-.27-.9-.27-1.44 0-.53.1-.86.3-1.22.2-.36.5-.65.84-.88a3.6 3.6 0 0 1 1.24-.5 7.07 7.07 0 0 1 2.2-.1c.26.03.54.08.84.15v-.35c0-.24-.03-.48-.1-.7a1.5 1.5 0 0 0-.3-.58c-.15-.17-.34-.3-.58-.4a2.54 2.54 0 0 0-.9-.15c-.5 0-.96.05-1.37.12-.4.07-.75.15-1 .24l-.26-1.75c.27-.08.67-.17 1.18-.26a8.9 8.9 0 0 1 1.66-.15zm.2 7.73c.65 0 1.14-.04 1.48-.1v-2.17a5.1 5.1 0 0 0-1.98-.1c-.24.03-.46.1-.65.18a1.17 1.17 0 0 0-.47.4c-.12.17-.17.26-.17.52 0 .5.18.8.5.98.32.2.75.3 1.3.3zm8.68 1.74c-3.5 0-3.5-2.82-3.5-3.28L89.45.92 91.6.6v10c0 .25 0 1.87 1.38 1.88v1.8z'/%3E%3Cpath fill='%25231D3657' d='M5.03 11.03c0 .7-.26 1.24-.76 1.64-.5.4-1.2.6-2.1.6-.88 0-1.6-.14-2.17-.42v-1.2c.36.16.74.3 1.14.38.4.1.78.15 1.13.15.5 0 .88-.1 1.12-.3a.94.94 0 0 0 .35-.77.98.98 0 0 0-.33-.74c-.22-.2-.68-.44-1.37-.72-.72-.3-1.22-.62-1.52-1C.23 8.27.1 7.82.1 7.3c0-.65.22-1.17.7-1.55.46-.37 1.08-.56 1.86-.56.76 0 1.5.16 2.25.48l-.4 1.05c-.7-.3-1.32-.44-1.87-.44-.4 0-.73.08-.94.26a.9.9 0 0 0-.33.72c0 .2.04.38.12.52.08.15.22.3.42.4.2.14.55.3 1.06.52.58.24 1 .47 1.27.67.27.2.47.44.6.7.12.26.18.57.18.92zM9 13.27c-.92 0-1.64-.27-2.16-.8-.52-.55-.78-1.3-.78-2.24 0-.97.24-1.73.72-2.3.5-.54 1.15-.82 2-.82.78 0 1.4.25 1.85.72.46.48.7 1.14.7 1.97v.67H7.35c0 .58.17 1.02.46 1.33.3.3.7.47 1.24.47.36 0 .68-.04.98-.1a5.1 5.1 0 0 0 .98-.33v1.02a3.87 3.87 0 0 1-.94.32 5.72 5.72 0 0 1-1.08.1zm-.22-5.2c-.4 0-.73.12-.97.38s-.37.62-.42 1.1h2.7c0-.48-.13-.85-.36-1.1-.23-.26-.54-.38-.94-.38zm7.7 5.1l-.26-.84h-.05c-.28.36-.57.6-.86.74-.28.13-.65.2-1.1.2-.6 0-1.05-.16-1.38-.48-.32-.32-.5-.77-.5-1.34 0-.62.24-1.08.7-1.4.45-.3 1.14-.47 2.07-.5l1.02-.03V9.2c0-.37-.1-.65-.27-.84-.17-.2-.45-.28-.82-.28-.3 0-.6.04-.88.13a6.68 6.68 0 0 0-.8.33l-.4-.9a4.4 4.4 0 0 1 1.05-.4 4.86 4.86 0 0 1 1.08-.12c.76 0 1.33.18 1.7.5.4.33.6.85.6 1.56v4h-.9zm-1.9-.87c.47 0 .83-.13 1.1-.38.3-.26.43-.62.43-1.08v-.52l-.76.03c-.6.03-1.02.13-1.3.3s-.4.45-.4.82c0 .26.08.47.24.6.16.16.4.23.7.23zm7.57-5.2c.25 0 .46.03.62.06l-.12 1.18a2.38 2.38 0 0 0-.56-.06c-.5 0-.92.16-1.24.5-.3.32-.47.75-.47 1.27v3.1h-1.27V7.23h1l.16 1.05h.05c.2-.36.45-.64.77-.85a1.83 1.83 0 0 1 1.02-.3zm4.12 6.17c-.9 0-1.58-.27-2.05-.8-.47-.52-.7-1.27-.7-2.25 0-1 .24-1.77.73-2.3.5-.54 1.2-.8 2.12-.8.63 0 1.2.1 1.7.34l-.4 1c-.52-.2-.96-.3-1.3-.3-1.04 0-1.55.68-1.55 2.05 0 .67.13 1.17.38 1.5.26.34.64.5 1.13.5a3.23 3.23 0 0 0 1.6-.4v1.1a2.53 2.53 0 0 1-.73.28 4.36 4.36 0 0 1-.93.08zm8.28-.1h-1.27V9.5c0-.45-.1-.8-.28-1.02-.18-.23-.47-.34-.88-.34-.53 0-.9.16-1.16.48-.25.3-.38.85-.38 1.6v2.94h-1.26V4.8h1.26v2.12c0 .34-.02.7-.06 1.1h.08a1.76 1.76 0 0 1 .72-.67c.3-.16.66-.24 1.07-.24 1.43 0 2.15.74 2.15 2.2v3.86zM42.2 7.1c.74 0 1.32.28 1.73.82.4.53.62 1.3.62 2.26 0 .97-.2 1.73-.63 2.27-.42.54-1 .82-1.75.82s-1.33-.27-1.75-.8h-.08l-.23.7h-.94V4.8h1.26v2l-.02.64-.03.56h.05c.4-.6 1-.9 1.78-.9zm-.33 1.04c-.5 0-.88.15-1.1.45-.22.3-.34.8-.35 1.5v.08c0 .72.12 1.24.35 1.57.23.32.6.48 1.12.48.44 0 .78-.17 1-.53.24-.35.36-.87.36-1.53 0-1.35-.47-2.03-1.4-2.03zm3.24-.92h1.4l1.2 3.37c.18.47.3.92.36 1.34h.04l.18-.72 1.37-4H51l-2.53 6.73c-.46 1.23-1.23 1.85-2.3 1.85-.3 0-.56-.03-.83-.1v-1c.2.05.4.08.65.08.6 0 1.03-.36 1.28-1.06l.22-.56-2.4-5.94z'/%3E%3C/g%3E%3C/svg%3E");
+ background-repeat: no-repeat;
+ background-position: center;
+ background-size: 100%;
+ overflow: hidden;
+ text-indent: -9000px;
+ width: 110px;
+ height: 100%;
+ display: block;
+ margin-left: auto;
+ margin-right: 5px;
+}
diff --git a/website/src/theme/SearchBar/index.js b/website/src/theme/SearchBar/index.js
new file mode 100644
index 000000000..bb8be607b
--- /dev/null
+++ b/website/src/theme/SearchBar/index.js
@@ -0,0 +1,121 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+import React, { useRef, useCallback, useState } from "react";
+import classnames from "classnames";
+import { useHistory } from "@docusaurus/router";
+import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
+import { usePluginData } from '@docusaurus/useGlobalData';
+import useIsBrowser from "@docusaurus/useIsBrowser";
+const Search = props => {
+ const initialized = useRef(false);
+ const searchBarRef = useRef(null);
+ const [indexReady, setIndexReady] = useState(false);
+ const history = useHistory();
+ const { siteConfig = {} } = useDocusaurusContext();
+ const isBrowser = useIsBrowser();
+ const { baseUrl } = siteConfig;
+ const initAlgolia = (searchDocs, searchIndex, DocSearch) => {
+ new DocSearch({
+ searchDocs,
+ searchIndex,
+ baseUrl,
+ inputSelector: "#search_input_react",
+ // Override algolia's default selection event, allowing us to do client-side
+ // navigation and avoiding a full page refresh.
+ handleSelected: (_input, _event, suggestion) => {
+ const url = suggestion.url || "/";
+ // Use an anchor tag to parse the absolute url into a relative url
+ // Alternatively, we can use new URL(suggestion.url) but its not supported in IE
+ const a = document.createElement("a");
+ a.href = url;
+ // Algolia use closest parent element id #__docusaurus when a h1 page title does not have an id
+ // So, we can safely remove it. See https://github.com/facebook/docusaurus/issues/1828 for more details.
+
+ history.push(url);
+ }
+ });
+ };
+
+ const pluginData = usePluginData('docusaurus-lunr-search');
+ const getSearchDoc = () =>
+ process.env.NODE_ENV === "production"
+ ? fetch(`${baseUrl}${pluginData.fileNames.searchDoc}`).then((content) => content.json())
+ : Promise.resolve([]);
+
+ const getLunrIndex = () =>
+ process.env.NODE_ENV === "production"
+ ? fetch(`${baseUrl}${pluginData.fileNames.lunrIndex}`).then((content) => content.json())
+ : Promise.resolve([]);
+
+ const loadAlgolia = () => {
+ if (!initialized.current) {
+ Promise.all([
+ getSearchDoc(),
+ getLunrIndex(),
+ import("./DocSearch"),
+ import("./algolia.css")
+ ]).then(([searchDocs, searchIndex, { default: DocSearch }]) => {
+ if (searchDocs.length === 0) {
+ return;
+ }
+ initAlgolia(searchDocs, searchIndex, DocSearch);
+ setIndexReady(true);
+ });
+ initialized.current = true;
+ }
+ };
+
+ const toggleSearchIconClick = useCallback(
+ e => {
+ if (!searchBarRef.current.contains(e.target)) {
+ searchBarRef.current.focus();
+ }
+
+ props.handleSearchBarToggle && props.handleSearchBarToggle(!props.isSearchBarExpanded);
+ },
+ [props.isSearchBarExpanded]
+ );
+
+ if (isBrowser) {
+ loadAlgolia();
+ }
+
+ return (
+
Keywords: ' + doc.keywords.substring(0, start) + '' + doc.keywords.substring(start, end) + '' + doc.keywords.substring(end, doc.keywords.length) + ''
+ return this.getHit(doc, formattedTitle)
+ }
+
+ getContentHit(doc, position) {
+ const start = position[0];
+ const end = position[0] + position[1];
+ let previewStart = start;
+ let previewEnd = end;
+ let ellipsesBefore = true;
+ let ellipsesAfter = true;
+ for (let k = 0; k < 3; k++) {
+ const nextSpace = doc.content.lastIndexOf(' ', previewStart - 2);
+ const nextDot = doc.content.lastIndexOf('.', previewStart - 2);
+ if ((nextDot > 0) && (nextDot > nextSpace)) {
+ previewStart = nextDot + 1;
+ ellipsesBefore = false;
+ break;
+ }
+ if (nextSpace < 0) {
+ previewStart = 0;
+ ellipsesBefore = false;
+ break;
+ }
+ previewStart = nextSpace + 1;
+ }
+ for (let k = 0; k < 10; k++) {
+ const nextSpace = doc.content.indexOf(' ', previewEnd + 1);
+ const nextDot = doc.content.indexOf('.', previewEnd + 1);
+ if ((nextDot > 0) && (nextDot < nextSpace)) {
+ previewEnd = nextDot;
+ ellipsesAfter = false;
+ break;
+ }
+ if (nextSpace < 0) {
+ previewEnd = doc.content.length;
+ ellipsesAfter = false;
+ break;
+ }
+ previewEnd = nextSpace;
+ }
+ let preview = doc.content.substring(previewStart, start);
+ if (ellipsesBefore) {
+ preview = '... ' + preview;
+ }
+ preview += '' + doc.content.substring(start, end) + '';
+ preview += doc.content.substring(end, previewEnd);
+ if (ellipsesAfter) {
+ preview += ' ...';
+ }
+ return this.getHit(doc, null, preview);
+
+ }
+ search(input) {
+ return new Promise((resolve, rej) => {
+ const results = this.getLunrResult(input);
+ const hits = [];
+ results.length > 5 && (results.length = 5);
+ this.titleHitsRes = []
+ this.contentHitsRes = []
+ results.forEach(result => {
+ const doc = this.searchDocs[result.ref];
+ const { metadata } = result.matchData;
+ for (let i in metadata) {
+ if (metadata[i].title) {
+ if (!this.titleHitsRes.includes(result.ref)) {
+ const position = metadata[i].title.position[0]
+ hits.push(this.getTitleHit(doc, position, input.length));
+ this.titleHitsRes.push(result.ref);
+ }
+ } else if (metadata[i].content) {
+ const position = metadata[i].content.position[0]
+ hits.push(this.getContentHit(doc, position))
+ } else if (metadata[i].keywords) {
+ const position = metadata[i].keywords.position[0]
+ hits.push(this.getKeywordHit(doc, position, input.length));
+ this.titleHitsRes.push(result.ref);
+ }
+ }
+ });
+ hits.length > 5 && (hits.length = 5);
+ resolve(hits);
+ });
+ }
+}
+
+export default LunrSearchAdapter;
diff --git a/website/src/theme/SearchBar/styles.css b/website/src/theme/SearchBar/styles.css
new file mode 100644
index 000000000..39fd06c7e
--- /dev/null
+++ b/website/src/theme/SearchBar/styles.css
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+.search-icon {
+ background-image: var(--ifm-navbar-search-input-icon);
+ height: auto;
+ width: 24px;
+ cursor: pointer;
+ padding: 8px;
+ line-height: 32px;
+ background-repeat: no-repeat;
+ background-position: center;
+ display: none;
+}
+
+.search-icon-hidden {
+ visibility: hidden;
+}
+
+@media (max-width: 360px) {
+ .search-bar {
+ width: 0 !important;
+ background: none !important;
+ padding: 0 !important;
+ transition: none !important;
+ }
+
+ .search-bar-expanded {
+ width: 9rem !important;
+ }
+
+ .search-icon {
+ display: inline;
+ vertical-align: sub;
+ }
+}
diff --git a/website/src/theme/SearchBar/templates.js b/website/src/theme/SearchBar/templates.js
new file mode 100644
index 000000000..e8112dff1
--- /dev/null
+++ b/website/src/theme/SearchBar/templates.js
@@ -0,0 +1,119 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+const prefix = 'algolia-docsearch';
+const suggestionPrefix = `${prefix}-suggestion`;
+const footerPrefix = `${prefix}-footer`;
+
+const templates = {
+ suggestion: `
+
+