@rubixstudios/payload-typesense 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +182 -0
- package/dist/components/HeadlessSearchInput.d.ts +86 -0
- package/dist/components/HeadlessSearchInput.d.ts.map +1 -0
- package/dist/components/HeadlessSearchInput.js +602 -0
- package/dist/components/ThemeProvider.d.ts +10 -0
- package/dist/components/ThemeProvider.d.ts.map +1 -0
- package/dist/components/ThemeProvider.js +17 -0
- package/dist/components/index.d.ts +6 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +3 -0
- package/dist/components/themes/hooks.d.ts +52 -0
- package/dist/components/themes/hooks.d.ts.map +1 -0
- package/dist/components/themes/hooks.js +177 -0
- package/dist/components/themes/index.d.ts +5 -0
- package/dist/components/themes/index.d.ts.map +1 -0
- package/dist/components/themes/index.js +4 -0
- package/dist/components/themes/themes.d.ts +6 -0
- package/dist/components/themes/themes.d.ts.map +1 -0
- package/dist/components/themes/themes.js +156 -0
- package/dist/components/themes/types.d.ts +147 -0
- package/dist/components/themes/types.d.ts.map +1 -0
- package/dist/components/themes/types.js +1 -0
- package/dist/components/themes/utils.d.ts +30 -0
- package/dist/components/themes/utils.d.ts.map +1 -0
- package/dist/components/themes/utils.js +397 -0
- package/dist/endpoints/customEndpointHandler.d.ts +3 -0
- package/dist/endpoints/customEndpointHandler.d.ts.map +1 -0
- package/dist/endpoints/customEndpointHandler.js +5 -0
- package/dist/endpoints/health.d.ts +12 -0
- package/dist/endpoints/health.d.ts.map +1 -0
- package/dist/endpoints/health.js +174 -0
- package/dist/endpoints/search.d.ts +13 -0
- package/dist/endpoints/search.d.ts.map +1 -0
- package/dist/endpoints/search.js +375 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +148 -0
- package/dist/lib/cache.d.ts +41 -0
- package/dist/lib/cache.d.ts.map +1 -0
- package/dist/lib/cache.js +96 -0
- package/dist/lib/config-validation.d.ts +75 -0
- package/dist/lib/config-validation.d.ts.map +1 -0
- package/dist/lib/config-validation.js +174 -0
- package/dist/lib/hooks.d.ts +4 -0
- package/dist/lib/hooks.d.ts.map +1 -0
- package/dist/lib/hooks.js +54 -0
- package/dist/lib/initialization.d.ts +5 -0
- package/dist/lib/initialization.d.ts.map +1 -0
- package/dist/lib/initialization.js +102 -0
- package/dist/lib/schema-mapper.d.ts +14 -0
- package/dist/lib/schema-mapper.d.ts.map +1 -0
- package/dist/lib/schema-mapper.js +137 -0
- package/dist/lib/types.d.ts +183 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +2 -0
- package/dist/lib/typesense-client.d.ts +5 -0
- package/dist/lib/typesense-client.d.ts.map +1 -0
- package/dist/lib/typesense-client.js +20 -0
- package/package.json +92 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Front Tribe (https://fronttribe.com)
|
|
4
|
+
Copyright (c) 2025 Rubix Studios Pty. Ltd. <hello@rubixstudios.com.au>
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# Typesense Plugin for Payload CMS
|
|
2
|
+
|
|
3
|
+
This plugin is a fork of FrontTribe's Typesense Search Plugin for Payload CMS…
|
|
4
|
+
|
|
5
|
+
A production-ready search plugin that integrates Typesense with Payload CMS, offering fast, typo-tolerant search with real-time synchronization. This fork by Rubix Studios reduces bloat and introduces targeted changes for improved performance, maintainability, and flexibility.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
pnpm add @rubixstudios/typesense
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
// payload.config.ts
|
|
15
|
+
import { buildConfig } from 'payload/config'
|
|
16
|
+
import { typesenseSearch } from '@rubixstudios/typesense'
|
|
17
|
+
|
|
18
|
+
export default buildConfig({
|
|
19
|
+
plugins: [
|
|
20
|
+
typesenseSearch({
|
|
21
|
+
typesense: {
|
|
22
|
+
apiKey: 'xyz',
|
|
23
|
+
nodes: [{ host: 'localhost', port: 8108, protocol: 'http' }],
|
|
24
|
+
},
|
|
25
|
+
collections: {
|
|
26
|
+
posts: {
|
|
27
|
+
enabled: true,
|
|
28
|
+
searchFields: ['title', 'content'],
|
|
29
|
+
facetFields: ['category', 'status'],
|
|
30
|
+
displayName: 'Blog Posts',
|
|
31
|
+
icon: '📝',
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
}),
|
|
35
|
+
],
|
|
36
|
+
})
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
// 4. Use the search component
|
|
41
|
+
import { HeadlessSearchInput } from '@rubixstudios/typesense'
|
|
42
|
+
|
|
43
|
+
function SearchPage() {
|
|
44
|
+
return (
|
|
45
|
+
<HeadlessSearchInput
|
|
46
|
+
baseUrl="http://localhost:3000"
|
|
47
|
+
theme="modern" // Choose from: modern, dark
|
|
48
|
+
placeholder="Search everything..."
|
|
49
|
+
onResultClick={(result) => {
|
|
50
|
+
console.log('Selected:', result.document)
|
|
51
|
+
}}
|
|
52
|
+
/>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Multi-collection search
|
|
57
|
+
function MultiCollectionSearch() {
|
|
58
|
+
return (
|
|
59
|
+
<HeadlessSearchInput
|
|
60
|
+
baseUrl="http://localhost:3000"
|
|
61
|
+
collections={['posts', 'products']}
|
|
62
|
+
placeholder="Search posts & products..."
|
|
63
|
+
onResultClick={(result) => {
|
|
64
|
+
console.log('Selected:', result.document)
|
|
65
|
+
}}
|
|
66
|
+
/>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Single collection search
|
|
71
|
+
function PostSearch() {
|
|
72
|
+
return (
|
|
73
|
+
<HeadlessSearchInput
|
|
74
|
+
baseUrl="http://localhost:3000"
|
|
75
|
+
collection="posts"
|
|
76
|
+
placeholder="Search posts..."
|
|
77
|
+
onResultClick={(result) => {
|
|
78
|
+
console.log('Selected:', result.document)
|
|
79
|
+
}}
|
|
80
|
+
/>
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Features
|
|
86
|
+
|
|
87
|
+
- **Performance**: Sub-millisecond response times for search queries
|
|
88
|
+
- **Flexible Search**: Single, multiple, or universal collection search with one component
|
|
89
|
+
- **Modern Interface**: Responsive design implemented with Tailwind CSS
|
|
90
|
+
- **Optimized API**: Automatically routes requests to the most efficient endpoint
|
|
91
|
+
- **Real-Time Sync**: Continuous data sync with Payload CMS
|
|
92
|
+
- **Built-in Caching**: In-memory cache with configurable time-to-live settings
|
|
93
|
+
- **Production Ready**: Robust error handling and performance optimization
|
|
94
|
+
- **Responsive**: Mobile-first architecture ensuring compatibility across devices
|
|
95
|
+
|
|
96
|
+
## API Endpoints
|
|
97
|
+
|
|
98
|
+
- `GET /api/search` - Universal search across all collections
|
|
99
|
+
- `GET /api/search/{collection}` - Search specific collection
|
|
100
|
+
- `POST /api/search/{collection}` - Advanced search with filters
|
|
101
|
+
- `GET /api/search/{collection}/suggest` - Search suggestions
|
|
102
|
+
- `GET /api/search/collections` - Collection metadata
|
|
103
|
+
- `GET /api/search/health` - Health check
|
|
104
|
+
|
|
105
|
+
## Components
|
|
106
|
+
|
|
107
|
+
- **HeadlessSearchInput** - Single component supporting all search patterns:
|
|
108
|
+
- **Single Collection**: `collection="posts"` - Direct API calls for optimal performance
|
|
109
|
+
- **Multiple Collections**: `collections={['posts', 'products']}` - Smart filtering with universal search
|
|
110
|
+
- **Universal Search**: No collection props - Search across all collections
|
|
111
|
+
- **Complete UI Control**: Customizable rendering with comprehensive theme system
|
|
112
|
+
|
|
113
|
+
## Theme System
|
|
114
|
+
|
|
115
|
+
The plugin includes a powerful theme system with 5 pre-built themes and unlimited customization:
|
|
116
|
+
|
|
117
|
+
### Pre-built Themes
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
// Modern theme (default) - Clean and professional
|
|
121
|
+
<HeadlessSearchInput theme="modern" />
|
|
122
|
+
|
|
123
|
+
// Minimal theme - Flat design with minimal styling
|
|
124
|
+
<HeadlessSearchInput theme="minimal" />
|
|
125
|
+
|
|
126
|
+
// Elegant theme - Sophisticated with gradients
|
|
127
|
+
<HeadlessSearchInput theme="elegant" />
|
|
128
|
+
|
|
129
|
+
// Dark theme - Perfect for dark mode
|
|
130
|
+
<HeadlessSearchInput theme="dark" />
|
|
131
|
+
|
|
132
|
+
// Colorful theme - Vibrant and modern
|
|
133
|
+
<HeadlessSearchInput theme="colorful" />
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Custom Themes
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
const customTheme = {
|
|
140
|
+
theme: 'modern',
|
|
141
|
+
colors: {
|
|
142
|
+
inputBorderFocus: '#10b981',
|
|
143
|
+
inputBackground: '#f0fdf4',
|
|
144
|
+
resultsBackground: '#f0fdf4',
|
|
145
|
+
},
|
|
146
|
+
spacing: {
|
|
147
|
+
inputPadding: '1rem 1.25rem',
|
|
148
|
+
inputBorderRadius: '1.5rem',
|
|
149
|
+
},
|
|
150
|
+
enableAnimations: true,
|
|
151
|
+
enableShadows: true,
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
<HeadlessSearchInput theme={customTheme} />
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Theme Features
|
|
158
|
+
|
|
159
|
+
- **2 Pre-built Themes**: Modern, Dark
|
|
160
|
+
- **Unlimited Customization**: Override any color, spacing, typography, or animation
|
|
161
|
+
- **Performance Options**: Disable animations/shadows for better performance
|
|
162
|
+
- **Responsive Design**: Automatic mobile optimization
|
|
163
|
+
- **CSS Variables**: Advanced styling with CSS custom properties
|
|
164
|
+
- **TypeScript Support**: Full type safety for all theme configurations
|
|
165
|
+
|
|
166
|
+
## Contributing
|
|
167
|
+
|
|
168
|
+
1. Fork the repository
|
|
169
|
+
2. Create a feature branch
|
|
170
|
+
3. Make your changes
|
|
171
|
+
4. Add tests
|
|
172
|
+
5. Submit a pull request
|
|
173
|
+
|
|
174
|
+
## License
|
|
175
|
+
|
|
176
|
+
MIT License - see [LICENSE](LICENSE) file for details.
|
|
177
|
+
|
|
178
|
+
## Acknowledgments
|
|
179
|
+
|
|
180
|
+
- [FrontTribe](https://github.com/FrontTribe/typesense-search)
|
|
181
|
+
- [Typesense](https://typesense.org/)
|
|
182
|
+
- [Payload CMS](https://payloadcms.com/)
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { BaseSearchInputProps, SearchResult } from '../lib/types.js';
|
|
3
|
+
import type { ThemeConfig } from './themes/types.js';
|
|
4
|
+
export interface HeadlessSearchInputProps<T = Record<string, unknown>> extends BaseSearchInputProps<T> {
|
|
5
|
+
/**
|
|
6
|
+
* Collection to search in (for single collection search)
|
|
7
|
+
*/
|
|
8
|
+
collection?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Collections to search in (for multi-collection search)
|
|
11
|
+
*/
|
|
12
|
+
collections?: string[];
|
|
13
|
+
/**
|
|
14
|
+
* Enable suggestions
|
|
15
|
+
*/
|
|
16
|
+
enableSuggestions?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Number of results to show per page
|
|
19
|
+
*/
|
|
20
|
+
perPage?: number;
|
|
21
|
+
/**
|
|
22
|
+
* Custom render function for error state
|
|
23
|
+
*/
|
|
24
|
+
renderError?: (error: string) => React.ReactNode;
|
|
25
|
+
/**
|
|
26
|
+
* Custom input element (for complete control)
|
|
27
|
+
*/
|
|
28
|
+
renderInput?: (props: {
|
|
29
|
+
className: string;
|
|
30
|
+
onBlur: (e: React.FocusEvent) => void;
|
|
31
|
+
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
32
|
+
onFocus: () => void;
|
|
33
|
+
onKeyDown: (e: React.KeyboardEvent) => void;
|
|
34
|
+
placeholder: string;
|
|
35
|
+
ref: React.RefObject<HTMLInputElement | null>;
|
|
36
|
+
value: string;
|
|
37
|
+
}) => React.ReactNode;
|
|
38
|
+
/**
|
|
39
|
+
* Custom render function for loading state
|
|
40
|
+
*/
|
|
41
|
+
renderLoading?: () => React.ReactNode;
|
|
42
|
+
/**
|
|
43
|
+
* Custom render function for no results
|
|
44
|
+
*/
|
|
45
|
+
renderNoResults?: (query: string) => React.ReactNode;
|
|
46
|
+
/**
|
|
47
|
+
* Custom render function for results
|
|
48
|
+
*/
|
|
49
|
+
renderResult?: (result: SearchResult<T>, index: number) => React.ReactNode;
|
|
50
|
+
/**
|
|
51
|
+
* Custom render function for results header
|
|
52
|
+
*/
|
|
53
|
+
renderResultsHeader?: (found: number, searchTime: number) => React.ReactNode;
|
|
54
|
+
/**
|
|
55
|
+
* Custom CSS class for individual result items
|
|
56
|
+
*/
|
|
57
|
+
resultItemClassName?: string;
|
|
58
|
+
/**
|
|
59
|
+
* Custom CSS class for the results container
|
|
60
|
+
*/
|
|
61
|
+
resultsClassName?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Custom CSS class for results container
|
|
64
|
+
*/
|
|
65
|
+
resultsContainerClassName?: string;
|
|
66
|
+
/**
|
|
67
|
+
* Show loading state
|
|
68
|
+
*/
|
|
69
|
+
showLoading?: boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Show result count
|
|
72
|
+
*/
|
|
73
|
+
showResultCount?: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Show search time
|
|
76
|
+
*/
|
|
77
|
+
showSearchTime?: boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Theme configuration
|
|
80
|
+
*/
|
|
81
|
+
theme?: string | ThemeConfig;
|
|
82
|
+
}
|
|
83
|
+
declare const HeadlessSearchInput: <T = Record<string, unknown>>({ baseUrl, className, collection, collections, debounceMs, enableSuggestions: _enableSuggestions, errorClassName, inputClassName, inputWrapperClassName, minQueryLength, noResultsClassName, onResultClick, onResults, onSearch, perPage, placeholder, renderError, renderInput, renderNoResults, renderResult, renderResultsHeader, resultItemClassName, resultsClassName, resultsContainerClassName, resultsHeaderClassName, resultsListClassName, showLoading, showResultCount, showSearchTime, theme, }: HeadlessSearchInputProps<T>) => React.ReactElement;
|
|
84
|
+
export default HeadlessSearchInput;
|
|
85
|
+
export { HeadlessSearchInput };
|
|
86
|
+
//# sourceMappingURL=HeadlessSearchInput.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HeadlessSearchInput.d.ts","sourceRoot":"","sources":["../../src/components/HeadlessSearchInput.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAmD,MAAM,OAAO,CAAA;AAEvE,OAAO,KAAK,EAAE,oBAAoB,EAAkB,YAAY,EAAE,MAAM,iBAAiB,CAAA;AACzF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAIpD,MAAM,WAAW,wBAAwB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CACnE,SAAQ,oBAAoB,CAAC,CAAC,CAAC;IAC/B;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;IACtB;;OAEG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;OAEG;IACH,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAA;IAChD;;OAEG;IACH,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE;QACpB,SAAS,EAAE,MAAM,CAAA;QACjB,MAAM,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAA;QACrC,QAAQ,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,WAAW,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAA;QAC1D,OAAO,EAAE,MAAM,IAAI,CAAA;QACnB,SAAS,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,KAAK,IAAI,CAAA;QAC3C,WAAW,EAAE,MAAM,CAAA;QACnB,GAAG,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAA;QAC7C,KAAK,EAAE,MAAM,CAAA;KACd,KAAK,KAAK,CAAC,SAAS,CAAA;IACrB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,KAAK,CAAC,SAAS,CAAA;IACrC;;OAEG;IACH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAA;IACpD;;OAEG;IACH,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAA;IAC1E;;OAEG;IACH,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAA;IAC5E;;OAEG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;OAEG;IACH,yBAAyB,CAAC,EAAE,MAAM,CAAA;IAClC;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB;;OAEG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,WAAW,CAAA;CAC7B;AAED,QAAA,MAAM,mBAAmB,GAAI,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAG,6eA+BxD,wBAAwB,CAAC,CAAC,CAAC,KAAG,KAAK,CAAC,YAotBtC,CAAA;AAED,eAAe,mBAAmB,CAAA;AAClC,OAAO,EAAE,mBAAmB,EAAE,CAAA"}
|