@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.
- package/LICENSE +21 -0
- package/dist/index.cjs +310 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +225 -0
- package/dist/index.d.ts +225 -0
- package/dist/index.js +279 -0
- package/dist/index.js.map +1 -0
- package/dist/preact/index.cjs +93 -0
- package/dist/preact/index.cjs.map +1 -0
- package/dist/preact/index.d.cts +27 -0
- package/dist/preact/index.d.ts +27 -0
- package/dist/preact/index.js +64 -0
- package/dist/preact/index.js.map +1 -0
- package/dist/react/index.cjs +93 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.d.cts +25 -0
- package/dist/react/index.d.ts +25 -0
- package/dist/react/index.js +64 -0
- package/dist/react/index.js.map +1 -0
- package/package.json +66 -0
package/dist/index.d.ts
ADDED
|
@@ -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":"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","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 };
|