Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(sourceId): Add sourceId to provide data-autocomplete-source-id on section source container #429

Merged
merged 8 commits into from
Feb 5, 2021
Merged
1 change: 1 addition & 0 deletions examples/js/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ autocomplete({

return [
{
sourceId: 'products',
getItems() {
return getAlgoliaHits<Product>({
searchClient,
Expand Down
1 change: 1 addition & 0 deletions examples/js/shortcutsPlugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const shortcutsPlugin: AutocompletePlugin<DarkModeItem> = {

return [
{
sourceId: 'shortcutsPlugin',
getItems() {
return [
{
Expand Down
6 changes: 3 additions & 3 deletions packages/autocomplete-core/src/__tests__/concurrency.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import userEvent from '@testing-library/user-event';

import { defer } from '../../../../test/utils';
import { createSource, defer } from '../../../../test/utils';
import { createAutocomplete } from '../createAutocomplete';

describe.skip('concurrency', () => {
Expand All @@ -14,11 +14,11 @@ describe.skip('concurrency', () => {

return defer(() => {
return [
{
createSource({
getItems() {
return [{ label: query }];
},
},
}),
];
}, delays[deferCount]);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1049,6 +1049,7 @@ describe('getInputProps', () => {
{ label: '2', url: '#2' },
],
source: {
sourceId: expect.any(String),
getItemInputValue: expect.any(Function),
getItemUrl: expect.any(Function),
getItems: expect.any(Function),
Expand Down
4 changes: 4 additions & 0 deletions packages/autocomplete-core/src/__tests__/getSources.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ describe('getSources', () => {
getSources: () => {
return [
{
sourceId: 'testSource',
getItems() {
return [];
},
Expand Down Expand Up @@ -78,6 +79,7 @@ describe('getSources', () => {
templates: expect.objectContaining({
item: expect.any(Function),
}),
sourceId: expect.any(String),
},
}),
]),
Expand All @@ -92,6 +94,7 @@ describe('getSources', () => {
getSources: () => {
return [
{
sourceId: 'pluginSource',
getItems() {
return [];
},
Expand All @@ -107,6 +110,7 @@ describe('getSources', () => {
getSources: () => {
return [
{
sourceId: 'testSource',
getItems() {
return [];
},
Expand Down
10 changes: 5 additions & 5 deletions packages/autocomplete-core/src/__tests__/stallThreshold.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import userEvent from '@testing-library/user-event';

import { defer } from '../../../../test/utils';
import { createSource, defer } from '../../../../test/utils';
import { createAutocomplete } from '../createAutocomplete';

describe('stallThreshold', () => {
Expand All @@ -11,11 +11,11 @@ describe('stallThreshold', () => {
getSources() {
return defer(() => {
return [
{
createSource({
getItems() {
return [{ label: '1' }, { label: 2 }];
},
},
}),
];
}, 500);
},
Expand Down Expand Up @@ -59,11 +59,11 @@ describe('stallThreshold', () => {
getSources() {
return defer(() => {
return [
{
createSource({
getItems() {
return [{ label: '1' }, { label: 2 }];
},
},
}),
];
}, 500);
},
Expand Down
4 changes: 4 additions & 0 deletions packages/autocomplete-core/src/types/AutocompleteSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ export interface AutocompleteSource<TItem extends BaseItem> {
* You can trigger different behaviors based on the event `type`.
*/
onActive?(params: OnHighlightParams<TItem>): void;
/**
* Identifier for the source.
*/
sourceId: string;
}

export type InternalAutocompleteSource<TItem extends BaseItem> = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { getNormalizedSources } from '../getNormalizedSources';

describe('getNormalizedSources', () => {
test('returns a promise of sources', async () => {
const getSources = () => [{ getItems: () => [] }];
const getSources = () => [{ sourceId: 'testSource', getItems: () => [] }];
const params = {
query: '',
state: createState({
Expand All @@ -23,12 +23,17 @@ describe('getNormalizedSources', () => {
getItems: expect.any(Function),
onActive: expect.any(Function),
onSelect: expect.any(Function),
sourceId: 'testSource',
},
]);
});

test('filters out falsy sources', async () => {
const getSources = () => [{ getItems: () => [] }, false, undefined];
const getSources = () => [
{ sourceId: 'testSource', getItems: () => [] },
false,
undefined,
];
const params = {
query: '',
state: createState({
Expand All @@ -44,6 +49,7 @@ describe('getNormalizedSources', () => {
getItems: expect.any(Function),
onActive: expect.any(Function),
onSelect: expect.any(Function),
sourceId: 'testSource',
},
]);
});
Expand All @@ -64,8 +70,55 @@ describe('getNormalizedSources', () => {
);
});

test('with missing `sourceId` triggers invariant', async () => {
const getSources = () => [
{
getItems() {
return [];
},
templates: {
item() {},
},
},
];
const params = {
query: '',
state: createState({}),
...createScopeApi(),
};

// @ts-expect-error
await expect(getNormalizedSources(getSources, params)).rejects.toEqual(
new Error('[Autocomplete] A source must provide a `sourceId` string.')
);
});

test('with wrong `sourceId` type triggers invariant', async () => {
shortcuts marked this conversation as resolved.
Show resolved Hide resolved
const getSources = () => [
{
sourceId: ['testSource'],
getItems() {
return [];
},
templates: {
item() {},
},
},
];
const params = {
query: '',
state: createState({}),
...createScopeApi(),
};

// @ts-expect-error
await expect(getNormalizedSources(getSources, params)).rejects.toEqual(
new Error('[Autocomplete] A source must provide a `sourceId` string.')
);
});

test('provides a default implementation for getItemInputValue which returns the query', async () => {
const getSources = () => [{ getItems: () => [] }];
const getSources = () => [{ sourceId: 'testSource', getItems: () => [] }];
const params = {
query: '',
state: createState({
Expand All @@ -82,7 +135,7 @@ describe('getNormalizedSources', () => {
});

test('provides a default implementation for getItemUrl', async () => {
const getSources = () => [{ getItems: () => [] }];
const getSources = () => [{ sourceId: 'testSource', getItems: () => [] }];
const params = {
query: '',
state: createState({}),
Expand All @@ -97,7 +150,7 @@ describe('getNormalizedSources', () => {
});

test('provides a default implementation for onSelect', async () => {
const getSources = () => [{ getItems: () => [] }];
const getSources = () => [{ sourceId: 'testSource', getItems: () => [] }];
const params = {
query: '',
state: createState({}),
Expand All @@ -119,7 +172,7 @@ describe('getNormalizedSources', () => {
});

test('provides a default implementation for onActive', async () => {
const getSources = () => [{ getItems: () => [] }];
const getSources = () => [{ sourceId: 'testSource', getItems: () => [] }];
const params = {
query: '',
state: createState({}),
Expand Down
5 changes: 5 additions & 0 deletions packages/autocomplete-core/src/utils/getNormalizedSources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ export function getNormalizedSources<TItem extends BaseItem>(
Boolean(maybeSource)
)
.map((source) => {
invariant(
typeof source.sourceId === 'string',
'A source must provide a `sourceId` string.'
);

const normalizedSource: InternalAutocompleteSource<TItem> = {
getItemInputValue({ state }) {
return state.query;
Expand Down
11 changes: 11 additions & 0 deletions packages/autocomplete-js/src/__tests__/autocomplete.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ describe('autocomplete-js', () => {
getSources() {
return [
{
sourceId: 'testSource',
getItems() {
return [
{ label: 'Item 1' },
Expand Down Expand Up @@ -167,6 +168,7 @@ describe('autocomplete-js', () => {
getSources() {
return [
{
sourceId: 'testSource',
getItems() {
return [];
},
Expand Down Expand Up @@ -206,6 +208,7 @@ describe('autocomplete-js', () => {
getSources() {
return [
{
sourceId: 'testSource',
getItems() {
return [];
},
Expand Down Expand Up @@ -245,6 +248,7 @@ describe('autocomplete-js', () => {
getSources() {
return [
{
sourceId: 'testSource',
getItems() {
return [];
},
Expand Down Expand Up @@ -290,6 +294,7 @@ describe('autocomplete-js', () => {
getSources() {
return [
{
sourceId: 'testSource',
getItems() {
return [];
},
Expand Down Expand Up @@ -338,6 +343,7 @@ describe('autocomplete-js', () => {
getSources() {
return [
{
sourceId: 'testSource',
getItems() {
return [];
},
Expand Down Expand Up @@ -383,6 +389,7 @@ describe('autocomplete-js', () => {
getSources() {
return [
{
sourceId: 'testSource',
getItems() {
return [
{ label: 'Item 1' },
Expand Down Expand Up @@ -418,6 +425,7 @@ describe('autocomplete-js', () => {
getSources() {
return [
{
sourceId: 'testSource',
getItems() {
return [
{ label: 'Item 1' },
Expand Down Expand Up @@ -449,6 +457,7 @@ describe('autocomplete-js', () => {
getSources() {
return [
{
sourceId: 'testSource',
getItems() {
return [
{ label: 'Item 1' },
Expand Down Expand Up @@ -482,6 +491,7 @@ describe('autocomplete-js', () => {
getSources() {
return [
{
sourceId: 'testSource',
getItems() {
return [
{ label: 'Item 1' },
Expand Down Expand Up @@ -512,6 +522,7 @@ describe('autocomplete-js', () => {
getSources() {
return [
{
sourceId: 'testSource',
getItems() {
return [
{ label: 'Item 1' },
Expand Down
1 change: 1 addition & 0 deletions packages/autocomplete-js/src/__tests__/positioning.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const querySuggestionsFixturePlugin: AutocompletePlugin<
getSources() {
return [
{
sourceId: 'testSource',
getItems() {
return querySuggestions;
},
Expand Down
6 changes: 5 additions & 1 deletion packages/autocomplete-js/src/render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,11 @@ export function renderPanel<TItem extends BaseItem>(
dom.panel.classList.toggle('aa-Panel--stalled', state.status === 'stalled');

const sections = state.collections.map(({ source, items }, sourceIndex) => (
<section key={sourceIndex} className={classNames.source}>
<section
key={sourceIndex}
className={classNames.source}
data-autocomplete-source-id={source.sourceId}
>
{source.templates.header && (
<div className={classNames.sourceHeader}>
{source.templates.header({
Expand Down
1 change: 1 addition & 0 deletions packages/autocomplete-js/src/types/AutocompleteSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export type AutocompleteSource<TItem extends BaseItem> = WithTemplates<
AutocompleteCoreSource<TItem>,
TItem
>;

export type InternalAutocompleteSource<TItem extends BaseItem> = WithTemplates<
InternalAutocompleteCoreSource<TItem>,
TItem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export function createQuerySuggestionsPlugin<
getSources({ query, setQuery, refresh, state }) {
return [
{
sourceId: 'querySuggestionsPlugin',
getItemInputValue({ item }) {
return item.query;
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export function createRecentSearchesPlugin<TItem extends RecentSearchesItem>({

return [
{
sourceId: 'recentSearchesPlugin',
getItemInputValue({ item }) {
return item.query;
},
Expand Down
1 change: 1 addition & 0 deletions packages/website/docs/autocomplete-js.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const autocompleteSearch = autocomplete({
getSources() {
return [
{
sourceId: 'querySuggestionsSources',
getItemInputValue: ({ item }) => item.query,
getItems({ query }) {
return getAlgoliaHits({
Expand Down
Loading