@seekora-ai/ui-sdk-react 0.2.0 → 0.2.4

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 (58) hide show
  1. package/dist/components/SearchResults.d.ts.map +1 -1
  2. package/dist/components/SearchResults.js +24 -58
  3. package/dist/docsearch/components/DocSearch.d.ts +4 -0
  4. package/dist/docsearch/components/DocSearch.d.ts.map +1 -0
  5. package/dist/docsearch/components/DocSearch.js +81 -0
  6. package/dist/docsearch/components/DocSearchButton.d.ts +4 -0
  7. package/dist/docsearch/components/DocSearchButton.d.ts.map +1 -0
  8. package/dist/docsearch/components/DocSearchButton.js +12 -0
  9. package/dist/docsearch/components/Footer.d.ts +8 -0
  10. package/dist/docsearch/components/Footer.d.ts.map +1 -0
  11. package/dist/docsearch/components/Footer.js +23 -0
  12. package/dist/docsearch/components/Highlight.d.ts +9 -0
  13. package/dist/docsearch/components/Highlight.d.ts.map +1 -0
  14. package/dist/docsearch/components/Highlight.js +48 -0
  15. package/dist/docsearch/components/Hit.d.ts +15 -0
  16. package/dist/docsearch/components/Hit.d.ts.map +1 -0
  17. package/dist/docsearch/components/Hit.js +96 -0
  18. package/dist/docsearch/components/Modal.d.ts +9 -0
  19. package/dist/docsearch/components/Modal.d.ts.map +1 -0
  20. package/dist/docsearch/components/Modal.js +54 -0
  21. package/dist/docsearch/components/Results.d.ts +21 -0
  22. package/dist/docsearch/components/Results.d.ts.map +1 -0
  23. package/dist/docsearch/components/Results.js +91 -0
  24. package/dist/docsearch/components/SearchBox.d.ts +12 -0
  25. package/dist/docsearch/components/SearchBox.d.ts.map +1 -0
  26. package/dist/docsearch/components/SearchBox.js +18 -0
  27. package/dist/docsearch/hooks/useDocSearch.d.ts +32 -0
  28. package/dist/docsearch/hooks/useDocSearch.d.ts.map +1 -0
  29. package/dist/docsearch/hooks/useDocSearch.js +208 -0
  30. package/dist/docsearch/hooks/useKeyboard.d.ts +17 -0
  31. package/dist/docsearch/hooks/useKeyboard.d.ts.map +1 -0
  32. package/dist/docsearch/hooks/useKeyboard.js +71 -0
  33. package/dist/docsearch/hooks/useSeekoraSearch.d.ts +27 -0
  34. package/dist/docsearch/hooks/useSeekoraSearch.d.ts.map +1 -0
  35. package/dist/docsearch/hooks/useSeekoraSearch.js +187 -0
  36. package/dist/docsearch/index.d.ts +13 -0
  37. package/dist/docsearch/index.d.ts.map +1 -0
  38. package/dist/docsearch/index.js +11 -0
  39. package/dist/docsearch/types.d.ts +170 -0
  40. package/dist/docsearch/types.d.ts.map +1 -0
  41. package/dist/docsearch/types.js +4 -0
  42. package/dist/docsearch.css +237 -0
  43. package/dist/hooks/useAnalytics.d.ts +8 -4
  44. package/dist/hooks/useAnalytics.d.ts.map +1 -1
  45. package/dist/hooks/useAnalytics.js +14 -9
  46. package/dist/hooks/useSuggestionsAnalytics.d.ts +3 -1
  47. package/dist/hooks/useSuggestionsAnalytics.d.ts.map +1 -1
  48. package/dist/hooks/useSuggestionsAnalytics.js +11 -9
  49. package/dist/index.d.ts +4 -0
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +11 -0
  52. package/dist/index.umd.js +1 -1
  53. package/dist/src/index.d.ts +258 -7
  54. package/dist/src/index.esm.js +1611 -79
  55. package/dist/src/index.esm.js.map +1 -1
  56. package/dist/src/index.js +1618 -78
  57. package/dist/src/index.js.map +1 -1
  58. package/package.json +8 -6
@@ -1 +1 @@
1
- {"version":3,"file":"SearchResults.d.ts","sourceRoot":"","sources":["../../src/components/SearchResults.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAC;AAKxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEnF,MAAM,WAAW,kBAAkB;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IAChC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;IACrB,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5D,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,OAAO,KAAK,KAAK,CAAC,SAAS,CAAC;IAC1F,WAAW,CAAC,EAAE,MAAM,KAAK,CAAC,SAAS,CAAC;IACpC,aAAa,CAAC,EAAE,MAAM,KAAK,CAAC,SAAS,CAAC;IACtC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,KAAK,CAAC,SAAS,CAAC;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,KAAK,CAAC,EAAE,kBAAkB,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,wDAAwD;IACxD,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,mEAAmE;IACnE,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,gFAAgF;IAChF,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,GAAG,EAAE,CAAC;IAC1C,+DAA+D;IAC/D,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,uCAAuC;IACvC,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAoBD,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA+oBtD,CAAC"}
1
+ {"version":3,"file":"SearchResults.d.ts","sourceRoot":"","sources":["../../src/components/SearchResults.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAC;AAKxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEnF,MAAM,WAAW,kBAAkB;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IAChC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;IACrB,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5D,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,OAAO,KAAK,KAAK,CAAC,SAAS,CAAC;IAC1F,WAAW,CAAC,EAAE,MAAM,KAAK,CAAC,SAAS,CAAC;IACpC,aAAa,CAAC,EAAE,MAAM,KAAK,CAAC,SAAS,CAAC;IACtC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,KAAK,CAAC,SAAS,CAAC;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,KAAK,CAAC,EAAE,kBAAkB,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,wDAAwD;IACxD,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,mEAAmE;IACnE,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,gFAAgF;IAChF,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,GAAG,EAAE,CAAC;IAC1C,+DAA+D;IAC/D,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,uCAAuC;IACvC,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAoBD,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAmmBtD,CAAC"}
@@ -102,38 +102,21 @@ export const SearchResults = ({ results: resultsProp, loading: loadingProp, erro
102
102
  const state = { currentPage, itemsPerPage: stateItemsPerPage };
103
103
  // Calculate absolute position (1-based) accounting for pagination
104
104
  const absolutePosition = (state.currentPage - 1) * state.itemsPerPage + index + 1;
105
- // Build search context from current state and response
106
- const searchContext = results?.context || (results ? {
107
- query: '', // Will be filled from state if needed
108
- page: state.currentPage,
109
- } : undefined);
110
- console.log('🔵 SearchResults: Tracking analytics event', {
111
- resultId: result.id,
112
- resultIndex: index,
113
- absolutePosition,
114
- currentPage: state.currentPage,
115
- itemsPerPage: state.itemsPerPage,
116
- hasContext: !!searchContext,
117
- });
118
- await client.trackEvent?.({
119
- event_name: 'product_click',
120
- clicked_item_id: result.id,
121
- metadata: {
122
- result: result,
123
- position: absolutePosition,
124
- },
125
- }, searchContext);
126
- console.log('🟢 SearchResults: Analytics event tracked successfully', {
127
- resultId: result.id,
128
- position: absolutePosition,
129
- });
105
+ const searchContext = results?.context;
106
+ if (client.trackClick) {
107
+ await client.trackClick(result.id, absolutePosition, searchContext);
108
+ }
109
+ else {
110
+ await client.trackEvent?.({
111
+ event_name: 'product_click',
112
+ clicked_item_id: result.id,
113
+ metadata: { result, position: absolutePosition },
114
+ }, searchContext);
115
+ }
130
116
  }
131
117
  catch (err) {
132
118
  const error = err instanceof Error ? err : new Error(String(err));
133
- console.error('SearchResults: Error tracking analytics event', {
134
- resultId: result.id,
135
- error: error.message,
136
- });
119
+ log.error('SearchResults: Error tracking click', { resultId: result.id, error: error.message });
137
120
  }
138
121
  }
139
122
  // Call user-provided callback
@@ -193,38 +176,21 @@ export const SearchResults = ({ results: resultsProp, loading: loadingProp, erro
193
176
  const state = { currentPage, itemsPerPage: stateItemsPerPage };
194
177
  // Calculate absolute position (1-based) accounting for pagination
195
178
  const absolutePosition = (state.currentPage - 1) * state.itemsPerPage + index + 1;
196
- // Build search context from current state and response
197
- const searchContext = results?.context || (results ? {
198
- query: '', // Will be filled from state if needed
199
- page: state.currentPage,
200
- } : undefined);
201
- console.log('🔵 SearchResults: Tracking analytics event', {
202
- resultId: result.id,
203
- resultIndex: index,
204
- absolutePosition,
205
- currentPage: state.currentPage,
206
- itemsPerPage: state.itemsPerPage,
207
- hasContext: !!searchContext,
208
- });
209
- await client.trackEvent?.({
210
- event_name: 'product_click',
211
- clicked_item_id: result.id,
212
- metadata: {
213
- result: result,
214
- position: absolutePosition,
215
- },
216
- }, searchContext);
217
- console.log('🟢 SearchResults: Analytics event tracked successfully', {
218
- resultId: result.id,
219
- position: absolutePosition,
220
- });
179
+ const searchContext = results?.context;
180
+ if (client.trackClick) {
181
+ await client.trackClick(result.id, absolutePosition, searchContext);
182
+ }
183
+ else {
184
+ await client.trackEvent?.({
185
+ event_name: 'product_click',
186
+ clicked_item_id: result.id,
187
+ metadata: { result, position: absolutePosition },
188
+ }, searchContext);
189
+ }
221
190
  }
222
191
  catch (err) {
223
192
  const error = err instanceof Error ? err : new Error(String(err));
224
- console.error('SearchResults: Error tracking analytics event', {
225
- resultId: result.id,
226
- error: error.message,
227
- });
193
+ log.error('SearchResults: Error tracking click', { resultId: result.id, error: error.message });
228
194
  }
229
195
  }
230
196
  // Call user-provided callback
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ import type { DocSearchProps } from '../types';
3
+ export declare function DocSearch({ storeId, storeSecret, seekoraApiEndpoint, apiEndpoint, apiKey, sources, placeholder, maxResults, debounceMs, onSelect, onClose, translations, renderButton, buttonComponent: ButtonComponent, initialOpen, disableShortcut, shortcutKey, }: DocSearchProps): React.JSX.Element;
4
+ //# sourceMappingURL=DocSearch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DocSearch.d.ts","sourceRoot":"","sources":["../../../src/docsearch/components/DocSearch.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAgC,MAAM,OAAO,CAAC;AASrD,OAAO,KAAK,EAAE,cAAc,EAAmD,MAAM,UAAU,CAAC;AAEhG,wBAAgB,SAAS,CAAC,EACxB,OAAO,EACP,WAAW,EACX,kBAAkB,EAClB,WAAW,EACX,MAAM,EACN,OAAO,EACP,WAAuC,EACvC,UAAe,EACf,UAAgB,EAChB,QAAQ,EACR,OAAO,EACP,YAAiB,EACjB,YAAmB,EACnB,eAAe,EAAE,eAAiC,EAClD,WAAmB,EACnB,eAAuB,EACvB,WAAiB,GAClB,EAAE,cAAc,qBA0HhB"}
@@ -0,0 +1,81 @@
1
+ import React, { useState, useCallback } from 'react';
2
+ import { Modal } from './Modal';
3
+ import { SearchBox } from './SearchBox';
4
+ import { Results } from './Results';
5
+ import { Footer } from './Footer';
6
+ import { DocSearchButton } from './DocSearchButton';
7
+ import { useDocSearch } from '../hooks/useDocSearch';
8
+ import { useSeekoraSearch } from '../hooks/useSeekoraSearch';
9
+ import { useKeyboard } from '../hooks/useKeyboard';
10
+ export function DocSearch({ storeId, storeSecret, seekoraApiEndpoint, apiEndpoint, apiKey, sources, placeholder = 'Search documentation...', maxResults = 10, debounceMs = 200, onSelect, onClose, translations = {}, renderButton = true, buttonComponent: ButtonComponent = DocSearchButton, initialOpen = false, disableShortcut = false, shortcutKey = 'k', }) {
11
+ const [isOpen, setIsOpen] = useState(initialOpen);
12
+ const useSeekoraSDK = !!storeId;
13
+ const seekoraSearch = useSeekoraSearch({
14
+ storeId: storeId || '',
15
+ storeSecret,
16
+ apiEndpoint: seekoraApiEndpoint,
17
+ maxResults,
18
+ debounceMs,
19
+ analyticsTags: ['docsearch'],
20
+ });
21
+ const legacySearch = useDocSearch({
22
+ apiEndpoint,
23
+ apiKey,
24
+ sources,
25
+ maxResults,
26
+ debounceMs,
27
+ });
28
+ const { query, suggestions, isLoading, error, selectedIndex, setQuery, selectNext, selectPrev, setSelectedIndex, reset, getSelectedItem, } = useSeekoraSDK ? seekoraSearch : legacySearch;
29
+ const groupedSuggestions = useSeekoraSDK ? undefined : legacySearch.groupedSuggestions;
30
+ const results = useSeekoraSDK ? suggestions : legacySearch.results;
31
+ const mode = useSeekoraSDK ? 'suggestions' : legacySearch.mode;
32
+ const searchSources = useSeekoraSDK
33
+ ? [{ id: 'seekora', name: 'Results', endpoint: '' }]
34
+ : legacySearch.sources;
35
+ const handleOpen = useCallback(() => setIsOpen(true), []);
36
+ const handleClose = useCallback(() => {
37
+ setIsOpen(false);
38
+ reset();
39
+ onClose?.();
40
+ }, [reset, onClose]);
41
+ const handleSelect = useCallback((hit) => {
42
+ if (useSeekoraSDK && seekoraSearch.trackDocClick) {
43
+ seekoraSearch.trackDocClick(hit, selectedIndex + 1);
44
+ }
45
+ if (onSelect) {
46
+ onSelect(hit);
47
+ }
48
+ else {
49
+ window.location.href = hit.url;
50
+ }
51
+ handleClose();
52
+ }, [onSelect, handleClose, useSeekoraSDK, seekoraSearch, selectedIndex]);
53
+ const handleEnter = useCallback(() => {
54
+ const selectedItem = getSelectedItem();
55
+ if (selectedItem)
56
+ handleSelect(selectedItem);
57
+ }, [getSelectedItem, handleSelect]);
58
+ const { handleModalKeyDown } = useKeyboard({
59
+ isOpen,
60
+ onOpen: handleOpen,
61
+ onClose: handleClose,
62
+ onSelectNext: selectNext,
63
+ onSelectPrev: selectPrev,
64
+ onEnter: handleEnter,
65
+ disableShortcut,
66
+ shortcutKey,
67
+ });
68
+ const handleKeyDown = useCallback((event) => handleModalKeyDown(event), [handleModalKeyDown]);
69
+ const displayHits = mode === 'results' ? results : suggestions;
70
+ return (React.createElement(React.Fragment, null,
71
+ renderButton && (React.createElement(ButtonComponent, { onClick: handleOpen, placeholder: translations.buttonText || placeholder })),
72
+ React.createElement(Modal, { isOpen: isOpen, onClose: handleClose },
73
+ React.createElement("div", { className: "seekora-docsearch-modal", onKeyDown: handleKeyDown },
74
+ React.createElement("header", { className: "seekora-docsearch-header" },
75
+ React.createElement(SearchBox, { value: query, onChange: setQuery, onKeyDown: handleKeyDown, placeholder: placeholder, isLoading: isLoading, onClear: reset }),
76
+ React.createElement("button", { type: "button", className: "seekora-docsearch-close", onClick: handleClose, "aria-label": "Close search" },
77
+ React.createElement("span", { className: "seekora-docsearch-close-text" }, "esc"))),
78
+ React.createElement("div", { className: "seekora-docsearch-body" },
79
+ React.createElement(Results, { hits: displayHits, groupedHits: groupedSuggestions, selectedIndex: selectedIndex, onSelect: handleSelect, onHover: setSelectedIndex, query: query, isLoading: isLoading, error: error, translations: translations, sources: searchSources })),
80
+ React.createElement(Footer, { translations: translations })))));
81
+ }
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ import type { DocSearchButtonProps } from '../types';
3
+ export declare function DocSearchButton({ onClick, placeholder }: DocSearchButtonProps): React.JSX.Element;
4
+ //# sourceMappingURL=DocSearchButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DocSearchButton.d.ts","sourceRoot":"","sources":["../../../src/docsearch/components/DocSearchButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAErD,wBAAgB,eAAe,CAAC,EAAE,OAAO,EAAE,WAAuC,EAAE,EAAE,oBAAoB,qBAezG"}
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import { getShortcutText } from '../hooks/useKeyboard';
3
+ export function DocSearchButton({ onClick, placeholder = 'Search documentation...' }) {
4
+ const shortcutText = getShortcutText('K');
5
+ return (React.createElement("button", { type: "button", className: "seekora-docsearch-button", onClick: onClick, "aria-label": "Search documentation" },
6
+ React.createElement("span", { className: "seekora-docsearch-button-icon" },
7
+ React.createElement("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true" },
8
+ React.createElement("path", { d: "M9 3.5a5.5 5.5 0 100 11 5.5 5.5 0 000-11zM2 9a7 7 0 1112.452 4.391l3.328 3.329a.75.75 0 11-1.06 1.06l-3.329-3.328A7 7 0 012 9z", fill: "currentColor" }))),
9
+ React.createElement("span", { className: "seekora-docsearch-button-placeholder" }, placeholder),
10
+ React.createElement("span", { className: "seekora-docsearch-button-keys" },
11
+ React.createElement("kbd", { className: "seekora-docsearch-button-key" }, shortcutText))));
12
+ }
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import type { DocSearchTranslations } from '../types';
3
+ interface FooterProps {
4
+ translations?: DocSearchTranslations;
5
+ }
6
+ export declare function Footer({ translations }: FooterProps): React.JSX.Element;
7
+ export {};
8
+ //# sourceMappingURL=Footer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Footer.d.ts","sourceRoot":"","sources":["../../../src/docsearch/components/Footer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAEtD,UAAU,WAAW;IACnB,YAAY,CAAC,EAAE,qBAAqB,CAAC;CACtC;AAED,wBAAgB,MAAM,CAAC,EAAE,YAAiB,EAAE,EAAE,WAAW,qBAkCxD"}
@@ -0,0 +1,23 @@
1
+ import React from 'react';
2
+ export function Footer({ translations = {} }) {
3
+ return (React.createElement("footer", { className: "seekora-docsearch-footer" },
4
+ React.createElement("div", { className: "seekora-docsearch-footer-commands" },
5
+ React.createElement("ul", { className: "seekora-docsearch-footer-commands-list" },
6
+ React.createElement("li", null,
7
+ React.createElement("span", { className: "seekora-docsearch-footer-command" },
8
+ React.createElement("kbd", { className: "seekora-docsearch-key" }, "\u21B5"),
9
+ React.createElement("span", null, "to select"))),
10
+ React.createElement("li", null,
11
+ React.createElement("span", { className: "seekora-docsearch-footer-command" },
12
+ React.createElement("kbd", { className: "seekora-docsearch-key" }, "\u2191"),
13
+ React.createElement("kbd", { className: "seekora-docsearch-key" }, "\u2193"),
14
+ React.createElement("span", null, "to navigate"))),
15
+ React.createElement("li", null,
16
+ React.createElement("span", { className: "seekora-docsearch-footer-command" },
17
+ React.createElement("kbd", { className: "seekora-docsearch-key" }, "esc"),
18
+ React.createElement("span", null, translations.closeText || 'to close'))))),
19
+ React.createElement("div", { className: "seekora-docsearch-footer-logo" },
20
+ React.createElement("span", { className: "seekora-docsearch-footer-logo-text" }, translations.searchByText || 'Search by'),
21
+ React.createElement("a", { href: "https://seekora.ai", target: "_blank", rel: "noopener noreferrer", className: "seekora-docsearch-footer-logo-link" },
22
+ React.createElement("span", { className: "seekora-docsearch-logo", style: { fontFamily: 'system-ui', fontSize: 14, fontWeight: 600 } }, "Seekora")))));
23
+ }
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ interface HighlightProps {
3
+ value: string;
4
+ highlightedValue?: string;
5
+ }
6
+ export declare function Highlight({ value, highlightedValue }: HighlightProps): React.JSX.Element;
7
+ export declare function truncateAroundMatch(content: string, maxLength?: number): string;
8
+ export {};
9
+ //# sourceMappingURL=Highlight.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Highlight.d.ts","sourceRoot":"","sources":["../../../src/docsearch/components/Highlight.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,UAAU,cAAc;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAkBD,wBAAgB,SAAS,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,EAAE,cAAc,qBAKpE;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,GAAE,MAAY,GAAG,MAAM,CAqBpF"}
@@ -0,0 +1,48 @@
1
+ import React from 'react';
2
+ function sanitizeHtml(html) {
3
+ const escaped = html
4
+ .replace(/&/g, '&')
5
+ .replace(/</g, '&lt;')
6
+ .replace(/>/g, '&gt;')
7
+ .replace(/"/g, '&quot;')
8
+ .replace(/'/g, '&#039;');
9
+ return escaped
10
+ .replace(/&lt;mark&gt;/g, '<mark>')
11
+ .replace(/&lt;\/mark&gt;/g, '</mark>')
12
+ .replace(/&lt;ais-highlight&gt;/g, '<mark>')
13
+ .replace(/&lt;\/ais-highlight&gt;/g, '</mark>')
14
+ .replace(/&lt;em&gt;/g, '<mark>')
15
+ .replace(/&lt;\/em&gt;/g, '</mark>');
16
+ }
17
+ export function Highlight({ value, highlightedValue }) {
18
+ if (!highlightedValue)
19
+ return React.createElement("span", null, value);
20
+ return (React.createElement("span", { className: "seekora-docsearch-highlight", dangerouslySetInnerHTML: { __html: sanitizeHtml(highlightedValue) } }));
21
+ }
22
+ export function truncateAroundMatch(content, maxLength = 150) {
23
+ const markIndex = content.indexOf('<mark>');
24
+ if (markIndex === -1 || content.length <= maxLength) {
25
+ if (content.length <= maxLength)
26
+ return content;
27
+ return content.slice(0, maxLength) + '...';
28
+ }
29
+ const halfLength = Math.floor(maxLength / 2);
30
+ let start = Math.max(0, markIndex - halfLength);
31
+ let end = Math.min(content.length, markIndex + halfLength);
32
+ if (start > 0) {
33
+ const spaceIndex = content.indexOf(' ', start);
34
+ if (spaceIndex !== -1 && spaceIndex < markIndex)
35
+ start = spaceIndex + 1;
36
+ }
37
+ if (end < content.length) {
38
+ const spaceIndex = content.lastIndexOf(' ', end);
39
+ if (spaceIndex !== -1 && spaceIndex > markIndex)
40
+ end = spaceIndex;
41
+ }
42
+ let result = content.slice(start, end);
43
+ if (start > 0)
44
+ result = '...' + result;
45
+ if (end < content.length)
46
+ result = result + '...';
47
+ return result;
48
+ }
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ import type { DocSearchHit, DocSearchSuggestion } from '../types';
3
+ interface HitProps {
4
+ hit: DocSearchHit | DocSearchSuggestion;
5
+ isSelected: boolean;
6
+ onClick: () => void;
7
+ onMouseEnter: () => void;
8
+ openInNewTab?: boolean;
9
+ isChild?: boolean;
10
+ isLastChild?: boolean;
11
+ hierarchyType?: string;
12
+ }
13
+ export declare function Hit({ hit, isSelected, onClick, onMouseEnter, openInNewTab, isChild, isLastChild, hierarchyType }: HitProps): React.JSX.Element;
14
+ export {};
15
+ //# sourceMappingURL=Hit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Hit.d.ts","sourceRoot":"","sources":["../../../src/docsearch/components/Hit.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAElE,UAAU,QAAQ;IAChB,GAAG,EAAE,YAAY,GAAG,mBAAmB,CAAC;IACxC,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,GAAG,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,EAAE,QAAQ,qBA2E1H"}
@@ -0,0 +1,96 @@
1
+ import React from 'react';
2
+ import { Highlight, truncateAroundMatch } from './Highlight';
3
+ export function Hit({ hit, isSelected, onClick, onMouseEnter, openInNewTab, isChild, isLastChild, hierarchyType }) {
4
+ const isFullHit = 'objectID' in hit;
5
+ const suggestion = hit;
6
+ const hitType = hierarchyType || suggestion.type;
7
+ const breadcrumb = suggestion.parentTitle
8
+ ? `${suggestion.category || ''} › ${suggestion.parentTitle}`.replace(/^› /, '')
9
+ : suggestion.category || '';
10
+ const title = getTitleForType(hit, hitType);
11
+ let highlightedTitle = title;
12
+ let highlightedContent = hit.content || suggestion.description || '';
13
+ if (isFullHit) {
14
+ const fullHit = hit;
15
+ if (fullHit._highlightResult) {
16
+ highlightedTitle = fullHit._highlightResult.title?.value || title;
17
+ highlightedContent = fullHit._highlightResult.content?.value || hit.content || '';
18
+ }
19
+ }
20
+ else {
21
+ if (suggestion.highlight) {
22
+ highlightedTitle = suggestion.highlight.title || title;
23
+ highlightedContent = suggestion.highlight.content || hit.content || suggestion.description || '';
24
+ }
25
+ }
26
+ const displayContent = highlightedContent ? truncateAroundMatch(highlightedContent, 120) : '';
27
+ const url = hit.url || suggestion.route || '#';
28
+ const classNames = ['seekora-docsearch-hit'];
29
+ if (isSelected)
30
+ classNames.push('seekora-docsearch-hit--selected');
31
+ if (isChild)
32
+ classNames.push('seekora-docsearch-hit--child');
33
+ if (isLastChild)
34
+ classNames.push('seekora-docsearch-hit--last-child');
35
+ return (React.createElement("a", { href: url, className: classNames.join(' '), onClick: (e) => { e.preventDefault(); onClick(); }, onMouseEnter: onMouseEnter, role: "option", "aria-selected": isSelected, target: openInNewTab ? '_blank' : undefined, rel: openInNewTab ? 'noopener noreferrer' : undefined },
36
+ isChild && (React.createElement("div", { className: "seekora-docsearch-hit-tree" },
37
+ React.createElement(TreeConnector, { isLast: isLastChild }))),
38
+ React.createElement("div", { className: "seekora-docsearch-hit-icon" },
39
+ React.createElement(HitIcon, { type: getHitTypeFromLevel(hitType) })),
40
+ React.createElement("div", { className: "seekora-docsearch-hit-content" },
41
+ !isChild && breadcrumb && React.createElement("span", { className: "seekora-docsearch-hit-breadcrumb" }, breadcrumb),
42
+ React.createElement("span", { className: "seekora-docsearch-hit-title" },
43
+ React.createElement(Highlight, { value: title, highlightedValue: highlightedTitle })),
44
+ displayContent && (React.createElement("span", { className: "seekora-docsearch-hit-description" },
45
+ React.createElement(Highlight, { value: hit.content || '', highlightedValue: displayContent })))),
46
+ React.createElement("div", { className: "seekora-docsearch-hit-action" }, openInNewTab ? (React.createElement("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true" },
47
+ React.createElement("path", { d: "M6 3H3v10h10v-3M9 3h4v4M14 2L7 9", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }))) : (React.createElement("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true" },
48
+ React.createElement("path", { d: "M6.75 3.25L11.5 8L6.75 12.75", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }))))));
49
+ }
50
+ function getTitleForType(hit, type) {
51
+ const hierarchy = hit.hierarchy || {};
52
+ if (!type)
53
+ return hit.title || hierarchy.lvl1 || hierarchy.lvl0 || 'Untitled';
54
+ const match = type.match(/^lvl(\d+)$/);
55
+ if (match) {
56
+ const level = parseInt(match[1], 10);
57
+ const levelKey = `lvl${level}`;
58
+ const levelTitle = hierarchy[levelKey];
59
+ if (levelTitle)
60
+ return levelTitle;
61
+ }
62
+ return hit.title || hierarchy.lvl1 || hierarchy.lvl0 || 'Untitled';
63
+ }
64
+ function getHitTypeFromLevel(type) {
65
+ if (!type)
66
+ return 'page';
67
+ const match = type.match(/^lvl(\d+)$/);
68
+ if (match) {
69
+ const level = parseInt(match[1], 10);
70
+ if (level === 1)
71
+ return 'page';
72
+ if (level <= 3)
73
+ return 'section';
74
+ return 'content';
75
+ }
76
+ return 'page';
77
+ }
78
+ function HitIcon({ type }) {
79
+ switch (type) {
80
+ case 'page':
81
+ return (React.createElement("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", "aria-hidden": "true" },
82
+ React.createElement("path", { d: "M4.5 3.5h11a1 1 0 011 1v11a1 1 0 01-1 1h-11a1 1 0 01-1-1v-11a1 1 0 011-1z", stroke: "currentColor", strokeWidth: "1.5", fill: "none" }),
83
+ React.createElement("path", { d: "M7 7h6M7 10h6M7 13h4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })));
84
+ case 'section':
85
+ return (React.createElement("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", "aria-hidden": "true" },
86
+ React.createElement("path", { d: "M4 5.5h12M4 10h12M4 14.5h8", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })));
87
+ case 'content':
88
+ return (React.createElement("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", "aria-hidden": "true" },
89
+ React.createElement("path", { d: "M4 6h12M4 10h8M4 14h10", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })));
90
+ }
91
+ }
92
+ function TreeConnector({ isLast }) {
93
+ return (React.createElement("svg", { width: "16", height: "20", viewBox: "0 0 16 20", fill: "none", "aria-hidden": "true", className: "seekora-docsearch-hit-tree-icon" }, isLast ? (React.createElement("path", { d: "M8 0V10H14", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })) : (React.createElement(React.Fragment, null,
94
+ React.createElement("path", { d: "M8 0V20", stroke: "currentColor", strokeWidth: "1.5" }),
95
+ React.createElement("path", { d: "M8 10H14", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })))));
96
+ }
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ interface ModalProps {
3
+ isOpen: boolean;
4
+ onClose: () => void;
5
+ children: React.ReactNode;
6
+ }
7
+ export declare function Modal({ isOpen, onClose, children }: ModalProps): React.ReactPortal | null;
8
+ export {};
9
+ //# sourceMappingURL=Modal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Modal.d.ts","sourceRoot":"","sources":["../../../src/docsearch/components/Modal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,OAAO,CAAC;AAGjD,UAAU,UAAU;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,wBAAgB,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,UAAU,4BAoD9D"}
@@ -0,0 +1,54 @@
1
+ import React, { useEffect, useRef } from 'react';
2
+ import { createPortal } from 'react-dom';
3
+ export function Modal({ isOpen, onClose, children }) {
4
+ const overlayRef = useRef(null);
5
+ const containerRef = useRef(null);
6
+ useEffect(() => {
7
+ const handleClickOutside = (event) => {
8
+ if (containerRef.current && !containerRef.current.contains(event.target)) {
9
+ onClose();
10
+ }
11
+ };
12
+ if (isOpen)
13
+ document.addEventListener('mousedown', handleClickOutside);
14
+ return () => document.removeEventListener('mousedown', handleClickOutside);
15
+ }, [isOpen, onClose]);
16
+ useEffect(() => {
17
+ if (isOpen) {
18
+ const originalOverflow = document.body.style.overflow;
19
+ document.body.style.overflow = 'hidden';
20
+ return () => { document.body.style.overflow = originalOverflow; };
21
+ }
22
+ }, [isOpen]);
23
+ useEffect(() => {
24
+ if (!isOpen || !containerRef.current)
25
+ return;
26
+ const container = containerRef.current;
27
+ const focusableElements = container.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
28
+ const firstElement = focusableElements[0];
29
+ const lastElement = focusableElements[focusableElements.length - 1];
30
+ const handleTabKey = (e) => {
31
+ if (e.key !== 'Tab')
32
+ return;
33
+ if (e.shiftKey) {
34
+ if (document.activeElement === firstElement) {
35
+ e.preventDefault();
36
+ lastElement?.focus();
37
+ }
38
+ }
39
+ else {
40
+ if (document.activeElement === lastElement) {
41
+ e.preventDefault();
42
+ firstElement?.focus();
43
+ }
44
+ }
45
+ };
46
+ container.addEventListener('keydown', handleTabKey);
47
+ return () => container.removeEventListener('keydown', handleTabKey);
48
+ }, [isOpen]);
49
+ if (!isOpen || typeof document === 'undefined')
50
+ return null;
51
+ const modalContent = (React.createElement("div", { ref: overlayRef, className: "seekora-docsearch-overlay", role: "dialog", "aria-modal": "true", "aria-label": "Search documentation" },
52
+ React.createElement("div", { ref: containerRef, className: "seekora-docsearch-container" }, children)));
53
+ return createPortal(modalContent, document.body);
54
+ }
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ import type { DocSearchHit, DocSearchSuggestion, DocSearchTranslations, SearchSource } from '../types';
3
+ interface GroupedHits {
4
+ source: SearchSource;
5
+ items: DocSearchSuggestion[];
6
+ }
7
+ interface ResultsProps {
8
+ hits: (DocSearchHit | DocSearchSuggestion)[];
9
+ groupedHits?: GroupedHits[];
10
+ selectedIndex: number;
11
+ onSelect: (hit: DocSearchHit | DocSearchSuggestion) => void;
12
+ onHover: (index: number) => void;
13
+ query: string;
14
+ isLoading: boolean;
15
+ error: string | null;
16
+ translations?: DocSearchTranslations;
17
+ sources?: SearchSource[];
18
+ }
19
+ export declare function Results({ hits, groupedHits, selectedIndex, onSelect, onHover, query, isLoading, error, translations, sources: _sources, }: ResultsProps): React.JSX.Element;
20
+ export {};
21
+ //# sourceMappingURL=Results.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Results.d.ts","sourceRoot":"","sources":["../../../src/docsearch/components/Results.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,OAAO,CAAC;AAEjD,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAEvG,UAAU,WAAW;IACnB,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,mBAAmB,EAAE,CAAC;CAC9B;AAED,UAAU,YAAY;IACpB,IAAI,EAAE,CAAC,YAAY,GAAG,mBAAmB,CAAC,EAAE,CAAC;IAC7C,WAAW,CAAC,EAAE,WAAW,EAAE,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,CAAC,GAAG,EAAE,YAAY,GAAG,mBAAmB,KAAK,IAAI,CAAC;IAC5D,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,YAAY,CAAC,EAAE,qBAAqB,CAAC;IACrC,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;CAC1B;AAmED,wBAAgB,OAAO,CAAC,EACtB,IAAI,EACJ,WAAW,EACX,aAAa,EACb,QAAQ,EACR,OAAO,EACP,KAAK,EACL,SAAS,EACT,KAAK,EACL,YAAiB,EACjB,OAAO,EAAE,QAAa,GACvB,EAAE,YAAY,qBAqFd"}