@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,26 @@
|
|
|
1
|
+
import { SelectionToken, selectionState } from '@embedpdf/plugin-selection';
|
|
2
|
+
import { useCapability, useCapabilityEvent } from '../runtime/readers.svelte.js';
|
|
3
|
+
import { settingsReader, stateReader } from '../runtime/state.svelte.js';
|
|
4
|
+
/**
|
|
5
|
+
* The public selection API (`select()`, `readText()`, `canCopy()`, …) for app chrome: toolbars,
|
|
6
|
+
* context menus, automation. A handle, always the capability of the document in scope.
|
|
7
|
+
*/
|
|
8
|
+
export function useSelection() {
|
|
9
|
+
return useCapability(SelectionToken);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The selection's state: whether anything is selected, whether the user is still selecting, the
|
|
13
|
+
* character range and the pages it's on (declared once in `selectionState`), as a reactive object
|
|
14
|
+
* (`state.hasSelection`). With a selector, the value it picks as `{ current }`. Empty without a
|
|
15
|
+
* document.
|
|
16
|
+
*/
|
|
17
|
+
export const useSelectionState = stateReader(selectionState);
|
|
18
|
+
/** The selection settings (`dragThreshold`, `color`, `handles`), with or without a document. */
|
|
19
|
+
export const useSelectionSettings = settingsReader(SelectionToken);
|
|
20
|
+
/**
|
|
21
|
+
* Subscribe to one selection event while the component lives:
|
|
22
|
+
* `useSelectionEvent((selection) => selection.onCommitted, handler)`.
|
|
23
|
+
*/
|
|
24
|
+
export function useSelectionEvent(select, handler) {
|
|
25
|
+
useCapabilityEvent(SelectionToken, select, handler);
|
|
26
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @embedpdf/svelte/selection — text selection.
|
|
3
|
+
*
|
|
4
|
+
* `<SelectionLayer>` paints the highlight on each page; `<SelectionMenu>` floats over a settled
|
|
5
|
+
* selection; `<SelectionHandles>` are the touch handles in a Stage's overlay;
|
|
6
|
+
* `<SelectionClipboard>` wires Ctrl+C / Cmd+C. The readers are the plugin's four:
|
|
7
|
+
* `useSelection()`, `useSelectionState()`, `useSelectionSettings()` and `useSelectionEvent()`.
|
|
8
|
+
*/
|
|
9
|
+
export * from '@embedpdf/plugin-selection';
|
|
10
|
+
export { copySelection } from '@embedpdf/web';
|
|
11
|
+
export { default as SelectionLayer } from './selection/SelectionLayer.svelte';
|
|
12
|
+
export { default as SelectionMenu } from './selection/SelectionMenu.svelte';
|
|
13
|
+
export { default as SelectionHandles } from './selection/SelectionHandles.svelte';
|
|
14
|
+
export { default as SelectionClipboard } from './selection/SelectionClipboard.svelte';
|
|
15
|
+
export type { SelectionClipboardProps, SelectionHandlesProps, SelectionMenuProps, } from './selection/props.js';
|
|
16
|
+
export { useSelection, useSelectionEvent, useSelectionSettings, useSelectionState, } from './selection/readers.svelte.js';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @embedpdf/svelte/selection — text selection.
|
|
3
|
+
*
|
|
4
|
+
* `<SelectionLayer>` paints the highlight on each page; `<SelectionMenu>` floats over a settled
|
|
5
|
+
* selection; `<SelectionHandles>` are the touch handles in a Stage's overlay;
|
|
6
|
+
* `<SelectionClipboard>` wires Ctrl+C / Cmd+C. The readers are the plugin's four:
|
|
7
|
+
* `useSelection()`, `useSelectionState()`, `useSelectionSettings()` and `useSelectionEvent()`.
|
|
8
|
+
*/
|
|
9
|
+
// Registration travels with the UI.
|
|
10
|
+
export * from '@embedpdf/plugin-selection';
|
|
11
|
+
// The clipboard write lives in @embedpdf/web (the plugin has no DOM); it's here too, so app code
|
|
12
|
+
// has one import for the feature.
|
|
13
|
+
export { copySelection } from '@embedpdf/web';
|
|
14
|
+
export { default as SelectionLayer } from './selection/SelectionLayer.svelte';
|
|
15
|
+
export { default as SelectionMenu } from './selection/SelectionMenu.svelte';
|
|
16
|
+
export { default as SelectionHandles } from './selection/SelectionHandles.svelte';
|
|
17
|
+
export { default as SelectionClipboard } from './selection/SelectionClipboard.svelte';
|
|
18
|
+
export { useSelection, useSelectionEvent, useSelectionSettings, useSelectionState, } from './selection/readers.svelte.js';
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shell plugin's readers. The app owns every surface's DOM; these bind its open and closed
|
|
3
|
+
* state to the kernel, so commands can drive it and an app can restore it.
|
|
4
|
+
*
|
|
5
|
+
* They work without a document: shell state is a document's, and chrome that uses it (panel
|
|
6
|
+
* buttons, menu anchors) stays mounted while none is open. With no document every surface reads
|
|
7
|
+
* as closed, no menu as open, and `useSurface`'s verbs do nothing; `useShell()` then reaches the
|
|
8
|
+
* stand-in, whose calls refuse with `not-ready`.
|
|
9
|
+
*/
|
|
10
|
+
import type { EventHook } from '@embedpdf/core';
|
|
11
|
+
import type { OpenSurfaceOptions, ShellCapability, SurfaceProps } from '@embedpdf/plugin-shell';
|
|
12
|
+
import { type MaybeGetter } from '../runtime/values.svelte.js';
|
|
13
|
+
/** The shell API: open and close panels, dialogs and menus. Without a document its calls refuse with `not-ready`. */
|
|
14
|
+
export declare function useShell(): ShellCapability;
|
|
15
|
+
/** Subscribe to one shell event while the component lives: `useShellEvent((shell) => shell.onSurfaceOpened, handler)`. */
|
|
16
|
+
export declare function useShellEvent<T>(select: (shell: ShellCapability) => EventHook<T>, handler: (event: T) => void): void;
|
|
17
|
+
/**
|
|
18
|
+
* Which panels, dialogs and menus are open (declared once in `shellState`), as a reactive object
|
|
19
|
+
* (`useShellState().openMenus`). Takes a selector. Without a document nothing is open.
|
|
20
|
+
*/
|
|
21
|
+
export declare const useShellState: import("../index.js").StateReader<{
|
|
22
|
+
openSurfaces: readonly import("@embedpdf/plugin-shell").SurfaceState[];
|
|
23
|
+
openMenus: readonly string[];
|
|
24
|
+
}>;
|
|
25
|
+
/** One surface: whether it's open and its props, read live, and the calls that change it. */
|
|
26
|
+
export interface SurfaceHandle {
|
|
27
|
+
readonly isOpen: boolean;
|
|
28
|
+
/** The props the surface was opened with, or updated to; empty when it has none. */
|
|
29
|
+
readonly props: SurfaceProps;
|
|
30
|
+
open(options?: OpenSurfaceOptions): void;
|
|
31
|
+
close(): void;
|
|
32
|
+
toggle(options?: OpenSurfaceOptions): void;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* One named surface (panel, dialog, overlay) of this component's document: `panel.isOpen` and
|
|
36
|
+
* `panel.props` update in a template, and `open`, `close` and `toggle` can be passed as handlers
|
|
37
|
+
* (`onclick={panel.close}`). Pass the id as a function to follow a prop. It reads as closed, and
|
|
38
|
+
* its calls do nothing, while no document is open.
|
|
39
|
+
*/
|
|
40
|
+
export declare function useSurface(id: MaybeGetter<string>): SurfaceHandle;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ShellToken, shellState } from '@embedpdf/plugin-shell';
|
|
2
|
+
import { useCapability, useCapabilityEvent, useOptionalCapability, useOptionalSelector, } from '../runtime/readers.svelte.js';
|
|
3
|
+
import { stateReader } from '../runtime/state.svelte.js';
|
|
4
|
+
import { valueOf } from '../runtime/values.svelte.js';
|
|
5
|
+
/** The shell API: open and close panels, dialogs and menus. Without a document its calls refuse with `not-ready`. */
|
|
6
|
+
export function useShell() {
|
|
7
|
+
return useCapability(ShellToken);
|
|
8
|
+
}
|
|
9
|
+
/** Subscribe to one shell event while the component lives: `useShellEvent((shell) => shell.onSurfaceOpened, handler)`. */
|
|
10
|
+
export function useShellEvent(select, handler) {
|
|
11
|
+
useCapabilityEvent(ShellToken, select, handler);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Which panels, dialogs and menus are open (declared once in `shellState`), as a reactive object
|
|
15
|
+
* (`useShellState().openMenus`). Takes a selector. Without a document nothing is open.
|
|
16
|
+
*/
|
|
17
|
+
export const useShellState = stateReader(shellState);
|
|
18
|
+
const NO_PROPS = Object.freeze({});
|
|
19
|
+
/**
|
|
20
|
+
* One named surface (panel, dialog, overlay) of this component's document: `panel.isOpen` and
|
|
21
|
+
* `panel.props` update in a template, and `open`, `close` and `toggle` can be passed as handlers
|
|
22
|
+
* (`onclick={panel.close}`). Pass the id as a function to follow a prop. It reads as closed, and
|
|
23
|
+
* its calls do nothing, while no document is open.
|
|
24
|
+
*/
|
|
25
|
+
export function useSurface(id) {
|
|
26
|
+
const shell = useOptionalCapability(ShellToken);
|
|
27
|
+
const isOpen = useOptionalSelector(ShellToken, (shell) => shell.isOpen(valueOf(id)), false);
|
|
28
|
+
const props = useOptionalSelector(ShellToken, (shell) => shell.getSurface(valueOf(id))?.props ?? NO_PROPS, NO_PROPS);
|
|
29
|
+
return {
|
|
30
|
+
get isOpen() {
|
|
31
|
+
return isOpen.current;
|
|
32
|
+
},
|
|
33
|
+
get props() {
|
|
34
|
+
return props.current;
|
|
35
|
+
},
|
|
36
|
+
open: (options) => shell.current?.open(valueOf(id), options),
|
|
37
|
+
close: () => shell.current?.close(valueOf(id)),
|
|
38
|
+
toggle: (options) => shell.current?.toggle(valueOf(id), options),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Attachment } from 'svelte/attachments';
|
|
2
|
+
import { type SurfaceFocusOptions } from '@embedpdf/web';
|
|
3
|
+
import { type MaybeGetter } from '../runtime/values.svelte.js';
|
|
4
|
+
export type { SurfaceFocusOptions };
|
|
5
|
+
/**
|
|
6
|
+
* An attachment that puts the cursor in its element when the surface `id` asks for it: on every
|
|
7
|
+
* `open(id, { focus: true })`, a command whose panel says `focus` among them, and when the
|
|
8
|
+
* element mounts while the request is up (the panel opened, or its code loaded, because of it).
|
|
9
|
+
* A plain open never moves it. `select` selects an input's text, so typing replaces it. It reads
|
|
10
|
+
* the surface of this component's document; pass the id as a function to follow a prop.
|
|
11
|
+
*
|
|
12
|
+
* ```svelte
|
|
13
|
+
* <input {@attach surfaceFocus('search', { select: true })} bind:value={query} />
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare function surfaceFocus(id: MaybeGetter<string>, options?: SurfaceFocusOptions): Attachment<HTMLElement>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Putting the cursor in an element when its panel asks for it. `@embedpdf/web`'s surface focus
|
|
3
|
+
* follower owns the rule (a new request moves the cursor in, and so does mounting while one is
|
|
4
|
+
* up); this binds it to Svelte as an attachment.
|
|
5
|
+
*/
|
|
6
|
+
import { untrack } from 'svelte';
|
|
7
|
+
import { ShellToken } from '@embedpdf/plugin-shell';
|
|
8
|
+
import { createSurfaceFocusFollower } from '@embedpdf/web';
|
|
9
|
+
import { useOptionalCapability, useOptionalSelector } from '../runtime/readers.svelte.js';
|
|
10
|
+
import { valueOf } from '../runtime/values.svelte.js';
|
|
11
|
+
/**
|
|
12
|
+
* An attachment that puts the cursor in its element when the surface `id` asks for it: on every
|
|
13
|
+
* `open(id, { focus: true })`, a command whose panel says `focus` among them, and when the
|
|
14
|
+
* element mounts while the request is up (the panel opened, or its code loaded, because of it).
|
|
15
|
+
* A plain open never moves it. `select` selects an input's text, so typing replaces it. It reads
|
|
16
|
+
* the surface of this component's document; pass the id as a function to follow a prop.
|
|
17
|
+
*
|
|
18
|
+
* ```svelte
|
|
19
|
+
* <input {@attach surfaceFocus('search', { select: true })} bind:value={query} />
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export function surfaceFocus(id, options = {}) {
|
|
23
|
+
const shell = useOptionalCapability(ShellToken);
|
|
24
|
+
const request = useOptionalSelector(ShellToken, (current) => current.getSurface(valueOf(id))?.focusRequest ?? 0, 0);
|
|
25
|
+
return (element) => {
|
|
26
|
+
const follower = createSurfaceFocusFollower();
|
|
27
|
+
$effect(() => {
|
|
28
|
+
const current = shell.current;
|
|
29
|
+
const value = request.current;
|
|
30
|
+
untrack(() => follower.follow(element, current, value, options));
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
}
|
package/dist/shell.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @embedpdf/svelte/shell — panels, dialogs and menus.
|
|
3
|
+
*
|
|
4
|
+
* Your app draws every surface; the readers bind whether each one is open (and its props) to the
|
|
5
|
+
* kernel, so commands can open them and a layout can be saved and restored. `surfaceFocus` puts
|
|
6
|
+
* the cursor in a panel's element when the panel asks for it.
|
|
7
|
+
*/
|
|
8
|
+
export * from '@embedpdf/plugin-shell';
|
|
9
|
+
export { useShell, useShellEvent, useShellState, useSurface } from './shell/readers.svelte.js';
|
|
10
|
+
export type { SurfaceHandle } from './shell/readers.svelte.js';
|
|
11
|
+
export { surfaceFocus } from './shell/surface-focus.svelte.js';
|
|
12
|
+
export type { SurfaceFocusOptions } from './shell/surface-focus.svelte.js';
|
package/dist/shell.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @embedpdf/svelte/shell — panels, dialogs and menus.
|
|
3
|
+
*
|
|
4
|
+
* Your app draws every surface; the readers bind whether each one is open (and its props) to the
|
|
5
|
+
* kernel, so commands can open them and a layout can be saved and restored. `surfaceFocus` puts
|
|
6
|
+
* the cursor in a panel's element when the panel asks for it.
|
|
7
|
+
*/
|
|
8
|
+
// Registration travels with the UI.
|
|
9
|
+
export * from '@embedpdf/plugin-shell';
|
|
10
|
+
export { useShell, useShellEvent, useShellState, useSurface } from './shell/readers.svelte.js';
|
|
11
|
+
export { surfaceFocus } from './shell/surface-focus.svelte.js';
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The signature plugin's readers: `useSignature()` (the API), the state and the settings,
|
|
3
|
+
* `useSignatureEvent()`, and `useSignerRows()`, the people whose marks this browser holds, for a
|
|
4
|
+
* signature picker.
|
|
5
|
+
*/
|
|
6
|
+
import type { EventHook } from '@embedpdf/core';
|
|
7
|
+
import { signatureState } from '@embedpdf/plugin-signature';
|
|
8
|
+
import type { SignatureCapability, SignerRow } from '@embedpdf/plugin-signature';
|
|
9
|
+
import { type StateReader } from '../runtime/state.svelte.js';
|
|
10
|
+
import { type CurrentValue } from '../runtime/values.svelte.js';
|
|
11
|
+
/**
|
|
12
|
+
* The signature API for the document in scope: sign, place a mark, fill or clear a field, check
|
|
13
|
+
* the signatures. A handle: keep it whole and call through it (`signature.sign(…)`).
|
|
14
|
+
*/
|
|
15
|
+
export declare function useSignature(): SignatureCapability;
|
|
16
|
+
/**
|
|
17
|
+
* The signatures' state: the signed fields with their verdicts (`signatures`), what they allow,
|
|
18
|
+
* the `target`, whether a signing runs (`busy`), a two-step signing in progress, and whether
|
|
19
|
+
* they're read, declared once in `signatureState`. A reactive object (`state.signatures`), or
|
|
20
|
+
* with a selector one value as `{ current }`. Empty without a document.
|
|
21
|
+
*
|
|
22
|
+
* Typed through the declaration, so the published types name it from `@embedpdf/plugin-signature`, a
|
|
23
|
+
* dependency of this package, and not from the engine package `protection`'s type comes from, which
|
|
24
|
+
* isn't one.
|
|
25
|
+
*/
|
|
26
|
+
export declare const useSignatureState: StateReader<ReturnType<typeof signatureState.read>>;
|
|
27
|
+
/**
|
|
28
|
+
* The signature settings (`key`, `mode`, `trust`, `allowCertify`), with or without a document.
|
|
29
|
+
* They belong to the plugin; change them with `useSignature().updateSettings()`.
|
|
30
|
+
*/
|
|
31
|
+
export declare const useSignatureSettings: import("../index.js").SettingsReader<import("@embedpdf/plugin-signature").SignatureSettings & object>;
|
|
32
|
+
/**
|
|
33
|
+
* Subscribe to one signature event while the component lives:
|
|
34
|
+
* `useSignatureEvent((signature) => signature.onSigned, handler)`.
|
|
35
|
+
*/
|
|
36
|
+
export declare function useSignatureEvent<T>(select: (signature: SignatureCapability) => EventHook<T>, handler: (event: T) => void): void;
|
|
37
|
+
/**
|
|
38
|
+
* The people whose marks this browser holds, one row per library of kind `signatures`, for a
|
|
39
|
+
* picker, as `{ current }`: `const rows = useSignerRows()`, then `rows.current`. Derived from the
|
|
40
|
+
* stamp plugin, so it needs `stampPlugin()`: rename, delete and export are the library verbs, and
|
|
41
|
+
* nothing is stored beyond the file.
|
|
42
|
+
*/
|
|
43
|
+
export declare function useSignerRows(): CurrentValue<readonly SignerRow[]>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { signatureState, signerRowsOf, SIGNATURES_LIBRARY_KIND, SignatureToken, } from '@embedpdf/plugin-signature';
|
|
2
|
+
import { useCapability, useCapabilityEvent } from '../runtime/readers.svelte.js';
|
|
3
|
+
import { settingsReader, stateReader } from '../runtime/state.svelte.js';
|
|
4
|
+
import { currentOf, derivedValue } from '../runtime/values.svelte.js';
|
|
5
|
+
import { useStampAssets, useStampLibraries } from '../stamp/readers.svelte.js';
|
|
6
|
+
/**
|
|
7
|
+
* The signature API for the document in scope: sign, place a mark, fill or clear a field, check
|
|
8
|
+
* the signatures. A handle: keep it whole and call through it (`signature.sign(…)`).
|
|
9
|
+
*/
|
|
10
|
+
export function useSignature() {
|
|
11
|
+
return useCapability(SignatureToken);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The signatures' state: the signed fields with their verdicts (`signatures`), what they allow,
|
|
15
|
+
* the `target`, whether a signing runs (`busy`), a two-step signing in progress, and whether
|
|
16
|
+
* they're read, declared once in `signatureState`. A reactive object (`state.signatures`), or
|
|
17
|
+
* with a selector one value as `{ current }`. Empty without a document.
|
|
18
|
+
*
|
|
19
|
+
* Typed through the declaration, so the published types name it from `@embedpdf/plugin-signature`, a
|
|
20
|
+
* dependency of this package, and not from the engine package `protection`'s type comes from, which
|
|
21
|
+
* isn't one.
|
|
22
|
+
*/
|
|
23
|
+
export const useSignatureState = stateReader(signatureState);
|
|
24
|
+
/**
|
|
25
|
+
* The signature settings (`key`, `mode`, `trust`, `allowCertify`), with or without a document.
|
|
26
|
+
* They belong to the plugin; change them with `useSignature().updateSettings()`.
|
|
27
|
+
*/
|
|
28
|
+
export const useSignatureSettings = settingsReader(SignatureToken);
|
|
29
|
+
/**
|
|
30
|
+
* Subscribe to one signature event while the component lives:
|
|
31
|
+
* `useSignatureEvent((signature) => signature.onSigned, handler)`.
|
|
32
|
+
*/
|
|
33
|
+
export function useSignatureEvent(select, handler) {
|
|
34
|
+
useCapabilityEvent(SignatureToken, select, handler);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The people whose marks this browser holds, one row per library of kind `signatures`, for a
|
|
38
|
+
* picker, as `{ current }`: `const rows = useSignerRows()`, then `rows.current`. Derived from the
|
|
39
|
+
* stamp plugin, so it needs `stampPlugin()`: rename, delete and export are the library verbs, and
|
|
40
|
+
* nothing is stored beyond the file.
|
|
41
|
+
*/
|
|
42
|
+
export function useSignerRows() {
|
|
43
|
+
const libraries = useStampLibraries({ kind: SIGNATURES_LIBRARY_KIND });
|
|
44
|
+
const assets = useStampAssets();
|
|
45
|
+
return currentOf(derivedValue(() => signerRowsOf(libraries.current, assets.current)));
|
|
46
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @embedpdf/svelte/signature — signing.
|
|
3
|
+
*
|
|
4
|
+
* Signing for the document in scope (`useSignature()`), its state as a reactive object (the
|
|
5
|
+
* signatures with their verdicts, what they allow, the target, a two-step signing in progress),
|
|
6
|
+
* the settings, the events, and the one derivation a signatures panel needs: the people
|
|
7
|
+
* (libraries of kind `signatures`) with their marks (`useSignerRows()`). The signers
|
|
8
|
+
* (`personalSigner`, `webCryptoSigner`, `remoteSigner`, `createTestSigner`) come with the plugin.
|
|
9
|
+
* An empty signature field is "sign here" in `<FormLayer>` (`@embedpdf/svelte/form`).
|
|
10
|
+
*
|
|
11
|
+
* const signature = useSignature();
|
|
12
|
+
* await signature.placeMark({ assetId }, { field: target }); // sign, fill or ask, by mode
|
|
13
|
+
*/
|
|
14
|
+
export * from '@embedpdf/plugin-signature';
|
|
15
|
+
export { useSignature, useSignatureEvent, useSignatureSettings, useSignatureState, useSignerRows, } from './signature/readers.svelte.js';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @embedpdf/svelte/signature — signing.
|
|
3
|
+
*
|
|
4
|
+
* Signing for the document in scope (`useSignature()`), its state as a reactive object (the
|
|
5
|
+
* signatures with their verdicts, what they allow, the target, a two-step signing in progress),
|
|
6
|
+
* the settings, the events, and the one derivation a signatures panel needs: the people
|
|
7
|
+
* (libraries of kind `signatures`) with their marks (`useSignerRows()`). The signers
|
|
8
|
+
* (`personalSigner`, `webCryptoSigner`, `remoteSigner`, `createTestSigner`) come with the plugin.
|
|
9
|
+
* An empty signature field is "sign here" in `<FormLayer>` (`@embedpdf/svelte/form`).
|
|
10
|
+
*
|
|
11
|
+
* const signature = useSignature();
|
|
12
|
+
* await signature.placeMark({ assetId }, { field: target }); // sign, fill or ask, by mode
|
|
13
|
+
*/
|
|
14
|
+
// Registration travels with the UI.
|
|
15
|
+
export * from '@embedpdf/plugin-signature';
|
|
16
|
+
export { useSignature, useSignatureEvent, useSignatureSettings, useSignatureState, useSignerRows, } from './signature/readers.svelte.js';
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
One visible page of a Stage: placed where the camera puts it, with its drop shadow, the page
|
|
3
|
+
content (which turns with the page) and the page chrome (which never turns). It provides the
|
|
4
|
+
page context to every layer inside.
|
|
5
|
+
|
|
6
|
+
All geometry comes from the page's transform: the display footprint (`viewWidth`/`viewHeight`,
|
|
7
|
+
already swapped for a quarter turn and snapped to device pixels) and the unturned content box
|
|
8
|
+
(`contentWidth`/`contentHeight`). Nothing here multiplies by the zoom or the pixel ratio.
|
|
9
|
+
-->
|
|
10
|
+
<script lang="ts">
|
|
11
|
+
import { untrack, type Snippet } from 'svelte';
|
|
12
|
+
import { toPageRef } from '@embedpdf/core';
|
|
13
|
+
import type { PageFrame } from '@embedpdf/core-geometry';
|
|
14
|
+
import type { VisiblePage } from '@embedpdf/plugin-stage';
|
|
15
|
+
import type { StageHostCapability } from '@embedpdf/plugin-stage/contract/host';
|
|
16
|
+
import type { PageViewDemand } from '@embedpdf/plugin-render/contract';
|
|
17
|
+
import {
|
|
18
|
+
livePageContext,
|
|
19
|
+
makePageContext,
|
|
20
|
+
pageSurfaceLayout,
|
|
21
|
+
paint,
|
|
22
|
+
stagePageDemand,
|
|
23
|
+
} from '@embedpdf/web';
|
|
24
|
+
import { useViewerSettings } from '../runtime/documents.svelte.js';
|
|
25
|
+
import { setPageContext, type PageContextValue } from '../runtime/page.js';
|
|
26
|
+
|
|
27
|
+
let {
|
|
28
|
+
documentId,
|
|
29
|
+
page,
|
|
30
|
+
frame,
|
|
31
|
+
stage,
|
|
32
|
+
content,
|
|
33
|
+
chrome,
|
|
34
|
+
}: {
|
|
35
|
+
documentId: string;
|
|
36
|
+
/** This page as the stage places it now: a new object on every camera frame. */
|
|
37
|
+
page: VisiblePage;
|
|
38
|
+
/** The bands reserved around the page, in screen pixels; the layout left room for them. */
|
|
39
|
+
frame: PageFrame;
|
|
40
|
+
stage: StageHostCapability;
|
|
41
|
+
content: Snippet<[page: PageContextValue]>;
|
|
42
|
+
chrome?: Snippet<[page: PageContextValue]>;
|
|
43
|
+
} = $props();
|
|
44
|
+
|
|
45
|
+
let contentElement: HTMLDivElement | undefined;
|
|
46
|
+
|
|
47
|
+
// The viewer's `page` settings; `--epdf-page-*` CSS variables win over them.
|
|
48
|
+
const look = useViewerSettings((settings) => settings.page);
|
|
49
|
+
|
|
50
|
+
// The Stage keys its pages by object number, so this surface's number never changes: one
|
|
51
|
+
// PageRef for its lifetime, safe for layers to key their work on.
|
|
52
|
+
const pageRef = toPageRef(untrack(() => page.ref.objectNumber));
|
|
53
|
+
// Each its own derived value, so the context below changes only when one of them does, not on
|
|
54
|
+
// every camera frame.
|
|
55
|
+
const pageIndex = $derived(page.pageIndex);
|
|
56
|
+
const transform = $derived(page.transform);
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* How much of this page the view wants, for raster planning: read live from the stage, a zero
|
|
60
|
+
* box while the page is off screen. It reads `page` first, so a reaction that asks (the tile
|
|
61
|
+
* plane) asks again on every camera frame.
|
|
62
|
+
*/
|
|
63
|
+
function viewDemand(): PageViewDemand {
|
|
64
|
+
const placed = page;
|
|
65
|
+
return stagePageDemand(stage, pageRef.objectNumber, placed.transform.deviceWidth);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const context = $derived(
|
|
69
|
+
makePageContext(
|
|
70
|
+
documentId,
|
|
71
|
+
// The hosting lens: raster planning keys tiles by it, so a thumbnail rail and the main
|
|
72
|
+
// view never fight over one plan.
|
|
73
|
+
stage.getLensId(),
|
|
74
|
+
pageRef,
|
|
75
|
+
pageIndex,
|
|
76
|
+
frame,
|
|
77
|
+
transform,
|
|
78
|
+
() => contentElement!.getBoundingClientRect(),
|
|
79
|
+
viewDemand,
|
|
80
|
+
),
|
|
81
|
+
);
|
|
82
|
+
const live = livePageContext(() => context);
|
|
83
|
+
setPageContext(live);
|
|
84
|
+
|
|
85
|
+
// The outer box (one frame further out than the footprint, so the content keeps its place),
|
|
86
|
+
// the shadow at the footprint, and the content box centred on it and turned about its centre.
|
|
87
|
+
const layout = $derived(
|
|
88
|
+
pageSurfaceLayout(transform, frame, { x: page.screenX, y: page.screenY }),
|
|
89
|
+
);
|
|
90
|
+
</script>
|
|
91
|
+
|
|
92
|
+
<div
|
|
93
|
+
style:position="absolute"
|
|
94
|
+
style:left="{layout.outer.left}px"
|
|
95
|
+
style:top="{layout.outer.top}px"
|
|
96
|
+
style:width="{layout.outer.width}px"
|
|
97
|
+
style:height="{layout.outer.height}px"
|
|
98
|
+
>
|
|
99
|
+
<!-- The drop shadow only: at the content box, with no fill, so it never shows behind the
|
|
100
|
+
picture, and it stays put while the page turns. -->
|
|
101
|
+
<div
|
|
102
|
+
style:position="absolute"
|
|
103
|
+
style:left="{layout.shadow.left}px"
|
|
104
|
+
style:top="{layout.shadow.top}px"
|
|
105
|
+
style:width="{layout.shadow.width}px"
|
|
106
|
+
style:height="{layout.shadow.height}px"
|
|
107
|
+
style:box-shadow={paint('page-shadow', look.current.shadow)}
|
|
108
|
+
></div>
|
|
109
|
+
<!-- The page: its background and its layers as one box, the only thing the rotation turns.
|
|
110
|
+
Native text and image selection is off: the selection layer draws its own. -->
|
|
111
|
+
<div
|
|
112
|
+
bind:this={contentElement}
|
|
113
|
+
style="user-select: none; -webkit-user-select: none"
|
|
114
|
+
style:position="absolute"
|
|
115
|
+
style:left="{layout.content.left}px"
|
|
116
|
+
style:top="{layout.content.top}px"
|
|
117
|
+
style:width="{layout.content.width}px"
|
|
118
|
+
style:height="{layout.content.height}px"
|
|
119
|
+
style:background={paint('page-background', look.current.background)}
|
|
120
|
+
style:transform={layout.turn ?? undefined}
|
|
121
|
+
>
|
|
122
|
+
{@render content(live)}
|
|
123
|
+
</div>
|
|
124
|
+
<!-- The page chrome fills the outer box and never turns. -->
|
|
125
|
+
{@render chrome?.(live)}
|
|
126
|
+
</div>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type Snippet } from 'svelte';
|
|
2
|
+
import type { PageFrame } from '@embedpdf/core-geometry';
|
|
3
|
+
import type { VisiblePage } from '@embedpdf/plugin-stage';
|
|
4
|
+
import type { StageHostCapability } from '@embedpdf/plugin-stage/contract/host';
|
|
5
|
+
import { type PageContextValue } from '../runtime/page.js';
|
|
6
|
+
type $$ComponentProps = {
|
|
7
|
+
documentId: string;
|
|
8
|
+
/** This page as the stage places it now: a new object on every camera frame. */
|
|
9
|
+
page: VisiblePage;
|
|
10
|
+
/** The bands reserved around the page, in screen pixels; the layout left room for them. */
|
|
11
|
+
frame: PageFrame;
|
|
12
|
+
stage: StageHostCapability;
|
|
13
|
+
content: Snippet<[page: PageContextValue]>;
|
|
14
|
+
chrome?: Snippet<[page: PageContextValue]>;
|
|
15
|
+
};
|
|
16
|
+
declare const PageSurface: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
17
|
+
type PageSurface = ReturnType<typeof PageSurface>;
|
|
18
|
+
export default PageSurface;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
A scrollbar for a Stage lens that you style yourself: a view of `stage.getScrollMetrics()`.
|
|
3
|
+
|
|
4
|
+
Thumb drag with pointer capture and a kept grab point, track paging with press-and-hold repeat
|
|
5
|
+
that stops at the pointer, a minimum thumb length on long documents, and macOS-style auto-hide.
|
|
6
|
+
On an unbounded stage the metrics already carry the union of content and view, so the bar
|
|
7
|
+
shrinks as you pan away; the mapping is frozen during a thumb drag, so the thumb never chases
|
|
8
|
+
itself while that union changes.
|
|
9
|
+
|
|
10
|
+
Geometry and behavior live here, looks in your CSS, against
|
|
11
|
+
[data-embedpdf-scrollbar][data-axis="y"][data-state="visible|hidden"]
|
|
12
|
+
[data-embedpdf-scrollbar][data-dragging]
|
|
13
|
+
[data-embedpdf-scrollbar-thumb]
|
|
14
|
+
Unstyled, it's a transparent track at the viewport's edge with a `--epdf-scrollbar-thumb` pill.
|
|
15
|
+
Build anything else (a minimap, a progress ring) from `useScrollMetrics()` and `stage.scrollTo()`.
|
|
16
|
+
-->
|
|
17
|
+
<script lang="ts">
|
|
18
|
+
import {
|
|
19
|
+
createScrollbarPresses,
|
|
20
|
+
paintDefault,
|
|
21
|
+
scrollbarLayout,
|
|
22
|
+
type ScrollbarTrack,
|
|
23
|
+
} from '@embedpdf/web';
|
|
24
|
+
import { useCapability } from '../runtime/readers.svelte.js';
|
|
25
|
+
import type { ScrollbarProps } from './props.js';
|
|
26
|
+
import { asHost, scrollMetricsOf } from './readers.svelte.js';
|
|
27
|
+
import { stageTokenOf } from './stage-scope.js';
|
|
28
|
+
|
|
29
|
+
let {
|
|
30
|
+
axis,
|
|
31
|
+
token: explicitToken,
|
|
32
|
+
autoHide = 1200,
|
|
33
|
+
minThumbSize = 24,
|
|
34
|
+
trackPress = 'page',
|
|
35
|
+
class: className,
|
|
36
|
+
style,
|
|
37
|
+
thumbClass,
|
|
38
|
+
thumbStyle,
|
|
39
|
+
}: ScrollbarProps = $props();
|
|
40
|
+
|
|
41
|
+
const lens = stageTokenOf(() => explicitToken);
|
|
42
|
+
const stage = useCapability(() => asHost(lens()));
|
|
43
|
+
const metrics = scrollMetricsOf(lens);
|
|
44
|
+
|
|
45
|
+
const vertical = $derived(axis === 'y');
|
|
46
|
+
const scrollable = $derived(vertical ? metrics.scrollableY : metrics.scrollableX);
|
|
47
|
+
|
|
48
|
+
let track: HTMLDivElement | undefined = $state();
|
|
49
|
+
let trackPx = $state(0);
|
|
50
|
+
let dragging = $state(false);
|
|
51
|
+
let hovered = $state(false);
|
|
52
|
+
let active = $state(true); // the view moved recently
|
|
53
|
+
|
|
54
|
+
// The thumb along the track: one formula for drawing, dragging and paging, shared with every
|
|
55
|
+
// framework.
|
|
56
|
+
const layout = $derived(scrollbarLayout(metrics, vertical, trackPx, minThumbSize));
|
|
57
|
+
|
|
58
|
+
// ── auto-hide: any metrics change shows the bar and starts the fade again ──
|
|
59
|
+
const hideAfter = $derived(autoHide === false ? 0 : autoHide);
|
|
60
|
+
$effect(() => {
|
|
61
|
+
// Every number, so any movement counts.
|
|
62
|
+
void [metrics.scrollTop, metrics.scrollLeft, metrics.scrollHeight, metrics.scrollWidth];
|
|
63
|
+
void [metrics.clientHeight, metrics.clientWidth];
|
|
64
|
+
if (!hideAfter) return;
|
|
65
|
+
active = true;
|
|
66
|
+
const timer = setTimeout(() => (active = false), hideAfter);
|
|
67
|
+
return () => clearTimeout(timer);
|
|
68
|
+
});
|
|
69
|
+
const shown = $derived(!hideAfter || active || hovered || dragging);
|
|
70
|
+
|
|
71
|
+
// ── the track's length, which the pixel mapping needs ──
|
|
72
|
+
$effect(() => {
|
|
73
|
+
const element = track;
|
|
74
|
+
const isVertical = vertical;
|
|
75
|
+
if (!element) return;
|
|
76
|
+
const measure = () => (trackPx = isVertical ? element.clientHeight : element.clientWidth);
|
|
77
|
+
const observer = new ResizeObserver(measure);
|
|
78
|
+
observer.observe(element);
|
|
79
|
+
measure();
|
|
80
|
+
return () => observer.disconnect();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// ── input: `@embedpdf/web`'s press handling (thumb drags, track paging and jumps), handed the
|
|
84
|
+
// bar as it is now on every event. ──
|
|
85
|
+
const presses = createScrollbarPresses((value) => (dragging = value));
|
|
86
|
+
const pressedTrack = (): ScrollbarTrack => ({
|
|
87
|
+
stage,
|
|
88
|
+
vertical,
|
|
89
|
+
element: track!,
|
|
90
|
+
layout,
|
|
91
|
+
// Fresh geometry for paging steps, from the capability rather than the last drawn frame.
|
|
92
|
+
liveLayout: () => scrollbarLayout(stage.getScrollMetrics(), vertical, trackPx, minThumbSize),
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// No repeat timer outlives the bar.
|
|
96
|
+
$effect(() => () => presses.release());
|
|
97
|
+
|
|
98
|
+
const trackDefaults = $derived(
|
|
99
|
+
vertical
|
|
100
|
+
? 'position: absolute; top: 0; right: 0; bottom: 0; width: 12px;'
|
|
101
|
+
: 'position: absolute; left: 0; right: 0; bottom: 0; height: 12px;',
|
|
102
|
+
);
|
|
103
|
+
const thumbDefaults = $derived(
|
|
104
|
+
vertical
|
|
105
|
+
? `position: absolute; left: 2px; right: 2px; top: ${layout.thumbPosition}px; height: ${layout.thumbLength}px;`
|
|
106
|
+
: `position: absolute; top: 2px; bottom: 2px; left: ${layout.thumbPosition}px; width: ${layout.thumbLength}px;`,
|
|
107
|
+
);
|
|
108
|
+
</script>
|
|
109
|
+
|
|
110
|
+
{#if scrollable}
|
|
111
|
+
<!-- The bar drives the Stage, which is no single element to name in aria-controls, and the
|
|
112
|
+
pointer is its input: like a native overlay scrollbar, it takes no focus. -->
|
|
113
|
+
<!-- svelte-ignore a11y_role_has_required_aria_props, a11y_interactive_supports_focus -->
|
|
114
|
+
<div
|
|
115
|
+
bind:this={track}
|
|
116
|
+
role="scrollbar"
|
|
117
|
+
aria-orientation={vertical ? 'vertical' : 'horizontal'}
|
|
118
|
+
aria-valuemin={0}
|
|
119
|
+
aria-valuemax={Math.round(layout.maxOffset)}
|
|
120
|
+
aria-valuenow={Math.round(layout.offset)}
|
|
121
|
+
data-embedpdf-scrollbar=""
|
|
122
|
+
data-axis={axis}
|
|
123
|
+
data-state={shown ? 'visible' : 'hidden'}
|
|
124
|
+
data-dragging={dragging ? '' : undefined}
|
|
125
|
+
class={className}
|
|
126
|
+
style="{trackDefaults} touch-action: none; user-select: none; opacity: {shown
|
|
127
|
+
? 1
|
|
128
|
+
: 0}; transition: opacity 200ms; pointer-events: {shown ? 'auto' : 'none'};{style
|
|
129
|
+
? ` ${style}`
|
|
130
|
+
: ''}"
|
|
131
|
+
onpointerdown={(event) => presses.pressTrack(event, pressedTrack(), trackPress)}
|
|
132
|
+
onpointermove={(event) => presses.move(event, pressedTrack())}
|
|
133
|
+
onpointerup={() => presses.release()}
|
|
134
|
+
onpointercancel={() => presses.release()}
|
|
135
|
+
onpointerenter={() => (hovered = true)}
|
|
136
|
+
onpointerleave={() => (hovered = false)}
|
|
137
|
+
>
|
|
138
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
139
|
+
<div
|
|
140
|
+
data-embedpdf-scrollbar-thumb=""
|
|
141
|
+
class={thumbClass}
|
|
142
|
+
style="{thumbDefaults} border-radius: 6px; background: {paintDefault(
|
|
143
|
+
'scrollbar-thumb',
|
|
144
|
+
)};{thumbStyle ? ` ${thumbStyle}` : ''}"
|
|
145
|
+
onpointerdown={(event) => presses.pressThumb(event, pressedTrack())}
|
|
146
|
+
></div>
|
|
147
|
+
</div>
|
|
148
|
+
{/if}
|