feat(composable-api): Document Composable API (#2793)
This commit is contained in:
parent
b91e3099c6
commit
e5ae33fe90
8 changed files with 330 additions and 9 deletions
|
|
@ -99,7 +99,6 @@ function DocSearch(): JSX.Element {
|
|||
initialScrollY={window.scrollY}
|
||||
initialQuery={initialQuery}
|
||||
isAskAiActive={isAskAiActive}
|
||||
canHandleAskAi={true}
|
||||
onClose={closeModal}
|
||||
onAskAiToggle={toggleAskAi}
|
||||
/>,
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ import { DocSearchButton as Button, type DocSearchButtonProps as ButtonProps } f
|
|||
import type { JSX } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
export type DocSearchButtonProps = Omit<ButtonProps, 'keyboardShortcuts'>;
|
||||
export type DocSearchButtonProps = Omit<ButtonProps, 'keyboardShortcuts' | 'theme'>;
|
||||
|
||||
export function DocSearchButton(props: DocSearchButtonProps): JSX.Element {
|
||||
export function DocSearchButton({ onClick, ...props }: DocSearchButtonProps): JSX.Element {
|
||||
const { searchButtonRef, keyboardShortcuts, openModal } = useDocSearch();
|
||||
|
||||
return (
|
||||
|
|
@ -13,8 +13,8 @@ export function DocSearchButton(props: DocSearchButtonProps): JSX.Element {
|
|||
ref={searchButtonRef}
|
||||
keyboardShortcuts={keyboardShortcuts}
|
||||
onClick={(evt) => {
|
||||
if (props.onClick) {
|
||||
props.onClick(evt);
|
||||
if (onClick) {
|
||||
onClick(evt);
|
||||
}
|
||||
openModal();
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,10 @@ import type { JSX } from 'react';
|
|||
import React from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
|
||||
export type DocSearchModalProps = Omit<ModalProps, 'initialScrollY' | 'isAskAiActive' | 'onAskAiToggle'>;
|
||||
export type DocSearchModalProps = Omit<
|
||||
ModalProps,
|
||||
'initialScrollY' | 'isAskAiActive' | 'keyboardShortcuts' | 'onAskAiToggle' | 'onClose' | 'theme'
|
||||
>;
|
||||
|
||||
export function DocSearchModal(props: DocSearchModalProps): JSX.Element | null {
|
||||
const { isModalActive, onAskAiToggle, closeModal, isAskAiActive, initialQuery } = useDocSearch();
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ export type DocSearchModalProps = DocSearchProps & {
|
|||
onAskAiToggle: (toggle: boolean) => void;
|
||||
onClose?: () => void;
|
||||
isAskAiActive?: boolean;
|
||||
canHandleAskAi?: boolean;
|
||||
translations?: ModalTranslations;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -198,6 +198,7 @@ docsearch({
|
|||
},
|
||||
|
||||
// Enables/disables showing suggested questions on Ask AI's new conversation screen
|
||||
// NOTE: Only available with version >= 4.3
|
||||
suggestedQuestions: true,
|
||||
},
|
||||
// ...
|
||||
|
|
@ -239,6 +240,7 @@ in case you want to use different credentials for askAi
|
|||
},
|
||||
|
||||
// Enables/disables showing suggested questions on Ask AI's new conversation screen
|
||||
// NOTE: Only available with version >= 4.3
|
||||
suggestedQuestions: true,
|
||||
}}
|
||||
/>
|
||||
|
|
|
|||
315
packages/website/docs/composable-api.mdx
Normal file
315
packages/website/docs/composable-api.mdx
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
---
|
||||
title: Composable API
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
:::info
|
||||
The Composable API is available from version `>= 4.3`
|
||||
:::
|
||||
|
||||
DocSearch has a new Composable API for rendering the DocSearch button and modal. This API was
|
||||
introduced to help with more explicit control over where and how the components are rendered within a page.
|
||||
|
||||
## Introduction
|
||||
|
||||
The Composable API was introduced to help give more flexibility on how you render and use DocSearch on your website. With it,
|
||||
you have more control of where, when and how you want to bundle the components and render them.
|
||||
|
||||
With Composable API comes two new NPM packages:
|
||||
|
||||
- `@docsearch/core` - Shared core logic for managing different states of DocSearch
|
||||
- `@docsearch/modal` - The actual components used for the DocSearch Modal
|
||||
|
||||
:::warning
|
||||
Because of the nature of composability, this API is only available within React, and not within the `@docsearch/js` package.
|
||||
:::
|
||||
|
||||
## Getting Started
|
||||
|
||||
In order to start using the Composable API, you will need to install the following three packages:
|
||||
|
||||
<Tabs
|
||||
groupId="language"
|
||||
defaultValue="npm"
|
||||
values={[
|
||||
{ label: 'npm', value: 'npm', },
|
||||
{ label: 'yarn', value: 'yarn', },
|
||||
{ label: 'pnpm', value: 'pnpm' },
|
||||
{ label: 'bun', value: 'bun' }
|
||||
]
|
||||
}>
|
||||
<TabItem value="npm">
|
||||
|
||||
```bash
|
||||
npm install @docsearch/core @docsearch/modal @docsearch/css
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="yarn">
|
||||
|
||||
```bash
|
||||
yarn add @docsearch/core @docsearch/modal @docsearch/css
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="pnpm">
|
||||
|
||||
```bash
|
||||
pnpm add @docsearch/core @docsearch/modal @docsearch/css
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="bun">
|
||||
|
||||
```bash
|
||||
bun add @docsearch/core @docsearch/modal @docsearch/css
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
> Or using your package manager of choice
|
||||
|
||||
## Implementation
|
||||
|
||||
The most simple implementation would be as follows:
|
||||
|
||||
```tsx
|
||||
import { DocSearch } from '@docsearch/core';
|
||||
import { DocSearchButton, DocSearchModal } from '@docsearch/modal';
|
||||
import '@docsearch/css/style.css';
|
||||
|
||||
export function Search() {
|
||||
return (
|
||||
<DocSearch>
|
||||
<DocSearchButton />
|
||||
<DocSearchModal
|
||||
indexName="YOUR_INDEX_NAME"
|
||||
appId="YOUR_APP_ID"
|
||||
apiKey="YOUR_SEARCH_API_KEY"
|
||||
/>
|
||||
</DocSearch>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
:::info
|
||||
The actual components MUST be rendered within the `<DocSearch>` Provider in order for them to communicate with the global state.
|
||||
:::
|
||||
|
||||
This setup is slightly more involved with now rendering three different components:
|
||||
|
||||
- `<DocSearch>` is the parent element which controls and shares all state with the child components
|
||||
- `<DocSearchButton />` is the actual button element that is rendered and triggers the DocSearch Modal to open
|
||||
- `<DocSearchModal />` is the main modal containing the search form, search results, and Ask AI
|
||||
|
||||
|
||||
### Ask AI
|
||||
|
||||
Using Ask AI with the Composable API is quite similar to the normal way of using DocSearch. All that is needed is the `askAi` configuration:
|
||||
|
||||
```tsx
|
||||
import { DocSearch } from '@docsearch/core';
|
||||
import { DocSearchButton, DocSearchModal } from '@docsearch/modal';
|
||||
import '@docsearch/css/style.css';
|
||||
|
||||
export function Search() {
|
||||
return (
|
||||
<DocSearch>
|
||||
<DocSearchButton />
|
||||
<DocSearchModal
|
||||
indexName="YOUR_INDEX_NAME"
|
||||
appId="YOUR_APP_ID"
|
||||
apiKey="YOUR_SEARCH_API_KEY"
|
||||
// With just a simple assistant ID
|
||||
askAi="YOUR_ALGOLIA_ASSISTANT_ID"
|
||||
// Or with a more complex configuration
|
||||
askAi={{
|
||||
indexName: 'YOUR_MARKDOWN_INDEX', // Optional: use a different index for Ask AI
|
||||
apiKey: 'YOUR_SEARCH_API_KEY', // Optional: use a different API key for Ask AI
|
||||
appId: 'YOUR_APP_ID', // Optional: use a different App ID for Ask AI
|
||||
assistantId: 'YOUR_ALGOLIA_ASSISTANT_ID',
|
||||
searchParameters: {
|
||||
facetFilters: ['language:en', 'version:1.0.0'], // Optional: filter Ask AI context
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</DocSearch>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
You can find more information on Ask AI, and it's setup in it's [dedicated docs][2].
|
||||
|
||||
### Advanced
|
||||
|
||||
```tsx
|
||||
export default function AdvancedSearch(): JSX.Element {
|
||||
return (
|
||||
<DocSearch
|
||||
keyboardShortcuts={{
|
||||
'/': false, // Disable opening/closing the DocSearchModal with '/' key
|
||||
}}
|
||||
>
|
||||
<DocSearchButton
|
||||
translations={{ buttonText: 'Advanced Search' }} // Change the displayed text on the DocSearchButton
|
||||
/>
|
||||
<DocSearchModal
|
||||
indexName="YOUR_INDEX_NAME"
|
||||
appId="YOUR_APP_ID"
|
||||
apiKey="YOUR_SEARCH_API_KEY"
|
||||
askAi={{ // Enable Ask AI
|
||||
assistantId: 'YOUR_ALGOLIA_ASSISTANT_ID',
|
||||
searchParameters: {
|
||||
facetFilters: ['language:en'],
|
||||
},
|
||||
}}
|
||||
portalContainer='#algolia-search' // Custom element that the DocSearchModal will be rendered into
|
||||
/>
|
||||
</DocSearch>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Bundle saving exports
|
||||
|
||||
To help aid in trimming initial bundle size, the `@docsearch/modal` package exposes explicit file exports as well:
|
||||
|
||||
```ts
|
||||
import { DocSearchButton } from '@docsearch/modal/button';
|
||||
import { DocSearchModal } from '@docsearch/modal/modal';
|
||||
```
|
||||
|
||||
Here is a basic example of delaying the loading of the `DocSearchModal` code until the search button is clicked:
|
||||
|
||||
```tsx
|
||||
import { DocSearch } from '@docsearch/core';
|
||||
import { DocSearchButton } from '@docsearch/modal/button';
|
||||
import type { DocSearchModal as DocSearchModalType } from '@docsearch/modal/modal';
|
||||
import { useState } from 'react';
|
||||
|
||||
let DocSearchModal: typeof DocSearchModalType | null = null;
|
||||
|
||||
async function importDocSearchModalIfNeeded() {
|
||||
if (DocSearchModal) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { DocSearchModal: Modal } = await import('@docsearch/modal/modal');
|
||||
|
||||
DocSearchModal = Modal;
|
||||
}
|
||||
|
||||
export default function DynamicModal() {
|
||||
const [modalLoaded, setModalLoaded] = useState(false);
|
||||
|
||||
const loadModal = () => {
|
||||
importDocSearchModalIfNeeded().then(() => {
|
||||
setModalLoaded(true);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<DocSearch>
|
||||
<DocSearchButton onClick={loadModal} />
|
||||
{modalLoaded && DocSearchModal && (
|
||||
<DocSearchModal
|
||||
indexName="YOUR_INDEX_NAME"
|
||||
appId="YOUR_APP_ID"
|
||||
apiKey="YOUR_SEARCH_API_KEY"
|
||||
/>
|
||||
)}
|
||||
</DocSearch>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Components
|
||||
|
||||
### `<DocSearch />`
|
||||
|
||||
The `<DocSearch />` component from the `@docsearch/core` package is the main state handler for all of DocSearch.
|
||||
It utilizes [React Context][1] to enable sharing it's state across nested components.
|
||||
|
||||
#### Props
|
||||
|
||||
```ts
|
||||
interface DocSearchProps {
|
||||
// React children to be rendered within the DocSearch Provider
|
||||
children: Array<JSX.Element | null> | JSX.Element | React.ReactNode | null;
|
||||
// Theme to be set enabling style changes for `light` or `dark` themes
|
||||
theme?: 'light' | 'dark';
|
||||
// Initial starting query for keyword search
|
||||
initialQuery?: string;
|
||||
// Manage supported keyboard shortcuts for opening/closing the DocSearch Modal
|
||||
keyboardShortcuts?: {
|
||||
'Ctrl/Cmd+K': boolean,
|
||||
'/': boolean,
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### `<DocSearchButton />`
|
||||
|
||||
The main DocSearch search button to trigger the DocSearch Modal.
|
||||
|
||||
#### Props
|
||||
|
||||
```ts
|
||||
interface DocSearchButtonProps {
|
||||
// Optional callback for when the button is clicked. The original click event is passed.
|
||||
onClick?: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
|
||||
// Translation strings specific to the button.
|
||||
translations: {
|
||||
buttonText?: string;
|
||||
buttonAriaLabel?: string;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### `<DocSearchModal />`
|
||||
|
||||
The main keyword search Modal used to search your documentation.
|
||||
|
||||
#### Props
|
||||
|
||||
```ts
|
||||
interface DocSearchModalProps {
|
||||
/**
|
||||
* Algolia application id used by the search client.
|
||||
*/
|
||||
appId: string;
|
||||
/**
|
||||
* Public api key with search permissions for the index.
|
||||
*/
|
||||
apiKey: string;
|
||||
/**
|
||||
* Name of the algolia index to query.
|
||||
*
|
||||
* @deprecated `indexName` will be removed in a future version. Please use `indices` property going forward.
|
||||
*/
|
||||
indexName?: string;
|
||||
/**
|
||||
* List of indices and _optional_ searchParameters to be used for search.
|
||||
*
|
||||
* @see {@link https://docsearch.algolia.com/docs/api#indices}
|
||||
*/
|
||||
indices?: Array<DocSearchIndex | string>;
|
||||
/**
|
||||
* Configuration or assistant id to enable ask ai mode. Pass a string assistant id or a full config object.
|
||||
*/
|
||||
askAi?: DocSearchAskAi | string;
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
More property documentation can be found in the [DocSearch API Reference][3] page.
|
||||
|
||||
[1]: https://react.dev/reference/react/createContext
|
||||
[2]: /docs/v4/askai
|
||||
[3]: /docs/api
|
||||
|
|
@ -11,6 +11,8 @@ DocSearch v4 provides a significant upgrade over previous versions, offering enh
|
|||
|
||||
## Installation
|
||||
|
||||
> Looking for the Composable API documentation? You can find it [here][17].
|
||||
|
||||
DocSearch packages are available on the [npm registry][10].
|
||||
|
||||
<Tabs
|
||||
|
|
@ -379,5 +381,6 @@ This helps the browser establish a quick connection with Algolia, enhancing user
|
|||
[12]: /docs/api
|
||||
[13]: /docs/required-configuration#introduce-global-information-as-meta-tags
|
||||
[14]: /docs/record-extractor#indexing-content-for-faceting
|
||||
[16]: https://www.algolia.com/doc/guides/managing-results/refine-results/filtering/#facetfilters
|
||||
[15]: https://www.algolia.com/doc/guides/managing-results/refine-results/faceting/
|
||||
[16]: https://www.algolia.com/doc/guides/managing-results/refine-results/filtering/#facetfilters
|
||||
[17]: /docs/composable-api
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export default {
|
|||
{
|
||||
type: 'category',
|
||||
label: 'DocSearch v4',
|
||||
items: ['docsearch', 'styling', 'api', 'examples', 'migrating-from-v3'],
|
||||
items: ['docsearch', 'composable-api', 'styling', 'api', 'examples', 'migrating-from-v3'],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
|
|
|
|||
Loading…
Reference in a new issue