@embedpdf/plugin-search 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.
@@ -0,0 +1,225 @@
1
+ import { BasePluginConfig, EventHook, Action, BasePlugin, PluginRegistry, PluginManifest, PluginPackage } from '@embedpdf/core';
2
+ import { MatchFlag, SearchAllPagesResult, SearchResult, PdfEngine } from '@embedpdf/models';
3
+
4
+ interface SearchPluginConfig extends BasePluginConfig {
5
+ flags?: MatchFlag[];
6
+ /**
7
+ * Whether to show all search results or only the active one
8
+ * @default true
9
+ */
10
+ showAllResults?: boolean;
11
+ }
12
+ interface SearchResultState {
13
+ /**
14
+ * Current search results from last search operation
15
+ */
16
+ results: SearchResult[];
17
+ /**
18
+ * Current active result index (0-based)
19
+ */
20
+ activeResultIndex: number;
21
+ /**
22
+ * Whether to show all search results or only the active one
23
+ */
24
+ showAllResults: boolean;
25
+ /**
26
+ * Whether search is currently active
27
+ */
28
+ active: boolean;
29
+ }
30
+ interface SearchState {
31
+ flags: MatchFlag[];
32
+ /**
33
+ * Current search results from last search operation
34
+ */
35
+ results: SearchResult[];
36
+ /**
37
+ * Total number of search results
38
+ */
39
+ total: number;
40
+ /**
41
+ * Current active result index (0-based)
42
+ */
43
+ activeResultIndex: number;
44
+ /**
45
+ * Whether to show all search results or only the active one
46
+ */
47
+ showAllResults: boolean;
48
+ /**
49
+ * Current search query
50
+ */
51
+ query: string;
52
+ /**
53
+ * Whether a search operation is in progress
54
+ */
55
+ loading: boolean;
56
+ /**
57
+ * Whether search is currently active
58
+ */
59
+ active: boolean;
60
+ }
61
+ interface SearchCapability {
62
+ /**
63
+ * Start a search session
64
+ */
65
+ startSearch: () => void;
66
+ /**
67
+ * Stop the active search session
68
+ */
69
+ stopSearch: () => void;
70
+ /**
71
+ * Search for all occurrences of the keyword throughout the document
72
+ * @param keyword - Text to search for
73
+ * @returns Promise that resolves to all search results or empty result if none found
74
+ */
75
+ searchAllPages: (keyword: string) => Promise<SearchAllPagesResult>;
76
+ /**
77
+ * Navigate to the next search result
78
+ * @returns The new active result index
79
+ */
80
+ nextResult: () => number;
81
+ /**
82
+ * Navigate to the previous search result
83
+ * @returns The new active result index
84
+ */
85
+ previousResult: () => number;
86
+ /**
87
+ * Go to a specific search result by index
88
+ * @param index - The index of the result to go to
89
+ * @returns The new active result index
90
+ */
91
+ goToResult: (index: number) => number;
92
+ /**
93
+ * Toggle visibility of all search results
94
+ * @param showAll - Whether to show all results or only the active one
95
+ */
96
+ setShowAllResults: (showAll: boolean) => void;
97
+ /**
98
+ * Get current state of search results visibility
99
+ * @returns Whether all results are visible
100
+ */
101
+ getShowAllResults: () => boolean;
102
+ /**
103
+ * Subscribe to search results
104
+ * @param handler - Handler function to receive search results
105
+ * @returns Function to unsubscribe the handler
106
+ */
107
+ onSearchResult: EventHook<SearchAllPagesResult>;
108
+ /**
109
+ * Subscribe to search session start events
110
+ * @param handler - Handler function called when search session starts
111
+ * @returns Function to unsubscribe the handler
112
+ */
113
+ onSearchStart: EventHook;
114
+ /**
115
+ * Subscribe to search session stop events
116
+ * @param handler - Handler function called when search session stops
117
+ * @returns Function to unsubscribe the handler
118
+ */
119
+ onSearchStop: EventHook;
120
+ /**
121
+ * Subscribe to active result change events
122
+ * @param handler - Handler function called when active result changes
123
+ * @returns Function to unsubscribe the handler
124
+ */
125
+ onActiveResultChange: EventHook<number>;
126
+ /**
127
+ * Subscribe to search result state change events
128
+ * @param handler - Handler function called when search state changes
129
+ * @returns Function to unsubscribe the handler
130
+ */
131
+ onSearchResultStateChange: EventHook<SearchResultState>;
132
+ /**
133
+ * Get the current search flags
134
+ * @returns Array of active search flags
135
+ */
136
+ getFlags: () => MatchFlag[];
137
+ /**
138
+ * Set the search flags
139
+ * @param flags - Array of search flags to use
140
+ */
141
+ setFlags: (flags: MatchFlag[]) => void;
142
+ /**
143
+ * Subscribe to state change events
144
+ * @param handler - Handler function called when state changes
145
+ * @returns Function to unsubscribe the handler
146
+ */
147
+ onStateChange: (handler: (state: SearchState) => void) => () => void;
148
+ }
149
+
150
+ declare const START_SEARCH_SESSION = "START_SEARCH_SESSION";
151
+ declare const STOP_SEARCH_SESSION = "STOP_SEARCH_SESSION";
152
+ declare const SET_SEARCH_FLAGS = "SET_SEARCH_FLAGS";
153
+ declare const SET_SHOW_ALL_RESULTS = "SET_SHOW_ALL_RESULTS";
154
+ declare const START_SEARCH = "START_SEARCH";
155
+ declare const SET_SEARCH_RESULTS = "SET_SEARCH_RESULTS";
156
+ declare const SET_ACTIVE_RESULT_INDEX = "SET_ACTIVE_RESULT_INDEX";
157
+ interface StartSearchSessionAction extends Action {
158
+ type: typeof START_SEARCH_SESSION;
159
+ }
160
+ interface StopSearchSessionAction extends Action {
161
+ type: typeof STOP_SEARCH_SESSION;
162
+ }
163
+ interface SetSearchFlagsAction extends Action {
164
+ type: typeof SET_SEARCH_FLAGS;
165
+ payload: MatchFlag[];
166
+ }
167
+ interface SetShowAllResultsAction extends Action {
168
+ type: typeof SET_SHOW_ALL_RESULTS;
169
+ payload: boolean;
170
+ }
171
+ interface StartSearchAction extends Action {
172
+ type: typeof START_SEARCH;
173
+ payload: string;
174
+ }
175
+ interface SetSearchResultsAction extends Action {
176
+ type: typeof SET_SEARCH_RESULTS;
177
+ payload: {
178
+ results: SearchResult[];
179
+ total: number;
180
+ activeResultIndex: number;
181
+ };
182
+ }
183
+ interface SetActiveResultIndexAction extends Action {
184
+ type: typeof SET_ACTIVE_RESULT_INDEX;
185
+ payload: number;
186
+ }
187
+ type SearchAction = StartSearchSessionAction | StopSearchSessionAction | SetSearchFlagsAction | SetShowAllResultsAction | StartSearchAction | SetSearchResultsAction | SetActiveResultIndexAction;
188
+
189
+ declare class SearchPlugin extends BasePlugin<SearchPluginConfig, SearchCapability, SearchState, SearchAction> {
190
+ static readonly id: "search";
191
+ private loader;
192
+ private currentDocument?;
193
+ private engine;
194
+ private readonly searchStop$;
195
+ private readonly searchStart$;
196
+ private readonly searchResult$;
197
+ private readonly searchActiveResultChange$;
198
+ private readonly searchResultState$;
199
+ constructor(id: string, registry: PluginRegistry, engine: PdfEngine);
200
+ private handleDocumentLoaded;
201
+ private handleLoaderEvent;
202
+ initialize(config: SearchPluginConfig): Promise<void>;
203
+ onStoreUpdated(_prevState: SearchState, newState: SearchState): void;
204
+ protected buildCapability(): SearchCapability;
205
+ private setFlags;
206
+ private notifySearchStart;
207
+ private notifySearchStop;
208
+ private notifyActiveResultChange;
209
+ private startSearchSession;
210
+ private stopSearchSession;
211
+ private searchAllPages;
212
+ private nextResult;
213
+ private previousResult;
214
+ private goToResult;
215
+ destroy(): Promise<void>;
216
+ }
217
+
218
+ declare const initialState: SearchState;
219
+
220
+ declare const SEARCH_PLUGIN_ID = "search";
221
+ declare const manifest: PluginManifest<SearchPluginConfig>;
222
+
223
+ declare const SearchPluginPackage: PluginPackage<SearchPlugin, SearchPluginConfig, SearchState, SearchAction>;
224
+
225
+ export { SEARCH_PLUGIN_ID, type SearchCapability, SearchPlugin, type SearchPluginConfig, SearchPluginPackage, type SearchResultState, type SearchState, initialState, manifest };
package/dist/index.js ADDED
@@ -0,0 +1,279 @@
1
+ // src/lib/search-plugin.ts
2
+ import { BasePlugin, createBehaviorEmitter } from "@embedpdf/core";
3
+
4
+ // src/lib/actions.ts
5
+ var START_SEARCH_SESSION = "START_SEARCH_SESSION";
6
+ var STOP_SEARCH_SESSION = "STOP_SEARCH_SESSION";
7
+ var SET_SEARCH_FLAGS = "SET_SEARCH_FLAGS";
8
+ var SET_SHOW_ALL_RESULTS = "SET_SHOW_ALL_RESULTS";
9
+ var START_SEARCH = "START_SEARCH";
10
+ var SET_SEARCH_RESULTS = "SET_SEARCH_RESULTS";
11
+ var SET_ACTIVE_RESULT_INDEX = "SET_ACTIVE_RESULT_INDEX";
12
+ function startSearchSession() {
13
+ return { type: START_SEARCH_SESSION };
14
+ }
15
+ function stopSearchSession() {
16
+ return { type: STOP_SEARCH_SESSION };
17
+ }
18
+ function setSearchFlags(flags) {
19
+ return { type: SET_SEARCH_FLAGS, payload: flags };
20
+ }
21
+ function setShowAllResults(showAll) {
22
+ return { type: SET_SHOW_ALL_RESULTS, payload: showAll };
23
+ }
24
+ function startSearch(query) {
25
+ return { type: START_SEARCH, payload: query };
26
+ }
27
+ function setSearchResults(results, total, activeResultIndex) {
28
+ return { type: SET_SEARCH_RESULTS, payload: { results, total, activeResultIndex } };
29
+ }
30
+ function setActiveResultIndex(index) {
31
+ return { type: SET_ACTIVE_RESULT_INDEX, payload: index };
32
+ }
33
+
34
+ // src/lib/search-plugin.ts
35
+ var SearchPlugin = class extends BasePlugin {
36
+ constructor(id, registry, engine) {
37
+ super(id, registry);
38
+ this.searchStop$ = createBehaviorEmitter();
39
+ this.searchStart$ = createBehaviorEmitter();
40
+ this.searchResult$ = createBehaviorEmitter();
41
+ this.searchActiveResultChange$ = createBehaviorEmitter();
42
+ this.searchResultState$ = createBehaviorEmitter();
43
+ this.engine = engine;
44
+ this.loader = this.registry.getPlugin("loader").provides();
45
+ this.loader.onDocumentLoaded(this.handleDocumentLoaded.bind(this));
46
+ this.loader.onLoaderEvent(this.handleLoaderEvent.bind(this));
47
+ }
48
+ handleDocumentLoaded(doc) {
49
+ this.currentDocument = doc;
50
+ if (this.getState().active) {
51
+ this.startSearchSession();
52
+ }
53
+ }
54
+ handleLoaderEvent(event) {
55
+ if (event.type === "error" || event.type === "start" && this.currentDocument) {
56
+ if (this.getState().active) {
57
+ this.stopSearchSession();
58
+ }
59
+ this.currentDocument = void 0;
60
+ }
61
+ }
62
+ async initialize(config) {
63
+ this.dispatch(setSearchFlags(config.flags || []));
64
+ this.dispatch(
65
+ setShowAllResults(config.showAllResults !== void 0 ? config.showAllResults : true)
66
+ );
67
+ }
68
+ onStoreUpdated(_prevState, newState) {
69
+ this.searchResultState$.emit({
70
+ results: newState.results,
71
+ activeResultIndex: newState.activeResultIndex,
72
+ showAllResults: newState.showAllResults,
73
+ active: newState.active
74
+ });
75
+ }
76
+ buildCapability() {
77
+ return {
78
+ startSearch: this.startSearchSession.bind(this),
79
+ stopSearch: this.stopSearchSession.bind(this),
80
+ searchAllPages: this.searchAllPages.bind(this),
81
+ nextResult: this.nextResult.bind(this),
82
+ previousResult: this.previousResult.bind(this),
83
+ goToResult: this.goToResult.bind(this),
84
+ setShowAllResults: (showAll) => this.dispatch(setShowAllResults(showAll)),
85
+ getShowAllResults: () => this.getState().showAllResults,
86
+ onSearchResult: this.searchResult$.on,
87
+ onSearchStart: this.searchStart$.on,
88
+ onSearchStop: this.searchStop$.on,
89
+ onActiveResultChange: this.searchActiveResultChange$.on,
90
+ onSearchResultStateChange: this.searchResultState$.on,
91
+ onStateChange: (handler) => {
92
+ const unsubscribe = this.subscribe((_, state) => handler(state));
93
+ return unsubscribe;
94
+ },
95
+ getFlags: () => this.getState().flags,
96
+ setFlags: (flags) => this.setFlags(flags)
97
+ };
98
+ }
99
+ setFlags(flags) {
100
+ const state = this.getState();
101
+ this.dispatch(setSearchFlags(flags));
102
+ if (state.active) {
103
+ this.searchAllPages(state.query, true);
104
+ }
105
+ }
106
+ notifySearchStart() {
107
+ this.searchStart$.emit();
108
+ }
109
+ notifySearchStop() {
110
+ this.searchStop$.emit();
111
+ }
112
+ notifyActiveResultChange(index) {
113
+ this.searchActiveResultChange$.emit(index);
114
+ }
115
+ startSearchSession() {
116
+ if (!this.currentDocument) {
117
+ return;
118
+ }
119
+ this.dispatch(startSearchSession());
120
+ this.notifySearchStart();
121
+ }
122
+ stopSearchSession() {
123
+ if (!this.currentDocument || !this.getState().active) {
124
+ return;
125
+ }
126
+ this.dispatch(stopSearchSession());
127
+ this.notifySearchStop();
128
+ }
129
+ async searchAllPages(keyword, force = false) {
130
+ const trimmedKeyword = keyword.trim();
131
+ const state = this.getState();
132
+ if (state.query === trimmedKeyword && !force) {
133
+ return { results: state.results, total: state.total };
134
+ }
135
+ this.dispatch(startSearch(trimmedKeyword));
136
+ if (!trimmedKeyword) {
137
+ this.dispatch(setSearchResults([], 0, -1));
138
+ return { results: [], total: 0 };
139
+ }
140
+ if (!this.currentDocument) {
141
+ this.dispatch(setSearchResults([], 0, -1));
142
+ return { results: [], total: 0 };
143
+ }
144
+ if (!state.active) {
145
+ this.startSearchSession();
146
+ }
147
+ return new Promise((resolve) => {
148
+ this.engine.searchAllPages(this.currentDocument, trimmedKeyword, state.flags).wait(
149
+ (results) => {
150
+ const activeResultIndex = results.total > 0 ? 0 : -1;
151
+ this.dispatch(setSearchResults(results.results, results.total, activeResultIndex));
152
+ this.searchResult$.emit(results);
153
+ if (results.total > 0) {
154
+ this.notifyActiveResultChange(0);
155
+ }
156
+ resolve(results);
157
+ },
158
+ (error) => {
159
+ console.error("Error during search:", error);
160
+ this.dispatch(setSearchResults([], 0, -1));
161
+ resolve({ results: [], total: 0 });
162
+ }
163
+ );
164
+ });
165
+ }
166
+ nextResult() {
167
+ const state = this.getState();
168
+ if (state.results.length === 0) {
169
+ return -1;
170
+ }
171
+ const nextIndex = state.activeResultIndex >= state.results.length - 1 ? 0 : state.activeResultIndex + 1;
172
+ return this.goToResult(nextIndex);
173
+ }
174
+ previousResult() {
175
+ const state = this.getState();
176
+ if (state.results.length === 0) {
177
+ return -1;
178
+ }
179
+ const prevIndex = state.activeResultIndex <= 0 ? state.results.length - 1 : state.activeResultIndex - 1;
180
+ return this.goToResult(prevIndex);
181
+ }
182
+ goToResult(index) {
183
+ const state = this.getState();
184
+ if (state.results.length === 0 || index < 0 || index >= state.results.length) {
185
+ return -1;
186
+ }
187
+ this.dispatch(setActiveResultIndex(index));
188
+ this.notifyActiveResultChange(index);
189
+ return index;
190
+ }
191
+ async destroy() {
192
+ if (this.getState().active && this.currentDocument) {
193
+ this.stopSearchSession();
194
+ }
195
+ this.searchResult$.clear();
196
+ this.searchStart$.clear();
197
+ this.searchStop$.clear();
198
+ this.searchActiveResultChange$.clear();
199
+ this.searchResultState$.clear();
200
+ }
201
+ };
202
+ SearchPlugin.id = "search";
203
+
204
+ // src/lib/manifest.ts
205
+ var SEARCH_PLUGIN_ID = "search";
206
+ var manifest = {
207
+ id: SEARCH_PLUGIN_ID,
208
+ name: "Search Plugin",
209
+ version: "1.0.0",
210
+ provides: ["search"],
211
+ requires: ["loader"],
212
+ optional: [],
213
+ defaultConfig: {
214
+ enabled: true,
215
+ flags: []
216
+ }
217
+ };
218
+
219
+ // src/lib/reducer.ts
220
+ var initialState = {
221
+ flags: [],
222
+ results: [],
223
+ total: 0,
224
+ activeResultIndex: -1,
225
+ showAllResults: true,
226
+ query: "",
227
+ loading: false,
228
+ active: false
229
+ };
230
+ var searchReducer = (state = initialState, action) => {
231
+ switch (action.type) {
232
+ case START_SEARCH_SESSION:
233
+ return { ...state, active: true };
234
+ case STOP_SEARCH_SESSION:
235
+ return {
236
+ ...state,
237
+ results: [],
238
+ total: 0,
239
+ activeResultIndex: -1,
240
+ query: "",
241
+ loading: false,
242
+ active: false
243
+ };
244
+ case SET_SEARCH_FLAGS:
245
+ return { ...state, flags: action.payload };
246
+ case SET_SHOW_ALL_RESULTS:
247
+ return { ...state, showAllResults: action.payload };
248
+ case START_SEARCH:
249
+ return { ...state, loading: true, query: action.payload };
250
+ case SET_SEARCH_RESULTS:
251
+ return {
252
+ ...state,
253
+ results: action.payload.results,
254
+ total: action.payload.total,
255
+ activeResultIndex: action.payload.activeResultIndex,
256
+ loading: false
257
+ };
258
+ case SET_ACTIVE_RESULT_INDEX:
259
+ return { ...state, activeResultIndex: action.payload };
260
+ default:
261
+ return state;
262
+ }
263
+ };
264
+
265
+ // src/lib/index.ts
266
+ var SearchPluginPackage = {
267
+ manifest,
268
+ create: (registry, engine) => new SearchPlugin(SEARCH_PLUGIN_ID, registry, engine),
269
+ reducer: searchReducer,
270
+ initialState
271
+ };
272
+ export {
273
+ SEARCH_PLUGIN_ID,
274
+ SearchPlugin,
275
+ SearchPluginPackage,
276
+ initialState,
277
+ manifest
278
+ };
279
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/search-plugin.ts","../src/lib/actions.ts","../src/lib/manifest.ts","../src/lib/reducer.ts","../src/lib/index.ts"],"sourcesContent":["import { BasePlugin, createBehaviorEmitter, PluginRegistry } from '@embedpdf/core';\nimport {\n MatchFlag,\n PdfDocumentObject,\n SearchAllPagesResult,\n TaskError,\n PdfEngine,\n} from '@embedpdf/models';\nimport { SearchPluginConfig, SearchCapability, SearchState, SearchResultState } from './types';\nimport { LoaderCapability, LoaderEvent, LoaderPlugin } from '@embedpdf/plugin-loader';\nimport {\n startSearchSession,\n stopSearchSession,\n setSearchFlags,\n setShowAllResults,\n startSearch,\n setSearchResults,\n setActiveResultIndex,\n SearchAction,\n} from './actions';\n\nexport class SearchPlugin extends BasePlugin<\n SearchPluginConfig,\n SearchCapability,\n SearchState,\n SearchAction\n> {\n static readonly id = 'search' as const;\n private loader: LoaderCapability;\n private currentDocument?: PdfDocumentObject;\n private engine: PdfEngine;\n\n private readonly searchStop$ = createBehaviorEmitter();\n private readonly searchStart$ = createBehaviorEmitter();\n private readonly searchResult$ = createBehaviorEmitter<SearchAllPagesResult>();\n private readonly searchActiveResultChange$ = createBehaviorEmitter<number>();\n private readonly searchResultState$ = createBehaviorEmitter<SearchResultState>();\n\n constructor(id: string, registry: PluginRegistry, engine: PdfEngine) {\n super(id, registry);\n this.engine = engine;\n this.loader = this.registry.getPlugin<LoaderPlugin>('loader')!.provides();\n\n this.loader.onDocumentLoaded(this.handleDocumentLoaded.bind(this));\n this.loader.onLoaderEvent(this.handleLoaderEvent.bind(this));\n }\n\n private handleDocumentLoaded(doc: PdfDocumentObject): void {\n this.currentDocument = doc;\n if (this.getState().active) {\n this.startSearchSession();\n }\n }\n\n private handleLoaderEvent(event: LoaderEvent): void {\n if (event.type === 'error' || (event.type === 'start' && this.currentDocument)) {\n if (this.getState().active) {\n this.stopSearchSession();\n }\n this.currentDocument = undefined;\n }\n }\n\n async initialize(config: SearchPluginConfig): Promise<void> {\n this.dispatch(setSearchFlags(config.flags || []));\n this.dispatch(\n setShowAllResults(config.showAllResults !== undefined ? config.showAllResults : true),\n );\n }\n\n override onStoreUpdated(_prevState: SearchState, newState: SearchState): void {\n this.searchResultState$.emit({\n results: newState.results,\n activeResultIndex: newState.activeResultIndex,\n showAllResults: newState.showAllResults,\n active: newState.active,\n });\n }\n\n protected buildCapability(): SearchCapability {\n return {\n startSearch: this.startSearchSession.bind(this),\n stopSearch: this.stopSearchSession.bind(this),\n searchAllPages: this.searchAllPages.bind(this),\n nextResult: this.nextResult.bind(this),\n previousResult: this.previousResult.bind(this),\n goToResult: this.goToResult.bind(this),\n setShowAllResults: (showAll) => this.dispatch(setShowAllResults(showAll)),\n getShowAllResults: () => this.getState().showAllResults,\n onSearchResult: this.searchResult$.on,\n onSearchStart: this.searchStart$.on,\n onSearchStop: this.searchStop$.on,\n onActiveResultChange: this.searchActiveResultChange$.on,\n onSearchResultStateChange: this.searchResultState$.on,\n onStateChange: (handler) => {\n const unsubscribe = this.subscribe((_, state) => handler(state));\n return unsubscribe;\n },\n getFlags: () => this.getState().flags,\n setFlags: (flags) => this.setFlags(flags),\n };\n }\n\n private setFlags(flags: MatchFlag[]): void {\n const state = this.getState();\n this.dispatch(setSearchFlags(flags));\n if (state.active) {\n this.searchAllPages(state.query, true);\n }\n }\n\n private notifySearchStart(): void {\n this.searchStart$.emit();\n }\n\n private notifySearchStop(): void {\n this.searchStop$.emit();\n }\n\n private notifyActiveResultChange(index: number): void {\n this.searchActiveResultChange$.emit(index);\n }\n\n private startSearchSession(): void {\n if (!this.currentDocument) {\n return;\n }\n this.dispatch(startSearchSession());\n this.notifySearchStart();\n }\n\n private stopSearchSession(): void {\n if (!this.currentDocument || !this.getState().active) {\n return;\n }\n this.dispatch(stopSearchSession());\n this.notifySearchStop();\n }\n\n private async searchAllPages(\n keyword: string,\n force: boolean = false,\n ): Promise<SearchAllPagesResult> {\n const trimmedKeyword = keyword.trim();\n const state = this.getState();\n\n if (state.query === trimmedKeyword && !force) {\n return { results: state.results, total: state.total };\n }\n\n this.dispatch(startSearch(trimmedKeyword));\n\n if (!trimmedKeyword) {\n this.dispatch(setSearchResults([], 0, -1));\n return { results: [], total: 0 };\n }\n if (!this.currentDocument) {\n this.dispatch(setSearchResults([], 0, -1));\n return { results: [], total: 0 };\n }\n\n if (!state.active) {\n this.startSearchSession();\n }\n\n return new Promise<SearchAllPagesResult>((resolve) => {\n this.engine.searchAllPages(this.currentDocument!, trimmedKeyword, state.flags).wait(\n (results) => {\n const activeResultIndex = results.total > 0 ? 0 : -1;\n this.dispatch(setSearchResults(results.results, results.total, activeResultIndex));\n this.searchResult$.emit(results);\n if (results.total > 0) {\n this.notifyActiveResultChange(0);\n }\n resolve(results);\n },\n (error: TaskError<any>) => {\n console.error('Error during search:', error);\n this.dispatch(setSearchResults([], 0, -1));\n resolve({ results: [], total: 0 });\n },\n );\n });\n }\n\n private nextResult(): number {\n const state = this.getState();\n if (state.results.length === 0) {\n return -1;\n }\n const nextIndex =\n state.activeResultIndex >= state.results.length - 1 ? 0 : state.activeResultIndex + 1;\n return this.goToResult(nextIndex);\n }\n\n private previousResult(): number {\n const state = this.getState();\n if (state.results.length === 0) {\n return -1;\n }\n const prevIndex =\n state.activeResultIndex <= 0 ? state.results.length - 1 : state.activeResultIndex - 1;\n return this.goToResult(prevIndex);\n }\n\n private goToResult(index: number): number {\n const state = this.getState();\n if (state.results.length === 0 || index < 0 || index >= state.results.length) {\n return -1;\n }\n this.dispatch(setActiveResultIndex(index));\n this.notifyActiveResultChange(index);\n return index;\n }\n\n async destroy(): Promise<void> {\n if (this.getState().active && this.currentDocument) {\n this.stopSearchSession();\n }\n this.searchResult$.clear();\n this.searchStart$.clear();\n this.searchStop$.clear();\n this.searchActiveResultChange$.clear();\n this.searchResultState$.clear();\n }\n}\n","import { Action } from '@embedpdf/core';\nimport { MatchFlag, SearchResult } from '@embedpdf/models';\n\n// Action Types\nexport const START_SEARCH_SESSION = 'START_SEARCH_SESSION';\nexport const STOP_SEARCH_SESSION = 'STOP_SEARCH_SESSION';\nexport const SET_SEARCH_FLAGS = 'SET_SEARCH_FLAGS';\nexport const SET_SHOW_ALL_RESULTS = 'SET_SHOW_ALL_RESULTS';\nexport const START_SEARCH = 'START_SEARCH';\nexport const SET_SEARCH_RESULTS = 'SET_SEARCH_RESULTS';\nexport const SET_ACTIVE_RESULT_INDEX = 'SET_ACTIVE_RESULT_INDEX';\n\n// Action Interfaces\nexport interface StartSearchSessionAction extends Action {\n type: typeof START_SEARCH_SESSION;\n}\n\nexport interface StopSearchSessionAction extends Action {\n type: typeof STOP_SEARCH_SESSION;\n}\n\nexport interface SetSearchFlagsAction extends Action {\n type: typeof SET_SEARCH_FLAGS;\n payload: MatchFlag[];\n}\n\nexport interface SetShowAllResultsAction extends Action {\n type: typeof SET_SHOW_ALL_RESULTS;\n payload: boolean;\n}\n\nexport interface StartSearchAction extends Action {\n type: typeof START_SEARCH;\n payload: string;\n}\n\nexport interface SetSearchResultsAction extends Action {\n type: typeof SET_SEARCH_RESULTS;\n payload: {\n results: SearchResult[];\n total: number;\n activeResultIndex: number;\n };\n}\n\nexport interface SetActiveResultIndexAction extends Action {\n type: typeof SET_ACTIVE_RESULT_INDEX;\n payload: number;\n}\n\n// Union Type for All Actions\nexport type SearchAction =\n | StartSearchSessionAction\n | StopSearchSessionAction\n | SetSearchFlagsAction\n | SetShowAllResultsAction\n | StartSearchAction\n | SetSearchResultsAction\n | SetActiveResultIndexAction;\n\n// Action Creators\nexport function startSearchSession(): StartSearchSessionAction {\n return { type: START_SEARCH_SESSION };\n}\n\nexport function stopSearchSession(): StopSearchSessionAction {\n return { type: STOP_SEARCH_SESSION };\n}\n\nexport function setSearchFlags(flags: MatchFlag[]): SetSearchFlagsAction {\n return { type: SET_SEARCH_FLAGS, payload: flags };\n}\n\nexport function setShowAllResults(showAll: boolean): SetShowAllResultsAction {\n return { type: SET_SHOW_ALL_RESULTS, payload: showAll };\n}\n\nexport function startSearch(query: string): StartSearchAction {\n return { type: START_SEARCH, payload: query };\n}\n\nexport function setSearchResults(\n results: SearchResult[],\n total: number,\n activeResultIndex: number,\n): SetSearchResultsAction {\n return { type: SET_SEARCH_RESULTS, payload: { results, total, activeResultIndex } };\n}\n\nexport function setActiveResultIndex(index: number): SetActiveResultIndexAction {\n return { type: SET_ACTIVE_RESULT_INDEX, payload: index };\n}\n","import { PluginManifest } from '@embedpdf/core';\nimport { SearchPluginConfig } from './types';\n\nexport const SEARCH_PLUGIN_ID = 'search';\n\nexport const manifest: PluginManifest<SearchPluginConfig> = {\n id: SEARCH_PLUGIN_ID,\n name: 'Search Plugin',\n version: '1.0.0',\n provides: ['search'],\n requires: ['loader'],\n optional: [],\n defaultConfig: {\n enabled: true,\n flags: [],\n },\n};\n","import { Reducer } from '@embedpdf/core';\nimport { SearchState } from './types';\nimport {\n START_SEARCH_SESSION,\n STOP_SEARCH_SESSION,\n SET_SEARCH_FLAGS,\n SET_SHOW_ALL_RESULTS,\n START_SEARCH,\n SET_SEARCH_RESULTS,\n SET_ACTIVE_RESULT_INDEX,\n SearchAction,\n} from './actions';\n\nexport const initialState: SearchState = {\n flags: [],\n results: [],\n total: 0,\n activeResultIndex: -1,\n showAllResults: true,\n query: '',\n loading: false,\n active: false,\n};\n\nexport const searchReducer: Reducer<SearchState, SearchAction> = (state = initialState, action) => {\n switch (action.type) {\n case START_SEARCH_SESSION:\n return { ...state, active: true };\n\n case STOP_SEARCH_SESSION:\n return {\n ...state,\n results: [],\n total: 0,\n activeResultIndex: -1,\n query: '',\n loading: false,\n active: false,\n };\n\n case SET_SEARCH_FLAGS:\n return { ...state, flags: action.payload };\n\n case SET_SHOW_ALL_RESULTS:\n return { ...state, showAllResults: action.payload };\n\n case START_SEARCH:\n return { ...state, loading: true, query: action.payload };\n\n case SET_SEARCH_RESULTS:\n return {\n ...state,\n results: action.payload.results,\n total: action.payload.total,\n activeResultIndex: action.payload.activeResultIndex,\n loading: false,\n };\n\n case SET_ACTIVE_RESULT_INDEX:\n return { ...state, activeResultIndex: action.payload };\n\n default:\n return state;\n }\n};\n","import { PluginPackage } from '@embedpdf/core';\nimport { SearchPlugin } from './search-plugin';\nimport { manifest, SEARCH_PLUGIN_ID } from './manifest';\nimport { SearchPluginConfig, SearchState } from './types';\nimport { searchReducer, initialState } from './reducer';\nimport { SearchAction } from './actions';\n\nexport const SearchPluginPackage: PluginPackage<\n SearchPlugin,\n SearchPluginConfig,\n SearchState,\n SearchAction\n> = {\n manifest,\n create: (registry, engine) => new SearchPlugin(SEARCH_PLUGIN_ID, registry, engine),\n reducer: searchReducer,\n initialState,\n};\n\nexport * from './search-plugin';\nexport * from './types';\nexport * from './manifest';\nexport { initialState };\n"],"mappings":";AAAA,SAAS,YAAY,6BAA6C;;;ACI3D,IAAM,uBAAuB;AAC7B,IAAM,sBAAsB;AAC5B,IAAM,mBAAmB;AACzB,IAAM,uBAAuB;AAC7B,IAAM,eAAe;AACrB,IAAM,qBAAqB;AAC3B,IAAM,0BAA0B;AAmDhC,SAAS,qBAA+C;AAC7D,SAAO,EAAE,MAAM,qBAAqB;AACtC;AAEO,SAAS,oBAA6C;AAC3D,SAAO,EAAE,MAAM,oBAAoB;AACrC;AAEO,SAAS,eAAe,OAA0C;AACvE,SAAO,EAAE,MAAM,kBAAkB,SAAS,MAAM;AAClD;AAEO,SAAS,kBAAkB,SAA2C;AAC3E,SAAO,EAAE,MAAM,sBAAsB,SAAS,QAAQ;AACxD;AAEO,SAAS,YAAY,OAAkC;AAC5D,SAAO,EAAE,MAAM,cAAc,SAAS,MAAM;AAC9C;AAEO,SAAS,iBACd,SACA,OACA,mBACwB;AACxB,SAAO,EAAE,MAAM,oBAAoB,SAAS,EAAE,SAAS,OAAO,kBAAkB,EAAE;AACpF;AAEO,SAAS,qBAAqB,OAA2C;AAC9E,SAAO,EAAE,MAAM,yBAAyB,SAAS,MAAM;AACzD;;;ADtEO,IAAM,eAAN,cAA2B,WAKhC;AAAA,EAYA,YAAY,IAAY,UAA0B,QAAmB;AACnE,UAAM,IAAI,QAAQ;AAPpB,SAAiB,cAAc,sBAAsB;AACrD,SAAiB,eAAe,sBAAsB;AACtD,SAAiB,gBAAgB,sBAA4C;AAC7E,SAAiB,4BAA4B,sBAA8B;AAC3E,SAAiB,qBAAqB,sBAAyC;AAI7E,SAAK,SAAS;AACd,SAAK,SAAS,KAAK,SAAS,UAAwB,QAAQ,EAAG,SAAS;AAExE,SAAK,OAAO,iBAAiB,KAAK,qBAAqB,KAAK,IAAI,CAAC;AACjE,SAAK,OAAO,cAAc,KAAK,kBAAkB,KAAK,IAAI,CAAC;AAAA,EAC7D;AAAA,EAEQ,qBAAqB,KAA8B;AACzD,SAAK,kBAAkB;AACvB,QAAI,KAAK,SAAS,EAAE,QAAQ;AAC1B,WAAK,mBAAmB;AAAA,IAC1B;AAAA,EACF;AAAA,EAEQ,kBAAkB,OAA0B;AAClD,QAAI,MAAM,SAAS,WAAY,MAAM,SAAS,WAAW,KAAK,iBAAkB;AAC9E,UAAI,KAAK,SAAS,EAAE,QAAQ;AAC1B,aAAK,kBAAkB;AAAA,MACzB;AACA,WAAK,kBAAkB;AAAA,IACzB;AAAA,EACF;AAAA,EAEA,MAAM,WAAW,QAA2C;AAC1D,SAAK,SAAS,eAAe,OAAO,SAAS,CAAC,CAAC,CAAC;AAChD,SAAK;AAAA,MACH,kBAAkB,OAAO,mBAAmB,SAAY,OAAO,iBAAiB,IAAI;AAAA,IACtF;AAAA,EACF;AAAA,EAES,eAAe,YAAyB,UAA6B;AAC5E,SAAK,mBAAmB,KAAK;AAAA,MAC3B,SAAS,SAAS;AAAA,MAClB,mBAAmB,SAAS;AAAA,MAC5B,gBAAgB,SAAS;AAAA,MACzB,QAAQ,SAAS;AAAA,IACnB,CAAC;AAAA,EACH;AAAA,EAEU,kBAAoC;AAC5C,WAAO;AAAA,MACL,aAAa,KAAK,mBAAmB,KAAK,IAAI;AAAA,MAC9C,YAAY,KAAK,kBAAkB,KAAK,IAAI;AAAA,MAC5C,gBAAgB,KAAK,eAAe,KAAK,IAAI;AAAA,MAC7C,YAAY,KAAK,WAAW,KAAK,IAAI;AAAA,MACrC,gBAAgB,KAAK,eAAe,KAAK,IAAI;AAAA,MAC7C,YAAY,KAAK,WAAW,KAAK,IAAI;AAAA,MACrC,mBAAmB,CAAC,YAAY,KAAK,SAAS,kBAAkB,OAAO,CAAC;AAAA,MACxE,mBAAmB,MAAM,KAAK,SAAS,EAAE;AAAA,MACzC,gBAAgB,KAAK,cAAc;AAAA,MACnC,eAAe,KAAK,aAAa;AAAA,MACjC,cAAc,KAAK,YAAY;AAAA,MAC/B,sBAAsB,KAAK,0BAA0B;AAAA,MACrD,2BAA2B,KAAK,mBAAmB;AAAA,MACnD,eAAe,CAAC,YAAY;AAC1B,cAAM,cAAc,KAAK,UAAU,CAAC,GAAG,UAAU,QAAQ,KAAK,CAAC;AAC/D,eAAO;AAAA,MACT;AAAA,MACA,UAAU,MAAM,KAAK,SAAS,EAAE;AAAA,MAChC,UAAU,CAAC,UAAU,KAAK,SAAS,KAAK;AAAA,IAC1C;AAAA,EACF;AAAA,EAEQ,SAAS,OAA0B;AACzC,UAAM,QAAQ,KAAK,SAAS;AAC5B,SAAK,SAAS,eAAe,KAAK,CAAC;AACnC,QAAI,MAAM,QAAQ;AAChB,WAAK,eAAe,MAAM,OAAO,IAAI;AAAA,IACvC;AAAA,EACF;AAAA,EAEQ,oBAA0B;AAChC,SAAK,aAAa,KAAK;AAAA,EACzB;AAAA,EAEQ,mBAAyB;AAC/B,SAAK,YAAY,KAAK;AAAA,EACxB;AAAA,EAEQ,yBAAyB,OAAqB;AACpD,SAAK,0BAA0B,KAAK,KAAK;AAAA,EAC3C;AAAA,EAEQ,qBAA2B;AACjC,QAAI,CAAC,KAAK,iBAAiB;AACzB;AAAA,IACF;AACA,SAAK,SAAS,mBAAmB,CAAC;AAClC,SAAK,kBAAkB;AAAA,EACzB;AAAA,EAEQ,oBAA0B;AAChC,QAAI,CAAC,KAAK,mBAAmB,CAAC,KAAK,SAAS,EAAE,QAAQ;AACpD;AAAA,IACF;AACA,SAAK,SAAS,kBAAkB,CAAC;AACjC,SAAK,iBAAiB;AAAA,EACxB;AAAA,EAEA,MAAc,eACZ,SACA,QAAiB,OACc;AAC/B,UAAM,iBAAiB,QAAQ,KAAK;AACpC,UAAM,QAAQ,KAAK,SAAS;AAE5B,QAAI,MAAM,UAAU,kBAAkB,CAAC,OAAO;AAC5C,aAAO,EAAE,SAAS,MAAM,SAAS,OAAO,MAAM,MAAM;AAAA,IACtD;AAEA,SAAK,SAAS,YAAY,cAAc,CAAC;AAEzC,QAAI,CAAC,gBAAgB;AACnB,WAAK,SAAS,iBAAiB,CAAC,GAAG,GAAG,EAAE,CAAC;AACzC,aAAO,EAAE,SAAS,CAAC,GAAG,OAAO,EAAE;AAAA,IACjC;AACA,QAAI,CAAC,KAAK,iBAAiB;AACzB,WAAK,SAAS,iBAAiB,CAAC,GAAG,GAAG,EAAE,CAAC;AACzC,aAAO,EAAE,SAAS,CAAC,GAAG,OAAO,EAAE;AAAA,IACjC;AAEA,QAAI,CAAC,MAAM,QAAQ;AACjB,WAAK,mBAAmB;AAAA,IAC1B;AAEA,WAAO,IAAI,QAA8B,CAAC,YAAY;AACpD,WAAK,OAAO,eAAe,KAAK,iBAAkB,gBAAgB,MAAM,KAAK,EAAE;AAAA,QAC7E,CAAC,YAAY;AACX,gBAAM,oBAAoB,QAAQ,QAAQ,IAAI,IAAI;AAClD,eAAK,SAAS,iBAAiB,QAAQ,SAAS,QAAQ,OAAO,iBAAiB,CAAC;AACjF,eAAK,cAAc,KAAK,OAAO;AAC/B,cAAI,QAAQ,QAAQ,GAAG;AACrB,iBAAK,yBAAyB,CAAC;AAAA,UACjC;AACA,kBAAQ,OAAO;AAAA,QACjB;AAAA,QACA,CAAC,UAA0B;AACzB,kBAAQ,MAAM,wBAAwB,KAAK;AAC3C,eAAK,SAAS,iBAAiB,CAAC,GAAG,GAAG,EAAE,CAAC;AACzC,kBAAQ,EAAE,SAAS,CAAC,GAAG,OAAO,EAAE,CAAC;AAAA,QACnC;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,aAAqB;AAC3B,UAAM,QAAQ,KAAK,SAAS;AAC5B,QAAI,MAAM,QAAQ,WAAW,GAAG;AAC9B,aAAO;AAAA,IACT;AACA,UAAM,YACJ,MAAM,qBAAqB,MAAM,QAAQ,SAAS,IAAI,IAAI,MAAM,oBAAoB;AACtF,WAAO,KAAK,WAAW,SAAS;AAAA,EAClC;AAAA,EAEQ,iBAAyB;AAC/B,UAAM,QAAQ,KAAK,SAAS;AAC5B,QAAI,MAAM,QAAQ,WAAW,GAAG;AAC9B,aAAO;AAAA,IACT;AACA,UAAM,YACJ,MAAM,qBAAqB,IAAI,MAAM,QAAQ,SAAS,IAAI,MAAM,oBAAoB;AACtF,WAAO,KAAK,WAAW,SAAS;AAAA,EAClC;AAAA,EAEQ,WAAW,OAAuB;AACxC,UAAM,QAAQ,KAAK,SAAS;AAC5B,QAAI,MAAM,QAAQ,WAAW,KAAK,QAAQ,KAAK,SAAS,MAAM,QAAQ,QAAQ;AAC5E,aAAO;AAAA,IACT;AACA,SAAK,SAAS,qBAAqB,KAAK,CAAC;AACzC,SAAK,yBAAyB,KAAK;AACnC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,UAAyB;AAC7B,QAAI,KAAK,SAAS,EAAE,UAAU,KAAK,iBAAiB;AAClD,WAAK,kBAAkB;AAAA,IACzB;AACA,SAAK,cAAc,MAAM;AACzB,SAAK,aAAa,MAAM;AACxB,SAAK,YAAY,MAAM;AACvB,SAAK,0BAA0B,MAAM;AACrC,SAAK,mBAAmB,MAAM;AAAA,EAChC;AACF;AA5Ma,aAMK,KAAK;;;AExBhB,IAAM,mBAAmB;AAEzB,IAAM,WAA+C;AAAA,EAC1D,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,SAAS;AAAA,EACT,UAAU,CAAC,QAAQ;AAAA,EACnB,UAAU,CAAC,QAAQ;AAAA,EACnB,UAAU,CAAC;AAAA,EACX,eAAe;AAAA,IACb,SAAS;AAAA,IACT,OAAO,CAAC;AAAA,EACV;AACF;;;ACHO,IAAM,eAA4B;AAAA,EACvC,OAAO,CAAC;AAAA,EACR,SAAS,CAAC;AAAA,EACV,OAAO;AAAA,EACP,mBAAmB;AAAA,EACnB,gBAAgB;AAAA,EAChB,OAAO;AAAA,EACP,SAAS;AAAA,EACT,QAAQ;AACV;AAEO,IAAM,gBAAoD,CAAC,QAAQ,cAAc,WAAW;AACjG,UAAQ,OAAO,MAAM;AAAA,IACnB,KAAK;AACH,aAAO,EAAE,GAAG,OAAO,QAAQ,KAAK;AAAA,IAElC,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,SAAS,CAAC;AAAA,QACV,OAAO;AAAA,QACP,mBAAmB;AAAA,QACnB,OAAO;AAAA,QACP,SAAS;AAAA,QACT,QAAQ;AAAA,MACV;AAAA,IAEF,KAAK;AACH,aAAO,EAAE,GAAG,OAAO,OAAO,OAAO,QAAQ;AAAA,IAE3C,KAAK;AACH,aAAO,EAAE,GAAG,OAAO,gBAAgB,OAAO,QAAQ;AAAA,IAEpD,KAAK;AACH,aAAO,EAAE,GAAG,OAAO,SAAS,MAAM,OAAO,OAAO,QAAQ;AAAA,IAE1D,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,SAAS,OAAO,QAAQ;AAAA,QACxB,OAAO,OAAO,QAAQ;AAAA,QACtB,mBAAmB,OAAO,QAAQ;AAAA,QAClC,SAAS;AAAA,MACX;AAAA,IAEF,KAAK;AACH,aAAO,EAAE,GAAG,OAAO,mBAAmB,OAAO,QAAQ;AAAA,IAEvD;AACE,aAAO;AAAA,EACX;AACF;;;ACzDO,IAAM,sBAKT;AAAA,EACF;AAAA,EACA,QAAQ,CAAC,UAAU,WAAW,IAAI,aAAa,kBAAkB,UAAU,MAAM;AAAA,EACjF,SAAS;AAAA,EACT;AACF;","names":[]}
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/preact/index.ts
21
+ var preact_exports = {};
22
+ __export(preact_exports, {
23
+ SearchLayer: () => SearchLayer,
24
+ useSearch: () => useSearch,
25
+ useSearchCapability: () => useSearchCapability
26
+ });
27
+ module.exports = __toCommonJS(preact_exports);
28
+
29
+ // src/preact/hooks/use-search.ts
30
+ var import_preact = require("@embedpdf/core/preact");
31
+ var import_plugin_search = require("@embedpdf/plugin-search");
32
+ var useSearch = () => (0, import_preact.usePlugin)(import_plugin_search.SearchPlugin.id);
33
+ var useSearchCapability = () => (0, import_preact.useCapability)(import_plugin_search.SearchPlugin.id);
34
+
35
+ // src/preact/components/search-layer.tsx
36
+ var import_hooks = require("preact/hooks");
37
+ var import_jsx_runtime = require("preact/jsx-runtime");
38
+ function SearchLayer({
39
+ pageIndex,
40
+ scale,
41
+ style,
42
+ highlightColor = "#FFFF00",
43
+ activeHighlightColor = "#FFBF00",
44
+ ...props
45
+ }) {
46
+ const { provides: searchProvides } = useSearchCapability();
47
+ const [searchResultState, setSearchResultState] = (0, import_hooks.useState)(null);
48
+ (0, import_hooks.useEffect)(() => {
49
+ return searchProvides?.onSearchResultStateChange((state) => {
50
+ setSearchResultState(state);
51
+ });
52
+ }, [searchProvides]);
53
+ if (!searchResultState) {
54
+ return null;
55
+ }
56
+ const pageResults = searchResultState.results.map((result, originalIndex) => ({ result, originalIndex })).filter(({ result }) => result.pageIndex === pageIndex);
57
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
58
+ "div",
59
+ {
60
+ style: {
61
+ ...style
62
+ },
63
+ ...props,
64
+ children: pageResults.map(
65
+ ({ result, originalIndex }) => result.rects.map((rect) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
66
+ "div",
67
+ {
68
+ style: {
69
+ position: "absolute",
70
+ top: rect.origin.y * scale,
71
+ left: rect.origin.x * scale,
72
+ width: rect.size.width * scale,
73
+ height: rect.size.height * scale,
74
+ backgroundColor: originalIndex === searchResultState.activeResultIndex ? activeHighlightColor : highlightColor,
75
+ mixBlendMode: "multiply",
76
+ transform: "scale(1.02)",
77
+ transformOrigin: "center",
78
+ transition: "opacity .3s ease-in-out",
79
+ opacity: 1
80
+ }
81
+ }
82
+ ))
83
+ )
84
+ }
85
+ );
86
+ }
87
+ // Annotate the CommonJS export names for ESM import in node:
88
+ 0 && (module.exports = {
89
+ SearchLayer,
90
+ useSearch,
91
+ useSearchCapability
92
+ });
93
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/preact/index.ts","../../src/preact/hooks/use-search.ts","../../src/preact/components/search-layer.tsx"],"sourcesContent":["export * from './hooks';\nexport * from './components';\n","import { useCapability, usePlugin } from '@embedpdf/core/preact';\nimport { SearchPlugin } from '@embedpdf/plugin-search';\n\nexport const useSearch = () => usePlugin<SearchPlugin>(SearchPlugin.id);\nexport const useSearchCapability = () => useCapability<SearchPlugin>(SearchPlugin.id);\n","/** @jsxImportSource preact */\nimport { ComponentChildren, Fragment, JSX } from 'preact';\nimport { useEffect, useRef, useState } from 'preact/hooks';\nimport { SearchResultState } from '@embedpdf/plugin-search';\n\nimport { useSearchCapability } from '../hooks';\n\ntype SearchLayoutProps = Omit<JSX.HTMLAttributes<HTMLDivElement>, 'style'> & {\n pageIndex: number;\n scale: number;\n highlightColor?: string;\n activeHighlightColor?: string;\n style?: JSX.CSSProperties;\n};\n\nexport function SearchLayer({\n pageIndex,\n scale,\n style,\n highlightColor = '#FFFF00',\n activeHighlightColor = '#FFBF00',\n ...props\n}: SearchLayoutProps) {\n const { provides: searchProvides } = useSearchCapability();\n const [searchResultState, setSearchResultState] = useState<SearchResultState | null>(null);\n\n useEffect(() => {\n return searchProvides?.onSearchResultStateChange((state) => {\n setSearchResultState(state);\n });\n }, [searchProvides]);\n\n if (!searchResultState) {\n return null;\n }\n\n // Filter results for current page while preserving original indices\n const pageResults = searchResultState.results\n .map((result, originalIndex) => ({ result, originalIndex }))\n .filter(({ result }) => result.pageIndex === pageIndex);\n\n return (\n <div\n style={{\n ...style,\n }}\n {...props}\n >\n {pageResults.map(({ result, originalIndex }) =>\n result.rects.map((rect) => (\n <div\n style={{\n position: 'absolute',\n top: rect.origin.y * scale,\n left: rect.origin.x * scale,\n width: rect.size.width * scale,\n height: rect.size.height * scale,\n backgroundColor:\n originalIndex === searchResultState.activeResultIndex\n ? activeHighlightColor\n : highlightColor,\n mixBlendMode: 'multiply',\n transform: 'scale(1.02)',\n transformOrigin: 'center',\n transition: 'opacity .3s ease-in-out',\n opacity: 1,\n }}\n ></div>\n )),\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,oBAAyC;AACzC,2BAA6B;AAEtB,IAAM,YAAY,UAAM,yBAAwB,kCAAa,EAAE;AAC/D,IAAM,sBAAsB,UAAM,6BAA4B,kCAAa,EAAE;;;ACFpF,mBAA4C;AAgDlC;AAnCH,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA,iBAAiB;AAAA,EACjB,uBAAuB;AAAA,EACvB,GAAG;AACL,GAAsB;AACpB,QAAM,EAAE,UAAU,eAAe,IAAI,oBAAoB;AACzD,QAAM,CAAC,mBAAmB,oBAAoB,QAAI,uBAAmC,IAAI;AAEzF,8BAAU,MAAM;AACd,WAAO,gBAAgB,0BAA0B,CAAC,UAAU;AAC1D,2BAAqB,KAAK;AAAA,IAC5B,CAAC;AAAA,EACH,GAAG,CAAC,cAAc,CAAC;AAEnB,MAAI,CAAC,mBAAmB;AACtB,WAAO;AAAA,EACT;AAGA,QAAM,cAAc,kBAAkB,QACnC,IAAI,CAAC,QAAQ,mBAAmB,EAAE,QAAQ,cAAc,EAAE,EAC1D,OAAO,CAAC,EAAE,OAAO,MAAM,OAAO,cAAc,SAAS;AAExD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,QACL,GAAG;AAAA,MACL;AAAA,MACC,GAAG;AAAA,MAEH,sBAAY;AAAA,QAAI,CAAC,EAAE,QAAQ,cAAc,MACxC,OAAO,MAAM,IAAI,CAAC,SAChB;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,UAAU;AAAA,cACV,KAAK,KAAK,OAAO,IAAI;AAAA,cACrB,MAAM,KAAK,OAAO,IAAI;AAAA,cACtB,OAAO,KAAK,KAAK,QAAQ;AAAA,cACzB,QAAQ,KAAK,KAAK,SAAS;AAAA,cAC3B,iBACE,kBAAkB,kBAAkB,oBAChC,uBACA;AAAA,cACN,cAAc;AAAA,cACd,WAAW;AAAA,cACX,iBAAiB;AAAA,cACjB,YAAY;AAAA,cACZ,SAAS;AAAA,YACX;AAAA;AAAA,QACD,CACF;AAAA,MACH;AAAA;AAAA,EACF;AAEJ;","names":[]}
@@ -0,0 +1,27 @@
1
+ import * as _embedpdf_plugin_search from '@embedpdf/plugin-search';
2
+ import { SearchPlugin } from '@embedpdf/plugin-search';
3
+ import { JSX } from 'preact';
4
+
5
+ declare const useSearch: () => {
6
+ plugin: SearchPlugin | null;
7
+ isLoading: boolean;
8
+ ready: Promise<void>;
9
+ };
10
+ declare const useSearchCapability: () => {
11
+ provides: Readonly<_embedpdf_plugin_search.SearchCapability> | null;
12
+ isLoading: boolean;
13
+ ready: Promise<void>;
14
+ };
15
+
16
+ /** @jsxImportSource preact */
17
+
18
+ type SearchLayoutProps = Omit<JSX.HTMLAttributes<HTMLDivElement>, 'style'> & {
19
+ pageIndex: number;
20
+ scale: number;
21
+ highlightColor?: string;
22
+ activeHighlightColor?: string;
23
+ style?: JSX.CSSProperties;
24
+ };
25
+ declare function SearchLayer({ pageIndex, scale, style, highlightColor, activeHighlightColor, ...props }: SearchLayoutProps): JSX.Element | null;
26
+
27
+ export { SearchLayer, useSearch, useSearchCapability };