@rubixstudios/payload-typesense 1.1.0 → 1.1.2

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.
Files changed (105) hide show
  1. package/README.md +1 -16
  2. package/dist/components/HeadlessSearchInput.d.ts +2 -92
  3. package/dist/components/HeadlessSearchInput.d.ts.map +1 -1
  4. package/dist/components/HeadlessSearchInput.js +23 -140
  5. package/dist/components/ThemeProvider.d.ts +3 -2
  6. package/dist/components/ThemeProvider.d.ts.map +1 -1
  7. package/dist/components/ThemeProvider.js +1 -1
  8. package/dist/components/index.d.ts +5 -5
  9. package/dist/components/index.d.ts.map +1 -1
  10. package/dist/components/index.js +3 -3
  11. package/dist/components/themes/hooks.d.ts +5 -5
  12. package/dist/components/themes/hooks.d.ts.map +1 -1
  13. package/dist/components/themes/hooks.js +16 -16
  14. package/dist/components/themes/index.d.ts +4 -4
  15. package/dist/components/themes/index.js +4 -4
  16. package/dist/components/themes/themes.d.ts +1 -1
  17. package/dist/components/themes/themes.d.ts.map +1 -1
  18. package/dist/components/themes/themes.js +109 -109
  19. package/dist/components/themes/types.d.ts.map +1 -1
  20. package/dist/components/themes/utils.d.ts +1 -1
  21. package/dist/components/themes/utils.d.ts.map +1 -1
  22. package/dist/components/themes/utils.js +140 -140
  23. package/dist/endpoints/handler/createAdvancedSearch.d.ts +5 -0
  24. package/dist/endpoints/handler/createAdvancedSearch.d.ts.map +1 -0
  25. package/dist/endpoints/handler/createAdvancedSearch.js +40 -0
  26. package/dist/endpoints/handler/createCollections.d.ts +4 -0
  27. package/dist/endpoints/handler/createCollections.d.ts.map +1 -0
  28. package/dist/endpoints/handler/createCollections.js +23 -0
  29. package/dist/endpoints/handler/createSearch.d.ts +5 -0
  30. package/dist/endpoints/handler/createSearch.d.ts.map +1 -0
  31. package/dist/endpoints/handler/createSearch.js +119 -0
  32. package/dist/endpoints/handler/createSuggest.d.ts +5 -0
  33. package/dist/endpoints/handler/createSuggest.d.ts.map +1 -0
  34. package/dist/endpoints/handler/createSuggest.js +50 -0
  35. package/dist/endpoints/health.d.ts +4 -10
  36. package/dist/endpoints/health.d.ts.map +1 -1
  37. package/dist/endpoints/health.js +45 -103
  38. package/dist/endpoints/search.d.ts +4 -5
  39. package/dist/endpoints/search.d.ts.map +1 -1
  40. package/dist/endpoints/search.js +26 -355
  41. package/dist/index.d.ts +3 -3
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +6 -101
  44. package/dist/lib/cache.d.ts +6 -27
  45. package/dist/lib/cache.d.ts.map +1 -1
  46. package/dist/lib/cache.js +11 -29
  47. package/dist/lib/client.d.ts +4 -0
  48. package/dist/lib/client.d.ts.map +1 -0
  49. package/dist/lib/{typesense-client.js → client.js} +10 -18
  50. package/dist/lib/headlessSearch.d.ts +89 -0
  51. package/dist/lib/headlessSearch.d.ts.map +1 -0
  52. package/dist/lib/headlessSearch.js +2 -0
  53. package/dist/lib/hooks.d.ts +12 -3
  54. package/dist/lib/hooks.d.ts.map +1 -1
  55. package/dist/lib/hooks.js +37 -37
  56. package/dist/lib/initialization.d.ts +3 -3
  57. package/dist/lib/initialization.d.ts.map +1 -1
  58. package/dist/lib/initialization.js +36 -49
  59. package/dist/lib/schema-mapper.d.ts +17 -7
  60. package/dist/lib/schema-mapper.d.ts.map +1 -1
  61. package/dist/lib/schema-mapper.js +53 -89
  62. package/dist/lib/{config-validation.d.ts → validation.d.ts} +18 -22
  63. package/dist/lib/validation.d.ts.map +1 -0
  64. package/dist/lib/{config-validation.js → validation.js} +32 -49
  65. package/dist/{lib/types.d.ts → types.d.ts} +22 -5
  66. package/dist/types.d.ts.map +1 -0
  67. package/dist/utils/buildError.d.ts +2 -0
  68. package/dist/utils/buildError.d.ts.map +1 -0
  69. package/dist/utils/buildError.js +10 -0
  70. package/dist/utils/ensureCollection.d.ts +3 -0
  71. package/dist/utils/ensureCollection.d.ts.map +1 -0
  72. package/dist/utils/ensureCollection.js +13 -0
  73. package/dist/utils/extractText.d.ts +2 -0
  74. package/dist/utils/extractText.d.ts.map +1 -0
  75. package/dist/utils/extractText.js +20 -0
  76. package/dist/utils/getAllCollections.d.ts +9 -0
  77. package/dist/utils/getAllCollections.d.ts.map +1 -0
  78. package/dist/utils/getAllCollections.js +84 -0
  79. package/dist/utils/getCacheStats.d.ts +6 -0
  80. package/dist/utils/getCacheStats.d.ts.map +1 -0
  81. package/dist/utils/getCacheStats.js +9 -0
  82. package/dist/utils/getCollectionInfo.d.ts +3 -0
  83. package/dist/utils/getCollectionInfo.d.ts.map +1 -0
  84. package/dist/utils/getCollectionInfo.js +8 -0
  85. package/dist/utils/keyboard.d.ts +8 -0
  86. package/dist/utils/keyboard.d.ts.map +1 -0
  87. package/dist/utils/keyboard.js +41 -0
  88. package/dist/utils/testConnection.d.ts +3 -0
  89. package/dist/utils/testConnection.d.ts.map +1 -0
  90. package/dist/utils/testConnection.js +8 -0
  91. package/dist/utils/useDebounce.d.ts +2 -0
  92. package/dist/utils/useDebounce.d.ts.map +1 -0
  93. package/dist/utils/useDebounce.js +15 -0
  94. package/dist/utils/useSearch.d.ts +17 -0
  95. package/dist/utils/useSearch.d.ts.map +1 -0
  96. package/dist/utils/useSearch.js +78 -0
  97. package/package.json +14 -11
  98. package/dist/endpoints/customEndpointHandler.d.ts +0 -3
  99. package/dist/endpoints/customEndpointHandler.d.ts.map +0 -1
  100. package/dist/endpoints/customEndpointHandler.js +0 -5
  101. package/dist/lib/config-validation.d.ts.map +0 -1
  102. package/dist/lib/types.d.ts.map +0 -1
  103. package/dist/lib/typesense-client.d.ts +0 -5
  104. package/dist/lib/typesense-client.d.ts.map +0 -1
  105. /package/dist/{lib/types.js → types.js} +0 -0
package/README.md CHANGED
@@ -63,8 +63,7 @@ function SearchPage() {
63
63
  )
64
64
  }
65
65
 
66
- // Multi-collection search
67
- function MultiCollectionSearch() {
66
+ function CollectionSearch() {
68
67
  return (
69
68
  <HeadlessSearchInput
70
69
  baseUrl="http://localhost:3000"
@@ -76,20 +75,6 @@ function MultiCollectionSearch() {
76
75
  />
77
76
  )
78
77
  }
79
-
80
- // Single collection search
81
- function PostSearch() {
82
- return (
83
- <HeadlessSearchInput
84
- baseUrl="http://localhost:3000"
85
- collection="posts"
86
- placeholder="Search posts..."
87
- onResultClick={(result) => {
88
- console.log('Selected:', result.document)
89
- }}
90
- />
91
- )
92
- }
93
78
  ```
94
79
 
95
80
  ## Features
@@ -1,96 +1,6 @@
1
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
- * Show date in search results
23
- */
24
- renderDate?: boolean;
25
- /**
26
- * Custom render function for error state
27
- */
28
- renderError?: (error: string) => React.ReactNode;
29
- /**
30
- * Custom input element (for complete control)
31
- */
32
- renderInput?: (props: {
33
- className: string;
34
- onBlur: (e: React.FocusEvent) => void;
35
- onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
36
- onFocus: () => void;
37
- onKeyDown: (e: React.KeyboardEvent) => void;
38
- placeholder: string;
39
- ref: React.RefObject<HTMLInputElement | null>;
40
- value: string;
41
- }) => React.ReactNode;
42
- /**
43
- * Custom render function for loading state
44
- */
45
- renderLoading?: () => React.ReactNode;
46
- /**
47
- * Show match percentage in search results
48
- */
49
- renderMatchPercentage?: boolean;
50
- /**
51
- * Custom render function for no results
52
- */
53
- renderNoResults?: (query: string) => React.ReactNode;
54
- /**
55
- * Custom render function for results
56
- */
57
- renderResult?: (result: SearchResult<T>, index: number, handlers: {
58
- onClick: (result: SearchResult<T>) => void;
59
- }) => React.ReactNode;
60
- /**
61
- * Custom render function for results header
62
- */
63
- renderResultsHeader?: (found: number, searchTime: number) => React.ReactNode;
64
- /**
65
- * Custom CSS class for individual result items
66
- */
67
- resultItemClassName?: string;
68
- /**
69
- * Custom CSS class for the results container
70
- */
71
- resultsClassName?: string;
72
- /**
73
- * Custom CSS class for results container
74
- */
75
- resultsContainerClassName?: string;
76
- /**
77
- * Show loading state
78
- */
79
- showLoading?: boolean;
80
- /**
81
- * Show result count
82
- */
83
- showResultCount?: boolean;
84
- /**
85
- * Show search time
86
- */
87
- showSearchTime?: boolean;
88
- /**
89
- * Theme configuration
90
- */
91
- theme?: string | ThemeConfig;
92
- }
93
- declare const HeadlessSearchInput: <T = Record<string, unknown>>({ baseUrl, className, collection, collections, debounceMs, enableSuggestions: _enableSuggestions, errorClassName, inputClassName, inputWrapperClassName, minQueryLength, noResultsClassName, onResultClick, onResults, onSearch, perPage, placeholder, renderDate, renderError, renderInput, renderMatchPercentage, renderNoResults, renderResult, renderResultsHeader, resultItemClassName, resultsClassName, resultsContainerClassName, resultsHeaderClassName, resultsListClassName, showLoading, showResultCount, showSearchTime, theme, }: HeadlessSearchInputProps<T>) => React.ReactElement;
2
+ import { type HeadlessSearchInputProps } from '../lib/headlessSearch.js';
3
+ declare const HeadlessSearchInput: <T = Record<string, unknown>>({ baseUrl, className, collections, debounceMs, enableSuggestions: _enableSuggestions, errorClassName, inputClassName, inputWrapperClassName, minQueryLength, noResultsClassName, onResultClick, onResults, onSearch, perPage, placeholder, renderDate, renderError, renderInput, renderMatchPercentage, renderNoResults, renderResult, renderResultsHeader, resultItemClassName, resultsClassName, resultsContainerClassName, resultsHeaderClassName, resultsListClassName, showLoading, showResultCount, showSearchTime, theme, }: HeadlessSearchInputProps<T>) => React.ReactElement;
94
4
  export default HeadlessSearchInput;
95
5
  export { HeadlessSearchInput };
96
6
  //# sourceMappingURL=HeadlessSearchInput.d.ts.map
@@ -1 +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,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;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,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B;;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,EAAE,QAAQ,EAAE;QAAE,OAAO,EAAE,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;KAAE,KAAK,KAAK,CAAC,SAAS,CAAA;IACpI;;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,ghBAiCxD,wBAAwB,CAAC,CAAC,CAAC,KAAG,KAAK,CAAC,YA4sBtC,CAAA;AAED,eAAe,mBAAmB,CAAA;AAClC,OAAO,EAAE,mBAAmB,EAAE,CAAA"}
1
+ {"version":3,"file":"HeadlessSearchInput.d.ts","sourceRoot":"","sources":["../../src/components/HeadlessSearchInput.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAsC,MAAM,OAAO,CAAA;AAE1D,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,0BAA0B,CAAA;AAOxE,QAAA,MAAM,mBAAmB,GAAI,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAG,ogBAgCxD,wBAAwB,CAAC,CAAC,CAAC,KAAG,KAAK,CAAC,YAmkBtC,CAAA;AAED,eAAe,mBAAmB,CAAA;AAClC,OAAO,EAAE,mBAAmB,EAAE,CAAA"}
@@ -1,182 +1,65 @@
1
1
  'use client';
2
- import React, { useCallback, useEffect, useRef, useState } from 'react';
2
+ import React, { useEffect, useRef, useState } from 'react';
3
+ import { handleKeyboard } from '../utils/keyboard.js';
4
+ import { useDebounce } from '../utils/useDebounce.js';
5
+ import { useSearch } from '../utils/useSearch.js';
3
6
  import { useThemeConfig } from './themes/hooks.js';
4
- const HeadlessSearchInput = ({ baseUrl, className = '', collection, collections, debounceMs = 300, enableSuggestions: _enableSuggestions = true, errorClassName = '', inputClassName = '', inputWrapperClassName = '', minQueryLength = 2, noResultsClassName = '', onResultClick, onResults, onSearch, perPage = 10, placeholder = 'Search...', renderDate = true, renderError, renderInput, renderMatchPercentage = true, renderNoResults, renderResult, renderResultsHeader, resultItemClassName = '', resultsClassName = '', resultsContainerClassName = '', resultsHeaderClassName = '', resultsListClassName = '', showLoading = true, showResultCount = true, showSearchTime = true, theme = 'modern' })=>{
7
+ const HeadlessSearchInput = ({ baseUrl, className = '', collections, debounceMs = 300, enableSuggestions: _enableSuggestions = true, errorClassName = '', inputClassName = '', inputWrapperClassName = '', minQueryLength = 2, noResultsClassName = '', onResultClick, onResults, onSearch, perPage = 10, placeholder = 'Search...', renderDate = true, renderError, renderInput, renderMatchPercentage = true, renderNoResults, renderResult, renderResultsHeader, resultItemClassName = '', resultsClassName = '', resultsContainerClassName = '', resultsHeaderClassName = '', resultsListClassName = '', showLoading = true, showResultCount = true, showSearchTime = true, theme = 'modern' })=>{
5
8
  const [query, setQuery] = useState('');
6
- const [results, setResults] = useState(null);
7
- const [isLoading, setIsLoading] = useState(false);
8
9
  const [isOpen, setIsOpen] = useState(false);
9
- const [error, setError] = useState(null);
10
10
  const inputRef = useRef(null);
11
11
  const resultsRef = useRef(null);
12
- const debounceRef = useRef(undefined);
13
- const collectionsRef = useRef(collections);
14
12
  const themeConfig = useThemeConfig({
15
13
  theme: typeof theme === 'string' ? theme : theme.theme || 'modern',
16
14
  ...typeof theme === 'object' ? theme : {}
17
15
  });
18
- // Note: If neither collection nor collections is provided, the component will search all collections
19
- // Update collections ref when prop changes
20
- useEffect(()=>{
21
- collectionsRef.current = collections;
22
- }, [
23
- collections
24
- ]);
25
- // Debounced search function
26
- const onResultsRef = useRef(onResults);
27
- const onSearchRef = useRef(onSearch);
28
- onResultsRef.current = onResults;
29
- onSearchRef.current = onSearch;
30
- const performSearch = useCallback(async (searchQuery)=>{
31
- if (searchQuery.length < minQueryLength) {
32
- setResults(null);
33
- setIsLoading(false);
34
- return;
35
- }
36
- setIsLoading(true);
37
- setError(null);
38
- try {
39
- let searchUrl;
40
- let searchResults;
41
- if (collection) {
42
- // Single collection search
43
- searchUrl = `${baseUrl}/api/search/${collection}?q=${encodeURIComponent(searchQuery)}&per_page=${perPage}`;
44
- } else if (collectionsRef.current && collectionsRef.current.length > 0) {
45
- // Multiple collections specified - use universal search and filter client-side
46
- searchUrl = `${baseUrl}/api/search?q=${encodeURIComponent(searchQuery)}&per_page=${perPage * 2}`;
47
- } else {
48
- // No collections specified - use universal search
49
- searchUrl = `${baseUrl}/api/search?q=${encodeURIComponent(searchQuery)}&per_page=${perPage}`;
50
- }
51
- const response = await fetch(searchUrl);
52
- if (!response.ok) {
53
- throw new Error(`Search failed: ${response.status} ${response.statusText}`);
54
- }
55
- searchResults = await response.json();
56
- if (collectionsRef.current && collectionsRef.current.length > 0) {
57
- const filteredHits = searchResults.hits?.filter((hit)=>hit.collection && collectionsRef.current.includes(hit.collection)) || [];
58
- const filteredCollections = searchResults.collections?.filter((col)=>col.collection && collectionsRef.current.includes(col.collection)) || [];
59
- searchResults = {
60
- ...searchResults,
61
- collections: filteredCollections,
62
- found: filteredHits.length,
63
- hits: filteredHits
64
- };
65
- }
66
- setResults(searchResults);
67
- onResultsRef.current?.(searchResults);
68
- onSearchRef.current?.(searchQuery, searchResults);
69
- } catch (err) {
70
- setError(err instanceof Error ? err.message : 'Search failed');
71
- setResults(null);
72
- } finally{
73
- setIsLoading(false);
74
- }
75
- }, [
16
+ const debouncedQuery = useDebounce(query, debounceMs);
17
+ const { error, isLoading, results, search } = useSearch({
76
18
  baseUrl,
77
- collection,
78
- perPage,
79
- minQueryLength
80
- ]);
19
+ collections,
20
+ minQueryLength,
21
+ onResults,
22
+ onSearch,
23
+ perPage
24
+ });
81
25
  useEffect(()=>{
82
- if (debounceRef.current) {
83
- clearTimeout(debounceRef.current);
26
+ if (debouncedQuery.length >= minQueryLength) {
27
+ void search(debouncedQuery);
84
28
  }
85
- if (query.length >= minQueryLength) {
86
- debounceRef.current = setTimeout(()=>{
87
- void performSearch(query);
88
- void onSearchRef.current?.(query, results || {
89
- found: 0,
90
- hits: [],
91
- page: 1,
92
- request_params: {
93
- per_page: 10,
94
- q: query
95
- },
96
- search_cutoff: false,
97
- search_time_ms: 0
98
- });
99
- }, debounceMs);
100
- } else {
101
- setResults(null);
102
- setIsLoading(false);
103
- }
104
- return ()=>{
105
- if (debounceRef.current) {
106
- clearTimeout(debounceRef.current);
107
- }
108
- };
109
- // eslint-disable-next-line react-hooks/exhaustive-deps
110
29
  }, [
111
- query,
112
- debounceMs,
30
+ debouncedQuery,
113
31
  minQueryLength,
114
- performSearch
32
+ search
115
33
  ]);
116
- // Handle input change
117
34
  const handleInputChange = (e)=>{
118
35
  const value = e.target.value;
119
36
  setQuery(value);
120
37
  setIsOpen(value.length >= minQueryLength);
121
38
  };
122
- // Handle input focus
123
39
  const handleInputFocus = ()=>{
124
40
  if (query.length >= minQueryLength) {
125
41
  setIsOpen(true);
126
42
  }
127
43
  };
128
- // Handle input blur
129
44
  const handleInputBlur = (_e)=>{
130
- // Delay hiding results to allow clicking on them
131
45
  setTimeout(()=>{
132
46
  if (!resultsRef.current?.contains(document.activeElement)) {
133
47
  setIsOpen(false);
134
48
  }
135
49
  }, 150);
136
50
  };
137
- // Handle result click
138
51
  const handleResultClick = (result)=>{
139
52
  onResultClick?.(result);
140
53
  setIsOpen(false);
141
54
  setQuery('');
142
55
  };
143
- // Handle keyboard navigation
144
56
  const handleKeyDown = (e)=>{
145
- if (!isOpen || !results) {
146
- return;
147
- }
148
- const resultItems = resultsRef.current?.querySelectorAll('[data-result-item]');
149
- if (!resultItems) {
150
- return;
151
- }
152
- const currentIndex = Array.from(resultItems).findIndex((item)=>item === document.activeElement);
153
- switch(e.key){
154
- case 'ArrowDown':
155
- {
156
- e.preventDefault();
157
- const nextIndex = currentIndex < resultItems.length - 1 ? currentIndex + 1 : 0;
158
- resultItems[nextIndex]?.focus();
159
- break;
160
- }
161
- case 'ArrowUp':
162
- {
163
- e.preventDefault();
164
- const prevIndex = currentIndex > 0 ? currentIndex - 1 : resultItems.length - 1;
165
- resultItems[prevIndex]?.focus();
166
- break;
167
- }
168
- case 'Enter':
169
- e.preventDefault();
170
- if (currentIndex >= 0 && resultItems[currentIndex]) {
171
- ;
172
- resultItems[currentIndex]?.click();
173
- }
174
- break;
175
- case 'Escape':
176
- setIsOpen(false);
177
- inputRef.current?.blur();
178
- break;
179
- }
57
+ handleKeyboard(e, {
58
+ inputRef,
59
+ isOpen,
60
+ results,
61
+ resultsRef
62
+ });
180
63
  };
181
64
  // Default render functions
182
65
  const defaultRenderResult = (result, _index)=>{
@@ -1,9 +1,10 @@
1
- import type { ThemeConfig, ThemeContextValue } from './themes/types.js';
1
+ import React from 'react';
2
+ import { type ThemeConfig, type ThemeContextValue } from './themes/types.js';
2
3
  interface ThemeProviderProps {
3
4
  children: React.ReactNode;
4
5
  config: ThemeConfig;
5
6
  }
6
- export declare function ThemeProvider({ children, config }: ThemeProviderProps): import("react").JSX.Element;
7
+ export declare function ThemeProvider({ children, config }: ThemeProviderProps): React.JSX.Element;
7
8
  export declare function useTheme(): ThemeContextValue;
8
9
  export {};
9
10
  //# sourceMappingURL=ThemeProvider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ThemeProvider.d.ts","sourceRoot":"","sources":["../../src/components/ThemeProvider.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAIvE,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,MAAM,EAAE,WAAW,CAAA;CACpB;AAID,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,kBAAkB,+BAIrE;AAED,wBAAgB,QAAQ,IAAI,iBAAiB,CAM5C"}
1
+ {"version":3,"file":"ThemeProvider.d.ts","sourceRoot":"","sources":["../../src/components/ThemeProvider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA6B,MAAM,OAAO,CAAA;AAGjD,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAE5E,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,MAAM,EAAE,WAAW,CAAA;CACpB;AAID,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,kBAAkB,qBAIrE;AAED,wBAAgB,QAAQ,IAAI,iBAAiB,CAM5C"}
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import { createContext, use } from 'react';
2
+ import React, { createContext, use } from 'react';
3
3
  import { useThemeConfig } from './themes/hooks.js';
4
4
  const ThemeContext = /*#__PURE__*/ createContext(null);
5
5
  export function ThemeProvider({ children, config }) {
@@ -1,6 +1,6 @@
1
- export type { BaseSearchInputProps, HealthCheckResponse, SearchResponse, SearchResult, SearchResultProps, TypesenseSearchConfig, } from "../lib/types.js";
2
- export { default as HeadlessSearchInput } from "./HeadlessSearchInput.js";
3
- export type { HeadlessSearchInputProps } from "./HeadlessSearchInput.js";
4
- export { ThemeProvider } from "./ThemeProvider.js";
5
- export * from "./themes/index.js";
1
+ export { type HeadlessSearchInputProps } from '../lib/headlessSearch.js';
2
+ export { type BaseSearchInputProps, type HealthCheckResponse, type SearchResponse, type SearchResult, type SearchResultProps, type TypesenseSearchConfig, } from '../types.js';
3
+ export { default as HeadlessSearchInput } from './HeadlessSearchInput.js';
4
+ export { ThemeProvider } from './ThemeProvider.js';
5
+ export * from './themes/index.js';
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACX,oBAAoB,EACpB,mBAAmB,EACnB,cAAc,EACd,YAAY,EACZ,iBAAiB,EACjB,qBAAqB,GACrB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AACzE,YAAY,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAA;AACxE,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAElD,cAAc,mBAAmB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,0BAA0B,CAAA;AACxE,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,GAC3B,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AACzE,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAElD,cAAc,mBAAmB,CAAA"}
@@ -1,3 +1,3 @@
1
- export { default as HeadlessSearchInput } from "./HeadlessSearchInput.js";
2
- export { ThemeProvider } from "./ThemeProvider.js";
3
- export * from "./themes/index.js";
1
+ export { default as HeadlessSearchInput } from './HeadlessSearchInput.js';
2
+ export { ThemeProvider } from './ThemeProvider.js';
3
+ export * from './themes/index.js';
@@ -1,4 +1,4 @@
1
- import type { Theme, ThemeConfig, ThemeContextValue } from "./types.js";
1
+ import type { Theme, ThemeConfig, ThemeContextValue } from './types.js';
2
2
  declare const ThemeContext: import("react").Context<ThemeContextValue | null>;
3
3
  /**
4
4
  * Hook to access theme context
@@ -27,19 +27,19 @@ export declare function useThemeClasses(config: ThemeConfig): Record<string, str
27
27
  /**
28
28
  * Hook to get theme-aware color values
29
29
  */
30
- export declare function useThemeColors(config: ThemeConfig): Theme["colors"];
30
+ export declare function useThemeColors(config: ThemeConfig): Theme['colors'];
31
31
  /**
32
32
  * Hook to get theme-aware spacing values
33
33
  */
34
- export declare function useThemeSpacing(config: ThemeConfig): Theme["spacing"];
34
+ export declare function useThemeSpacing(config: ThemeConfig): Theme['spacing'];
35
35
  /**
36
36
  * Hook to get theme-aware typography values
37
37
  */
38
- export declare function useThemeTypography(config: ThemeConfig): Theme["typography"];
38
+ export declare function useThemeTypography(config: ThemeConfig): Theme['typography'];
39
39
  /**
40
40
  * Hook to detect system theme preference
41
41
  */
42
- export declare function useSystemTheme(): "dark" | "light";
42
+ export declare function useSystemTheme(): 'dark' | 'light';
43
43
  /**
44
44
  * Hook to create auto theme configuration based on system preference
45
45
  */
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../../src/components/themes/hooks.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAWvE,QAAA,MAAM,YAAY,mDAAgD,CAAA;AAElE;;GAEG;AACH,wBAAgB,QAAQ,IAAI,iBAAiB,CAM5C;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,iBAAiB,CAuBrE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAK1E;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CACjC,UAAU,EAAE,WAAW,EACvB,QAAQ,EAAE,OAAO,GACf,WAAW,CA8Bb;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC7B,WAAW,EAAE,WAAW,EACxB,UAAU,EAAE,WAAW,EACvB,MAAM,EAAE,OAAO,GACb,WAAW,CAIb;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAc3E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,KAAK,CAAC,QAAQ,CAAC,CAKnE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,KAAK,CAAC,SAAS,CAAC,CAKrE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,GAAG,KAAK,CAAC,YAAY,CAAC,CAK3E;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,MAAM,GAAG,OAAO,CAUjD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAM1E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC7B,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,OAAO,CAAC,WAAW,CAAC,GAC7B,WAAW,CAOb;AAGD,OAAO,EAAE,YAAY,EAAE,CAAA"}
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../../src/components/themes/hooks.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAWvE,QAAA,MAAM,YAAY,mDAAgD,CAAA;AAElE;;GAEG;AACH,wBAAgB,QAAQ,IAAI,iBAAiB,CAM5C;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,iBAAiB,CAoBrE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAK1E;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,GAAG,WAAW,CA8B1F;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,WAAW,EAAE,WAAW,EACxB,UAAU,EAAE,WAAW,EACvB,MAAM,EAAE,OAAO,GACd,WAAW,CAIb;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAc3E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,KAAK,CAAC,QAAQ,CAAC,CAKnE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,KAAK,CAAC,SAAS,CAAC,CAKrE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,GAAG,KAAK,CAAC,YAAY,CAAC,CAK3E;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,MAAM,GAAG,OAAO,CAQjD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAM1E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,OAAO,CAAC,WAAW,CAAC,GAC9B,WAAW,CAOb;AAGD,OAAO,EAAE,YAAY,EAAE,CAAA"}
@@ -1,13 +1,13 @@
1
- "use client";
2
- import { createContext, useCallback, useContext, useMemo } from "react";
3
- import { applyTheme, generateThemeClasses, getThemeVariables, isDarkTheme, isLightTheme, mergeThemeConfig } from "./utils.js";
1
+ 'use client';
2
+ import { createContext, useCallback, useContext, useMemo } from 'react';
3
+ import { applyTheme, generateThemeClasses, getThemeVariables, isDarkTheme, isLightTheme, mergeThemeConfig } from './utils.js';
4
4
  const ThemeContext = createContext(null);
5
5
  /**
6
6
  * Hook to access theme context
7
7
  */ export function useTheme() {
8
8
  const context = useContext(ThemeContext);
9
9
  if (!context) {
10
- throw new Error("useTheme must be used within a ThemeProvider");
10
+ throw new Error('useTheme must be used within a ThemeProvider');
11
11
  }
12
12
  return context;
13
13
  }
@@ -60,18 +60,18 @@ const ThemeContext = createContext(null);
60
60
  spacing: {
61
61
  ...baseConfig.spacing,
62
62
  // Adjust spacing for mobile
63
- headerPadding: "0.75rem 1rem",
64
- inputFontSize: "16px",
65
- inputPadding: "0.875rem 1rem",
66
- itemPadding: "0.875rem 1rem",
67
- resultsMaxHeight: "20rem"
63
+ headerPadding: '0.75rem 1rem',
64
+ inputFontSize: '16px',
65
+ inputPadding: '0.875rem 1rem',
66
+ itemPadding: '0.875rem 1rem',
67
+ resultsMaxHeight: '20rem'
68
68
  },
69
69
  // Disable animations on mobile for better performance
70
70
  animations: isMobile ? {
71
71
  ...baseConfig.animations,
72
- transitionFast: "0s",
73
- transitionNormal: "0s",
74
- transitionSlow: "0s"
72
+ transitionFast: '0s',
73
+ transitionNormal: '0s',
74
+ transitionSlow: '0s'
75
75
  } : baseConfig.animations
76
76
  };
77
77
  return mobileConfig;
@@ -141,10 +141,10 @@ const ThemeContext = createContext(null);
141
141
  * Hook to detect system theme preference
142
142
  */ export function useSystemTheme() {
143
143
  return useMemo(()=>{
144
- if (typeof window === "undefined") {
145
- return "light";
144
+ if (typeof window === 'undefined') {
145
+ return 'light';
146
146
  }
147
- return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
147
+ return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
148
148
  }, []);
149
149
  }
150
150
  /**
@@ -152,7 +152,7 @@ const ThemeContext = createContext(null);
152
152
  */ export function useAutoTheme(lightTheme, darkTheme) {
153
153
  const systemTheme = useSystemTheme();
154
154
  return useMemo(()=>{
155
- return systemTheme === "dark" ? darkTheme : lightTheme;
155
+ return systemTheme === 'dark' ? darkTheme : lightTheme;
156
156
  }, [
157
157
  systemTheme,
158
158
  lightTheme,
@@ -1,5 +1,5 @@
1
- export * from "./hooks.js";
2
- export * from "./themes.js";
3
- export * from "./types.js";
4
- export * from "./utils.js";
1
+ export * from './hooks.js';
2
+ export * from './themes.js';
3
+ export * from './types.js';
4
+ export * from './utils.js';
5
5
  //# sourceMappingURL=index.d.ts.map
@@ -1,4 +1,4 @@
1
- export * from "./hooks.js";
2
- export * from "./themes.js";
3
- export * from "./types.js";
4
- export * from "./utils.js";
1
+ export * from './hooks.js';
2
+ export * from './themes.js';
3
+ export * from './types.js';
4
+ export * from './utils.js';
@@ -1,4 +1,4 @@
1
- import type { Theme } from "./types.js";
1
+ import type { Theme } from './types.js';
2
2
  export declare const modernTheme: Theme;
3
3
  export declare const darkTheme: Theme;
4
4
  export declare const themes: Record<string, Theme>;
@@ -1 +1 @@
1
- {"version":3,"file":"themes.d.ts","sourceRoot":"","sources":["../../../src/components/themes/themes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AA8DvC,eAAO,MAAM,WAAW,EAAE,KAsDzB,CAAA;AAGD,eAAO,MAAM,SAAS,EAAE,KAqDvB,CAAA;AAGD,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAGxC,CAAA;AAGD,eAAO,MAAM,YAAY,OAAc,CAAA"}
1
+ {"version":3,"file":"themes.d.ts","sourceRoot":"","sources":["../../../src/components/themes/themes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AA2DvC,eAAO,MAAM,WAAW,EAAE,KAqDzB,CAAA;AAGD,eAAO,MAAM,SAAS,EAAE,KAqDvB,CAAA;AAGD,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAGxC,CAAA;AAGD,eAAO,MAAM,YAAY,OAAc,CAAA"}