@embedpdf/svelte 0.0.0-stage → 3.0.0-next.16
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 +51 -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 +28 -0
- package/dist/annotation/text-box.svelte.js +87 -0
- package/dist/annotation.d.ts +32 -0
- package/dist/annotation.js +31 -0
- package/dist/attachment/readers.d.ts +23 -0
- package/dist/attachment/readers.js +21 -0
- package/dist/attachment.d.ts +13 -0
- package/dist/attachment.js +14 -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 +30 -0
- package/dist/index.js +30 -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/outline/readers.d.ts +26 -0
- package/dist/outline/readers.js +22 -0
- package/dist/outline.d.ts +12 -0
- package/dist/outline.js +13 -0
- package/dist/page-edit/readers.d.ts +17 -0
- package/dist/page-edit/readers.js +18 -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 +130 -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 +207 -3
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
The armed stamp's ghost: a see-through picture of the stamp in the exact box a click would place
|
|
3
|
+
it (the plugin computes it with the same fit and clamp as placing it). Every other tool's ghost
|
|
4
|
+
rides the page items like a drawing in progress. The picture's bytes stay in the plugin; this
|
|
5
|
+
owns only the object URL, keyed on the armed stamp: a new arm swaps the picture, a disarm (or
|
|
6
|
+
another tool) drops it.
|
|
7
|
+
-->
|
|
8
|
+
<script lang="ts">
|
|
9
|
+
import { untrack } from 'svelte';
|
|
10
|
+
import {
|
|
11
|
+
AnnotationToken as AnnotationHostToken,
|
|
12
|
+
previewBucket,
|
|
13
|
+
} from '@embedpdf/plugin-annotation/contract/host';
|
|
14
|
+
import { ghostOpacity, loadObjectUrl, rectInPixels } from '@embedpdf/web';
|
|
15
|
+
import type { PageContextValue } from '../runtime/page.js';
|
|
16
|
+
import { useOptionalCapability, useOptionalSelector } from '../runtime/readers.svelte.js';
|
|
17
|
+
|
|
18
|
+
let { page }: { page: PageContextValue } = $props();
|
|
19
|
+
|
|
20
|
+
const capability = useOptionalCapability(AnnotationHostToken);
|
|
21
|
+
const ghost = useOptionalSelector(
|
|
22
|
+
AnnotationHostToken,
|
|
23
|
+
(annotation) => annotation.getImageGhost(page.ref),
|
|
24
|
+
null,
|
|
25
|
+
);
|
|
26
|
+
const armed = useOptionalSelector(
|
|
27
|
+
AnnotationHostToken,
|
|
28
|
+
(annotation) => annotation.getArmedStamp(),
|
|
29
|
+
null,
|
|
30
|
+
);
|
|
31
|
+
// The ghost is a picture of vector artwork, right at one size: ask for the bucket that covers
|
|
32
|
+
// the box's device width (points × device pixels per point), so it stays sharp at every zoom
|
|
33
|
+
// and density. The plugin keeps one picture per bucket.
|
|
34
|
+
const bucket = $derived(
|
|
35
|
+
ghost.current ? previewBucket(ghost.current.box.width * page.transform.renderScale) : 0,
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
let url = $state<string | null>(null);
|
|
39
|
+
|
|
40
|
+
$effect(() => {
|
|
41
|
+
const annotation = capability.current;
|
|
42
|
+
const size = bucket;
|
|
43
|
+
void armed.current;
|
|
44
|
+
if (!annotation || !size) {
|
|
45
|
+
url = null;
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
// The previous bucket's picture stays up until this one arrives: no flicker while a zoom
|
|
49
|
+
// crosses a bucket boundary.
|
|
50
|
+
return untrack(() =>
|
|
51
|
+
loadObjectUrl(
|
|
52
|
+
() => annotation.renderArmedStampPreview(size),
|
|
53
|
+
(next) => (url = next),
|
|
54
|
+
),
|
|
55
|
+
);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const frame = $derived(ghost.current ? rectInPixels(ghost.current.box, page.transform) : null);
|
|
59
|
+
</script>
|
|
60
|
+
|
|
61
|
+
{#if ghost.current && frame && url}
|
|
62
|
+
<!-- The same explicit size as a baked appearance: a global img reset must never clamp it. -->
|
|
63
|
+
<img
|
|
64
|
+
src={url}
|
|
65
|
+
alt=""
|
|
66
|
+
draggable="false"
|
|
67
|
+
style:position="absolute"
|
|
68
|
+
style:left="{frame.left}px"
|
|
69
|
+
style:top="{frame.top}px"
|
|
70
|
+
style:width="{frame.width}px"
|
|
71
|
+
style:height="{frame.height}px"
|
|
72
|
+
style:max-width="none"
|
|
73
|
+
style:max-height="none"
|
|
74
|
+
style:pointer-events="none"
|
|
75
|
+
style:opacity={ghostOpacity(ghost.current.opacity)}
|
|
76
|
+
style:transform={ghost.current.rot ? `rotate(${ghost.current.rot}deg)` : undefined}
|
|
77
|
+
style:transform-origin={ghost.current.rot ? 'center' : undefined}
|
|
78
|
+
/>
|
|
79
|
+
{/if}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { PageContextValue } from '../runtime/page.js';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
page: PageContextValue;
|
|
4
|
+
};
|
|
5
|
+
declare const StampGhost: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
6
|
+
type StampGhost = ReturnType<typeof StampGhost>;
|
|
7
|
+
export default StampGhost;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The selection chrome's paint, following the annotation settings and the viewer's accent live:
|
|
3
|
+
* every color, width and dash as CSS text for a `style` attribute (`annotationChromePaint` from
|
|
4
|
+
* `@embedpdf/web` gives them as records, each its `--epdf-annotation-*` variable first).
|
|
5
|
+
*/
|
|
6
|
+
import type { ChromeSettings } from '@embedpdf/plugin-annotation';
|
|
7
|
+
/** The painted chrome, as CSS text per part. */
|
|
8
|
+
export interface ChromePaintCss {
|
|
9
|
+
/** The selection box. */
|
|
10
|
+
outline: string;
|
|
11
|
+
/** The resize and point handles. */
|
|
12
|
+
handle: string;
|
|
13
|
+
/** The rotation handle. */
|
|
14
|
+
rotationHandle: string;
|
|
15
|
+
/** The rotation handle's stalk: the handle's stroke. */
|
|
16
|
+
rotationStalk: string;
|
|
17
|
+
/** A snapped move's alignment guide. */
|
|
18
|
+
guide: string;
|
|
19
|
+
/** The reference cross and the angle line while turning. */
|
|
20
|
+
rotationGuide: string;
|
|
21
|
+
/** The box dragged to select. */
|
|
22
|
+
marquee: string;
|
|
23
|
+
/** The outline color of a text box while someone types in it. */
|
|
24
|
+
textOutline: string;
|
|
25
|
+
}
|
|
26
|
+
/** The chrome settings and their paint; call it while a component is created. */
|
|
27
|
+
export declare function useChromePaint(): {
|
|
28
|
+
readonly chrome: ChromeSettings;
|
|
29
|
+
readonly css: ChromePaintCss;
|
|
30
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { annotationChromePaint, cssText } from '@embedpdf/web';
|
|
2
|
+
import { useViewerSettings } from '../runtime/documents.svelte.js';
|
|
3
|
+
import { useAnnotationSettings } from './state.js';
|
|
4
|
+
const asCss = (painted) => ({
|
|
5
|
+
outline: cssText(painted.outline),
|
|
6
|
+
handle: cssText(painted.handle),
|
|
7
|
+
rotationHandle: cssText(painted.rotationHandle),
|
|
8
|
+
rotationStalk: cssText({ stroke: painted.rotationHandle.stroke }),
|
|
9
|
+
guide: cssText(painted.guide),
|
|
10
|
+
rotationGuide: cssText(painted.rotationGuide),
|
|
11
|
+
marquee: cssText(painted.marquee),
|
|
12
|
+
textOutline: painted.textOutline,
|
|
13
|
+
});
|
|
14
|
+
/** The chrome settings and their paint; call it while a component is created. */
|
|
15
|
+
export function useChromePaint() {
|
|
16
|
+
const chrome = useAnnotationSettings((settings) => settings.chrome);
|
|
17
|
+
const accent = useViewerSettings((settings) => settings.accent);
|
|
18
|
+
const css = $derived(asCss(annotationChromePaint(chrome.current, accent.current)));
|
|
19
|
+
return {
|
|
20
|
+
get chrome() {
|
|
21
|
+
return chrome.current;
|
|
22
|
+
},
|
|
23
|
+
get css() {
|
|
24
|
+
return css;
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The types an app writes against when it draws annotations its own way: a renderer (which
|
|
3
|
+
* annotations, with which component), the props that component gets, what the layer's `handle`
|
|
4
|
+
* and `rotationHandle` snippets get, the props of the layer and the menus, and what
|
|
5
|
+
* `useRichTextEditor()` and `useCommentThreads()` return.
|
|
6
|
+
*/
|
|
7
|
+
import type { Component, Snippet } from 'svelte';
|
|
8
|
+
import type { Attachment } from 'svelte/attachments';
|
|
9
|
+
import type { CreationDraftAnchor, Point, RenderItem, RotationAnchor } from '@embedpdf/core-annotation';
|
|
10
|
+
import type { Annotation, CommentThread, HandleRole } from '@embedpdf/plugin-annotation';
|
|
11
|
+
import type { AnchoredPlacement } from '@embedpdf/web';
|
|
12
|
+
import type { PageContextValue } from '../runtime/page.js';
|
|
13
|
+
/** The box a renderer draws into: the size to draw at, how it's turned, and how it's scaled. */
|
|
14
|
+
export interface AnnotationFrame {
|
|
15
|
+
/** Its width in pixels at the annotation's 100% size, before its turn: draw at this. */
|
|
16
|
+
width: number;
|
|
17
|
+
/** Its height in pixels at the annotation's 100% size, before its turn: draw at this. */
|
|
18
|
+
height: number;
|
|
19
|
+
/**
|
|
20
|
+
* How it's turned on screen, degrees clockwise: the page's turn and the annotation's own. 0 is
|
|
21
|
+
* upright; turn your content by `-rotation` to keep it upright.
|
|
22
|
+
*/
|
|
23
|
+
rotation: number;
|
|
24
|
+
/**
|
|
25
|
+
* How much the layer scales what you draw, with the page: the zoom, or for an annotation that
|
|
26
|
+
* keeps its size on screen, the zoom up to 1.
|
|
27
|
+
*/
|
|
28
|
+
scale: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* What a renderer's component gets as props: the annotation, the frame to draw into, and the
|
|
32
|
+
* layer's own drawing of it to keep or wrap. The layer keeps handling the pointer (select, move,
|
|
33
|
+
* resize) unless the renderer is `interactive`.
|
|
34
|
+
*/
|
|
35
|
+
export interface AnnotationRendererProps {
|
|
36
|
+
/** The annotation, as `get()` returns it. */
|
|
37
|
+
annotation: Annotation;
|
|
38
|
+
/**
|
|
39
|
+
* The box you draw into. The layer places, turns and scales it like the annotation's own
|
|
40
|
+
* drawing, also during a drag, a resize or a turn. Fill it (`width: 100%; height: 100%`) and
|
|
41
|
+
* draw at the annotation's 100% size: your text and borders scale with the page.
|
|
42
|
+
*/
|
|
43
|
+
frame: AnnotationFrame;
|
|
44
|
+
/** The layer's own drawing of it, filling the frame: `{@render native()}` keeps the original look, to add to it. */
|
|
45
|
+
native: Snippet;
|
|
46
|
+
/** The engine's picture of the annotation as an image (`url`), or `null`. `native` draws it in place. */
|
|
47
|
+
appearance: {
|
|
48
|
+
url: string;
|
|
49
|
+
} | null;
|
|
50
|
+
/** True while the pointer is over it. */
|
|
51
|
+
hovered: boolean;
|
|
52
|
+
/** True while it's selected. */
|
|
53
|
+
selected: boolean;
|
|
54
|
+
/** True when what you draw takes the pointer (see `interactive` on the renderer). */
|
|
55
|
+
interactive: boolean;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* What a sibling plugin's renderer gets for the annotations its behavior owns (the form plugin's
|
|
59
|
+
* fill controls). It places its own controls: `item` is the layer's projection of the annotation
|
|
60
|
+
* (its box, style, text and raster box, in page coordinates), and `page.transform.toPixels()`
|
|
61
|
+
* turns those into the layer's pixels.
|
|
62
|
+
*/
|
|
63
|
+
export interface BehaviorRendererProps {
|
|
64
|
+
annotation: Annotation;
|
|
65
|
+
item: RenderItem;
|
|
66
|
+
page: PageContextValue;
|
|
67
|
+
/** The layer's own drawing of it, in its frame where the layer draws it: `{@render native()}`. */
|
|
68
|
+
native: Snippet;
|
|
69
|
+
hovered: boolean;
|
|
70
|
+
selected: boolean;
|
|
71
|
+
interactive: boolean;
|
|
72
|
+
}
|
|
73
|
+
/** What an `interactive` function is asked: the annotation, and the active tool. */
|
|
74
|
+
export interface AnnotationInteractiveContext {
|
|
75
|
+
annotation: Annotation;
|
|
76
|
+
toolId: string;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* One rule: "draw these annotations with this component". `for` gets the annotation with all its
|
|
80
|
+
* fields; the first renderer that matches wins. Without `interactive` the component only draws:
|
|
81
|
+
* the layer keeps handling the pointer. With `interactive` (or a function asked whenever it
|
|
82
|
+
* matters) the component takes the pointer, and the annotation can't be selected or moved while
|
|
83
|
+
* it does.
|
|
84
|
+
*
|
|
85
|
+
* Define the list once, in `<script>`: the layer registers each entry, and a list written inline
|
|
86
|
+
* in the markup is a new one whenever the markup runs again.
|
|
87
|
+
*
|
|
88
|
+
* `{ behavior, component }` draws what a sibling plugin's behavior owns (the form plugin's fill
|
|
89
|
+
* controls); the plugin decides when it's engaged.
|
|
90
|
+
*/
|
|
91
|
+
export type AnnotationRenderer = {
|
|
92
|
+
behavior: string;
|
|
93
|
+
component: Component<BehaviorRendererProps>;
|
|
94
|
+
} | {
|
|
95
|
+
/** A stable id for the registration (optional; generated). */
|
|
96
|
+
id?: string;
|
|
97
|
+
for: (annotation: Annotation) => boolean;
|
|
98
|
+
component: Component<AnnotationRendererProps>;
|
|
99
|
+
interactive?: boolean | ((context: AnnotationInteractiveContext) => boolean);
|
|
100
|
+
/**
|
|
101
|
+
* Scale what you draw with the page (the default): you draw at the annotation's 100% size.
|
|
102
|
+
* `false`: you draw at its size on screen, and size things yourself from `frame.scale`.
|
|
103
|
+
*/
|
|
104
|
+
scale?: boolean;
|
|
105
|
+
};
|
|
106
|
+
/** What the layer's `handle` snippet gets: one handle to draw. */
|
|
107
|
+
export interface HandleProps {
|
|
108
|
+
/** The handle's center, in pixels on the page. */
|
|
109
|
+
at: Point;
|
|
110
|
+
/** The `size` from the settings, px. */
|
|
111
|
+
size: number;
|
|
112
|
+
/** The selection's rotation (degrees clockwise), so a square handle can turn with it. */
|
|
113
|
+
rotation: number;
|
|
114
|
+
/** A box's `'corner'` or `'side'`, or one `'point'` of a line or a polygon. */
|
|
115
|
+
kind: HandleRole;
|
|
116
|
+
/** True while it's being dragged. */
|
|
117
|
+
active: boolean;
|
|
118
|
+
}
|
|
119
|
+
/** What the layer's `rotationHandle` snippet gets: a handle's props, and where its stalk starts on the box. */
|
|
120
|
+
export interface RotationHandleProps extends Omit<HandleProps, 'kind'> {
|
|
121
|
+
/** Where the stalk starts on the box, in pixels on the page. */
|
|
122
|
+
from: Point;
|
|
123
|
+
}
|
|
124
|
+
export interface AnnotationLayerProps {
|
|
125
|
+
/** Your own look for some annotations ({@link AnnotationRenderer}). Define the list once, in `<script>`. */
|
|
126
|
+
renderers?: AnnotationRenderer[];
|
|
127
|
+
/** Draw each handle yourself, in place of the layer's. The viewer still decides where it can be grabbed. */
|
|
128
|
+
handle?: Snippet<[handle: HandleProps]>;
|
|
129
|
+
/** Draw the rotation handle yourself, in place of the layer's. */
|
|
130
|
+
rotationHandle?: Snippet<[handle: RotationHandleProps]>;
|
|
131
|
+
}
|
|
132
|
+
/** What `useRichTextEditor()` gives the element you draw a text box with. */
|
|
133
|
+
export interface RichTextEditor {
|
|
134
|
+
/** Put it on your element (`{@attach editor.attach}`): it becomes the editor. Render nothing inside it. */
|
|
135
|
+
readonly attach: Attachment<HTMLElement>;
|
|
136
|
+
/** The box's body style as CSS (`style={editor.style}`): font, size, color and alignment. While typing it takes the pointer too. */
|
|
137
|
+
readonly style: string;
|
|
138
|
+
/** True while someone types in the box. */
|
|
139
|
+
readonly editing: boolean;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* A {@link CommentThread} with where its page is shown now. Identity stays `page` (like every
|
|
143
|
+
* annotation surface); these two fields are presentation, following page moves and deletes.
|
|
144
|
+
*/
|
|
145
|
+
export interface CommentThreadView extends CommentThread {
|
|
146
|
+
/** Current 0-based display index of the thread's page; `-1` when the page is no longer in the document (for the one update before it goes). */
|
|
147
|
+
pageIndex: number;
|
|
148
|
+
/** The page's `/PageLabels` label when the PDF declares one ("iv", "A-2"), else the 1-based position as a string: print it as it is. */
|
|
149
|
+
pageLabel: string;
|
|
150
|
+
}
|
|
151
|
+
export interface AnnotationMenuProps {
|
|
152
|
+
/** The menu: buttons that call `useAnnotation()`, built from `useAnnotationState()`. */
|
|
153
|
+
children: Snippet;
|
|
154
|
+
/** The gap in screen pixels between the selection box and the menu. Default 15. */
|
|
155
|
+
gap?: number;
|
|
156
|
+
/** Where the menu sits next to the selection box. Default `'top'`. */
|
|
157
|
+
placement?: AnchoredPlacement;
|
|
158
|
+
}
|
|
159
|
+
export interface AnnotationDraftMenuProps {
|
|
160
|
+
/**
|
|
161
|
+
* The menu, given the shape being drawn (`subtype`, `pointCount`, `minPoints`, `canFinish`, …).
|
|
162
|
+
* The verbs are capability calls: `useAnnotation().draft.finish()` and `.draft.cancel()`.
|
|
163
|
+
*/
|
|
164
|
+
children: Snippet<[draft: CreationDraftAnchor]>;
|
|
165
|
+
/** The gap in screen pixels between the shape being drawn and the menu. Default 8. */
|
|
166
|
+
gap?: number;
|
|
167
|
+
/** Where the menu sits next to the shape being drawn. Default `'top'`. */
|
|
168
|
+
placement?: AnchoredPlacement;
|
|
169
|
+
}
|
|
170
|
+
export interface AnnotationRotationBadgeProps {
|
|
171
|
+
/**
|
|
172
|
+
* The badge, given the rotation in progress (`angle`, degrees clockwise, as the commit will
|
|
173
|
+
* apply it). Without it, the badge shows the angle in the `chrome.readout` colors, when
|
|
174
|
+
* `chrome.readout.enabled`.
|
|
175
|
+
*/
|
|
176
|
+
children?: Snippet<[rotation: RotationAnchor]>;
|
|
177
|
+
/** The gap in screen pixels between the pointer and the badge. Default 16. */
|
|
178
|
+
gap?: number;
|
|
179
|
+
/** Where the badge sits next to the pointer. Default `'right'`. */
|
|
180
|
+
placement?: AnchoredPlacement;
|
|
181
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { EventHook } from '@embedpdf/core';
|
|
2
|
+
import { type Annotation, type AnnotationAnchor, type AnnotationCapability, type AnnotationFilter, type AnnotationProperties, type AnnotationRef, type CommentsApi, type FilePickerProvider, type ToolDefaults } from '@embedpdf/plugin-annotation';
|
|
3
|
+
import { type CurrentValue, type MaybeGetter } from '../runtime/values.svelte.js';
|
|
4
|
+
import type { CommentThreadView } from './props.js';
|
|
5
|
+
/** The API: a handle, always the capability of the document in scope. */
|
|
6
|
+
export declare function useAnnotation(): AnnotationCapability;
|
|
7
|
+
/** Listen to one annotation event while the component lives: `useAnnotationEvent((annotation) => annotation.onCreated, handler)`. */
|
|
8
|
+
export declare function useAnnotationEvent<T>(select: (annotation: AnnotationCapability) => EventHook<T>, handler: (event: T) => void): void;
|
|
9
|
+
/**
|
|
10
|
+
* The annotations matching `filter` (some pages, one kind), in drawing order, as the user sees
|
|
11
|
+
* them: `list.current`, the same array while they stay the same. Empty without a document.
|
|
12
|
+
*/
|
|
13
|
+
export declare function useAnnotationList(filter?: MaybeGetter<AnnotationFilter | undefined>): CurrentValue<readonly Annotation[]>;
|
|
14
|
+
/**
|
|
15
|
+
* A tool's defaults (`defaults.current`): the fields its next annotation starts with, over the
|
|
16
|
+
* engine's. It updates when they change, so a color picker always shows the current color. Empty
|
|
17
|
+
* without a document.
|
|
18
|
+
*/
|
|
19
|
+
export declare function useAnnotationDefaults(toolId: MaybeGetter<string>): CurrentValue<ToolDefaults>;
|
|
20
|
+
/**
|
|
21
|
+
* What a style panel shows (`panel.current`): the selection's properties
|
|
22
|
+
* (`selection.getProperties()`), or, given a tool id, the tool's (`tools.getProperties(id)`). It
|
|
23
|
+
* updates when they change. Empty without a document.
|
|
24
|
+
*/
|
|
25
|
+
export declare function useAnnotationProperties(toolId?: MaybeGetter<string | undefined>): CurrentValue<AnnotationProperties>;
|
|
26
|
+
/**
|
|
27
|
+
* An anchor for `<Anchored>` that keeps a card or a badge attached to one annotation
|
|
28
|
+
* (`anchor.current`): its page and the box around what it shows, following a move as it happens.
|
|
29
|
+
* `null` for `null`, or an annotation that isn't here. It updates when the annotation moves, not
|
|
30
|
+
* while people scroll or zoom: a note that keeps its size on screen hands `<Anchored>` its
|
|
31
|
+
* `boundsIn`.
|
|
32
|
+
*/
|
|
33
|
+
export declare function useAnnotationAnchor(ref: MaybeGetter<AnnotationRef | null>): CurrentValue<AnnotationAnchor | null>;
|
|
34
|
+
/** The comments API: the `comments` part of `useAnnotation()`. Pair it with {@link useCommentThreads} for the threads to show. */
|
|
35
|
+
export declare function useComments(): CommentsApi;
|
|
36
|
+
/**
|
|
37
|
+
* Every comment thread in the document (`threads.current`), in display order (page position, top
|
|
38
|
+
* of page, creation date), each with its page's `pageIndex` and `pageLabel`. Annotation writes
|
|
39
|
+
* (your own, remote ones, the first load) and page moves or deletes update it; the same array
|
|
40
|
+
* between changes.
|
|
41
|
+
*/
|
|
42
|
+
export declare function useCommentThreads(): CurrentValue<CommentThreadView[]>;
|
|
43
|
+
/** The thread holding any of its annotations (the comment, a reply, a state), or `null`: `thread.current`. */
|
|
44
|
+
export declare function useCommentThread(ref: MaybeGetter<AnnotationRef | null>): CurrentValue<CommentThreadView | null>;
|
|
45
|
+
/**
|
|
46
|
+
* The default file-picker provider: the browser's file dialog (from `@embedpdf/web`), honouring
|
|
47
|
+
* the tool's `accept` filter. The adapter fulfils the plugin's DOM-free port; the dialog lives
|
|
48
|
+
* here, never in the plugin.
|
|
49
|
+
*/
|
|
50
|
+
export declare const filePickerProvider: FilePickerProvider;
|
|
51
|
+
/**
|
|
52
|
+
* Install the file-picker provider for the document in scope: the one port behind every
|
|
53
|
+
* click-then-pick tool (a stamp's `'prompt'` source, the file-attachment tool). Call it once, in a
|
|
54
|
+
* component around the pages (not in a page layer). Without an argument it installs
|
|
55
|
+
* {@link filePickerProvider}, so those tools work out of the box; pass your own provider (an
|
|
56
|
+
* asset library, a cloud drive: switch on `request.subtype` / `request.toolId`), or `null` to
|
|
57
|
+
* make them do nothing. Removed when the component goes away. The provider is read once.
|
|
58
|
+
*/
|
|
59
|
+
export declare function useFilePickerProvider(provider?: FilePickerProvider | null): void;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The annotation plugin's readers: the API (`useAnnotation()`), its events, and the reads a
|
|
3
|
+
* component follows on their own, each `{ current }`: the annotations of a filter, a tool's
|
|
4
|
+
* defaults, a style panel's properties, an annotation's anchor, and the comment threads.
|
|
5
|
+
* `useFilePickerProvider()` installs the file dialog behind click-then-pick tools.
|
|
6
|
+
*
|
|
7
|
+
* An argument that changes is a function (`useAnnotationAnchor(() => note.ref)`), read again
|
|
8
|
+
* whenever the value is.
|
|
9
|
+
*/
|
|
10
|
+
import { untrack } from 'svelte';
|
|
11
|
+
import { AnnotationToken, annotationKey, } from '@embedpdf/plugin-annotation';
|
|
12
|
+
// The anchor of one annotation is a host read (the same runtime token, typed wider).
|
|
13
|
+
import { AnnotationToken as AnnotationHostToken } from '@embedpdf/plugin-annotation/contract/host';
|
|
14
|
+
import { enrichCommentThreads, installFilePickerProvider, pickRequestedFile, sameAnnotationAnchor, } from '@embedpdf/web';
|
|
15
|
+
import { devWarn } from '../runtime/dev.js';
|
|
16
|
+
import { shallowArray, useCapability, useCapabilityEvent, useDocumentId, useKernelValue, useOptionalCapability, useOptionalSelector, } from '../runtime/readers.svelte.js';
|
|
17
|
+
import { currentOf, derivedValue, valueOf, } from '../runtime/values.svelte.js';
|
|
18
|
+
/** The API: a handle, always the capability of the document in scope. */
|
|
19
|
+
export function useAnnotation() {
|
|
20
|
+
return useCapability(AnnotationToken);
|
|
21
|
+
}
|
|
22
|
+
/** Listen to one annotation event while the component lives: `useAnnotationEvent((annotation) => annotation.onCreated, handler)`. */
|
|
23
|
+
export function useAnnotationEvent(select, handler) {
|
|
24
|
+
useCapabilityEvent(AnnotationToken, select, handler);
|
|
25
|
+
}
|
|
26
|
+
const NO_ANNOTATIONS = Object.freeze([]);
|
|
27
|
+
/**
|
|
28
|
+
* The annotations matching `filter` (some pages, one kind), in drawing order, as the user sees
|
|
29
|
+
* them: `list.current`, the same array while they stay the same. Empty without a document.
|
|
30
|
+
*/
|
|
31
|
+
export function useAnnotationList(filter) {
|
|
32
|
+
return useOptionalSelector(AnnotationToken, (annotation) => annotation.list(valueOf(filter)), NO_ANNOTATIONS, shallowArray);
|
|
33
|
+
}
|
|
34
|
+
const NO_DEFAULTS = Object.freeze({});
|
|
35
|
+
/**
|
|
36
|
+
* A tool's defaults (`defaults.current`): the fields its next annotation starts with, over the
|
|
37
|
+
* engine's. It updates when they change, so a color picker always shows the current color. Empty
|
|
38
|
+
* without a document.
|
|
39
|
+
*/
|
|
40
|
+
export function useAnnotationDefaults(toolId) {
|
|
41
|
+
return useOptionalSelector(AnnotationToken, (annotation) => annotation.tools.getDefaults(valueOf(toolId)), NO_DEFAULTS);
|
|
42
|
+
}
|
|
43
|
+
const NO_PROPERTIES = Object.freeze({
|
|
44
|
+
properties: [],
|
|
45
|
+
values: {},
|
|
46
|
+
mixed: [],
|
|
47
|
+
});
|
|
48
|
+
/**
|
|
49
|
+
* What a style panel shows (`panel.current`): the selection's properties
|
|
50
|
+
* (`selection.getProperties()`), or, given a tool id, the tool's (`tools.getProperties(id)`). It
|
|
51
|
+
* updates when they change. Empty without a document.
|
|
52
|
+
*/
|
|
53
|
+
export function useAnnotationProperties(toolId) {
|
|
54
|
+
return useOptionalSelector(AnnotationToken, (annotation) => {
|
|
55
|
+
const tool = valueOf(toolId);
|
|
56
|
+
return tool === undefined
|
|
57
|
+
? annotation.selection.getProperties()
|
|
58
|
+
: annotation.tools.getProperties(tool);
|
|
59
|
+
}, NO_PROPERTIES);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* An anchor for `<Anchored>` that keeps a card or a badge attached to one annotation
|
|
63
|
+
* (`anchor.current`): its page and the box around what it shows, following a move as it happens.
|
|
64
|
+
* `null` for `null`, or an annotation that isn't here. It updates when the annotation moves, not
|
|
65
|
+
* while people scroll or zoom: a note that keeps its size on screen hands `<Anchored>` its
|
|
66
|
+
* `boundsIn`.
|
|
67
|
+
*/
|
|
68
|
+
export function useAnnotationAnchor(ref) {
|
|
69
|
+
return useOptionalSelector(AnnotationHostToken, (annotation) => {
|
|
70
|
+
const target = valueOf(ref);
|
|
71
|
+
return target ? annotation.getAnnotationAnchor(target) : null;
|
|
72
|
+
}, null, sameAnnotationAnchor);
|
|
73
|
+
}
|
|
74
|
+
// ── comments ─────────────────────────────────────────────────────────────────
|
|
75
|
+
/** The comments API: the `comments` part of `useAnnotation()`. Pair it with {@link useCommentThreads} for the threads to show. */
|
|
76
|
+
export function useComments() {
|
|
77
|
+
return useCapability(AnnotationToken).comments;
|
|
78
|
+
}
|
|
79
|
+
const NO_PAGES = Object.freeze([]);
|
|
80
|
+
const NO_THREADS = Object.freeze([]);
|
|
81
|
+
/**
|
|
82
|
+
* Every comment thread in the document (`threads.current`), in display order (page position, top
|
|
83
|
+
* of page, creation date), each with its page's `pageIndex` and `pageLabel`. Annotation writes
|
|
84
|
+
* (your own, remote ones, the first load) and page moves or deletes update it; the same array
|
|
85
|
+
* between changes.
|
|
86
|
+
*/
|
|
87
|
+
export function useCommentThreads() {
|
|
88
|
+
const documentId = useDocumentId();
|
|
89
|
+
const threads = useOptionalSelector(AnnotationToken, (annotation) => annotation.comments.listThreads(), NO_THREADS);
|
|
90
|
+
const pages = useKernelValue((kernel) => documentId.current ? kernel.documents.listPages(documentId.current) : NO_PAGES);
|
|
91
|
+
return currentOf(derivedValue(() => enrichCommentThreads(threads.current, pages.current)));
|
|
92
|
+
}
|
|
93
|
+
/** The thread holding any of its annotations (the comment, a reply, a state), or `null`: `thread.current`. */
|
|
94
|
+
export function useCommentThread(ref) {
|
|
95
|
+
const views = useCommentThreads();
|
|
96
|
+
const capability = useOptionalCapability(AnnotationToken);
|
|
97
|
+
return currentOf(derivedValue(() => {
|
|
98
|
+
// Read first: every annotation write gives new threads, so this runs again.
|
|
99
|
+
const shown = views.current;
|
|
100
|
+
const target = valueOf(ref);
|
|
101
|
+
const annotation = capability.current;
|
|
102
|
+
if (target == null || !annotation)
|
|
103
|
+
return null;
|
|
104
|
+
const thread = annotation.comments.getThread(target);
|
|
105
|
+
if (!thread)
|
|
106
|
+
return null;
|
|
107
|
+
const root = annotationKey(thread.root.ref);
|
|
108
|
+
return shown.find((view) => annotationKey(view.root.ref) === root) ?? null;
|
|
109
|
+
}));
|
|
110
|
+
}
|
|
111
|
+
// ── the file picker ──────────────────────────────────────────────────────────
|
|
112
|
+
/**
|
|
113
|
+
* The default file-picker provider: the browser's file dialog (from `@embedpdf/web`), honouring
|
|
114
|
+
* the tool's `accept` filter. The adapter fulfils the plugin's DOM-free port; the dialog lives
|
|
115
|
+
* here, never in the plugin.
|
|
116
|
+
*/
|
|
117
|
+
export const filePickerProvider = pickRequestedFile;
|
|
118
|
+
/**
|
|
119
|
+
* Install the file-picker provider for the document in scope: the one port behind every
|
|
120
|
+
* click-then-pick tool (a stamp's `'prompt'` source, the file-attachment tool). Call it once, in a
|
|
121
|
+
* component around the pages (not in a page layer). Without an argument it installs
|
|
122
|
+
* {@link filePickerProvider}, so those tools work out of the box; pass your own provider (an
|
|
123
|
+
* asset library, a cloud drive: switch on `request.subtype` / `request.toolId`), or `null` to
|
|
124
|
+
* make them do nothing. Removed when the component goes away. The provider is read once.
|
|
125
|
+
*/
|
|
126
|
+
export function useFilePickerProvider(provider = filePickerProvider) {
|
|
127
|
+
const capability = useOptionalCapability(AnnotationToken);
|
|
128
|
+
$effect(() => {
|
|
129
|
+
const annotation = capability.current;
|
|
130
|
+
if (!annotation)
|
|
131
|
+
return;
|
|
132
|
+
// One port per document: a second caller silently replaces the first.
|
|
133
|
+
return untrack(() => installFilePickerProvider(annotation, provider, () => devWarn('file-picker-provider-twice', 'useFilePickerProvider() is called from two mounted components for the same document — ' +
|
|
134
|
+
'the later one wins. Call it once, in a component around the pages.')));
|
|
135
|
+
});
|
|
136
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The annotation state: `status` (`'loading'` until every annotation is in, then `'ready'`), the
|
|
3
|
+
* `selected` annotations, the one `hovered` under the pointer and the text box being typed in
|
|
4
|
+
* (`editing`). A reactive object (`state.selected`), each field updating on its own; with a
|
|
5
|
+
* selector, the value it picks as `{ current }`. Empty without a document.
|
|
6
|
+
*/
|
|
7
|
+
export declare const useAnnotationState: import("../index.js").StateReader<{
|
|
8
|
+
status: import("@embedpdf/core").ResourceStatus;
|
|
9
|
+
selected: readonly import("@embedpdf/plugin-annotation").Annotation[];
|
|
10
|
+
hovered: import("@embedpdf/plugin-annotation").Annotation | null;
|
|
11
|
+
editing: import("@embedpdf/plugin-annotation").Annotation | null;
|
|
12
|
+
}>;
|
|
13
|
+
/**
|
|
14
|
+
* The annotation settings (`snap`, `chrome`, `afterCreate`, `tools`), or the value `select` picks
|
|
15
|
+
* as `{ current }`. They belong to the plugin, so they read without a document; change them with
|
|
16
|
+
* `useAnnotation().updateSettings()`.
|
|
17
|
+
*/
|
|
18
|
+
export declare const useAnnotationSettings: import("../index.js").SettingsReader<import("@embedpdf/plugin-annotation").AnnotationSettings & object>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The annotation readers other feature entries use too (the form plugin reads the selection),
|
|
3
|
+
* kept apart so they don't import the whole annotation entry: the state and the settings, each
|
|
4
|
+
* from its declaration.
|
|
5
|
+
*/
|
|
6
|
+
import { AnnotationToken, annotationState } from '@embedpdf/plugin-annotation/contract';
|
|
7
|
+
import { settingsReader, stateReader } from '../runtime/state.svelte.js';
|
|
8
|
+
/**
|
|
9
|
+
* The annotation state: `status` (`'loading'` until every annotation is in, then `'ready'`), the
|
|
10
|
+
* `selected` annotations, the one `hovered` under the pointer and the text box being typed in
|
|
11
|
+
* (`editing`). A reactive object (`state.selected`), each field updating on its own; with a
|
|
12
|
+
* selector, the value it picks as `{ current }`. Empty without a document.
|
|
13
|
+
*/
|
|
14
|
+
export const useAnnotationState = stateReader(annotationState);
|
|
15
|
+
/**
|
|
16
|
+
* The annotation settings (`snap`, `chrome`, `afterCreate`, `tools`), or the value `select` picks
|
|
17
|
+
* as `{ current }`. They belong to the plugin, so they read without a document; change them with
|
|
18
|
+
* `useAnnotation().updateSettings()`.
|
|
19
|
+
*/
|
|
20
|
+
export const useAnnotationSettings = settingsReader(AnnotationToken);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Attachment } from 'svelte/attachments';
|
|
2
|
+
import type { Annotation, TextItem } from '@embedpdf/plugin-annotation';
|
|
3
|
+
import { type MaybeGetter } from '../runtime/values.svelte.js';
|
|
4
|
+
import type { RichTextEditor } from './props.js';
|
|
5
|
+
/**
|
|
6
|
+
* An attachment that makes its element the editor of the text box `item()` gives, at `scale()`
|
|
7
|
+
* pixels per point. Call it while a component is created. The element must stay empty in the
|
|
8
|
+
* markup: the editor owns what's inside it.
|
|
9
|
+
*/
|
|
10
|
+
export declare function textBoxEditor(item: () => TextItem | null, scale: () => number): Attachment<HTMLElement>;
|
|
11
|
+
/** For the layer, around a look it scales: how much it scales what the look draws. */
|
|
12
|
+
export declare function setLookScale(scale: () => number): void;
|
|
13
|
+
/**
|
|
14
|
+
* Make your own element the editor of a text box you draw yourself (a renderer for free text):
|
|
15
|
+
* it draws the runs, turns typing back into runs, keeps the caret when the style changes, and
|
|
16
|
+
* handles pasting, input methods and the format shortcuts. The formatting calls
|
|
17
|
+
* (`text.toggleFormat`, `selection.update`) work on it as they do on the layer's own.
|
|
18
|
+
*
|
|
19
|
+
* ```svelte
|
|
20
|
+
* const editor = useRichTextEditor(() => annotation);
|
|
21
|
+
* <div {@attach editor.attach} class={['box', editor.editing && 'editing']} style={editor.style}></div>
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* `attach` goes on your element (render nothing inside it: the editor owns what's in it); `style`
|
|
25
|
+
* and `editing` follow the box. `style` fills the element's parent at a legible size: draw the
|
|
26
|
+
* box's frame on the parent.
|
|
27
|
+
*/
|
|
28
|
+
export declare function useRichTextEditor(annotation: MaybeGetter<Annotation>): RichTextEditor;
|