@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,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text boxes you type in. `@embedpdf/web`'s text box editor makes an element the editor of a free
|
|
3
|
+
* text box (rich text, focus and `contentEditable` following the plugin's `editing`, presses kept
|
|
4
|
+
* inside the box), and its follower attaches when the element and the capability are there and
|
|
5
|
+
* takes the box and the scale whenever they change; this binds the follower to Svelte as an
|
|
6
|
+
* attachment. The layer's own text boxes use it, and so does `useRichTextEditor()`, for a renderer
|
|
7
|
+
* that draws its text box itself.
|
|
8
|
+
*/
|
|
9
|
+
import { getContext, hasContext, setContext, untrack } from 'svelte';
|
|
10
|
+
import { annotationKey } from '@embedpdf/core';
|
|
11
|
+
// Typing reaches the plugin through its host lens (drafts, the text selection).
|
|
12
|
+
import { AnnotationToken as AnnotationHostToken } from '@embedpdf/plugin-annotation/contract/host';
|
|
13
|
+
import { createTextBoxEditorFollower, cssText, textBoxEditorScaleOf, textBoxStyleOf, } from '@embedpdf/web';
|
|
14
|
+
import { usePage } from '../runtime/page.js';
|
|
15
|
+
import { useOptionalCapability, useOptionalSelector } from '../runtime/readers.svelte.js';
|
|
16
|
+
import { valueOf } from '../runtime/values.svelte.js';
|
|
17
|
+
/**
|
|
18
|
+
* An attachment that makes its element the editor of the text box `item()` gives, at `scale()`
|
|
19
|
+
* pixels per point. Call it while a component is created. The element must stay empty in the
|
|
20
|
+
* markup: the editor owns what's inside it.
|
|
21
|
+
*/
|
|
22
|
+
export function textBoxEditor(item, scale) {
|
|
23
|
+
const capability = useOptionalCapability(AnnotationHostToken);
|
|
24
|
+
return (element) => {
|
|
25
|
+
const follower = createTextBoxEditorFollower();
|
|
26
|
+
// Another document attaches again; every change of the box or the scale reaches the editor,
|
|
27
|
+
// which redraws only when the text differs, so the caret never jumps while typing; focus
|
|
28
|
+
// follows `editing`.
|
|
29
|
+
$effect(() => {
|
|
30
|
+
const annotation = capability.current;
|
|
31
|
+
const current = item();
|
|
32
|
+
const pixelsPerPoint = scale();
|
|
33
|
+
untrack(() => follower.follow(element, annotation, current, pixelsPerPoint));
|
|
34
|
+
});
|
|
35
|
+
return () => follower.detach();
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
const LOOK_SCALE = Symbol('embedpdf.annotation-look-scale');
|
|
39
|
+
/** For the layer, around a look it scales: how much it scales what the look draws. */
|
|
40
|
+
export function setLookScale(scale) {
|
|
41
|
+
setContext(LOOK_SCALE, scale);
|
|
42
|
+
}
|
|
43
|
+
/** How much the layer scales the look around this component: 1 outside a look, or in one drawn at its size on screen. */
|
|
44
|
+
function lookScaleOf() {
|
|
45
|
+
return hasContext(LOOK_SCALE) ? getContext(LOOK_SCALE) : () => 1;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Make your own element the editor of a text box you draw yourself (a renderer for free text):
|
|
49
|
+
* it draws the runs, turns typing back into runs, keeps the caret when the style changes, and
|
|
50
|
+
* handles pasting, input methods and the format shortcuts. The formatting calls
|
|
51
|
+
* (`text.toggleFormat`, `selection.update`) work on it as they do on the layer's own.
|
|
52
|
+
*
|
|
53
|
+
* ```svelte
|
|
54
|
+
* const editor = useRichTextEditor(() => annotation);
|
|
55
|
+
* <div {@attach editor.attach} class={['box', editor.editing && 'editing']} style={editor.style}></div>
|
|
56
|
+
* ```
|
|
57
|
+
*
|
|
58
|
+
* `attach` goes on your element (render nothing inside it: the editor owns what's in it); `style`
|
|
59
|
+
* and `editing` follow the box.
|
|
60
|
+
*/
|
|
61
|
+
export function useRichTextEditor(annotation) {
|
|
62
|
+
const page = usePage();
|
|
63
|
+
const lookScale = lookScaleOf();
|
|
64
|
+
const item = useOptionalSelector(AnnotationHostToken, (host) => {
|
|
65
|
+
const key = annotationKey(valueOf(annotation).ref);
|
|
66
|
+
const { transform } = page;
|
|
67
|
+
return (host
|
|
68
|
+
.listTextItems(page.ref, { zoom: transform.zoom, rotation: transform.rotation })
|
|
69
|
+
.find((text) => text.ref !== null && annotationKey(text.ref) === key) ?? null);
|
|
70
|
+
}, null);
|
|
71
|
+
// Pixels per point where the element is: inside a scaled look, at the annotation's 100% size;
|
|
72
|
+
// the look's scale does the rest.
|
|
73
|
+
const scale = $derived(textBoxEditorScaleOf(item.current, page.transform, lookScale()));
|
|
74
|
+
// While typing, the element takes the pointer (the caret, a drag over words).
|
|
75
|
+
const style = $derived.by(() => {
|
|
76
|
+
const text = item.current;
|
|
77
|
+
if (!text)
|
|
78
|
+
return '';
|
|
79
|
+
return cssText({
|
|
80
|
+
...textBoxStyleOf(text.css, scale),
|
|
81
|
+
...(text.editing ? { pointerEvents: 'auto' } : {}),
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
const attach = textBoxEditor(() => item.current, () => scale);
|
|
85
|
+
return {
|
|
86
|
+
attach,
|
|
87
|
+
get style() {
|
|
88
|
+
return style;
|
|
89
|
+
},
|
|
90
|
+
get editing() {
|
|
91
|
+
return item.current?.editing ?? false;
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @embedpdf/svelte/annotation — the Svelte view of `@embedpdf/plugin-annotation`.
|
|
3
|
+
*
|
|
4
|
+
* `<AnnotationLayer>` draws a page's annotations, the selection's handles, the tool's preview and
|
|
5
|
+
* the text boxes being typed in, with `renderers` for your own looks and `handle` /
|
|
6
|
+
* `rotationHandle` snippets for your own handles. `<AnnotationMenu>`, `<AnnotationDraftMenu>` and
|
|
7
|
+
* `<AnnotationRotationBadge>` float your UI over the selection, a shape being drawn and a turn in
|
|
8
|
+
* progress.
|
|
9
|
+
*
|
|
10
|
+
* The readers follow every plugin's four: `useAnnotation()` (the API), `useAnnotationState()`
|
|
11
|
+
* (status, selected, hovered, editing), `useAnnotationEvent()` and `useAnnotationSettings()`; the
|
|
12
|
+
* reads a component follows on their own are `{ current }`: `useAnnotationList()`,
|
|
13
|
+
* `useAnnotationDefaults()`, `useAnnotationProperties()`, `useAnnotationAnchor()`, and the
|
|
14
|
+
* comments' `useCommentThreads()` and `useCommentThread()`. `useRichTextEditor()` makes your
|
|
15
|
+
* element a text box's editor (an attachment), and `useFilePickerProvider()` installs the file
|
|
16
|
+
* dialog behind click-then-pick tools.
|
|
17
|
+
*
|
|
18
|
+
* What isn't Svelte lives in `@embedpdf/web`, the same for every framework: the scene as SVG
|
|
19
|
+
* elements, the chrome's paint and pixels, the text box editor, which drawing each annotation gets
|
|
20
|
+
* and the behaviors renderers register, and the object URLs of baked appearances and the stamp
|
|
21
|
+
* ghost.
|
|
22
|
+
*/
|
|
23
|
+
export * from '@embedpdf/plugin-annotation';
|
|
24
|
+
export type { CreationDraftAnchor, RenderItem, LineEnding, LineEndings, Style, AnnotationFlags, FieldValues, TextAlign, TextStyle, } from '@embedpdf/core-annotation';
|
|
25
|
+
export { default as AnnotationLayer } from './annotation/AnnotationLayer.svelte';
|
|
26
|
+
export { default as AnnotationMenu } from './annotation/AnnotationMenu.svelte';
|
|
27
|
+
export { default as AnnotationDraftMenu } from './annotation/AnnotationDraftMenu.svelte';
|
|
28
|
+
export { default as AnnotationRotationBadge } from './annotation/AnnotationRotationBadge.svelte';
|
|
29
|
+
export type { AnnotationDraftMenuProps, AnnotationFrame, AnnotationInteractiveContext, AnnotationLayerProps, AnnotationMenuProps, AnnotationRenderer, AnnotationRendererProps, AnnotationRotationBadgeProps, BehaviorRendererProps, CommentThreadView, HandleProps, RichTextEditor, RotationHandleProps, } from './annotation/props.js';
|
|
30
|
+
export { useAnnotationSettings, useAnnotationState } from './annotation/state.js';
|
|
31
|
+
export { filePickerProvider, useAnnotation, useAnnotationAnchor, useAnnotationDefaults, useAnnotationEvent, useAnnotationList, useAnnotationProperties, useCommentThread, useCommentThreads, useComments, useFilePickerProvider, } from './annotation/readers.svelte.js';
|
|
32
|
+
export { useRichTextEditor } from './annotation/text-box.svelte.js';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @embedpdf/svelte/annotation — the Svelte view of `@embedpdf/plugin-annotation`.
|
|
3
|
+
*
|
|
4
|
+
* `<AnnotationLayer>` draws a page's annotations, the selection's handles, the tool's preview and
|
|
5
|
+
* the text boxes being typed in, with `renderers` for your own looks and `handle` /
|
|
6
|
+
* `rotationHandle` snippets for your own handles. `<AnnotationMenu>`, `<AnnotationDraftMenu>` and
|
|
7
|
+
* `<AnnotationRotationBadge>` float your UI over the selection, a shape being drawn and a turn in
|
|
8
|
+
* progress.
|
|
9
|
+
*
|
|
10
|
+
* The readers follow every plugin's four: `useAnnotation()` (the API), `useAnnotationState()`
|
|
11
|
+
* (status, selected, hovered, editing), `useAnnotationEvent()` and `useAnnotationSettings()`; the
|
|
12
|
+
* reads a component follows on their own are `{ current }`: `useAnnotationList()`,
|
|
13
|
+
* `useAnnotationDefaults()`, `useAnnotationProperties()`, `useAnnotationAnchor()`, and the
|
|
14
|
+
* comments' `useCommentThreads()` and `useCommentThread()`. `useRichTextEditor()` makes your
|
|
15
|
+
* element a text box's editor (an attachment), and `useFilePickerProvider()` installs the file
|
|
16
|
+
* dialog behind click-then-pick tools.
|
|
17
|
+
*
|
|
18
|
+
* What isn't Svelte lives in `@embedpdf/web`, the same for every framework: the scene as SVG
|
|
19
|
+
* elements, the chrome's paint and pixels, the text box editor, which drawing each annotation gets
|
|
20
|
+
* and the behaviors renderers register, and the object URLs of baked appearances and the stamp
|
|
21
|
+
* ghost.
|
|
22
|
+
*/
|
|
23
|
+
// Registration travels with the UI.
|
|
24
|
+
export * from '@embedpdf/plugin-annotation';
|
|
25
|
+
export { default as AnnotationLayer } from './annotation/AnnotationLayer.svelte';
|
|
26
|
+
export { default as AnnotationMenu } from './annotation/AnnotationMenu.svelte';
|
|
27
|
+
export { default as AnnotationDraftMenu } from './annotation/AnnotationDraftMenu.svelte';
|
|
28
|
+
export { default as AnnotationRotationBadge } from './annotation/AnnotationRotationBadge.svelte';
|
|
29
|
+
export { useAnnotationSettings, useAnnotationState } from './annotation/state.js';
|
|
30
|
+
export { filePickerProvider, useAnnotation, useAnnotationAnchor, useAnnotationDefaults, useAnnotationEvent, useAnnotationList, useAnnotationProperties, useCommentThread, useCommentThreads, useComments, useFilePickerProvider, } from './annotation/readers.svelte.js';
|
|
31
|
+
export { useRichTextEditor } from './annotation/text-box.svelte.js';
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { EventHook } from '@embedpdf/core';
|
|
2
|
+
import type { BoundCommand, CommandId, CommandRefusal, CommandsCapability } from '@embedpdf/plugin-commands';
|
|
3
|
+
import { type CurrentValue, type MaybeGetter } from '../runtime/values.svelte.js';
|
|
4
|
+
/**
|
|
5
|
+
* The commands every viewer has: zoom, pages, view rotation, `tool:<id>` for every tool, copy,
|
|
6
|
+
* delete, download and print, with shortcuts and labels in EmbedPDF's eight languages. Spread
|
|
7
|
+
* them into `commandsPlugin({ commands })`.
|
|
8
|
+
*/
|
|
9
|
+
export declare const standardCommands: readonly (import("@embedpdf/plugin-commands").CommandDef | import("@embedpdf/plugin-commands").CommandFamily)[];
|
|
10
|
+
/** The commands API: `execute`, `searchCommands`, `registerCommand`, the categories, the settings calls. */
|
|
11
|
+
export declare function useCommands(): CommandsCapability;
|
|
12
|
+
/** Subscribe to one commands event while the component lives: `useCommandsEvent((commands) => commands.onExecuted, handler)`. */
|
|
13
|
+
export declare function useCommandsEvent<T>(select: (commands: CommandsCapability) => EventHook<T>, handler: (event: T) => void): void;
|
|
14
|
+
/**
|
|
15
|
+
* The commands settings (`commands`, `disabledCategories`, `disabledCommands`, `notAllowed`),
|
|
16
|
+
* with or without a document. Takes a selector.
|
|
17
|
+
*/
|
|
18
|
+
export declare const useCommandsSettings: import("../index.js").SettingsReader<import("@embedpdf/plugin-commands").CommandsSettings & object>;
|
|
19
|
+
/** A shortcut as a tooltip shows it, for this platform: `'⌘K'` on a Mac, `'Ctrl+K'` elsewhere. */
|
|
20
|
+
export declare function formatShortcut(shortcut: string, options?: {
|
|
21
|
+
isMac?: boolean;
|
|
22
|
+
}): string;
|
|
23
|
+
/**
|
|
24
|
+
* A command for this component's document (the nearest `<DocumentScope>`, else the active one),
|
|
25
|
+
* as `{ current }`: its label, icon, state, `run` and `shortcut`. Pass the id as a function to
|
|
26
|
+
* follow a prop: `useCommand(() => id)`. `current` changes only when what the command shows
|
|
27
|
+
* does. Always a command: an id no plugin registered is labelled with its id, neither visible
|
|
28
|
+
* nor enabled, and warns once in development.
|
|
29
|
+
*/
|
|
30
|
+
export declare function useCommand(id: MaybeGetter<string>): CurrentValue<BoundCommand>;
|
|
31
|
+
/** Where {@link useCommandShortcuts} listens, and how it reads `Mod`. */
|
|
32
|
+
export interface CommandShortcutsOptions {
|
|
33
|
+
/** Whether `Mod` is Cmd (a Mac) or Ctrl. Default: what the browser says. */
|
|
34
|
+
isMac?: MaybeGetter<boolean | undefined>;
|
|
35
|
+
/**
|
|
36
|
+
* Listen only while focus is inside this element, for a page with more than one viewer. Pass a
|
|
37
|
+
* function (`() => area`, with `bind:this={area}`): the keys work once the element has mounted.
|
|
38
|
+
*/
|
|
39
|
+
target?: MaybeGetter<HTMLElement | null | undefined>;
|
|
40
|
+
/** Called when a key's command is turned off or not allowed, with why: say so to the user. */
|
|
41
|
+
onRefused?: (commandId: CommandId, refusal: CommandRefusal) => void;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Turn every command's shortcut into a working key, for the active document. Call it once, near
|
|
45
|
+
* the top of your viewer. Keys typed into text fields are left alone, and so is a key whose
|
|
46
|
+
* command can't run right now. A command that's turned off or not allowed still takes its key,
|
|
47
|
+
* and `onRefused` says why. The keys work anywhere on the page; with `target`, only while focus
|
|
48
|
+
* is inside that element. They stop when the component goes away.
|
|
49
|
+
*/
|
|
50
|
+
export declare function useCommandShortcuts(options?: CommandShortcutsOptions): void;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The commands plugin's readers: its API, settings and events, a command as a button needs it,
|
|
3
|
+
* and keyboard shortcuts. A command's state is derived from live state on read, so `useCommand`
|
|
4
|
+
* reads it again after every kernel change and passes it on only when what it shows changed.
|
|
5
|
+
*/
|
|
6
|
+
import { untrack } from 'svelte';
|
|
7
|
+
import { formatShortcut as formatKeys } from '@embedpdf/core-ui';
|
|
8
|
+
import { CommandsToken, boundCommandOf, resolvedCommandsEqual, unknownCommandWarning, unregisteredCommand, } from '@embedpdf/plugin-commands';
|
|
9
|
+
import { CommandsToken as CommandsHostToken } from '@embedpdf/plugin-commands/contract/host';
|
|
10
|
+
import { createStandardCommands } from '@embedpdf/plugin-commands/standard';
|
|
11
|
+
import { bindCommandShortcuts, isMacPlatform, standardCommandsBrowser } from '@embedpdf/web';
|
|
12
|
+
import { useCapability, useCapabilityEvent, useDocumentId, useKernelValue, } from '../runtime/readers.svelte.js';
|
|
13
|
+
import { devWarn } from '../runtime/dev.js';
|
|
14
|
+
import { settingsReader } from '../runtime/state.svelte.js';
|
|
15
|
+
import { currentOf, derivedValue, valueOf, } from '../runtime/values.svelte.js';
|
|
16
|
+
/**
|
|
17
|
+
* The commands every viewer has: zoom, pages, view rotation, `tool:<id>` for every tool, copy,
|
|
18
|
+
* delete, download and print, with shortcuts and labels in EmbedPDF's eight languages. Spread
|
|
19
|
+
* them into `commandsPlugin({ commands })`.
|
|
20
|
+
*/
|
|
21
|
+
export const standardCommands = /* @__PURE__ */ createStandardCommands(standardCommandsBrowser);
|
|
22
|
+
/** The commands API: `execute`, `searchCommands`, `registerCommand`, the categories, the settings calls. */
|
|
23
|
+
export function useCommands() {
|
|
24
|
+
return useCapability(CommandsToken);
|
|
25
|
+
}
|
|
26
|
+
/** Subscribe to one commands event while the component lives: `useCommandsEvent((commands) => commands.onExecuted, handler)`. */
|
|
27
|
+
export function useCommandsEvent(select, handler) {
|
|
28
|
+
useCapabilityEvent(CommandsToken, select, handler);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The commands settings (`commands`, `disabledCategories`, `disabledCommands`, `notAllowed`),
|
|
32
|
+
* with or without a document. Takes a selector.
|
|
33
|
+
*/
|
|
34
|
+
export const useCommandsSettings = settingsReader(CommandsToken);
|
|
35
|
+
/** A shortcut as a tooltip shows it, for this platform: `'⌘K'` on a Mac, `'Ctrl+K'` elsewhere. */
|
|
36
|
+
export function formatShortcut(shortcut, options = {}) {
|
|
37
|
+
return formatKeys(shortcut, { isMac: options.isMac ?? isMacPlatform() });
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* A command for this component's document (the nearest `<DocumentScope>`, else the active one),
|
|
41
|
+
* as `{ current }`: its label, icon, state, `run` and `shortcut`. Pass the id as a function to
|
|
42
|
+
* follow a prop: `useCommand(() => id)`. `current` changes only when what the command shows
|
|
43
|
+
* does. Always a command: an id no plugin registered is labelled with its id, neither visible
|
|
44
|
+
* nor enabled, and warns once in development.
|
|
45
|
+
*/
|
|
46
|
+
export function useCommand(id) {
|
|
47
|
+
const commands = useCapability(CommandsToken);
|
|
48
|
+
const documentId = useDocumentId();
|
|
49
|
+
const resolved = useKernelValue(() => commands.resolveCommand(valueOf(id), documentId.current ?? undefined), resolvedCommandsEqual);
|
|
50
|
+
// A new object only when the resolved command or the document changes.
|
|
51
|
+
return currentOf(derivedValue(() => {
|
|
52
|
+
const command = resolved.current;
|
|
53
|
+
const requested = valueOf(id);
|
|
54
|
+
if (command === null) {
|
|
55
|
+
devWarn(`useCommand:${requested}`, `useCommand(): ${unknownCommandWarning(requested, commands.listCommandIds())}`);
|
|
56
|
+
}
|
|
57
|
+
const scope = documentId.current ?? undefined;
|
|
58
|
+
return boundCommandOf(command ?? unregisteredCommand(requested), (commandId) => commands.execute(commandId, { documentId: scope }), { isMac: isMacPlatform() });
|
|
59
|
+
}));
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Turn every command's shortcut into a working key, for the active document. Call it once, near
|
|
63
|
+
* the top of your viewer. Keys typed into text fields are left alone, and so is a key whose
|
|
64
|
+
* command can't run right now. A command that's turned off or not allowed still takes its key,
|
|
65
|
+
* and `onRefused` says why. The keys work anywhere on the page; with `target`, only while focus
|
|
66
|
+
* is inside that element. They stop when the component goes away.
|
|
67
|
+
*/
|
|
68
|
+
export function useCommandShortcuts(options = {}) {
|
|
69
|
+
const commands = useCapability(CommandsHostToken);
|
|
70
|
+
const scoped = options.target !== undefined;
|
|
71
|
+
$effect(() => {
|
|
72
|
+
const isMac = valueOf(options.isMac);
|
|
73
|
+
const target = valueOf(options.target);
|
|
74
|
+
// A target that hasn't mounted yet binds nothing; this runs again once it has.
|
|
75
|
+
if (scoped && !target)
|
|
76
|
+
return;
|
|
77
|
+
return untrack(() => bindCommandShortcuts(commands, {
|
|
78
|
+
isMac,
|
|
79
|
+
target: target ?? undefined,
|
|
80
|
+
onRefused: (commandId, refusal) => options.onRefused?.(commandId, refusal),
|
|
81
|
+
}));
|
|
82
|
+
});
|
|
83
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @embedpdf/svelte/commands — commands as buttons, shortcuts and a palette.
|
|
3
|
+
*
|
|
4
|
+
* The readers are the commands plugin's API, settings and events; `useCommand()` gives a command
|
|
5
|
+
* with everything a button needs, and `useCommandShortcuts()` turns every shortcut into a key.
|
|
6
|
+
*/
|
|
7
|
+
export * from '@embedpdf/plugin-commands';
|
|
8
|
+
export { formatShortcut, standardCommands, useCommand, useCommandShortcuts, useCommands, useCommandsEvent, useCommandsSettings, } from './commands/readers.svelte.js';
|
|
9
|
+
export type { CommandShortcutsOptions } from './commands/readers.svelte.js';
|
package/dist/commands.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @embedpdf/svelte/commands — commands as buttons, shortcuts and a palette.
|
|
3
|
+
*
|
|
4
|
+
* The readers are the commands plugin's API, settings and events; `useCommand()` gives a command
|
|
5
|
+
* with everything a button needs, and `useCommandShortcuts()` turns every shortcut into a key.
|
|
6
|
+
*/
|
|
7
|
+
// Registration travels with the UI.
|
|
8
|
+
export * from '@embedpdf/plugin-commands';
|
|
9
|
+
export { formatShortcut, standardCommands, useCommand, useCommandShortcuts, useCommands, useCommandsEvent, useCommandsSettings, } from './commands/readers.svelte.js';
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
A push button: a transparent native `<button>` over the field's picture that runs the widget's
|
|
3
|
+
action. It never has an edge: the picture is the button.
|
|
4
|
+
-->
|
|
5
|
+
<script lang="ts">
|
|
6
|
+
import type { FormWidgetItem } from '@embedpdf/plugin-form';
|
|
7
|
+
import type { FormColors } from '@embedpdf/web';
|
|
8
|
+
import { FILL, useWidgetActivation } from './widget.js';
|
|
9
|
+
import WidgetBox from './WidgetBox.svelte';
|
|
10
|
+
|
|
11
|
+
let {
|
|
12
|
+
item,
|
|
13
|
+
colors,
|
|
14
|
+
}: { item: Extract<FormWidgetItem, { control: 'button' }>; colors: FormColors } = $props();
|
|
15
|
+
|
|
16
|
+
const activate = useWidgetActivation(() => item.annotationRef);
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<WidgetBox
|
|
20
|
+
{item}
|
|
21
|
+
{colors}
|
|
22
|
+
edge={false}
|
|
23
|
+
style="cursor: {item.disabled ? 'default' : 'pointer'}"
|
|
24
|
+
>
|
|
25
|
+
<!-- The box is the event surface: a disabled button must not swallow the pointer. -->
|
|
26
|
+
<button
|
|
27
|
+
type="button"
|
|
28
|
+
aria-label={item.label}
|
|
29
|
+
disabled={item.disabled}
|
|
30
|
+
onclick={activate}
|
|
31
|
+
style={FILL}
|
|
32
|
+
style:padding="0"
|
|
33
|
+
style:border="0"
|
|
34
|
+
style:background="transparent"
|
|
35
|
+
style:cursor="inherit"
|
|
36
|
+
style:pointer-events={item.disabled ? 'none' : 'auto'}
|
|
37
|
+
></button>
|
|
38
|
+
</WidgetBox>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { FormWidgetItem } from '@embedpdf/plugin-form';
|
|
2
|
+
import type { FormColors } from '@embedpdf/web';
|
|
3
|
+
type $$ComponentProps = {
|
|
4
|
+
item: Extract<FormWidgetItem, {
|
|
5
|
+
control: 'button';
|
|
6
|
+
}>;
|
|
7
|
+
colors: FormColors;
|
|
8
|
+
};
|
|
9
|
+
declare const ButtonControl: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
10
|
+
type ButtonControl = ReturnType<typeof ButtonControl>;
|
|
11
|
+
export default ButtonControl;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
A dropdown: an invisible native `<select>` over the field's picture. The browser owns the
|
|
3
|
+
dropdown, the engine the resting pixels.
|
|
4
|
+
-->
|
|
5
|
+
<script lang="ts">
|
|
6
|
+
import type { FormWidgetItem } from '@embedpdf/plugin-form';
|
|
7
|
+
import { FormToken as FormHostToken } from '@embedpdf/plugin-form/contract/host';
|
|
8
|
+
import type { FormColors } from '@embedpdf/web';
|
|
9
|
+
import { useCapability } from '../runtime/readers.svelte.js';
|
|
10
|
+
import FormFocusRing from './FormFocusRing.svelte';
|
|
11
|
+
import { FILL, useWidgetActivation } from './widget.js';
|
|
12
|
+
import WidgetBox from './WidgetBox.svelte';
|
|
13
|
+
|
|
14
|
+
let {
|
|
15
|
+
item,
|
|
16
|
+
colors,
|
|
17
|
+
}: { item: Extract<FormWidgetItem, { control: 'choice' }>; colors: FormColors } = $props();
|
|
18
|
+
|
|
19
|
+
const form = useCapability(FormHostToken);
|
|
20
|
+
const activate = useWidgetActivation(() => item.annotationRef);
|
|
21
|
+
let focused = $state(false);
|
|
22
|
+
|
|
23
|
+
function onChange(event: Event & { currentTarget: HTMLSelectElement }) {
|
|
24
|
+
void form.setValue(item.fieldRef, { value: event.currentTarget.value || null });
|
|
25
|
+
}
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<WidgetBox {item} {colors} onclick={activate}>
|
|
29
|
+
<!--
|
|
30
|
+
See-through over the picture. One-way: it shows the field's selection whenever that changes;
|
|
31
|
+
between changes the browser owns it, and a change writes through the plugin. A disabled
|
|
32
|
+
select must not swallow the box's clicks.
|
|
33
|
+
-->
|
|
34
|
+
<select
|
|
35
|
+
value={item.selected[0] ?? ''}
|
|
36
|
+
aria-label={item.label}
|
|
37
|
+
disabled={item.disabled}
|
|
38
|
+
onfocus={() => (focused = true)}
|
|
39
|
+
onblur={() => (focused = false)}
|
|
40
|
+
onchange={onChange}
|
|
41
|
+
style={FILL}
|
|
42
|
+
style:opacity="0"
|
|
43
|
+
style:cursor={item.disabled ? 'default' : 'pointer'}
|
|
44
|
+
style:pointer-events={item.disabled ? 'none' : undefined}
|
|
45
|
+
>
|
|
46
|
+
{#if item.selected.length === 0}<option value=""></option>{/if}
|
|
47
|
+
{#each item.options as option, index (index)}
|
|
48
|
+
<option value={option.value}>{option.label}</option>
|
|
49
|
+
{/each}
|
|
50
|
+
</select>
|
|
51
|
+
<FormFocusRing visible={focused} color={colors.focus} />
|
|
52
|
+
</WidgetBox>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { FormWidgetItem } from '@embedpdf/plugin-form';
|
|
2
|
+
import type { FormColors } from '@embedpdf/web';
|
|
3
|
+
type $$ComponentProps = {
|
|
4
|
+
item: Extract<FormWidgetItem, {
|
|
5
|
+
control: 'choice';
|
|
6
|
+
}>;
|
|
7
|
+
colors: FormColors;
|
|
8
|
+
};
|
|
9
|
+
declare const ComboControl: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
10
|
+
type ComboControl = ReturnType<typeof ComboControl>;
|
|
11
|
+
export default ComboControl;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
The page's fields as they look now. Each widget shows its picture, as the engine draws it (the
|
|
3
|
+
form plugin's, every state loaded, so a check box shows its new state at once), or the painter's
|
|
4
|
+
drawing while its look is pending or its picture is of an older version (`pictureOrPainting`): a
|
|
5
|
+
value, a calculation, a restyle shows at once. Hidden widgets aren't drawn.
|
|
6
|
+
-->
|
|
7
|
+
<script lang="ts">
|
|
8
|
+
import { untrack } from 'svelte';
|
|
9
|
+
import { annotationKey } from '@embedpdf/core';
|
|
10
|
+
import { MITER_LIMIT } from '@embedpdf/core-annotation';
|
|
11
|
+
import {
|
|
12
|
+
FormToken as FormHostToken,
|
|
13
|
+
type ShownWidget,
|
|
14
|
+
} from '@embedpdf/plugin-form/contract/host';
|
|
15
|
+
import { RenderToken } from '@embedpdf/plugin-render/contract/host';
|
|
16
|
+
import {
|
|
17
|
+
createShownUrls,
|
|
18
|
+
loadAppearanceUrls,
|
|
19
|
+
pictureOrPainting,
|
|
20
|
+
rectInPixels,
|
|
21
|
+
shownAppearance,
|
|
22
|
+
svgShapesOf,
|
|
23
|
+
type AppearanceUrl,
|
|
24
|
+
type PixelRect,
|
|
25
|
+
type SvgShape,
|
|
26
|
+
} from '@embedpdf/web';
|
|
27
|
+
import { usePage } from '../runtime/page.js';
|
|
28
|
+
import {
|
|
29
|
+
shallowArray,
|
|
30
|
+
useOptionalCapability,
|
|
31
|
+
useOptionalSelector,
|
|
32
|
+
} from '../runtime/readers.svelte.js';
|
|
33
|
+
import SvgShapes from '../runtime/SvgShapes.svelte';
|
|
34
|
+
|
|
35
|
+
const NO_WIDGETS: readonly ShownWidget[] = Object.freeze([]);
|
|
36
|
+
|
|
37
|
+
/** A widget as the template draws it: its picture, or the painter's shapes in its box. */
|
|
38
|
+
interface ShownLook {
|
|
39
|
+
key: string;
|
|
40
|
+
frame: PixelRect;
|
|
41
|
+
url: string | null;
|
|
42
|
+
painting: { viewBox: string; shapes: SvgShape[] } | null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const page = usePage();
|
|
46
|
+
const form = useOptionalCapability(FormHostToken);
|
|
47
|
+
// The same list until a widget on this page changes.
|
|
48
|
+
const widgets = useOptionalSelector(
|
|
49
|
+
FormHostToken,
|
|
50
|
+
(form) => form.listShownWidgets(page.ref),
|
|
51
|
+
NO_WIDGETS,
|
|
52
|
+
shallowArray,
|
|
53
|
+
);
|
|
54
|
+
// Loaded again when one of the page's widgets is drawn again, and at appearance-scale crossings.
|
|
55
|
+
const epoch = useOptionalSelector(FormHostToken, (form) => form.getAppearanceEpoch(page.ref), '');
|
|
56
|
+
const scale = useOptionalSelector(
|
|
57
|
+
RenderToken,
|
|
58
|
+
(renderer) => renderer.getAppearanceScale(page.transform.renderScale),
|
|
59
|
+
0,
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
// `null` until the page's first pictures arrive.
|
|
63
|
+
let urls = $state.raw<Record<string, AppearanceUrl> | null>(null);
|
|
64
|
+
// The pictures shown stay valid until the next ones are shown.
|
|
65
|
+
const shown = createShownUrls();
|
|
66
|
+
$effect(() => () => shown.release());
|
|
67
|
+
$effect(() => {
|
|
68
|
+
const host = form.current;
|
|
69
|
+
const ref = page.ref;
|
|
70
|
+
const at = scale.current;
|
|
71
|
+
void epoch.current;
|
|
72
|
+
if (!host || !at) return;
|
|
73
|
+
return untrack(() =>
|
|
74
|
+
loadAppearanceUrls(
|
|
75
|
+
shown,
|
|
76
|
+
(signal) => host.renderAppearances(ref, at, signal),
|
|
77
|
+
annotationKey,
|
|
78
|
+
(loaded) => (urls = loaded),
|
|
79
|
+
),
|
|
80
|
+
);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const looks = $derived(
|
|
84
|
+
widgets.current.flatMap((widget): ShownLook[] => {
|
|
85
|
+
const key = annotationKey(widget.ref);
|
|
86
|
+
const look = pictureOrPainting({
|
|
87
|
+
pending: widget.pending,
|
|
88
|
+
picture: urls && shownAppearance(urls, key, widget.appearanceState),
|
|
89
|
+
version: widget.pictureVersion,
|
|
90
|
+
loaded: urls !== null,
|
|
91
|
+
paint: () => form.current?.getWidgetPainting(widget.ref) ?? null,
|
|
92
|
+
});
|
|
93
|
+
if (!look) return [];
|
|
94
|
+
if (look.kind === 'picture') {
|
|
95
|
+
return [
|
|
96
|
+
{
|
|
97
|
+
key,
|
|
98
|
+
url: look.picture.url,
|
|
99
|
+
painting: null,
|
|
100
|
+
frame: rectInPixels(look.picture.box, page.transform),
|
|
101
|
+
},
|
|
102
|
+
];
|
|
103
|
+
}
|
|
104
|
+
const { x, y, width, height } = widget.rect;
|
|
105
|
+
return [
|
|
106
|
+
{
|
|
107
|
+
key,
|
|
108
|
+
url: null,
|
|
109
|
+
painting: {
|
|
110
|
+
viewBox: `${x} ${y} ${width} ${height}`,
|
|
111
|
+
shapes: svgShapesOf(look.painting.scene, { miterLimit: MITER_LIMIT }),
|
|
112
|
+
},
|
|
113
|
+
frame: rectInPixels(widget.rect, page.transform),
|
|
114
|
+
},
|
|
115
|
+
];
|
|
116
|
+
}),
|
|
117
|
+
);
|
|
118
|
+
</script>
|
|
119
|
+
|
|
120
|
+
{#each looks as look (look.key)}
|
|
121
|
+
{#if look.painting}
|
|
122
|
+
<svg
|
|
123
|
+
viewBox={look.painting.viewBox}
|
|
124
|
+
style="position: absolute; overflow: visible; pointer-events: none"
|
|
125
|
+
style:left="{look.frame.left}px"
|
|
126
|
+
style:top="{look.frame.top}px"
|
|
127
|
+
style:width="{look.frame.width}px"
|
|
128
|
+
style:height="{look.frame.height}px"
|
|
129
|
+
>
|
|
130
|
+
<SvgShapes shapes={look.painting.shapes} />
|
|
131
|
+
</svg>
|
|
132
|
+
{:else if look.url}
|
|
133
|
+
<!-- A global `img { max-width: 100% }` reset would clamp a picture: the sizes are explicit. -->
|
|
134
|
+
<img
|
|
135
|
+
src={look.url}
|
|
136
|
+
alt=""
|
|
137
|
+
draggable="false"
|
|
138
|
+
style="position: absolute; max-width: none; max-height: none; pointer-events: none"
|
|
139
|
+
style:left="{look.frame.left}px"
|
|
140
|
+
style:top="{look.frame.top}px"
|
|
141
|
+
style:width="{look.frame.width}px"
|
|
142
|
+
style:height="{look.frame.height}px"
|
|
143
|
+
/>
|
|
144
|
+
{/if}
|
|
145
|
+
{/each}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
The focus ring of a field, painted above the field's picture and its see-through native
|
|
3
|
+
control. An inset outline on the box itself would sit under an opaque child, so rectangular
|
|
4
|
+
checkboxes and dropdowns would look unfocused while they are active in the native Tab order.
|
|
5
|
+
-->
|
|
6
|
+
<script lang="ts">
|
|
7
|
+
import { cssText, formFocusRingStyleOf } from '@embedpdf/web';
|
|
8
|
+
|
|
9
|
+
let {
|
|
10
|
+
visible,
|
|
11
|
+
color,
|
|
12
|
+
}: {
|
|
13
|
+
visible: boolean;
|
|
14
|
+
/** The ring's CSS color: the form's `focus.color` setting, through its CSS variable. */
|
|
15
|
+
color: string;
|
|
16
|
+
} = $props();
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
{#if visible}
|
|
20
|
+
<span
|
|
21
|
+
aria-hidden="true"
|
|
22
|
+
data-embedpdf-form-focus-ring=""
|
|
23
|
+
style={cssText(formFocusRingStyleOf(color))}
|
|
24
|
+
></span>
|
|
25
|
+
{/if}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
type $$ComponentProps = {
|
|
2
|
+
visible: boolean;
|
|
3
|
+
/** The ring's CSS color: the form's `focus.color` setting, through its CSS variable. */
|
|
4
|
+
color: string;
|
|
5
|
+
};
|
|
6
|
+
declare const FormFocusRing: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
7
|
+
type FormFocusRing = ReturnType<typeof FormFocusRing>;
|
|
8
|
+
export default FormFocusRing;
|