search-optimizer
Version:
An optimized, framework-agnostic solution for handling search-as-you-type functionality
312 lines (225 loc) โข 9.38 kB
Markdown
# ๐ SearchOptimizer
[](https://www.npmjs.com/package/search-optimizer)
[](https://github.com/N1ghtHunter/search-optimizer/actions)
[](https://codecov.io/gh/N1ghtHunter/search-optimizer)
[](LICENSE)
> An optimized, framework-agnostic solution for handling search-as-you-type functionality.
## ๐ Table of Contents
1. [Overview](#-overview)
2. [Installation](#๏ธ-installation)
3. [Quick Start](#-quick-start)
4. [API Reference](#-api-reference)
5. [Adapters & Hooks](#-adapters--hooks)
6. [Examples](#-examples)
7. [Contributing](#-contributing)
8. [Changelog](#-changelog)
9. [License](#-license)
## ๐ Overview
SearchOptimizer is a lightweight, framework-agnostic library that helps optimize search inputs with real-time results (search-as-you-type). It provides a clean, efficient way to:
- Debounce user input to reduce unnecessary API calls
- Prevent race conditions by automatically canceling outdated requests
- Apply minimum character limits before triggering searches
- Process input uniformly (trim, lowercase, etc.)
- Works with any request library or framework
## โ๏ธ Installation
```bash
npm install search-optimizer
# or
yarn add search-optimizer
```
## ๐ Quick Start
### Basic Usage
```javascript
import { createSearchOptimizer } from 'search-optimizer';
import { createFetchExecutor } from 'search-optimizer/adapters/fetch';
// Create a search executor using fetch
const searchExecutor = createFetchExecutor({
baseUrl: 'https://api.example.com/search',
queryParam: 'q',
});
// Create the search optimizer
const searchOptimizer = createSearchOptimizer(searchExecutor, {
debounceDelay: 500,
minChars: 3,
});
// Get the search input element
const searchInput = document.getElementById('search-input');
// Connect the input to the search optimizer
searchInput.addEventListener('input', event => {
searchOptimizer.setQuery(event.target.value);
});
// Subscribe to changes in the search state
setInterval(() => {
console.log('Loading:', searchOptimizer.loading);
console.log('Results:', searchOptimizer.results);
console.log('Error:', searchOptimizer.error);
}, 1000);
```
### React Hook Usage
```jsx
import React from 'react';
import { useSearchOptimizer } from 'search-optimizer/adapters/react';
import { createFetchExecutor } from 'search-optimizer/adapters/fetch';
function SearchComponent() {
// Create the search executor
const searchExecutor = React.useMemo(
() =>
createFetchExecutor({
baseUrl: 'https://api.example.com/search',
queryParam: 'q',
}),
[],
);
// Use the hook to manage search state
const { inputProps, loading, results, error } = useSearchOptimizer(searchExecutor, {
debounceDelay: 400,
minChars: 2,
});
return (
<div>
<input type="text" placeholder="Search..." {...inputProps} />
{loading && <div>Loading...</div>}
{results && (
<ul>
{results.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
)}
{error && <div>Error: {error.message}</div>}
</div>
);
}
```
## ๐ API Reference
### Core
#### `createSearchOptimizer(executor, options)`
Creates a new SearchOptimizer instance.
**Parameters:**
- `executor`: A SearchExecutor implementation
- `options`: Configuration options
**Returns:** A SearchOptimizerResult object with methods and state properties
**Options:**
- `debounceDelay`: Debounce delay in milliseconds (default: 500)
- `minChars`: Minimum characters required before triggering search (default: 3)
- `trimInput`: Whether to trim the input value (default: true)
- `lowercaseInput`: Whether to convert the input to lowercase (default: true)
- `enableCancellation`: Whether to enable request cancellation (default: true)
- `inputProcessor`: Custom function to process input
- `onSearchStart`: Callback when search starts
- `onSearchSuccess`: Callback when search succeeds
- `onSearchError`: Callback when search fails
- `onSearchCanceled`: Callback when search is canceled
## ๐ Adapters & Hooks
### Import Paths
Each adapter is now available as a separate import:
```javascript
// Core functionality
import { createSearchOptimizer } from 'search-optimizer';
// Fetch adapter
import { createFetchExecutor } from 'search-optimizer/adapters/fetch';
// Axios adapter
import { createAxiosExecutor } from 'search-optimizer/adapters/axios';
// GraphQL adapter
import { createGraphQLExecutor } from 'search-optimizer/adapters/graphql';
// Generic adapter for custom implementations
import { createGenericExecutor } from 'search-optimizer/adapters/generic';
// React hook
import { useSearchOptimizer } from 'search-optimizer/adapters/react';
```
### Adapters
#### `createFetchExecutor(options)`
Creates a SearchExecutor using the Fetch API.
**Options:**
- `baseUrl`: Base URL for the search endpoint (required)
- `queryParam`: Query parameter name for the search term (default: 'q')
- `fetchOptions`: Additional fetch request options
- `responseTransformer`: Function to transform the fetch response
#### `createAxiosExecutor(options)`
Creates a SearchExecutor using Axios.
**Options:**
- `axios`: Axios instance to use for requests (required)
- `baseUrl`: Base URL for the search endpoint (required)
- `queryParam`: Query parameter name for the search term (default: 'q')
- `axiosOptions`: Additional axios request options
#### `createGraphQLExecutor(options)`
Creates a SearchExecutor for GraphQL clients.
**Options:**
- `client`: GraphQL client instance (required)
- `query`: GraphQL query document (required)
- `queryVariableName`: Name of the variable to pass the search term (default: 'query')
- `resultExtractor`: Function to extract search results from the GraphQL response
- `additionalVariables`: Additional variables to include with every GraphQL request
#### `createGenericExecutor(searchFn, options)`
Creates a SearchExecutor using any custom search implementation.
**Parameters:**
- `searchFn`: Function that performs the search, with signature `(query: string, signal?: AbortSignal) => Promise<T>`
- `options`: Additional configuration options
- `name`: Name for this custom executor (optional, useful for debugging)
- `errorHandler`: Optional custom error handler function
**Example:**
```javascript
// Create a custom executor with any search implementation
const myCustomExecutor = createGenericExecutor(
async (query, signal) => {
// Custom implementation using any API/library
const results = await customSearchLibrary.search(query, { signal });
return results.items;
},
{ name: 'CustomLibraryExecutor' },
);
// Use with SearchOptimizer
const searchOptimizer = createSearchOptimizer(myCustomExecutor);
```
#### Creating a Custom Adapter (Direct Implementation)
You can also implement the `SearchExecutor` interface directly for complete control:
```javascript
import { SearchExecutor, createSearchOptimizer } from 'search-optimizer';
// Implement the SearchExecutor interface directly
const myCustomExecutor: SearchExecutor = {
execute: async (query, signal) => {
// Your custom implementation here
// Full control over error handling, request formatting, etc.
const response = await fetch(`https://api.example.com/search?term=${query}`, {
headers: { 'Authorization': 'Bearer YOUR_API_KEY' },
signal
});
if (!response.ok) {
throw new Error(`Search failed: ${response.status}`);
}
const data = await response.json();
return data.results;
}
};
// Use with SearchOptimizer
const searchOptimizer = createSearchOptimizer(myCustomExecutor);
```
### React Hook
#### `useSearchOptimizer(executor, options)`
React hook for using SearchOptimizer in functional components.
**Returns:**
- `query`: Current search query string
- `loading`: Boolean indicating if a search is in progress
- `results`: Search results (null if no search has been performed)
- `error`: Error object (null if no error occurred)
- `setQuery`: Function to update the search query
- `search`: Function to manually trigger a search
- `cancel`: Function to cancel the current search
- `reset`: Function to reset the search state
- `inputProps`: Props object for easy React input element integration
## ๐งช Examples
Check out the examples directory for complete working demos:
- [Basic React Example](examples/react/SearchOptimizerHookExample.tsx)
- [React Query Integration](examples/react-query/) (Coming soon)
## ๐ค Contributing
We welcome contributions to SearchOptimizer! If you'd like to contribute, please:
1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request
Please make sure to update tests as appropriate.
## ๐ Changelog
See the [CHANGELOG.md](CHANGELOG.md) file for details on version updates.
## ๐ License
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.