@embedpdf/svelte 0.0.0-stage → 3.0.0-next.15
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 +192 -0
- package/README.md +312 -2
- package/dist/actions/readers.svelte.d.ts +29 -0
- package/dist/actions/readers.svelte.js +55 -0
- package/dist/actions.d.ts +13 -0
- package/dist/actions.js +13 -0
- package/dist/anchored/Anchored.svelte +24 -0
- package/dist/anchored/Anchored.svelte.d.ts +4 -0
- package/dist/anchored/PlacedAnchored.svelte +97 -0
- package/dist/anchored/PlacedAnchored.svelte.d.ts +4 -0
- package/dist/anchored/context.d.ts +31 -0
- package/dist/anchored/context.js +36 -0
- package/dist/anchored/props.d.ts +29 -0
- package/dist/anchored/props.js +1 -0
- package/dist/anchored.d.ts +12 -0
- package/dist/anchored.js +2 -0
- package/dist/annotation/AnnotationChrome.svelte +173 -0
- package/dist/annotation/AnnotationChrome.svelte.d.ts +11 -0
- package/dist/annotation/AnnotationDraftMenu.svelte +27 -0
- package/dist/annotation/AnnotationDraftMenu.svelte.d.ts +4 -0
- package/dist/annotation/AnnotationFrame.svelte +46 -0
- package/dist/annotation/AnnotationFrame.svelte.d.ts +15 -0
- package/dist/annotation/AnnotationLayer.svelte +241 -0
- package/dist/annotation/AnnotationLayer.svelte.d.ts +4 -0
- package/dist/annotation/AnnotationLook.svelte +67 -0
- package/dist/annotation/AnnotationLook.svelte.d.ts +21 -0
- package/dist/annotation/AnnotationMenu.svelte +47 -0
- package/dist/annotation/AnnotationMenu.svelte.d.ts +4 -0
- package/dist/annotation/AnnotationRotationBadge.svelte +52 -0
- package/dist/annotation/AnnotationRotationBadge.svelte.d.ts +4 -0
- package/dist/annotation/AnnotationScene.svelte +27 -0
- package/dist/annotation/AnnotationScene.svelte.d.ts +7 -0
- package/dist/annotation/FreeTextBox.svelte +55 -0
- package/dist/annotation/FreeTextBox.svelte.d.ts +9 -0
- package/dist/annotation/NativeDrawing.svelte +61 -0
- package/dist/annotation/NativeDrawing.svelte.d.ts +10 -0
- package/dist/annotation/StampGhost.svelte +79 -0
- package/dist/annotation/StampGhost.svelte.d.ts +7 -0
- package/dist/annotation/chrome-paint.svelte.d.ts +30 -0
- package/dist/annotation/chrome-paint.svelte.js +27 -0
- package/dist/annotation/props.d.ts +181 -0
- package/dist/annotation/props.js +1 -0
- package/dist/annotation/readers.svelte.d.ts +59 -0
- package/dist/annotation/readers.svelte.js +136 -0
- package/dist/annotation/state.d.ts +18 -0
- package/dist/annotation/state.js +20 -0
- package/dist/annotation/text-box.svelte.d.ts +27 -0
- package/dist/annotation/text-box.svelte.js +94 -0
- package/dist/annotation.d.ts +32 -0
- package/dist/annotation.js +31 -0
- package/dist/commands/readers.svelte.d.ts +50 -0
- package/dist/commands/readers.svelte.js +83 -0
- package/dist/commands.d.ts +9 -0
- package/dist/commands.js +9 -0
- package/dist/form/ButtonControl.svelte +38 -0
- package/dist/form/ButtonControl.svelte.d.ts +11 -0
- package/dist/form/ComboControl.svelte +52 -0
- package/dist/form/ComboControl.svelte.d.ts +11 -0
- package/dist/form/FieldPictures.svelte +145 -0
- package/dist/form/FieldPictures.svelte.d.ts +3 -0
- package/dist/form/FormFocusRing.svelte +25 -0
- package/dist/form/FormFocusRing.svelte.d.ts +8 -0
- package/dist/form/FormLayer.svelte +98 -0
- package/dist/form/FormLayer.svelte.d.ts +3 -0
- package/dist/form/ListControl.svelte +49 -0
- package/dist/form/ListControl.svelte.d.ts +11 -0
- package/dist/form/NativeListBox.svelte +57 -0
- package/dist/form/NativeListBox.svelte.d.ts +4 -0
- package/dist/form/SignatureControl.svelte +53 -0
- package/dist/form/SignatureControl.svelte.d.ts +11 -0
- package/dist/form/TextControl.svelte +107 -0
- package/dist/form/TextControl.svelte.d.ts +11 -0
- package/dist/form/ToggleControl.svelte +50 -0
- package/dist/form/ToggleControl.svelte.d.ts +11 -0
- package/dist/form/WidgetBox.svelte +82 -0
- package/dist/form/WidgetBox.svelte.d.ts +15 -0
- package/dist/form/props.d.ts +21 -0
- package/dist/form/props.js +1 -0
- package/dist/form/readers.svelte.d.ts +46 -0
- package/dist/form/readers.svelte.js +52 -0
- package/dist/form/widget.d.ts +16 -0
- package/dist/form/widget.js +20 -0
- package/dist/form.d.ts +11 -0
- package/dist/form.js +12 -0
- package/dist/history/readers.d.ts +22 -0
- package/dist/history/readers.js +21 -0
- package/dist/history.d.ts +10 -0
- package/dist/history.js +11 -0
- package/dist/i18n/readers.svelte.d.ts +32 -0
- package/dist/i18n/readers.svelte.js +30 -0
- package/dist/i18n.d.ts +8 -0
- package/dist/i18n.js +9 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +28 -0
- package/dist/interaction/PagePointerSource.svelte +37 -0
- package/dist/interaction/PagePointerSource.svelte.d.ts +3 -0
- package/dist/interaction/readers.svelte.d.ts +26 -0
- package/dist/interaction/readers.svelte.js +47 -0
- package/dist/interaction.d.ts +11 -0
- package/dist/interaction.js +13 -0
- package/dist/link/LinkLayer.svelte +164 -0
- package/dist/link/LinkLayer.svelte.d.ts +4 -0
- package/dist/link/props.d.ts +17 -0
- package/dist/link/props.js +1 -0
- package/dist/link/readers.svelte.d.ts +18 -0
- package/dist/link/readers.svelte.js +38 -0
- package/dist/link.d.ts +11 -0
- package/dist/link.js +11 -0
- package/dist/measurement/readers.d.ts +44 -0
- package/dist/measurement/readers.js +46 -0
- package/dist/measurement.d.ts +12 -0
- package/dist/measurement.js +13 -0
- package/dist/metadata/readers.d.ts +22 -0
- package/dist/metadata/readers.js +22 -0
- package/dist/metadata.d.ts +12 -0
- package/dist/metadata.js +13 -0
- package/dist/page-edit/readers.d.ts +7 -0
- package/dist/page-edit/readers.js +11 -0
- package/dist/page-edit.d.ts +12 -0
- package/dist/page-edit.js +13 -0
- package/dist/page-view/PageView.svelte +192 -0
- package/dist/page-view/PageView.svelte.d.ts +4 -0
- package/dist/page-view/props.d.ts +32 -0
- package/dist/page-view/props.js +1 -0
- package/dist/page-view.d.ts +8 -0
- package/dist/page-view.js +7 -0
- package/dist/redaction/readers.d.ts +37 -0
- package/dist/redaction/readers.js +38 -0
- package/dist/redaction.d.ts +12 -0
- package/dist/redaction.js +13 -0
- package/dist/render/RenderLayer.svelte +116 -0
- package/dist/render/RenderLayer.svelte.d.ts +4 -0
- package/dist/render/TileImage.svelte +65 -0
- package/dist/render/TileImage.svelte.d.ts +11 -0
- package/dist/render/TilePlane.svelte +88 -0
- package/dist/render/TilePlane.svelte.d.ts +7 -0
- package/dist/render/props.d.ts +16 -0
- package/dist/render/props.js +1 -0
- package/dist/render/readers.svelte.d.ts +9 -0
- package/dist/render/readers.svelte.js +13 -0
- package/dist/render.d.ts +10 -0
- package/dist/render.js +10 -0
- package/dist/runtime/DocumentGate.svelte +26 -0
- package/dist/runtime/DocumentGate.svelte.d.ts +4 -0
- package/dist/runtime/DocumentScope.svelte +14 -0
- package/dist/runtime/DocumentScope.svelte.d.ts +4 -0
- package/dist/runtime/KernelProvider.svelte +33 -0
- package/dist/runtime/KernelProvider.svelte.d.ts +4 -0
- package/dist/runtime/SvgShapes.svelte +30 -0
- package/dist/runtime/SvgShapes.svelte.d.ts +8 -0
- package/dist/runtime/Viewer.svelte +124 -0
- package/dist/runtime/Viewer.svelte.d.ts +4 -0
- package/dist/runtime/binding.svelte.d.ts +33 -0
- package/dist/runtime/binding.svelte.js +71 -0
- package/dist/runtime/capability-handle.d.ts +6 -0
- package/dist/runtime/capability-handle.js +71 -0
- package/dist/runtime/dev.d.ts +10 -0
- package/dist/runtime/dev.js +23 -0
- package/dist/runtime/documents.svelte.d.ts +34 -0
- package/dist/runtime/documents.svelte.js +49 -0
- package/dist/runtime/page-layers.svelte.d.ts +20 -0
- package/dist/runtime/page-layers.svelte.js +40 -0
- package/dist/runtime/page.d.ts +10 -0
- package/dist/runtime/page.js +23 -0
- package/dist/runtime/props.d.ts +63 -0
- package/dist/runtime/props.js +1 -0
- package/dist/runtime/readers.svelte.d.ts +47 -0
- package/dist/runtime/readers.svelte.js +122 -0
- package/dist/runtime/state.svelte.d.ts +35 -0
- package/dist/runtime/state.svelte.js +90 -0
- package/dist/runtime/theme.d.ts +12 -0
- package/dist/runtime/theme.js +15 -0
- package/dist/runtime/values.svelte.d.ts +28 -0
- package/dist/runtime/values.svelte.js +51 -0
- package/dist/runtime.d.ts +26 -0
- package/dist/runtime.js +25 -0
- package/dist/search/SearchLayer.svelte +94 -0
- package/dist/search/SearchLayer.svelte.d.ts +4 -0
- package/dist/search/props.d.ts +11 -0
- package/dist/search/props.js +1 -0
- package/dist/search/readers.svelte.d.ts +41 -0
- package/dist/search/readers.svelte.js +40 -0
- package/dist/search.d.ts +11 -0
- package/dist/search.js +11 -0
- package/dist/selection/SelectionClipboard.svelte +35 -0
- package/dist/selection/SelectionClipboard.svelte.d.ts +4 -0
- package/dist/selection/SelectionHandles.svelte +192 -0
- package/dist/selection/SelectionHandles.svelte.d.ts +4 -0
- package/dist/selection/SelectionLayer.svelte +67 -0
- package/dist/selection/SelectionLayer.svelte.d.ts +3 -0
- package/dist/selection/SelectionMenu.svelte +36 -0
- package/dist/selection/SelectionMenu.svelte.d.ts +4 -0
- package/dist/selection/props.d.ts +26 -0
- package/dist/selection/props.js +1 -0
- package/dist/selection/readers.svelte.d.ts +31 -0
- package/dist/selection/readers.svelte.js +26 -0
- package/dist/selection.d.ts +16 -0
- package/dist/selection.js +18 -0
- package/dist/shell/readers.svelte.d.ts +40 -0
- package/dist/shell/readers.svelte.js +40 -0
- package/dist/shell/surface-focus.svelte.d.ts +16 -0
- package/dist/shell/surface-focus.svelte.js +33 -0
- package/dist/shell.d.ts +12 -0
- package/dist/shell.js +11 -0
- package/dist/signature/readers.svelte.d.ts +43 -0
- package/dist/signature/readers.svelte.js +46 -0
- package/dist/signature.d.ts +15 -0
- package/dist/signature.js +16 -0
- package/dist/stage/PageSurface.svelte +126 -0
- package/dist/stage/PageSurface.svelte.d.ts +18 -0
- package/dist/stage/Scrollbar.svelte +148 -0
- package/dist/stage/Scrollbar.svelte.d.ts +4 -0
- package/dist/stage/Stage.svelte +181 -0
- package/dist/stage/Stage.svelte.d.ts +4 -0
- package/dist/stage/StageScope.svelte +14 -0
- package/dist/stage/StageScope.svelte.d.ts +9 -0
- package/dist/stage/props.d.ts +71 -0
- package/dist/stage/props.js +1 -0
- package/dist/stage/readers.svelte.d.ts +39 -0
- package/dist/stage/readers.svelte.js +84 -0
- package/dist/stage/stage-scope.d.ts +18 -0
- package/dist/stage/stage-scope.js +35 -0
- package/dist/stage/two-way.svelte.d.ts +13 -0
- package/dist/stage/two-way.svelte.js +26 -0
- package/dist/stage.d.ts +17 -0
- package/dist/stage.js +15 -0
- package/dist/stamp/readers.svelte.d.ts +50 -0
- package/dist/stamp/readers.svelte.js +76 -0
- package/dist/stamp.d.ts +16 -0
- package/dist/stamp.js +18 -0
- package/dist/toolbar/DefaultCollapsed.svelte +39 -0
- package/dist/toolbar/DefaultCollapsed.svelte.d.ts +9 -0
- package/dist/toolbar/DefaultCommand.svelte +33 -0
- package/dist/toolbar/DefaultCommand.svelte.d.ts +8 -0
- package/dist/toolbar/DefaultGroupTrigger.svelte +39 -0
- package/dist/toolbar/DefaultGroupTrigger.svelte.d.ts +9 -0
- package/dist/toolbar/DefaultOverflowMenu.svelte +106 -0
- package/dist/toolbar/DefaultOverflowMenu.svelte.d.ts +9 -0
- package/dist/toolbar/DefaultOverflowTrigger.svelte +25 -0
- package/dist/toolbar/DefaultOverflowTrigger.svelte.d.ts +7 -0
- package/dist/toolbar/Measured.svelte +46 -0
- package/dist/toolbar/Measured.svelte.d.ts +11 -0
- package/dist/toolbar/NativeSlotSocket.svelte +43 -0
- package/dist/toolbar/NativeSlotSocket.svelte.d.ts +11 -0
- package/dist/toolbar/Toolbar.svelte +314 -0
- package/dist/toolbar/Toolbar.svelte.d.ts +4 -0
- package/dist/toolbar/paint.d.ts +3 -0
- package/dist/toolbar/paint.js +9 -0
- package/dist/toolbar/props.d.ts +48 -0
- package/dist/toolbar/props.js +1 -0
- package/dist/toolbar/strip.svelte.d.ts +14 -0
- package/dist/toolbar/strip.svelte.js +35 -0
- package/dist/toolbar/views.d.ts +14 -0
- package/dist/toolbar/views.js +1 -0
- package/dist/toolbar.d.ts +16 -0
- package/dist/toolbar.js +12 -0
- package/dist/view-manager/readers.d.ts +19 -0
- package/dist/view-manager/readers.js +17 -0
- package/dist/view-manager.d.ts +11 -0
- package/dist/view-manager.js +12 -0
- package/package.json +195 -3
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The generic readers every plugin binding is built from: a value derived from the kernel, a
|
|
3
|
+
* plugin's capability (as a handle, or the raw object), a value selected from it, and its events.
|
|
4
|
+
*
|
|
5
|
+
* Call them while a component is created, like every `use…()` function: they read the viewer and
|
|
6
|
+
* the document scope from context, and the event readers clean up when the component goes away.
|
|
7
|
+
*/
|
|
8
|
+
import { untrack } from 'svelte';
|
|
9
|
+
import { standInFor } from '@embedpdf/core';
|
|
10
|
+
import { documentScopeOf, useKernelBinding } from './binding.svelte.js';
|
|
11
|
+
import { capabilityHandle } from './capability-handle.js';
|
|
12
|
+
import { currentOf, derivedValue, valueOf, } from './values.svelte.js';
|
|
13
|
+
/** Equal when the two arrays hold the same items in the same order. */
|
|
14
|
+
export const shallowArray = (left, right) => left === right || (left.length === right.length && left.every((item, i) => item === right[i]));
|
|
15
|
+
/**
|
|
16
|
+
* A value derived from the kernel, computed again after every kernel change and passed on only
|
|
17
|
+
* when `isEqual` says it changed.
|
|
18
|
+
*/
|
|
19
|
+
export function useKernelValue(select, isEqual = Object.is) {
|
|
20
|
+
const binding = useKernelBinding();
|
|
21
|
+
return currentOf(derivedValue(() => {
|
|
22
|
+
binding.track();
|
|
23
|
+
return select(binding.kernel);
|
|
24
|
+
}, isEqual));
|
|
25
|
+
}
|
|
26
|
+
/** The active document's id, or null with none open. */
|
|
27
|
+
export function useActiveDocumentId() {
|
|
28
|
+
return useKernelValue((kernel) => kernel.documents.getActiveId());
|
|
29
|
+
}
|
|
30
|
+
/** The document the nearest `<DocumentScope>` names, or null when this subtree follows the active one. */
|
|
31
|
+
export function useDocumentScope() {
|
|
32
|
+
return currentOf(documentScopeOf());
|
|
33
|
+
}
|
|
34
|
+
/** The document this subtree talks to: the nearest `<DocumentScope>`'s, else the active one. */
|
|
35
|
+
export function useDocumentId() {
|
|
36
|
+
const scoped = documentScopeOf();
|
|
37
|
+
return useKernelValue((kernel) => scoped() ?? kernel.documents.getActiveId());
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* A plugin's capability, as a handle that is always the capability of the document in scope
|
|
41
|
+
* (see `./capability-handle.ts`). Outside a ready document a document plugin's calls refuse with
|
|
42
|
+
* `not-ready` (a method that returns a promise rejects), and its settings calls still work. A token no plugin provides throws now: a setup
|
|
43
|
+
* mistake. The token may be a function, for a component whose token is a prop.
|
|
44
|
+
*/
|
|
45
|
+
export function useCapability(token) {
|
|
46
|
+
const binding = useKernelBinding();
|
|
47
|
+
const { kernel } = binding;
|
|
48
|
+
const scoped = documentScopeOf();
|
|
49
|
+
const initial = untrack(() => valueOf(token));
|
|
50
|
+
if (kernel.scopeOf(initial) !== 'document')
|
|
51
|
+
kernel.capability(initial);
|
|
52
|
+
return capabilityHandle(() => {
|
|
53
|
+
const current = valueOf(token);
|
|
54
|
+
return kernel.tryCapability(current, scoped() ?? undefined) ?? standInFor(kernel, current);
|
|
55
|
+
}, () => binding.track());
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The capability itself, or null while the token can't resolve (no plugin, no document, or a
|
|
59
|
+
* document that isn't ready yet). The object is the plugin's own, so it can be handed to code
|
|
60
|
+
* that keeps it, such as an effect that registers something with it.
|
|
61
|
+
*/
|
|
62
|
+
export function useOptionalCapability(token) {
|
|
63
|
+
const binding = useKernelBinding();
|
|
64
|
+
const scoped = documentScopeOf();
|
|
65
|
+
return currentOf(derivedValue(() => {
|
|
66
|
+
binding.track();
|
|
67
|
+
return binding.kernel.tryCapability(valueOf(token), scoped() ?? undefined);
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* A value selected from a capability. Strict: while the token can't resolve, reading it throws
|
|
72
|
+
* the kernel's reason (no document, the document is loading), for code that knows a document
|
|
73
|
+
* exists, such as anything inside a `<DocumentGate>`. {@link useOptionalSelector} is its total twin.
|
|
74
|
+
*/
|
|
75
|
+
export function useSelector(token, select, isEqual = Object.is) {
|
|
76
|
+
const binding = useKernelBinding();
|
|
77
|
+
const scoped = documentScopeOf();
|
|
78
|
+
return currentOf(derivedValue(() => {
|
|
79
|
+
binding.track();
|
|
80
|
+
const current = valueOf(token);
|
|
81
|
+
const documentId = scoped() ?? undefined;
|
|
82
|
+
const capability = binding.kernel.tryCapability(current, documentId) ??
|
|
83
|
+
binding.kernel.capability(current, documentId);
|
|
84
|
+
return select(capability);
|
|
85
|
+
}, isEqual));
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* A value selected from a capability, or `fallback` while the token can't resolve: for chrome
|
|
89
|
+
* that stays mounted while no document is open (a zoom readout). A read through a capability
|
|
90
|
+
* whose document closed a moment ago gives `fallback` too.
|
|
91
|
+
*/
|
|
92
|
+
export function useOptionalSelector(token, select, fallback, isEqual = Object.is) {
|
|
93
|
+
const binding = useKernelBinding();
|
|
94
|
+
const scoped = documentScopeOf();
|
|
95
|
+
return currentOf(derivedValue(() => {
|
|
96
|
+
binding.track();
|
|
97
|
+
const capability = binding.kernel.tryCapability(valueOf(token), scoped() ?? undefined);
|
|
98
|
+
if (capability === null)
|
|
99
|
+
return fallback;
|
|
100
|
+
try {
|
|
101
|
+
return select(capability);
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return fallback;
|
|
105
|
+
}
|
|
106
|
+
}, isEqual));
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Subscribe to one of a capability's events while the component lives:
|
|
110
|
+
* `useCapabilityEvent(StageToken, (stage) => stage.onZoomChanged, handler)`. It subscribes again
|
|
111
|
+
* when the document in scope changes, and not at all without one. Events say what happened;
|
|
112
|
+
* the current value is a state reader's.
|
|
113
|
+
*/
|
|
114
|
+
export function useCapabilityEvent(token, select, handler) {
|
|
115
|
+
const capability = useOptionalCapability(token);
|
|
116
|
+
$effect(() => {
|
|
117
|
+
const current = capability.current;
|
|
118
|
+
if (!current)
|
|
119
|
+
return;
|
|
120
|
+
return untrack(() => select(current)((event) => handler(event)));
|
|
121
|
+
});
|
|
122
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { CapabilityToken, SettingsOf, StateDeclaration } from '@embedpdf/core';
|
|
2
|
+
import { type KernelBinding } from './binding.svelte.js';
|
|
3
|
+
import { type CurrentValue, type MaybeGetter } from './values.svelte.js';
|
|
4
|
+
/** A declared state's reader: the whole state, or the value `select` picks from it. */
|
|
5
|
+
export interface StateReader<State extends object> {
|
|
6
|
+
(): Readonly<State>;
|
|
7
|
+
<Selected>(select: (state: State) => Selected): CurrentValue<Selected>;
|
|
8
|
+
}
|
|
9
|
+
/** A plugin's settings reader: the settings, or the value `select` picks from them. */
|
|
10
|
+
export interface SettingsReader<Settings extends object> {
|
|
11
|
+
(): Readonly<Settings>;
|
|
12
|
+
<Selected>(select: (settings: Settings) => Selected): CurrentValue<Selected>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The whole state, read through the capability `token` resolves for this subtree's document, or
|
|
16
|
+
* `empty` while it can't resolve. Resolved on every read: a document that closes reads as `empty`,
|
|
17
|
+
* never through its closed capability.
|
|
18
|
+
*/
|
|
19
|
+
export declare function declaredState<Capability, State extends object>(binding: KernelBinding, token: MaybeGetter<CapabilityToken<Capability>>, read: (capability: Capability) => State, empty: State): () => State;
|
|
20
|
+
/** The reader's two forms over one getter: a reactive object with `keys`, or a selected value. */
|
|
21
|
+
export declare function readRecord<Record extends object, Selected>(whole: () => Record, keys: readonly (keyof Record)[], select: ((record: Record) => Selected) | undefined): Readonly<Record> | CurrentValue<Selected>;
|
|
22
|
+
/**
|
|
23
|
+
* Turn a state declaration into its reader. It reads this subtree's document (the nearest
|
|
24
|
+
* `<DocumentScope>`, else the active one) and gives the declaration's `empty` while that
|
|
25
|
+
* document is missing or not ready, so it works anywhere. State the plugin loads on demand
|
|
26
|
+
* (the declaration's `ensure`) loads once a ready document's capability is in scope.
|
|
27
|
+
*/
|
|
28
|
+
export declare function stateReader<Capability, State extends object>(declaration: StateDeclaration<Capability, State>): StateReader<State>;
|
|
29
|
+
/**
|
|
30
|
+
* Turn a plugin's token into its settings reader. A plugin's settings belong to the plugin as
|
|
31
|
+
* the app registered it, not to a document, so the reader works before the first document opens
|
|
32
|
+
* and every document shows the same settings. `getSettings()` keeps its object until a setting
|
|
33
|
+
* changes. A token whose plugin isn't installed, or has no settings, throws: a setup mistake.
|
|
34
|
+
*/
|
|
35
|
+
export declare function settingsReader<Capability>(token: CapabilityToken<Capability>): SettingsReader<SettingsOf<Capability> & object>;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declared state and settings as Svelte readers. A plugin declares its state once with
|
|
3
|
+
* `defineState` and its settings once in its definition (both in `@embedpdf/core`), and its
|
|
4
|
+
* Svelte bindings are one line each:
|
|
5
|
+
*
|
|
6
|
+
* export const useSearchState = stateReader(searchState);
|
|
7
|
+
* export const useSearchSettings = settingsReader(SearchToken);
|
|
8
|
+
*
|
|
9
|
+
* Called with no argument, a reader returns a reactive object (`state.hitCount`), one derived
|
|
10
|
+
* value per field. Called with a selector, it returns the value the selector picks as
|
|
11
|
+
* `{ current }`, compared field by field so a fresh object passes nothing on until a field changes.
|
|
12
|
+
*/
|
|
13
|
+
import { untrack } from 'svelte';
|
|
14
|
+
import { shallowEqual } from '@embedpdf/core';
|
|
15
|
+
import { documentScopeOf, useKernelBinding } from './binding.svelte.js';
|
|
16
|
+
import { currentOf, derivedValue, reactiveRecord, valueOf, } from './values.svelte.js';
|
|
17
|
+
/**
|
|
18
|
+
* The whole state, read through the capability `token` resolves for this subtree's document, or
|
|
19
|
+
* `empty` while it can't resolve. Resolved on every read: a document that closes reads as `empty`,
|
|
20
|
+
* never through its closed capability.
|
|
21
|
+
*/
|
|
22
|
+
export function declaredState(binding, token, read, empty) {
|
|
23
|
+
const scoped = documentScopeOf();
|
|
24
|
+
return derivedValue(() => {
|
|
25
|
+
binding.track();
|
|
26
|
+
const capability = binding.kernel.tryCapability(valueOf(token), scoped() ?? undefined);
|
|
27
|
+
return capability ? read(capability) : empty;
|
|
28
|
+
}, shallowEqual);
|
|
29
|
+
}
|
|
30
|
+
/** The reader's two forms over one getter: a reactive object with `keys`, or a selected value. */
|
|
31
|
+
export function readRecord(whole, keys, select) {
|
|
32
|
+
if (!select)
|
|
33
|
+
return reactiveRecord(whole, keys);
|
|
34
|
+
return currentOf(derivedValue(() => select(whole()), shallowEqual));
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Load state the plugin loads on demand (`ensure`) for each capability the reader comes to read:
|
|
38
|
+
* once a ready document's capability is in scope, and again for the next document's.
|
|
39
|
+
*/
|
|
40
|
+
function ensureWhileRead(binding, token, ensure) {
|
|
41
|
+
const scoped = documentScopeOf();
|
|
42
|
+
let ensured = null;
|
|
43
|
+
$effect(() => {
|
|
44
|
+
binding.track();
|
|
45
|
+
const capability = binding.kernel.tryCapability(token, scoped() ?? undefined);
|
|
46
|
+
if (!capability || capability === ensured)
|
|
47
|
+
return;
|
|
48
|
+
ensured = capability;
|
|
49
|
+
// The state says when the load fails (its status), so the rejection has nothing to add.
|
|
50
|
+
untrack(() => ensure(capability).catch(() => { }));
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Turn a state declaration into its reader. It reads this subtree's document (the nearest
|
|
55
|
+
* `<DocumentScope>`, else the active one) and gives the declaration's `empty` while that
|
|
56
|
+
* document is missing or not ready, so it works anywhere. State the plugin loads on demand
|
|
57
|
+
* (the declaration's `ensure`) loads once a ready document's capability is in scope.
|
|
58
|
+
*/
|
|
59
|
+
export function stateReader(declaration) {
|
|
60
|
+
const keys = Object.keys(declaration.empty);
|
|
61
|
+
const { ensure } = declaration;
|
|
62
|
+
return function useDeclaredState(select) {
|
|
63
|
+
const binding = useKernelBinding();
|
|
64
|
+
const whole = declaredState(binding, declaration.token, declaration.read, declaration.empty);
|
|
65
|
+
if (ensure)
|
|
66
|
+
ensureWhileRead(binding, declaration.token, ensure);
|
|
67
|
+
return readRecord(whole, keys, select);
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/** A plugin's settings through the kernel: the same with or without a document. */
|
|
71
|
+
function settingsOf(kernel, token) {
|
|
72
|
+
return kernel.settingsOf(token).getSettings();
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Turn a plugin's token into its settings reader. A plugin's settings belong to the plugin as
|
|
76
|
+
* the app registered it, not to a document, so the reader works before the first document opens
|
|
77
|
+
* and every document shows the same settings. `getSettings()` keeps its object until a setting
|
|
78
|
+
* changes. A token whose plugin isn't installed, or has no settings, throws: a setup mistake.
|
|
79
|
+
*/
|
|
80
|
+
export function settingsReader(token) {
|
|
81
|
+
return function useSettings(select) {
|
|
82
|
+
const binding = useKernelBinding();
|
|
83
|
+
const initial = settingsOf(binding.kernel, token);
|
|
84
|
+
const whole = derivedValue(() => {
|
|
85
|
+
binding.track();
|
|
86
|
+
return settingsOf(binding.kernel, token);
|
|
87
|
+
}, shallowEqual);
|
|
88
|
+
return readRecord(whole, Object.keys(initial), select);
|
|
89
|
+
};
|
|
90
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `epdfTheme()`: a theme written with setting names, as a `style` for the element around your
|
|
3
|
+
* viewer. The variables and their lookup are framework-free (`@embedpdf/web`); this writes them
|
|
4
|
+
* as the CSS text a Svelte `style` attribute takes.
|
|
5
|
+
*/
|
|
6
|
+
import { type EpdfTheme } from '@embedpdf/web';
|
|
7
|
+
export type { EpdfTheme } from '@embedpdf/web';
|
|
8
|
+
/**
|
|
9
|
+
* The CSS variables of a theme, for a `style` attribute: `<div style={epdfTheme({ accent })}>`.
|
|
10
|
+
* Everything inside the element follows them, and a CSS variable wins over any setting.
|
|
11
|
+
*/
|
|
12
|
+
export declare function epdfTheme(theme: EpdfTheme): string;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `epdfTheme()`: a theme written with setting names, as a `style` for the element around your
|
|
3
|
+
* viewer. The variables and their lookup are framework-free (`@embedpdf/web`); this writes them
|
|
4
|
+
* as the CSS text a Svelte `style` attribute takes.
|
|
5
|
+
*/
|
|
6
|
+
import { epdfThemeVariables } from '@embedpdf/web';
|
|
7
|
+
/**
|
|
8
|
+
* The CSS variables of a theme, for a `style` attribute: `<div style={epdfTheme({ accent })}>`.
|
|
9
|
+
* Everything inside the element follows them, and a CSS variable wins over any setting.
|
|
10
|
+
*/
|
|
11
|
+
export function epdfTheme(theme) {
|
|
12
|
+
return Object.entries(epdfThemeVariables(theme))
|
|
13
|
+
.map(([name, value]) => `${name}: ${value};`)
|
|
14
|
+
.join(' ');
|
|
15
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two shapes a reader returns, and the derived value both are made of.
|
|
3
|
+
*
|
|
4
|
+
* - One value is `{ current }`, like Svelte's own `MediaQuery`: `pages.current`.
|
|
5
|
+
* - A record of named values (a plugin's state, its settings) is a reactive object whose fields
|
|
6
|
+
* are getters: `state.zoomLevel`. Each field is its own `$derived`, so a template or an effect
|
|
7
|
+
* that reads `zoomLevel` runs again only when `zoomLevel` changes.
|
|
8
|
+
*/
|
|
9
|
+
/** A value that changes: read `current` in a template, a `$derived` or an effect. */
|
|
10
|
+
export interface CurrentValue<T> {
|
|
11
|
+
readonly current: T;
|
|
12
|
+
}
|
|
13
|
+
/** An argument that may change: the value, or a function that returns it (`() => note.ref`). */
|
|
14
|
+
export type MaybeGetter<T> = T | (() => T);
|
|
15
|
+
/** The value of a {@link MaybeGetter}. Only for values that are never functions themselves. */
|
|
16
|
+
export declare function valueOf<T>(value: MaybeGetter<T>): T;
|
|
17
|
+
/**
|
|
18
|
+
* A `$derived` that keeps its last value while `isEqual` says the new one is the same, so a value
|
|
19
|
+
* built fresh on every read (an object a selector returns) passes nothing on until a field changes.
|
|
20
|
+
*/
|
|
21
|
+
export declare function derivedValue<T>(compute: () => T, isEqual?: (left: T, right: T) => boolean): () => T;
|
|
22
|
+
/** `{ current }` over a getter. */
|
|
23
|
+
export declare function currentOf<T>(read: () => T): CurrentValue<T>;
|
|
24
|
+
/**
|
|
25
|
+
* A reactive object with `keys` as getters over `whole()`, each its own derived value. The keys
|
|
26
|
+
* are fixed when it is made: a declared state's `empty`, or the settings it starts with.
|
|
27
|
+
*/
|
|
28
|
+
export declare function reactiveRecord<Record extends object>(whole: () => Record, keys: readonly (keyof Record)[]): Readonly<Record>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two shapes a reader returns, and the derived value both are made of.
|
|
3
|
+
*
|
|
4
|
+
* - One value is `{ current }`, like Svelte's own `MediaQuery`: `pages.current`.
|
|
5
|
+
* - A record of named values (a plugin's state, its settings) is a reactive object whose fields
|
|
6
|
+
* are getters: `state.zoomLevel`. Each field is its own `$derived`, so a template or an effect
|
|
7
|
+
* that reads `zoomLevel` runs again only when `zoomLevel` changes.
|
|
8
|
+
*/
|
|
9
|
+
/** The value of a {@link MaybeGetter}. Only for values that are never functions themselves. */
|
|
10
|
+
export function valueOf(value) {
|
|
11
|
+
return typeof value === 'function' ? value() : value;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* A `$derived` that keeps its last value while `isEqual` says the new one is the same, so a value
|
|
15
|
+
* built fresh on every read (an object a selector returns) passes nothing on until a field changes.
|
|
16
|
+
*/
|
|
17
|
+
export function derivedValue(compute, isEqual = Object.is) {
|
|
18
|
+
let last = null;
|
|
19
|
+
const value = $derived.by(() => {
|
|
20
|
+
const next = compute();
|
|
21
|
+
if (last !== null && isEqual(last.value, next))
|
|
22
|
+
return last.value;
|
|
23
|
+
last = { value: next };
|
|
24
|
+
return next;
|
|
25
|
+
});
|
|
26
|
+
return () => value;
|
|
27
|
+
}
|
|
28
|
+
/** `{ current }` over a getter. */
|
|
29
|
+
export function currentOf(read) {
|
|
30
|
+
return {
|
|
31
|
+
get current() {
|
|
32
|
+
return read();
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/** One field of a record, as its own `$derived`: it passes a change on only when the field changed. */
|
|
37
|
+
function fieldOf(whole, key) {
|
|
38
|
+
const field = $derived(whole()[key]);
|
|
39
|
+
return () => field;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* A reactive object with `keys` as getters over `whole()`, each its own derived value. The keys
|
|
43
|
+
* are fixed when it is made: a declared state's `empty`, or the settings it starts with.
|
|
44
|
+
*/
|
|
45
|
+
export function reactiveRecord(whole, keys) {
|
|
46
|
+
const record = {};
|
|
47
|
+
for (const key of keys) {
|
|
48
|
+
Object.defineProperty(record, key, { get: fieldOf(whole, key), enumerable: true });
|
|
49
|
+
}
|
|
50
|
+
return record;
|
|
51
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @embedpdf/svelte/runtime — the generic binding.
|
|
3
|
+
*
|
|
4
|
+
* `<Viewer>` owns the kernel, and `<KernelProvider>` gives a subtree a kernel someone else owns;
|
|
5
|
+
* the readers turn its one change stream into Svelte reactivity and resolve capabilities against
|
|
6
|
+
* the document in scope (the active one, or a `<DocumentScope>`'s), with a stand-in while there is
|
|
7
|
+
* none; the page context is the seam every layer draws through. Every plugin binding is built from
|
|
8
|
+
* these. How to add one: this package's README.
|
|
9
|
+
*/
|
|
10
|
+
export * from '@embedpdf/core';
|
|
11
|
+
export { mountWebFont, saveFile } from '@embedpdf/web';
|
|
12
|
+
export { default as Viewer } from './runtime/Viewer.svelte';
|
|
13
|
+
export { default as KernelProvider } from './runtime/KernelProvider.svelte';
|
|
14
|
+
export { default as DocumentGate } from './runtime/DocumentGate.svelte';
|
|
15
|
+
export { default as DocumentScope } from './runtime/DocumentScope.svelte';
|
|
16
|
+
export type { DocumentGateProps, DocumentScopeProps, KernelProviderProps, ViewerProps, } from './runtime/props.js';
|
|
17
|
+
export { useKernel } from './runtime/binding.svelte.js';
|
|
18
|
+
export { shallowArray, useActiveDocumentId, useCapability, useCapabilityEvent, useDocumentId, useDocumentScope, useKernelValue, useOptionalCapability, useOptionalSelector, useSelector, } from './runtime/readers.svelte.js';
|
|
19
|
+
export { useDocument, useDocuments, useDocumentsEvent, useDocumentsState, usePageList, useViewerSettings, } from './runtime/documents.svelte.js';
|
|
20
|
+
export { settingsReader, stateReader } from './runtime/state.svelte.js';
|
|
21
|
+
export type { SettingsReader, StateReader } from './runtime/state.svelte.js';
|
|
22
|
+
export type { CurrentValue, MaybeGetter } from './runtime/values.svelte.js';
|
|
23
|
+
export { makePageContext, setPageContext, usePage } from './runtime/page.js';
|
|
24
|
+
export type { PageContextValue } from './runtime/page.js';
|
|
25
|
+
export { epdfTheme } from './runtime/theme.js';
|
|
26
|
+
export type { EpdfTheme } from './runtime/theme.js';
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @embedpdf/svelte/runtime — the generic binding.
|
|
3
|
+
*
|
|
4
|
+
* `<Viewer>` owns the kernel, and `<KernelProvider>` gives a subtree a kernel someone else owns;
|
|
5
|
+
* the readers turn its one change stream into Svelte reactivity and resolve capabilities against
|
|
6
|
+
* the document in scope (the active one, or a `<DocumentScope>`'s), with a stand-in while there is
|
|
7
|
+
* none; the page context is the seam every layer draws through. Every plugin binding is built from
|
|
8
|
+
* these. How to add one: this package's README.
|
|
9
|
+
*/
|
|
10
|
+
// Registration travels with the UI: the kernel's types, tokens and helpers come from here too.
|
|
11
|
+
export * from '@embedpdf/core';
|
|
12
|
+
// What a page with a viewer needs from the browser: handing bytes to the user as a download,
|
|
13
|
+
// and a font the engine draws with, for text you draw yourself.
|
|
14
|
+
export { mountWebFont, saveFile } from '@embedpdf/web';
|
|
15
|
+
export { default as Viewer } from './runtime/Viewer.svelte';
|
|
16
|
+
export { default as KernelProvider } from './runtime/KernelProvider.svelte';
|
|
17
|
+
export { default as DocumentGate } from './runtime/DocumentGate.svelte';
|
|
18
|
+
export { default as DocumentScope } from './runtime/DocumentScope.svelte';
|
|
19
|
+
export { useKernel } from './runtime/binding.svelte.js';
|
|
20
|
+
export { shallowArray, useActiveDocumentId, useCapability, useCapabilityEvent, useDocumentId, useDocumentScope, useKernelValue, useOptionalCapability, useOptionalSelector, useSelector, } from './runtime/readers.svelte.js';
|
|
21
|
+
export { useDocument, useDocuments, useDocumentsEvent, useDocumentsState, usePageList, useViewerSettings, } from './runtime/documents.svelte.js';
|
|
22
|
+
export { settingsReader, stateReader } from './runtime/state.svelte.js';
|
|
23
|
+
export { makePageContext, setPageContext, usePage } from './runtime/page.js';
|
|
24
|
+
// A theme written with setting names, as the style for the element around a viewer.
|
|
25
|
+
export { epdfTheme } from './runtime/theme.js';
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
The search matches on one page, the selection layer's twin: it reads the page's matches in page
|
|
3
|
+
space from the plugin and maps them through the page's transform, in the colors of the plugin's
|
|
4
|
+
`highlight` setting, which the `--epdf-search-*` CSS variables win over. It calls no engine:
|
|
5
|
+
searching is app chrome's, through `useSearch()`.
|
|
6
|
+
-->
|
|
7
|
+
<script lang="ts">
|
|
8
|
+
import type { SearchHit } from '@embedpdf/plugin-search';
|
|
9
|
+
import { createClickDetector, paint, searchHighlightsOf } from '@embedpdf/web';
|
|
10
|
+
import { usePage } from '../runtime/page.js';
|
|
11
|
+
import type { SearchLayerProps } from './props.js';
|
|
12
|
+
import { useSearchHits, useSearchSettings, useSearchState } from './readers.svelte.js';
|
|
13
|
+
|
|
14
|
+
let { onHitClick }: SearchLayerProps = $props();
|
|
15
|
+
|
|
16
|
+
const page = usePage();
|
|
17
|
+
// The plugin keeps a page's list until matches land on it, so this redraws only then.
|
|
18
|
+
const hits = useSearchHits(() => page.ref);
|
|
19
|
+
// The record form: `activeHit` passes on only when it is another match (compared by identity).
|
|
20
|
+
const search = useSearchState();
|
|
21
|
+
const highlight = useSearchSettings((settings) => settings.highlight);
|
|
22
|
+
// Tells a click on a match from a drag that starts there (and selects text).
|
|
23
|
+
const clicks = createClickDetector();
|
|
24
|
+
|
|
25
|
+
// Each color is its CSS variable first, then the setting: CSS wins.
|
|
26
|
+
const color = $derived(paint('search-highlight', highlight.current.color));
|
|
27
|
+
const activeColor = $derived(paint('search-highlight-active', highlight.current.activeColor));
|
|
28
|
+
const blendMode = $derived(paint('search-blend-mode', highlight.current.blendMode));
|
|
29
|
+
// One piece per line of each match: a rounded box when upright, its true quad when turned.
|
|
30
|
+
const pieces = $derived(
|
|
31
|
+
searchHighlightsOf(hits.current, {
|
|
32
|
+
active: search.activeHit,
|
|
33
|
+
page: page.transform,
|
|
34
|
+
color,
|
|
35
|
+
activeColor,
|
|
36
|
+
}),
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
// Nothing here stops the press, so it reaches the page as well: a drag that starts on a match
|
|
40
|
+
// selects text, and only a click counts.
|
|
41
|
+
const press = (event: PointerEvent) => clicks.press(event);
|
|
42
|
+
const click = (hit: SearchHit, event: MouseEvent) => {
|
|
43
|
+
if (clicks.isClick(event)) onHitClick?.(hit);
|
|
44
|
+
};
|
|
45
|
+
</script>
|
|
46
|
+
|
|
47
|
+
{#if hits.current.length > 0}
|
|
48
|
+
<div style="position: absolute; inset: 0; pointer-events: none">
|
|
49
|
+
<!-- Only a clickable match takes the pointer; a plain highlight stays inert. A match isn't a
|
|
50
|
+
control of its own: the keyboard moves between matches with the search's next and
|
|
51
|
+
previous. -->
|
|
52
|
+
{#each pieces as piece (piece.key)}
|
|
53
|
+
{#if piece.box}
|
|
54
|
+
<!-- An upright line is a rounded box. -->
|
|
55
|
+
<!-- svelte-ignore a11y_click_events_have_key_events, a11y_no_static_element_interactions -->
|
|
56
|
+
<div
|
|
57
|
+
style:position="absolute"
|
|
58
|
+
style:left="{piece.box.left}px"
|
|
59
|
+
style:top="{piece.box.top}px"
|
|
60
|
+
style:width="{piece.box.width}px"
|
|
61
|
+
style:height="{piece.box.height}px"
|
|
62
|
+
style:background-color={piece.fill}
|
|
63
|
+
style:mix-blend-mode={blendMode}
|
|
64
|
+
style:border-radius="2px"
|
|
65
|
+
style:pointer-events={onHitClick ? 'auto' : undefined}
|
|
66
|
+
style:cursor={onHitClick ? 'pointer' : undefined}
|
|
67
|
+
onpointerdown={onHitClick ? press : undefined}
|
|
68
|
+
onclick={onHitClick ? (event) => click(piece.hit, event) : undefined}
|
|
69
|
+
></div>
|
|
70
|
+
{:else}
|
|
71
|
+
<!-- A turned line draws its true quad. -->
|
|
72
|
+
<svg
|
|
73
|
+
style:position="absolute"
|
|
74
|
+
style:inset="0"
|
|
75
|
+
style:width="100%"
|
|
76
|
+
style:height="100%"
|
|
77
|
+
style:overflow="visible"
|
|
78
|
+
style:mix-blend-mode={blendMode}
|
|
79
|
+
>
|
|
80
|
+
<!-- The fill is in `style`: an SVG attribute doesn't read var(). -->
|
|
81
|
+
<!-- svelte-ignore a11y_click_events_have_key_events, a11y_no_static_element_interactions -->
|
|
82
|
+
<polygon
|
|
83
|
+
points={piece.points}
|
|
84
|
+
style:fill={piece.fill}
|
|
85
|
+
style:pointer-events={onHitClick ? 'auto' : undefined}
|
|
86
|
+
style:cursor={onHitClick ? 'pointer' : undefined}
|
|
87
|
+
onpointerdown={onHitClick ? press : undefined}
|
|
88
|
+
onclick={onHitClick ? (event) => click(piece.hit, event) : undefined}
|
|
89
|
+
/>
|
|
90
|
+
</svg>
|
|
91
|
+
{/if}
|
|
92
|
+
{/each}
|
|
93
|
+
</div>
|
|
94
|
+
{/if}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** The props of `<SearchLayer>`. */
|
|
2
|
+
import type { SearchHit } from '@embedpdf/plugin-search';
|
|
3
|
+
export interface SearchLayerProps {
|
|
4
|
+
/**
|
|
5
|
+
* Make matches clickable: called with the match someone clicks, for example to make it the
|
|
6
|
+
* active one with `search.goToHit(hit)`. The press still reaches the page, so a drag that
|
|
7
|
+
* starts on a match selects text, and only a click calls this. Without it, matches are only
|
|
8
|
+
* paint and the pointer goes straight through.
|
|
9
|
+
*/
|
|
10
|
+
onHitClick?: (hit: SearchHit) => void;
|
|
11
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The search plugin's readers: `useSearch()` (the API), `useSearchState()`,
|
|
3
|
+
* `useSearchSettings()`, `useSearchEvent()`, and `useSearchHits()` for a results list.
|
|
4
|
+
*/
|
|
5
|
+
import type { EventHook, PageRef } from '@embedpdf/core';
|
|
6
|
+
import type { SearchCapability, SearchHit } from '@embedpdf/plugin-search';
|
|
7
|
+
import { type CurrentValue, type MaybeGetter } from '../runtime/values.svelte.js';
|
|
8
|
+
/**
|
|
9
|
+
* The search API (`search()`, `clear()`, `nextHit()`, `goToHit()`, …) for app chrome. A handle,
|
|
10
|
+
* always the capability of the document in scope.
|
|
11
|
+
*/
|
|
12
|
+
export declare function useSearch(): SearchCapability;
|
|
13
|
+
/**
|
|
14
|
+
* The search's state: the query, status, count, active match, progress and error (declared once
|
|
15
|
+
* in `searchState`), as a reactive object (`state.hitCount`). With a selector, the value it picks
|
|
16
|
+
* as `{ current }`. Empty without a document.
|
|
17
|
+
*/
|
|
18
|
+
export declare const useSearchState: import("../index.js").StateReader<{
|
|
19
|
+
query: import("@embedpdf/plugin-search").SearchQuery | null;
|
|
20
|
+
status: import("@embedpdf/plugin-search").SearchStatus;
|
|
21
|
+
hitCount: number;
|
|
22
|
+
activeHitIndex: number;
|
|
23
|
+
activeHit: SearchHit | null;
|
|
24
|
+
progress: import("@embedpdf/plugin-search").SearchProgress;
|
|
25
|
+
error: import("@embedpdf/core").PluginErrorInfo | null;
|
|
26
|
+
}>;
|
|
27
|
+
/** The search settings (`reveal`, `highlight`), with or without a document. */
|
|
28
|
+
export declare const useSearchSettings: import("../index.js").SettingsReader<import("@embedpdf/plugin-search").SearchSettings & object>;
|
|
29
|
+
/**
|
|
30
|
+
* Subscribe to one search event while the component lives:
|
|
31
|
+
* `useSearchEvent((search) => search.onCompleted, handler)`.
|
|
32
|
+
*/
|
|
33
|
+
export declare function useSearchEvent<T>(select: (search: SearchCapability) => EventHook<T>, handler: (event: T) => void): void;
|
|
34
|
+
/**
|
|
35
|
+
* Every match found so far, or one page's (its ref or its index), as `{ current }`: for a results
|
|
36
|
+
* list or a count per thumbnail. A page that changes is passed as a function
|
|
37
|
+
* (`useSearchHits(() => page.ref)`). The plugin keeps each list's identity until matches land on
|
|
38
|
+
* it, so a list redraws only then. Empty without a document, and for a page that has just left
|
|
39
|
+
* the document.
|
|
40
|
+
*/
|
|
41
|
+
export declare function useSearchHits(page?: MaybeGetter<PageRef | number | undefined>): CurrentValue<readonly SearchHit[]>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { SearchToken, searchState } from '@embedpdf/plugin-search';
|
|
2
|
+
import { useCapability, useCapabilityEvent, useOptionalSelector } from '../runtime/readers.svelte.js';
|
|
3
|
+
import { settingsReader, stateReader } from '../runtime/state.svelte.js';
|
|
4
|
+
import { valueOf } from '../runtime/values.svelte.js';
|
|
5
|
+
/**
|
|
6
|
+
* The search API (`search()`, `clear()`, `nextHit()`, `goToHit()`, …) for app chrome. A handle,
|
|
7
|
+
* always the capability of the document in scope.
|
|
8
|
+
*/
|
|
9
|
+
export function useSearch() {
|
|
10
|
+
return useCapability(SearchToken);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The search's state: the query, status, count, active match, progress and error (declared once
|
|
14
|
+
* in `searchState`), as a reactive object (`state.hitCount`). With a selector, the value it picks
|
|
15
|
+
* as `{ current }`. Empty without a document.
|
|
16
|
+
*/
|
|
17
|
+
export const useSearchState = stateReader(searchState);
|
|
18
|
+
/** The search settings (`reveal`, `highlight`), with or without a document. */
|
|
19
|
+
export const useSearchSettings = settingsReader(SearchToken);
|
|
20
|
+
/**
|
|
21
|
+
* Subscribe to one search event while the component lives:
|
|
22
|
+
* `useSearchEvent((search) => search.onCompleted, handler)`.
|
|
23
|
+
*/
|
|
24
|
+
export function useSearchEvent(select, handler) {
|
|
25
|
+
useCapabilityEvent(SearchToken, select, handler);
|
|
26
|
+
}
|
|
27
|
+
const NO_HITS = Object.freeze([]);
|
|
28
|
+
/**
|
|
29
|
+
* Every match found so far, or one page's (its ref or its index), as `{ current }`: for a results
|
|
30
|
+
* list or a count per thumbnail. A page that changes is passed as a function
|
|
31
|
+
* (`useSearchHits(() => page.ref)`). The plugin keeps each list's identity until matches land on
|
|
32
|
+
* it, so a list redraws only then. Empty without a document, and for a page that has just left
|
|
33
|
+
* the document.
|
|
34
|
+
*/
|
|
35
|
+
export function useSearchHits(page) {
|
|
36
|
+
return useOptionalSelector(SearchToken, (search) => {
|
|
37
|
+
const only = valueOf(page);
|
|
38
|
+
return search.listHits(only === undefined ? undefined : { page: only });
|
|
39
|
+
}, NO_HITS);
|
|
40
|
+
}
|
package/dist/search.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @embedpdf/svelte/search — full-text search.
|
|
3
|
+
*
|
|
4
|
+
* `<SearchLayer>` paints the matches on each page (and makes them clickable with `onHitClick`);
|
|
5
|
+
* the readers are the plugin's four, `useSearch()`, `useSearchState()`, `useSearchSettings()` and
|
|
6
|
+
* `useSearchEvent()`, and `useSearchHits()` for a results list.
|
|
7
|
+
*/
|
|
8
|
+
export * from '@embedpdf/plugin-search';
|
|
9
|
+
export { default as SearchLayer } from './search/SearchLayer.svelte';
|
|
10
|
+
export type { SearchLayerProps } from './search/props.js';
|
|
11
|
+
export { useSearch, useSearchEvent, useSearchHits, useSearchSettings, useSearchState, } from './search/readers.svelte.js';
|
package/dist/search.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @embedpdf/svelte/search — full-text search.
|
|
3
|
+
*
|
|
4
|
+
* `<SearchLayer>` paints the matches on each page (and makes them clickable with `onHitClick`);
|
|
5
|
+
* the readers are the plugin's four, `useSearch()`, `useSearchState()`, `useSearchSettings()` and
|
|
6
|
+
* `useSearchEvent()`, and `useSearchHits()` for a results list.
|
|
7
|
+
*/
|
|
8
|
+
// Registration travels with the UI.
|
|
9
|
+
export * from '@embedpdf/plugin-search';
|
|
10
|
+
export { default as SearchLayer } from './search/SearchLayer.svelte';
|
|
11
|
+
export { useSearch, useSearchEvent, useSearchHits, useSearchSettings, useSearchState, } from './search/readers.svelte.js';
|