Skip to content
This repository was archived by the owner on Dec 30, 2022. It is now read-only.

Commit 5cc18d1

Browse files
authored
feat(hooks-web): expose sendEvent to hitComponent (#3476)
* feat(hooks-web): expose sendEvent to hitComponent This makes it straightforward to implement eg. a conversion event on the hit component
1 parent 1c436e1 commit 5cc18d1

File tree

6 files changed

+59
-7
lines changed

6 files changed

+59
-7
lines changed

packages/react-instantsearch-hooks-web/src/ui/Hits.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,15 @@ import React from 'react';
33
import { cx } from './lib/cx';
44

55
import type { Hit } from 'instantsearch.js';
6+
import type { SendEventForHits } from 'instantsearch.js/es/lib/utils';
67

78
export type HitsProps<THit> = React.ComponentProps<'div'> & {
89
hits: THit[];
9-
hitComponent?: React.JSXElementConstructor<{ hit: THit }>;
10+
sendEvent: SendEventForHits;
11+
hitComponent?: React.JSXElementConstructor<{
12+
hit: THit;
13+
sendEvent: SendEventForHits;
14+
}>;
1015
classNames?: Partial<HitsClassNames>;
1116
};
1217

@@ -39,6 +44,7 @@ export type HitsClassNames = {
3944

4045
export function Hits<THit extends Hit>({
4146
hits,
47+
sendEvent,
4248
hitComponent: HitComponent = DefaultHitComponent,
4349
classNames = {},
4450
...props
@@ -59,7 +65,7 @@ export function Hits<THit extends Hit>({
5965
key={hit.objectID}
6066
className={cx('ais-Hits-item', classNames.item)}
6167
>
62-
<HitComponent hit={hit} />
68+
<HitComponent hit={hit} sendEvent={sendEvent} />
6369
</li>
6470
))}
6571
</ol>

packages/react-instantsearch-hooks-web/src/ui/InfiniteHits.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,15 @@ import React from 'react';
33
import { cx } from './lib/cx';
44

55
import type { Hit } from 'instantsearch.js';
6+
import type { SendEventForHits } from 'instantsearch.js/es/lib/utils';
67

78
export type InfiniteHitsProps<THit> = React.ComponentProps<'div'> & {
8-
hitComponent?: React.JSXElementConstructor<{ hit: THit }>;
99
hits: THit[];
10+
sendEvent: SendEventForHits;
11+
hitComponent?: React.JSXElementConstructor<{
12+
hit: THit;
13+
sendEvent: SendEventForHits;
14+
}>;
1015
isFirstPage: boolean;
1116
isLastPage: boolean;
1217
onShowPrevious?: () => void;
@@ -66,6 +71,7 @@ function DefaultHitComponent({ hit }: { hit: Hit }) {
6671
export function InfiniteHits<THit extends Hit>({
6772
hitComponent: HitComponent = DefaultHitComponent,
6873
hits,
74+
sendEvent,
6975
isFirstPage,
7076
isLastPage,
7177
onShowPrevious,
@@ -108,7 +114,7 @@ export function InfiniteHits<THit extends Hit>({
108114
key={hit.objectID}
109115
className={cx('ais-InfiniteHits-item', classNames.item)}
110116
>
111-
<HitComponent hit={hit} />
117+
<HitComponent hit={hit} sendEvent={sendEvent} />
112118
</li>
113119
))}
114120
</ol>

packages/react-instantsearch-hooks-web/src/ui/__tests__/Hits.test.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { render } from '@testing-library/react';
2+
import userEvent from '@testing-library/user-event';
23
import React from 'react';
34

45
import { Hits } from '../Hits';
@@ -15,6 +16,7 @@ describe('Hits', () => {
1516
{ objectID: 'abc', __position: 1 },
1617
{ objectID: 'def', __position: 2 },
1718
] as THit[],
19+
sendEvent: jest.fn(),
1820
...props,
1921
};
2022
}
@@ -101,6 +103,21 @@ describe('Hits', () => {
101103
`);
102104
});
103105

106+
test('passes sendEvent to hitComponent', () => {
107+
const props = createProps({
108+
hitComponent: ({ hit, sendEvent }) => (
109+
<button onClick={() => sendEvent(hit)}>{hit.objectID}</button>
110+
),
111+
});
112+
113+
const { container } = render(<Hits {...props} />);
114+
115+
userEvent.click(container.querySelector('button')!);
116+
117+
expect(props.sendEvent).toHaveBeenCalledTimes(1);
118+
expect(props.sendEvent).toHaveBeenLastCalledWith(props.hits[0]);
119+
});
120+
104121
test('accepts custom class names', () => {
105122
const props = createProps({
106123
className: 'MyCustomHits',

packages/react-instantsearch-hooks-web/src/ui/__tests__/InfiniteHits.test.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ describe('InfiniteHits', () => {
1616
{ objectID: 'abc', __position: 1 },
1717
{ objectID: 'def', __position: 2 },
1818
],
19+
sendEvent: jest.fn(),
1920
isFirstPage: true,
2021
isLastPage: false,
2122
onShowPrevious: jest.fn(),
@@ -183,6 +184,23 @@ describe('InfiniteHits', () => {
183184
`);
184185
});
185186

187+
test('passes sendEvent to hitComponent', () => {
188+
const props = createProps({
189+
hitComponent: ({ hit, sendEvent }) => (
190+
<button className="hitButton" onClick={() => sendEvent(hit)}>
191+
{hit.objectID}
192+
</button>
193+
),
194+
});
195+
196+
const { container } = render(<InfiniteHits {...props} />);
197+
198+
userEvent.click(container.querySelector('.hitButton')!);
199+
200+
expect(props.sendEvent).toHaveBeenCalledTimes(1);
201+
expect(props.sendEvent).toHaveBeenLastCalledWith(props.hits[0]);
202+
});
203+
186204
describe('showPrevious', () => {
187205
test('renders without showPrevious if disabled', () => {
188206
const props = createProps({});

packages/react-instantsearch-hooks-web/src/widgets/Hits.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import type { UseHitsProps } from 'react-instantsearch-hooks';
99

1010
type UiProps<THit extends BaseHit> = Pick<
1111
HitsUiComponentProps<Hit<THit>>,
12-
'hits'
12+
'hits' | 'sendEvent'
1313
>;
1414

1515
export type HitsProps<THit extends BaseHit> = Omit<
@@ -19,10 +19,13 @@ export type HitsProps<THit extends BaseHit> = Omit<
1919
UseHitsProps<THit>;
2020

2121
export function Hits<THit extends BaseHit = BaseHit>(props: HitsProps<THit>) {
22-
const { hits } = useHits<THit>(props, { $$widgetType: 'ais.hits' });
22+
const { hits, sendEvent } = useHits<THit>(props, {
23+
$$widgetType: 'ais.hits',
24+
});
2325

2426
const uiProps: UiProps<THit> = {
2527
hits,
28+
sendEvent,
2629
};
2730

2831
return <HitsUiComponent {...props} {...uiProps} />;

packages/react-instantsearch-hooks-web/src/widgets/InfiniteHits.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import type { UseInfiniteHitsProps } from 'react-instantsearch-hooks';
1010
type UiProps<THit extends BaseHit = BaseHit> = Pick<
1111
InfiniteHitsUiComponentProps<Hit<THit>>,
1212
| 'hits'
13+
| 'sendEvent'
1314
| 'onShowPrevious'
1415
| 'onShowMore'
1516
| 'isFirstPage'
@@ -34,11 +35,12 @@ export function InfiniteHits<THit extends BaseHit = BaseHit>({
3435
showPrevious: shouldShowPrevious = true,
3536
...props
3637
}: InfiniteHitsProps<THit>) {
37-
const { hits, showPrevious, showMore, isFirstPage, isLastPage } =
38+
const { hits, sendEvent, showPrevious, showMore, isFirstPage, isLastPage } =
3839
useInfiniteHits<THit>(props, { $$widgetType: 'ais.infiniteHits' });
3940

4041
const uiProps: UiProps<THit> = {
4142
hits,
43+
sendEvent,
4244
onShowPrevious: shouldShowPrevious ? showPrevious : undefined,
4345
onShowMore: showMore,
4446
isFirstPage,

0 commit comments

Comments
 (0)