Skip to content
Merged
Show file tree
Hide file tree
Changes from 109 commits
Commits
Show all changes
115 commits
Select commit Hold shift + click to select a range
40636a0
feat(ui-components): introduce chat components
FabienMotte Jul 23, 2025
6f1ed20
chore: add passphrase input
FabienMotte Jul 23, 2025
0b70363
wip
Haroenv Jul 30, 2025
78ed732
toggle and header part of satellite
Haroenv Aug 1, 2025
62880e9
revert js example
shaejaz Sep 3, 2025
9f83bde
revert react example
shaejaz Sep 3, 2025
13b1e28
remove todo
shaejaz Sep 3, 2025
556c1d0
remove toggle button duplicate
shaejaz Sep 3, 2025
5d2e92b
add tests
shaejaz Sep 3, 2025
6ceffff
update bundlesize
shaejaz Sep 3, 2025
dd12b04
fix lint
shaejaz Sep 3, 2025
b095c41
Merge branch 'master' into feat/chat-components
shaejaz Sep 4, 2025
040c035
markdown
Haroenv Aug 29, 2025
8adc9ef
add chat component
shaejaz Sep 4, 2025
4b2531e
update chat message
shaejaz Sep 4, 2025
deb8c8a
fix polyfill errors
shaejaz Sep 4, 2025
5ca5ec2
update lock file
shaejaz Sep 4, 2025
000f255
add chat test
shaejaz Sep 4, 2025
adf7f8f
address comments
shaejaz Sep 4, 2025
95a463e
address comments
shaejaz Sep 5, 2025
032cd1d
add base lib in is.js
shaejaz Sep 5, 2025
c978854
add hook in react core
shaejaz Sep 5, 2025
51f350f
add react widget
shaejaz Sep 5, 2025
c2df1ac
move transport handling to hook
shaejaz Sep 5, 2025
205ab67
update types
shaejaz Sep 8, 2025
2c7406e
export it anyway
Haroenv Sep 8, 2025
8b26037
add chat component props
shaejaz Sep 8, 2025
88cf87d
add refine button
shaejaz Sep 8, 2025
69ab089
address comment
shaejaz Sep 8, 2025
5cc91f7
add tests
shaejaz Sep 9, 2025
2609211
update tools usage
shaejaz Sep 10, 2025
09e8b51
fix ci
shaejaz Sep 10, 2025
e5e5259
fix type error
shaejaz Sep 10, 2025
e71e483
address comments
shaejaz Sep 10, 2025
9041a1a
Merge branch 'master' into feat/react-chat
shaejaz Sep 10, 2025
2229762
fix is version
shaejaz Sep 10, 2025
bfc6b25
just one zod
Haroenv Sep 10, 2025
1dd7a0a
add more tests
shaejaz Sep 11, 2025
729f629
use user provided search index tool
shaejaz Sep 11, 2025
678e292
init
shaejaz Aug 13, 2025
52ea485
remove stick to bottom hook
shaejaz Aug 13, 2025
989b274
move ui to ui components
shaejaz Aug 13, 2025
93d7756
add chat components
shaejaz Aug 14, 2025
f5b06d3
fix widget types
shaejaz Aug 15, 2025
3fea3b3
forward props
shaejaz Aug 18, 2025
e82095a
wip: use ai dependency in connector
Haroenv Aug 18, 2025
e219a32
move usechat to react core
shaejaz Aug 19, 2025
c136118
remove is components and widgets
shaejaz Aug 19, 2025
ad39f22
remove unecessary react widgets
shaejaz Aug 19, 2025
84b919c
fix test
shaejaz Aug 20, 2025
3b1b853
deps
Haroenv Aug 20, 2025
527a280
revert rollup alias
shaejaz Aug 20, 2025
38c0d1c
init
shaejaz Aug 28, 2025
373ce70
use carousel
shaejaz Aug 29, 2025
a39aece
add tools prop
shaejaz Sep 2, 2025
3473921
add carousel default tool
shaejaz Sep 2, 2025
bfc6910
add transport to props
shaejaz Sep 2, 2025
d79465c
feat(react-instantsearch-ui): implement chat components design
FabienMotte Sep 11, 2025
5cd47c9
chore: review considered
FabienMotte Sep 15, 2025
72375c6
chore: review considered
FabienMotte Sep 16, 2025
5da6059
remove
FabienMotte Sep 16, 2025
692b1d0
chore: review considered
FabienMotte Sep 16, 2025
3ddfcde
chore: review considered
FabienMotte Sep 16, 2025
37ecdbd
chore: revert lock
FabienMotte Sep 16, 2025
1b4c24f
chore: clean types
FabienMotte Sep 17, 2025
a493c5d
chore: fix types
FabienMotte Sep 17, 2025
33da4d5
chore: clean comments
FabienMotte Sep 17, 2025
e83ff45
chore: fix conflicts
FabienMotte Sep 18, 2025
002ce28
feat: add clear button
FabienMotte Sep 18, 2025
69eecf6
feat: add default chat prompt disclaimer
FabienMotte Sep 18, 2025
6d392a5
chore: revert
FabienMotte Sep 18, 2025
3580993
chore: use polyfills
FabienMotte Sep 18, 2025
d7fc569
chore: revert
FabienMotte Sep 18, 2025
c59e143
chore: revert
FabienMotte Sep 18, 2025
20d493f
feat: add header/prompt gradients
FabienMotte Sep 18, 2025
8ef5bff
fix: chat prompt gradient z-index
FabienMotte Sep 18, 2025
39dfe62
refactor: move `use-stick-to-bottom` to Chat widget
FabienMotte Sep 18, 2025
f17db28
chore: add `useStickToBottom` hook instead of lib
FabienMotte Sep 18, 2025
87851d2
fix: mobile fixes
FabienMotte Sep 18, 2025
37656d9
chore: update bundlesizes
FabienMotte Sep 18, 2025
daf1409
Merge master into feat/chat-design
FabienMotte Sep 18, 2025
fbafb54
test: fix
FabienMotte Sep 19, 2025
85332c0
test: fix lint
FabienMotte Sep 19, 2025
1808886
init
shaejaz Sep 15, 2025
b7da559
don't rerender in connector
shaejaz Sep 15, 2025
f6b3d06
add tools support
shaejaz Sep 16, 2025
cd70c1d
move open and input to connector
shaejaz Sep 16, 2025
00a3b18
fix vue build
shaejaz Sep 16, 2025
d5ec6c4
fix build fr
shaejaz Sep 16, 2025
49e4d4f
fine-tune connector implementation
dhayab Sep 17, 2025
17c060e
add connector unit tests
dhayab Sep 17, 2025
0bd250f
add connector cts tests
dhayab Sep 17, 2025
19a0f02
fine-tune widget implementation
dhayab Sep 18, 2025
3f7fe7f
add widget unit and cts tests
dhayab Sep 18, 2025
1b0e11a
support maximized and clear in widget
dhayab Sep 19, 2025
43716b2
test: fix
FabienMotte Sep 19, 2025
14bcc15
Merge remote-tracking branch 'origin/feat/chat-design' into feat/js-chat
dhayab Sep 19, 2025
59f864d
update widget test
dhayab Sep 19, 2025
30b75dc
bump bundlesize
dhayab Sep 19, 2025
bfd906b
dont export chat in umd js bundle
dhayab Sep 22, 2025
9842b33
silence issue with invalid ref in preact
dhayab Sep 22, 2025
bbda654
fix lint issues
dhayab Sep 22, 2025
b9443a4
more fixes?
dhayab Sep 22, 2025
3ca11da
take 3
dhayab Sep 23, 2025
209fd1c
Merge remote-tracking branch 'origin/master' into feat/js-chat
dhayab Sep 23, 2025
8b37701
post-merge fixes
dhayab Sep 23, 2025
3f656f1
delete remnant files
dhayab Sep 23, 2025
1ba3d74
additional post-merge fixes
dhayab Sep 23, 2025
894af6c
bump bundlesize
dhayab Sep 23, 2025
e384874
readjust bundlesize
dhayab Sep 23, 2025
85fae59
Merge remote-tracking branch 'origin/master' into feat/js-chat
dhayab Sep 23, 2025
5dc4944
ensure no dependency on ai in algolia-experiences
dhayab Sep 24, 2025
3c26b90
ensure no dependency on ai in js storybook
dhayab Sep 24, 2025
11cd5a2
ensure no dependency on ai in vue-instantsearch
dhayab Sep 24, 2025
3c25444
apply suggestions
dhayab Sep 24, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions bundlesize.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@
},
{
"path": "./packages/instantsearch.js/dist/instantsearch.production.min.js",
"maxSize": "84.75 kB"
"maxSize": "100 kB"
Comment thread
dhayab marked this conversation as resolved.
Outdated
},
{
"path": "./packages/instantsearch.js/dist/instantsearch.development.js",
"maxSize": "185 kB"
"maxSize": "205.25 kB"
},
{
"path": "packages/react-instantsearch-core/dist/umd/ReactInstantSearchCore.min.js",
"maxSize": "53.75 kB"
},
{
"path": "packages/react-instantsearch/dist/umd/ReactInstantSearch.min.js",
"maxSize": "81.25 kB"
"maxSize": "81.5 kB"
},
{
"path": "packages/vue-instantsearch/vue2/umd/index.js",
Expand Down
1 change: 1 addition & 0 deletions packages/algolia-experiences/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const createConfiguration = ({ mode, filename }) => ({
banner: license,
sourcemap: true,
},
external: ['ai', 'zod'],
Comment thread
dhayab marked this conversation as resolved.
Outdated
onwarn(warning, warn) {
if (warning.code === 'CIRCULAR_DEPENDENCY')
throw new Error(warning.message);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export function createChatComponent({ createElement, Fragment }: Renderer) {
{...toggleButtonProps}
onClick={() => {
toggleButtonProps.onClick?.();
promptRef.current?.focus();
promptRef.current?.focus?.();
}}
/>
</div>
Expand Down
1 change: 1 addition & 0 deletions packages/instantsearch.js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"@types/google.maps": "^3.55.12",
"@types/hogan.js": "^3.0.0",
"@types/qs": "^6.5.3",
"ai": "^5.0.18",

Check warning on line 34 in packages/instantsearch.js/package.json

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

packages/instantsearch.js/package.json#L34

Package dependencies with variant versions may lead to dependency hijack and confusion attacks.
"algoliasearch-helper": "3.26.0",
"hogan.js": "^3.0.2",
"htm": "^3.0.0",
Expand Down
1 change: 1 addition & 0 deletions packages/instantsearch.js/scripts/rollup/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const plugins = [

const createConfiguration = ({ mode, filename }) => ({
input: 'src/index.ts',
external: ['ai', 'zod'],
Comment thread
dhayab marked this conversation as resolved.
Outdated
output: {
file: `dist/${filename}`,
name: 'instantsearch',
Expand Down
47 changes: 47 additions & 0 deletions packages/instantsearch.js/src/__tests__/common-connectors.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
connectFrequentlyBoughtTogether,
connectTrendingItems,
connectLookingSimilar,
connectChat,
} from '../connectors';
import instantsearch from '../index.es';
import { refinementList } from '../widgets';
Expand Down Expand Up @@ -530,6 +531,51 @@ const testSetups: TestSetupsMap<TestSuites> = {

search.start();
},
createChatConnectorTests({ instantSearchOptions, widgetParams }) {
const customChat = connectChat<{
container: HTMLElement;
}>((renderOptions) => {
const { input, setInput, open, setOpen } = renderOptions;
renderOptions.widgetParams.container.innerHTML = `
<div data-testid="Chat-root" style="display: ${
open ? 'block' : 'none'
}">
<input data-testid="Chat-input" type="text" value="${input}" />
<button data-testid="Chat-updateInput">update input</button>
</div>
<button data-testid="Chat-toggleButton">
toggle chat
</button>
`;

renderOptions.widgetParams.container
.querySelector('[data-testid="Chat-toggleButton"]')!
.addEventListener('click', () => {
setOpen(!open);
});

renderOptions.widgetParams.container
.querySelector('[data-testid="Chat-updateInput"]')!
.addEventListener('click', () => {
setInput('hello world');
});
});

instantsearch(instantSearchOptions)
.addWidgets([
customChat({
container: document.body.appendChild(document.createElement('div')),
...widgetParams,
}),
])
.on('error', () => {
/*
* prevent rethrowing InstantSearch errors, so tests can be asserted.
* IRL this isn't needed, as the error doesn't stop execution.
*/
})
.start();
},
};

function addWidgetToggleUi(search: InstantSearch, widget: Widget) {
Expand Down Expand Up @@ -561,6 +607,7 @@ const testOptions: TestOptionsMap<TestSuites> = {
createFrequentlyBoughtTogetherConnectorTests: undefined,
createTrendingItemsConnectorTests: undefined,
createLookingSimilarConnectorTests: undefined,
createChatConnectorTests: undefined,
};

describe('Common connector tests (InstantSearch.js)', () => {
Expand Down
18 changes: 18 additions & 0 deletions packages/instantsearch.js/src/__tests__/common-widgets.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
poweredBy,
menuSelect,
dynamicWidgets,
chat,
} from '../widgets';

import type { TestOptionsMap, TestSetupsMap } from '@instantsearch/tests';
Expand Down Expand Up @@ -617,6 +618,22 @@ const testSetups: TestSetupsMap<TestSuites> = {
])
.start();
},
createChatWidgetTests({ instantSearchOptions, widgetParams }) {
instantsearch(instantSearchOptions)
.addWidgets([
chat({
container: document.body.appendChild(document.createElement('div')),
...widgetParams,
}),
])
.on('error', () => {
/*
* prevent rethrowing InstantSearch errors, so tests can be asserted.
* IRL this isn't needed, as the error doesn't stop execution.
*/
})
.start();
},
};

const testOptions: TestOptionsMap<TestSuites> = {
Expand Down Expand Up @@ -649,6 +666,7 @@ const testOptions: TestOptionsMap<TestSuites> = {
createPoweredByWidgetTests: undefined,
createMenuSelectWidgetTests: undefined,
createDynamicWidgetsWidgetTests: undefined,
createChatWidgetTests: undefined,
};

describe('Common widget tests (InstantSearch.js)', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { createSearchClient } from '@instantsearch/mocks';
import algoliasearchHelper from 'algoliasearch-helper';

import {
createInitOptions,
createRenderOptions,
} from '../../../../test/createWidget';
import connectChat from '../connectChat';

describe('connectChat', () => {
it('throws without render function', () => {
expect(() => {
// @ts-expect-error
connectChat()({});
}).toThrowErrorMatchingInlineSnapshot(`
"The render function is not valid (received type Undefined).

See documentation: https://www.algolia.com/doc/api-reference/widgets/chat/js/#connector"
`);
});

it('is a widget', () => {
const render = jest.fn();
const unmount = jest.fn();

const customChat = connectChat(render, unmount);
const widget = customChat({});

expect(widget).toEqual(
expect.objectContaining({
$$type: 'ais.chat',
init: expect.any(Function),
render: expect.any(Function),
dispose: expect.any(Function),
})
);
});

it('Renders during init and render', () => {
const renderFn = jest.fn();
const makeWidget = connectChat(renderFn);
const widget = makeWidget({ agentId: 'agentId' });

// test if widget is not rendered yet at this point
expect(renderFn).toHaveBeenCalledTimes(0);

const helper = algoliasearchHelper(createSearchClient(), '', {});
helper.search = jest.fn();

widget.init(createInitOptions({ helper, state: helper.state }));

expect(renderFn).toHaveBeenCalledTimes(1);
expect(renderFn).toHaveBeenLastCalledWith(
expect.objectContaining({ widgetParams: { agentId: 'agentId' } }),
true
);

const renderOptions = createRenderOptions({ helper });
widget.render(renderOptions);

expect(renderFn).toHaveBeenCalledTimes(2);
expect(renderFn).toHaveBeenLastCalledWith(
expect.objectContaining({ widgetParams: { agentId: 'agentId' } }),
false
);
});

describe('dispose', () => {
it('calls the unmount function', () => {
const unmountFn = jest.fn();
const makeWidget = connectChat(() => {}, unmountFn);
const widget = makeWidget({ agentId: 'agentId' });

expect(unmountFn).toHaveBeenCalledTimes(0);

widget.dispose();
expect(unmountFn).toHaveBeenCalledTimes(1);
});

it('does not throw without the unmount function', () => {
const makeWidget = connectChat(() => {});
const widget = makeWidget({ agentId: 'agentId' });

expect(() => widget.dispose()).not.toThrow();
});
});
});
Loading