@algolia/react-instantsearch-widget-loadmore-with-progressbar
Version:
React InstantSearch widget that displays a load more button with a progress bar
212 lines (211 loc) • 8.58 kB
JavaScript
import { createConnector, translatable } from "react-instantsearch-core";
import classNames from "classnames";
import React, { useMemo } from "react";
import { createClassNames } from "react-instantsearch-dom";
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function ownKeys(object, enumerableOnly) {
var keys = Object.keys(object);
if (Object.getOwnPropertySymbols) {
var symbols = Object.getOwnPropertySymbols(object);
enumerableOnly && (symbols = symbols.filter(function(sym) {
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
})), keys.push.apply(keys, symbols);
}
return keys;
}
function _objectSpread(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? arguments[i] : {};
i % 2 ? ownKeys(Object(source), true).forEach(function(key) {
_defineProperty(target, key, source[key]);
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function(key) {
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
});
}
return target;
}
function getIndexId(context) {
return hasMultipleIndices(context) ? context.multiIndexContext.targetedIndex : context.ais.mainTargetedIndex;
}
function getResults(searchResults, context) {
if (searchResults.results) {
if (searchResults.results.hits) {
return searchResults.results;
}
var indexId = getIndexId(context);
if (searchResults.results[indexId]) {
return searchResults.results[indexId];
}
}
return null;
}
function hasMultipleIndices(context) {
return context && context.multiIndexContext;
}
function refineValue(searchState, nextRefinement, context, resetPage, namespace) {
if (hasMultipleIndices(context)) {
var indexId = getIndexId(context);
return namespace ? refineMultiIndexWithNamespace(searchState, nextRefinement, indexId, resetPage, namespace) : refineMultiIndex(searchState, nextRefinement, indexId, resetPage);
} else {
if (searchState.indices && resetPage) {
Object.keys(searchState.indices).forEach(function(targetedIndex) {
searchState = refineValue(searchState, {
page: 1
}, {
multiIndexContext: {
targetedIndex
}
}, true, namespace);
});
}
return namespace ? refineSingleIndexWithNamespace(searchState, nextRefinement, resetPage, namespace) : refineSingleIndex(searchState, nextRefinement, resetPage);
}
}
function refineMultiIndex(searchState, nextRefinement, indexId, resetPage) {
var page = resetPage ? {
page: 1
} : void 0;
var state = searchState.indices && searchState.indices[indexId] ? _objectSpread(_objectSpread({}, searchState.indices), {}, _defineProperty({}, indexId, _objectSpread(_objectSpread(_objectSpread({}, searchState.indices[indexId]), nextRefinement), page))) : _objectSpread(_objectSpread({}, searchState.indices), {}, _defineProperty({}, indexId, _objectSpread(_objectSpread({}, nextRefinement), page)));
return _objectSpread(_objectSpread({}, searchState), {}, {
indices: state
});
}
function refineSingleIndex(searchState, nextRefinement, resetPage) {
var page = resetPage ? {
page: 1
} : void 0;
return _objectSpread(_objectSpread(_objectSpread({}, searchState), nextRefinement), page);
}
function refineMultiIndexWithNamespace(searchState, nextRefinement, indexId, resetPage, namespace) {
var _objectSpread4;
var page = resetPage ? {
page: 1
} : void 0;
var state = searchState.indices && searchState.indices[indexId] ? _objectSpread(_objectSpread({}, searchState.indices), {}, _defineProperty({}, indexId, _objectSpread(_objectSpread({}, searchState.indices[indexId]), {}, (_objectSpread4 = {}, _defineProperty(_objectSpread4, namespace, _objectSpread(_objectSpread({}, searchState.indices[indexId][namespace]), nextRefinement)), _defineProperty(_objectSpread4, "page", 1), _objectSpread4)))) : _objectSpread(_objectSpread({}, searchState.indices), {}, _defineProperty({}, indexId, _objectSpread(_defineProperty({}, namespace, nextRefinement), page)));
return _objectSpread(_objectSpread({}, searchState), {}, {
indices: state
});
}
function refineSingleIndexWithNamespace(searchState, nextRefinement, resetPage, namespace) {
var page = resetPage ? {
page: 1
} : void 0;
return _objectSpread(_objectSpread({}, searchState), {}, _defineProperty({}, namespace, _objectSpread(_objectSpread({}, searchState[namespace]), nextRefinement)), page);
}
function getId() {
return "page";
}
const connectLoadMoreWithProgressBar = createConnector({
displayName: "AlgoliaLoadMoreWithProgressBar",
$$type: "ais.loadMoreWithProgressBar",
getProvidedProps(props, searchState, searchResults) {
const results = getResults(searchResults, {
ais: props.contextValue,
multiIndexContext: props.indexContextValue
});
if (!results) {
return {
nbSeenHits: 0,
nbTotalHits: 0,
refineNext: () => {
},
isSearchStalled: searchResults.isSearchStalled
};
}
const { page, nbPages, nbHits: nbTotalHits, hitsPerPage } = results;
const isLastPage = page + 1 === nbPages;
let nbSeenHits = (page + 1) * hitsPerPage;
nbSeenHits += isLastPage ? nbTotalHits - nbSeenHits : 0;
return {
nbSeenHits,
nbTotalHits,
refineNext: () => this.refine(page + 1),
isSearchStalled: searchResults.isSearchStalled
};
},
refine(props, searchState, index) {
const id = getId();
const nextValue = { [id]: index + 1 };
const resetPage = false;
return refineValue(searchState, nextValue, { ais: props.contextValue, multiIndexContext: props.indexContextValue }, resetPage, null);
},
cleanUp(props, searchState) {
return searchState;
},
getSearchParameters(searchParameters) {
return searchParameters;
}
});
const cx = (...args) => classNames(createClassNames("LoadMoreWithProgressBar")(...args));
const ButtonComponent = ({
translations: translations2,
isSearchStalled,
refineNext
}) => /* @__PURE__ */ React.createElement("button", {
type: "button",
className: classNames(cx("loadMore"), "ais-InfiniteHits-loadMore"),
disabled: isSearchStalled,
onClick: refineNext
}, isSearchStalled ? translations2.searchStalled : translations2.loadMore);
const LoadMoreWithProgressBar$1 = ({
nbSeenHits,
nbTotalHits,
isSearchStalled,
refineNext,
translate,
buttonComponent: CustomButtonComponent,
className
}) => {
const hasMore = nbSeenHits < nbTotalHits;
const hasResults = nbTotalHits > 0;
const progress = hasResults ? Math.floor(nbSeenHits / nbTotalHits * 100) : 0;
const translations2 = useMemo(() => ({
loadMore: translate("loadMore"),
searchStalled: translate("searchStalled"),
text: translate("text", { nbSeenHits, nbTotalHits })
}), [translate, nbSeenHits, nbTotalHits]);
const Button = CustomButtonComponent != null ? CustomButtonComponent : ButtonComponent;
return /* @__PURE__ */ React.createElement("div", {
className: classNames(cx(""), className)
}, hasResults && /* @__PURE__ */ React.createElement("div", {
className: cx("progressBar")
}, /* @__PURE__ */ React.createElement("progress", {
className: cx("progressBar-bar"),
max: "100",
value: progress
}, /* @__PURE__ */ React.createElement("div", {
className: cx("progressBar-fallback")
}, /* @__PURE__ */ React.createElement("span", {
style: {
width: `${progress}%`
}
}))), /* @__PURE__ */ React.createElement("div", {
className: cx("progressBar-text")
}, translations2.text)), hasMore && hasResults && /* @__PURE__ */ React.createElement(Button, {
translations: translations2,
isSearchStalled,
refineNext
}));
};
const translations = {
loadMore: "Load more",
searchStalled: "Loading...",
text: ({ nbSeenHits, nbTotalHits }) => `You've seen ${nbSeenHits} item${nbSeenHits > 1 ? "s" : ""} out of ${nbTotalHits}`
};
const LoadMoreWithProgressBarComponent = translatable(translations)(LoadMoreWithProgressBar$1);
const LoadMoreWithProgressBar = connectLoadMoreWithProgressBar(LoadMoreWithProgressBarComponent, {
$$widgetType: "ais.loadMoreWithProgressBar"
});
export { LoadMoreWithProgressBar, LoadMoreWithProgressBarComponent, connectLoadMoreWithProgressBar };