Skip to content

Instantly share code, notes, and snippets.

@Fronix
Last active October 20, 2025 14:54
Show Gist options
  • Save Fronix/cbcc8ee66c00fa6986ce76ae95f29512 to your computer and use it in GitHub Desktop.
Save Fronix/cbcc8ee66c00fa6986ce76ae95f29512 to your computer and use it in GitHub Desktop.
Custom useRefinementList with operator switch support. It includes a modified version of connectClearRefinements to also make it clear the operator paramaters from the URL, not required for the refinments to work..
import type { AlgoliaSearchHelper, SearchResults } from 'algoliasearch-helper';
import type {
TransformItems,
CreateURL,
WidgetRenderState,
Connector,
ScopedResult
} from 'instantsearch.js';
import {
createDocumentationMessageGenerator,
checkRendering,
mergeSearchParameters,
getRefinements
} from 'instantsearch.js/es/lib/utils';
import { noop, uniq } from 'lodash';
const withUsage = createDocumentationMessageGenerator({
name: 'clear-refinements',
connector: true
});
export type ClearRefinementsConnectorParams = {
/**
* The attributes to include in the refinements to clear (all by default). Cannot be used with `excludedAttributes`.
*/
includedAttributes?: string[];
/**
* The attributes to exclude from the refinements to clear. Cannot be used with `includedAttributes`.
*/
excludedAttributes?: string[];
/**
* Function to transform the items passed to the templates.
*/
transformItems?: TransformItems<string>;
};
export type ClearRefinementsRenderState = {
/**
* Triggers the clear of all the currently refined values.
*/
refine: () => void;
/**
* Indicates if search state is refined.
* @deprecated prefer reading canRefine
*/
hasRefinements: boolean;
/**
* Indicates if search state can be refined.
*/
canRefine: boolean;
/**
* Creates a url for the next state when refinements are cleared.
*/
createURL: CreateURL<void>;
};
export type ClearRefinementsWidgetDescription = {
$$type: 'ais.clearRefinements';
renderState: ClearRefinementsRenderState;
indexRenderState: {
clearRefinements: WidgetRenderState<
ClearRefinementsRenderState,
ClearRefinementsConnectorParams
>;
};
};
export type ClearRefinementsConnector = Connector<
ClearRefinementsWidgetDescription,
ClearRefinementsConnectorParams
>;
type AttributesToClear = {
helper: AlgoliaSearchHelper;
items: string[];
};
const connectClearRefinements: ClearRefinementsConnector = function connectClearRefinements(
renderFn,
unmountFn = noop
) {
checkRendering(renderFn, withUsage());
return (widgetParams) => {
const {
includedAttributes = [],
excludedAttributes = ['query'],
transformItems = ((items) => items) as NonNullable<
ClearRefinementsConnectorParams['transformItems']
>
} = widgetParams || {};
if (widgetParams && widgetParams.includedAttributes && widgetParams.excludedAttributes) {
throw new Error(
withUsage(
'The options `includedAttributes` and `excludedAttributes` cannot be used together.'
)
);
}
type ConnectorState = {
refine: () => void;
createURL: () => string;
attributesToClear: AttributesToClear[];
};
const connectorState: ConnectorState = {
refine: noop,
createURL: () => '',
attributesToClear: []
};
const cachedRefine = () => connectorState.refine();
const cachedCreateURL = () => connectorState.createURL();
return {
$$type: 'ais.clearRefinements',
init(initOptions) {
const { instantSearchInstance } = initOptions;
renderFn(
{
...this.getWidgetRenderState(initOptions),
instantSearchInstance
},
true
);
},
render(renderOptions) {
const { instantSearchInstance } = renderOptions;
renderFn(
{
...this.getWidgetRenderState(renderOptions),
instantSearchInstance
},
false
);
},
dispose() {
unmountFn();
},
getRenderState(renderState, renderOptions) {
return {
...renderState,
clearRefinements: this.getWidgetRenderState(renderOptions)
};
},
getWidgetRenderState({ createURL, scopedResults, results }) {
connectorState.attributesToClear = scopedResults.reduce<
Array<ReturnType<typeof getAttributesToClear>>
>((attributesToClear, scopedResult) => {
return attributesToClear.concat(
getAttributesToClear({
scopedResult,
includedAttributes,
excludedAttributes,
transformItems,
results
})
);
}, []);
connectorState.refine = () => {
connectorState.attributesToClear.forEach(({ helper: indexHelper, items }) => {
// Use helper methods directly instead of clearRefinements widget
let newState = indexHelper.state;
items.forEach((attribute) => {
if (attribute === 'query') {
newState = newState.setQuery('');
} else {
newState = newState.clearRefinements(attribute);
}
});
indexHelper.setState(newState).search();
});
};
connectorState.createURL = () => {
return createURL(
mergeSearchParameters(
...connectorState.attributesToClear.map(({ helper: indexHelper, items }) => {
// Use the same approach as refine
let newState = indexHelper.state;
items.forEach((attribute) => {
if (attribute === 'query') {
newState = newState.setQuery('');
} else {
newState = newState.clearRefinements(attribute);
}
});
return newState;
})
)
);
};
const canRefine = connectorState.attributesToClear.some(
(attributeToClear) => attributeToClear.items.length > 0
);
return {
canRefine,
hasRefinements: canRefine,
refine: cachedRefine,
createURL: cachedCreateURL,
widgetParams
};
}
};
};
};
function getAttributesToClear({
scopedResult,
includedAttributes,
excludedAttributes,
transformItems,
results
}: {
scopedResult: ScopedResult;
includedAttributes: string[];
excludedAttributes: string[];
transformItems: TransformItems<string>;
results: SearchResults | undefined | null;
}): AttributesToClear {
const includesQuery =
includedAttributes.indexOf('query') !== -1 || excludedAttributes.indexOf('query') === -1;
return {
helper: scopedResult.helper,
items: transformItems(
uniq(
getRefinements(scopedResult.results, scopedResult.helper.state, includesQuery)
.map((refinement) => refinement.attribute)
.filter(
(attribute) =>
// If the array is empty (default case), we keep all the attributes
includedAttributes.length === 0 ||
// Otherwise, only add the specified attributes
includedAttributes.indexOf(attribute) !== -1
)
.filter(
(attribute) =>
// If the query is included, we ignore the default `excludedAttributes = ['query']`
(attribute === 'query' && includesQuery) ||
// Otherwise, ignore the excluded attributes
excludedAttributes.indexOf(attribute) === -1
)
),
{ results }
)
};
}
export default connectClearRefinements;
/**
This is based on connectRefinementList.ts with changes to handle switching operators
**/
import type { AlgoliaSearchHelper, SearchResults } from 'algoliasearch-helper';
import type {
SortBy,
TransformItems,
CreateURL,
WidgetRenderState,
Connector,
Widget,
RenderOptions,
InitOptions,
FacetHit,
IndexUiState
} from 'instantsearch.js';
import type { SendEventForFacet } from 'instantsearch.js/es/lib/utils';
import {
createDocumentationMessageGenerator,
checkRendering,
TAG_PLACEHOLDER,
TAG_REPLACEMENT,
escapeFacets,
createSendEventForFacet,
warning
} from 'instantsearch.js/es/lib/utils';
import { noop } from 'lodash';
const withUsage = createDocumentationMessageGenerator({
name: 'refinement-list-with-operator',
connector: true
});
const DEFAULT_SORT = ['isRefined', 'count:desc', 'name:asc'];
export type RefinementListWithOperatorItem = {
/**
* The value of the refinement list item.
*/
value: string;
/**
* Human-readable value of the refinement list item.
*/
label: string;
/**
* Human-readable value of the searched refinement list item.
*/
highlighted?: string;
/**
* Number of matched results after refinement is applied.
*/
count: number;
/**
* Indicates if the list item is refined.
*/
isRefined: boolean;
};
export type RefinementListWithOperatorConnectorParams = {
/**
* The name of the attribute in the records.
*/
attribute: string;
/**
* How the filters are combined together.
*/
operator?: 'and' | 'or';
/**
* The max number of items to display when
* `showMoreLimit` is not set or if the widget is showing less value.
*/
limit?: number;
/**
* Whether to display a button that expands the number of items.
*/
showMore?: boolean;
/**
* The max number of items to display if the widget
* is showing more items.
*/
showMoreLimit?: number;
/**
* How to sort refinements. Possible values: `count|isRefined|name:asc|name:desc`.
*/
sortBy?: SortBy<SearchResults.FacetValue>;
/**
* Escapes the content of the facet values.
*/
escapeFacetValues?: boolean;
/**
* Function to transform the items passed to the templates.
*/
transformItems?: TransformItems<RefinementListWithOperatorItem>;
};
export type RefinementListWithOperatorRenderState = {
/**
* The list of filtering values returned from Algolia API.
*/
items: RefinementListWithOperatorItem[];
/**
* indicates whether the results are exhaustive (complete)
*/
hasExhaustiveItems: boolean;
/**
* Creates the next state url for a selected refinement.
*/
createURL: CreateURL<string>;
/**
* Action to apply selected refinements.
*/
refine: (value: string) => void;
/**
* Current operator being used ('and' or 'or').
*/
operator: 'and' | 'or';
/**
* Function to change the operator and trigger URL update.
*/
setOperator: (operator: 'and' | 'or') => void;
/**
* Send event to insights middleware
*/
sendEvent: SendEventForFacet;
/**
* Searches for values inside the list.
*/
searchForItems: (query: string) => void;
/**
* `true` if the values are from an index search.
*/
isFromSearch: boolean;
/**
* `true` if a refinement can be applied.
*/
canRefine: boolean;
/**
* `true` if the toggleShowMore button can be activated.
*/
canToggleShowMore: boolean;
/**
* True if the menu is displaying all the menu items.
*/
isShowingMore: boolean;
/**
* Toggles the number of values displayed between `limit` and `showMoreLimit`.
*/
toggleShowMore: () => void;
};
export type RefinementListWithOperatorWidgetDescription = {
$$type: 'ais.refinementListWithOperator';
renderState: RefinementListWithOperatorRenderState;
indexRenderState: {
refinementListWithOperator: {
[attribute: string]: WidgetRenderState<
RefinementListWithOperatorRenderState,
RefinementListWithOperatorConnectorParams
>;
};
};
indexUiState: {
refinementList: {
[attribute: string]: string[];
};
refinementListOperators: {
[attribute: string]: 'and' | 'or';
};
};
};
export type RefinementListWithOperatorConnector = Connector<
RefinementListWithOperatorWidgetDescription,
RefinementListWithOperatorConnectorParams
>;
const connectRefinementListWithOperator: RefinementListWithOperatorConnector =
function connectRefinementListWithOperator(renderFn, unmountFn = noop) {
checkRendering(renderFn, withUsage());
return (widgetParams) => {
const {
attribute,
operator: defaultOperator = 'or',
limit = 10,
showMore = false,
showMoreLimit = 20,
sortBy = DEFAULT_SORT,
escapeFacetValues = true,
transformItems = ((items) => items) as NonNullable<
RefinementListWithOperatorConnectorParams['transformItems']
>
} = widgetParams || {};
type ThisWidget = Widget<
RefinementListWithOperatorWidgetDescription & {
widgetParams: typeof widgetParams;
}
>;
if (!attribute) {
throw new Error(withUsage('The `attribute` option is required.'));
}
if (!/^(and|or)$/.test(defaultOperator)) {
throw new Error(
withUsage(`The \`operator\` must one of: \`"and"\`, \`"or"\` (got "${defaultOperator}").`)
);
}
if (showMore === true && showMoreLimit <= limit) {
throw new Error(withUsage('`showMoreLimit` should be greater than `limit`.'));
}
const formatItems = ({
name: label,
escapedValue: value,
...item
}: SearchResults.FacetValue): RefinementListWithOperatorItem => ({
...item,
value,
label,
highlighted: label
});
let lastResultsFromMainSearch: SearchResults;
let lastItemsFromMainSearch: RefinementListWithOperatorItem[] = [];
let hasExhaustiveItems = true;
let triggerRefine: RefinementListWithOperatorRenderState['refine'] | undefined;
let sendEvent: RefinementListWithOperatorRenderState['sendEvent'] | undefined;
let isShowingMore = false;
let toggleShowMore = () => {};
function cachedToggleShowMore() {
toggleShowMore();
}
function createToggleShowMore(renderOptions: RenderOptions, widget: ThisWidget) {
return () => {
isShowingMore = !isShowingMore;
widget.render!(renderOptions);
};
}
function getLimit() {
return isShowingMore ? showMoreLimit : limit;
}
// Helper function to determine current operator from search state
function getCurrentOperator(state: any): 'and' | 'or' {
return state.isDisjunctiveFacet(attribute) ? 'or' : 'and';
}
let searchForFacetValues: (
renderOptions: RenderOptions | InitOptions
) => RefinementListWithOperatorRenderState['searchForItems'] = () => () => {};
const createSearchForFacetValues = function (
helper: AlgoliaSearchHelper,
widget: ThisWidget
) {
return (renderOptions: RenderOptions | InitOptions) => (query: string) => {
const { instantSearchInstance, results: searchResults } = renderOptions;
if (query === '' && lastItemsFromMainSearch) {
renderFn(
{
...widget.getWidgetRenderState({
...renderOptions,
results: lastResultsFromMainSearch
}),
instantSearchInstance
},
false
);
} else {
const tags = {
highlightPreTag: escapeFacetValues
? TAG_PLACEHOLDER.highlightPreTag
: TAG_REPLACEMENT.highlightPreTag,
highlightPostTag: escapeFacetValues
? TAG_PLACEHOLDER.highlightPostTag
: TAG_REPLACEMENT.highlightPostTag
};
helper
.searchForFacetValues(attribute, query, Math.min(getLimit(), 100), tags)
.then((results) => {
const facetValues = escapeFacetValues
? escapeFacets(results.facetHits)
: results.facetHits;
const normalizedFacetValues = transformItems(
facetValues.map(({ escapedValue, value, ...item }) => ({
...item,
value: escapedValue,
label: value
})),
{ results: searchResults }
);
renderFn(
{
...widget.getWidgetRenderState({
...renderOptions,
results: lastResultsFromMainSearch
}),
items: normalizedFacetValues,
canToggleShowMore: false,
canRefine: true,
isFromSearch: true,
instantSearchInstance
},
false
);
});
}
};
};
const createSetOperator = function (helper: AlgoliaSearchHelper, widget: ThisWidget) {
return (newOperator: 'and' | 'or') => {
const currentState = helper.state;
const actualCurrentOperator = getCurrentOperator(currentState);
if (newOperator === actualCurrentOperator) {
return;
}
// Get current refinements before changing configuration
const currentRefinements =
actualCurrentOperator === 'or'
? currentState.getDisjunctiveRefinements(attribute)
: currentState.getConjunctiveRefinements(attribute);
// Start with a clean state and clear all refinements for the current attribute
let nextState = currentState.clearRefinements(attribute);
// Remove existing facet configurations, ensure we check both conjunctive and disjunctive
if (nextState.facets && nextState.facets.indexOf(attribute) !== -1) {
nextState = nextState.removeFacet(attribute);
}
if (nextState.isDisjunctiveFacet(attribute)) {
nextState = nextState.removeDisjunctiveFacet(attribute);
}
// Configure the facet based on the new operator
if (newOperator === 'or') {
nextState = nextState.addDisjunctiveFacet(attribute);
} else {
nextState = nextState.addFacet(attribute);
}
// Re-add all existing refinements using the appropriate method
currentRefinements.forEach((value) => {
if (newOperator === 'or') {
nextState = nextState.addDisjunctiveFacetRefinement(attribute, value);
} else {
nextState = nextState.addFacetRefinement(attribute, value);
}
});
helper.setState(nextState).search();
};
};
return {
$$type: 'ais.refinementListWithOperator' as const,
init(initOptions) {
renderFn(
{
...this.getWidgetRenderState(initOptions),
instantSearchInstance: initOptions.instantSearchInstance
},
true
);
},
render(renderOptions) {
renderFn(
{
...this.getWidgetRenderState(renderOptions),
instantSearchInstance: renderOptions.instantSearchInstance
},
false
);
},
getRenderState(renderState, renderOptions) {
return {
...renderState,
refinementListWithOperator: {
...renderState.refinementListWithOperator,
[attribute]: this.getWidgetRenderState(renderOptions)
}
};
},
getWidgetRenderState(renderOptions) {
const { results, state, createURL, instantSearchInstance, helper } = renderOptions;
let items: RefinementListWithOperatorItem[] = [];
let facetValues: SearchResults.FacetValue[] | FacetHit[] = [];
// Get current operator from state
const currentOperator = getCurrentOperator(state);
if (!sendEvent || !triggerRefine || !searchForFacetValues) {
sendEvent = createSendEventForFacet({
instantSearchInstance,
helper,
attribute,
widgetType: this.$$type
});
triggerRefine = (facetValue) => {
sendEvent!('click:internal', facetValue);
helper.toggleFacetRefinement(attribute, facetValue).search();
};
searchForFacetValues = createSearchForFacetValues(helper, this);
}
if (results) {
const values = results.getFacetValues(attribute, {
sortBy,
facetOrdering: sortBy === DEFAULT_SORT
});
facetValues = values && Array.isArray(values) ? values : [];
items = transformItems(facetValues.slice(0, getLimit()).map(formatItems), { results });
const maxValuesPerFacetConfig = state.maxValuesPerFacet;
const currentLimit = getLimit();
hasExhaustiveItems =
maxValuesPerFacetConfig! > currentLimit
? facetValues.length <= currentLimit
: facetValues.length < currentLimit;
lastResultsFromMainSearch = results;
lastItemsFromMainSearch = items;
if (renderOptions.results) {
toggleShowMore = createToggleShowMore(renderOptions, this);
}
}
const searchFacetValues = searchForFacetValues && searchForFacetValues(renderOptions);
const canShowLess = isShowingMore && lastItemsFromMainSearch.length > limit;
const canShowMore = showMore && !hasExhaustiveItems;
const canToggleShowMore = canShowLess || canShowMore;
return {
createURL: (facetValue: string) => {
return createURL((uiState) => {
// Ensure we have proper facet configuration before toggling
let nextState = state.resetPage();
// Make sure the facet is properly configured
const isConfiguredAsDisjunctive = nextState.isDisjunctiveFacet(attribute);
const isConfiguredAsConjunctive =
nextState.facets && nextState.facets.indexOf(attribute) !== -1;
if (!isConfiguredAsDisjunctive && !isConfiguredAsConjunctive) {
// Configure the facet based on current operator
if (currentOperator === 'or') {
nextState = nextState.addDisjunctiveFacet(attribute);
} else {
nextState = nextState.addFacet(attribute);
}
}
// Now safely toggle the refinement
nextState = nextState.toggleFacetRefinement(attribute, facetValue);
return this.getWidgetUiState(uiState, {
searchParameters: nextState,
helper
});
});
},
items,
refine: triggerRefine,
operator: currentOperator,
setOperator: createSetOperator(helper, this),
searchForItems: searchFacetValues,
isFromSearch: false,
canRefine: items.length > 0,
widgetParams,
isShowingMore,
canToggleShowMore,
toggleShowMore: cachedToggleShowMore,
sendEvent,
hasExhaustiveItems
};
},
dispose({ state }) {
unmountFn();
const currentOperator = getCurrentOperator(state);
const withoutMaxValuesPerFacet = state.setQueryParameter('maxValuesPerFacet', undefined);
if (currentOperator === 'and') {
return withoutMaxValuesPerFacet.removeFacet(attribute);
}
return withoutMaxValuesPerFacet.removeDisjunctiveFacet(attribute);
},
getWidgetUiState(uiState, { searchParameters }) {
const currentOperator = getCurrentOperator(searchParameters);
const values =
currentOperator === 'or'
? searchParameters.getDisjunctiveRefinements(attribute)
: searchParameters.getConjunctiveRefinements(attribute);
// Store operator state in URL when it differs from default
const shouldStoreOperator = currentOperator !== defaultOperator;
// If there are no refinements, don't store the operator either
const hasRefinements = values && values.length > 0;
return removeEmptyRefinementsFromUiState(
{
...uiState,
refinementList: {
...uiState.refinementList,
[attribute]: values
},
// Only store operator state in URL when there are refinements AND it differs from default
...(shouldStoreOperator &&
hasRefinements && {
refinementListOperators: {
...uiState.refinementListOperators,
[attribute]: currentOperator
}
})
},
attribute
);
},
getWidgetSearchParameters(searchParameters, { uiState }) {
// Get operator from UI state first, then fall back to default
const operatorFromUiState = uiState.refinementListOperators?.[attribute];
const targetOperator = operatorFromUiState || defaultOperator;
if (searchParameters.isHierarchicalFacet(attribute)) {
warning(
false,
`RefinementListWithOperator: Attribute "${attribute}" is already used by another widget applying hierarchical faceting.`
);
return searchParameters;
}
const values = uiState.refinementList?.[attribute] || [];
// Start fresh - clear all refinements and configurations for this attribute
let withFacetConfiguration = searchParameters.clearRefinements(attribute);
// Remove existing configurations if they exist
if (
withFacetConfiguration.facets &&
withFacetConfiguration.facets.indexOf(attribute) !== -1
) {
withFacetConfiguration = withFacetConfiguration.removeFacet(attribute);
}
if (withFacetConfiguration.isDisjunctiveFacet(attribute)) {
withFacetConfiguration = withFacetConfiguration.removeDisjunctiveFacet(attribute);
}
// Configure facet based on target operator (from URL or default)
if (targetOperator === 'or') {
withFacetConfiguration = withFacetConfiguration.addDisjunctiveFacet(attribute);
} else {
withFacetConfiguration = withFacetConfiguration.addFacet(attribute);
}
// Set max values per facet
const currentMaxValuesPerFacet = withFacetConfiguration.maxValuesPerFacet || 0;
const nextMaxValuesPerFacet = Math.max(
currentMaxValuesPerFacet,
showMore ? showMoreLimit : limit
);
const withMaxValuesPerFacet = withFacetConfiguration.setQueryParameter(
'maxValuesPerFacet',
nextMaxValuesPerFacet
);
// Add refinements based on target operator
return values.reduce((parameters, value) => {
if (targetOperator === 'or') {
return parameters.addDisjunctiveFacetRefinement(attribute, value);
} else {
return parameters.addFacetRefinement(attribute, value);
}
}, withMaxValuesPerFacet);
}
};
};
};
function removeEmptyRefinementsFromUiState(
indexUiState: IndexUiState & {
refinementListOperators?: { [attribute: string]: 'and' | 'or' };
},
attribute: string
): IndexUiState & {
refinementListOperators?: { [attribute: string]: 'and' | 'or' };
} {
if (!indexUiState.refinementList) {
return indexUiState;
}
if (
!indexUiState.refinementList[attribute] ||
indexUiState.refinementList[attribute].length === 0
) {
delete indexUiState.refinementList[attribute];
// Also remove the operator for this attribute when refinements are cleared
if (indexUiState.refinementListOperators && indexUiState.refinementListOperators[attribute]) {
delete indexUiState.refinementListOperators[attribute];
}
}
if (Object.keys(indexUiState.refinementList).length === 0) {
delete indexUiState.refinementList;
}
// Clean up empty operator state
if (indexUiState.refinementListOperators) {
if (Object.keys(indexUiState.refinementListOperators).length === 0) {
delete indexUiState.refinementListOperators;
}
}
return indexUiState;
}
export default connectRefinementListWithOperator;
const RefinmentExample = () => {
const [operator, setOperator] = useState<'and' | 'or'>('and');
const refinementListProps = useRefinementListWithOperator({
limit: 100,
showMoreLimit: 5000,
sortBy: ['count'],
// ...rest of props
});
return (
<>
<button
onClick={() => {
setOperator((prev) => (prev === 'and' ? 'or' : 'and'));
refinementListProps.setOperator(operator === 'and' ? 'or' : 'and');
}}
>operator: {operator}</button>
<CustomRefinmentComponent attribute="brand" {...refinementListProps} />
</>
);
}
import type {
ClearRefinementsConnectorParams,
ClearRefinementsWidgetDescription
} from 'instantsearch.js/es/connectors/clear-refinements/connectClearRefinements';
import type { AdditionalWidgetProperties } from 'react-instantsearch';
import { useConnector } from 'react-instantsearch';
import connectClearRefinements from './connectClearRefinments';
export type UseClearRefinementsProps = ClearRefinementsConnectorParams;
export function useClearRefinements(
props?: UseClearRefinementsProps,
additionalWidgetProperties?: AdditionalWidgetProperties
) {
return useConnector<ClearRefinementsConnectorParams, ClearRefinementsWidgetDescription>(
connectClearRefinements,
props,
additionalWidgetProperties
);
}
import type { AdditionalWidgetProperties } from 'react-instantsearch';
import { useConnector } from 'react-instantsearch';
import type {
RefinementListWithOperatorConnectorParams,
RefinementListWithOperatorWidgetDescription
} from './connectRefinementListWithOperator';
import connectRefinementListWithOperator from './connectRefinementListWithOperator';
export type UseRefinementListWithOperatorProps = RefinementListWithOperatorConnectorParams;
export function useRefinementListWithOperator(
props: UseRefinementListWithOperatorProps,
additionalWidgetProperties?: AdditionalWidgetProperties
) {
return useConnector<
RefinementListWithOperatorConnectorParams,
RefinementListWithOperatorWidgetDescription
>(connectRefinementListWithOperator, props, additionalWidgetProperties);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment