@embedpdf/angular 3.0.0-next.13 → 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.
Files changed (81) hide show
  1. package/README.md +309 -0
  2. package/dist/README.md +309 -0
  3. package/dist/actions/index.d.ts +34 -16
  4. package/dist/anchored/index.d.ts +67 -0
  5. package/dist/annotation/index.d.ts +599 -0
  6. package/dist/commands/index.d.ts +109 -0
  7. package/dist/fesm2022/embedpdf-angular-actions.mjs +117 -36
  8. package/dist/fesm2022/embedpdf-angular-actions.mjs.map +1 -1
  9. package/dist/fesm2022/embedpdf-angular-anchored.mjs +148 -0
  10. package/dist/fesm2022/embedpdf-angular-anchored.mjs.map +1 -0
  11. package/dist/fesm2022/embedpdf-angular-annotation.mjs +1960 -0
  12. package/dist/fesm2022/embedpdf-angular-annotation.mjs.map +1 -0
  13. package/dist/fesm2022/embedpdf-angular-commands.mjs +235 -0
  14. package/dist/fesm2022/embedpdf-angular-commands.mjs.map +1 -0
  15. package/dist/fesm2022/embedpdf-angular-form.mjs +1074 -0
  16. package/dist/fesm2022/embedpdf-angular-form.mjs.map +1 -0
  17. package/dist/fesm2022/embedpdf-angular-history.mjs +54 -0
  18. package/dist/fesm2022/embedpdf-angular-history.mjs.map +1 -0
  19. package/dist/fesm2022/embedpdf-angular-i18n.mjs +100 -0
  20. package/dist/fesm2022/embedpdf-angular-i18n.mjs.map +1 -0
  21. package/dist/fesm2022/embedpdf-angular-interaction.mjs +157 -0
  22. package/dist/fesm2022/embedpdf-angular-interaction.mjs.map +1 -0
  23. package/dist/fesm2022/embedpdf-angular-link.mjs +306 -0
  24. package/dist/fesm2022/embedpdf-angular-link.mjs.map +1 -0
  25. package/dist/fesm2022/embedpdf-angular-measurement.mjs +106 -0
  26. package/dist/fesm2022/embedpdf-angular-measurement.mjs.map +1 -0
  27. package/dist/fesm2022/embedpdf-angular-metadata.mjs +77 -0
  28. package/dist/fesm2022/embedpdf-angular-metadata.mjs.map +1 -0
  29. package/dist/fesm2022/embedpdf-angular-page-edit.mjs +65 -0
  30. package/dist/fesm2022/embedpdf-angular-page-edit.mjs.map +1 -0
  31. package/dist/fesm2022/embedpdf-angular-page-view.mjs +297 -0
  32. package/dist/fesm2022/embedpdf-angular-page-view.mjs.map +1 -0
  33. package/dist/fesm2022/embedpdf-angular-redaction.mjs +93 -0
  34. package/dist/fesm2022/embedpdf-angular-redaction.mjs.map +1 -0
  35. package/dist/fesm2022/embedpdf-angular-render.mjs +331 -69
  36. package/dist/fesm2022/embedpdf-angular-render.mjs.map +1 -1
  37. package/dist/fesm2022/embedpdf-angular-runtime.mjs +1147 -390
  38. package/dist/fesm2022/embedpdf-angular-runtime.mjs.map +1 -1
  39. package/dist/fesm2022/embedpdf-angular-search.mjs +251 -0
  40. package/dist/fesm2022/embedpdf-angular-search.mjs.map +1 -0
  41. package/dist/fesm2022/embedpdf-angular-selection.mjs +477 -0
  42. package/dist/fesm2022/embedpdf-angular-selection.mjs.map +1 -0
  43. package/dist/fesm2022/embedpdf-angular-shell.mjs +177 -0
  44. package/dist/fesm2022/embedpdf-angular-shell.mjs.map +1 -0
  45. package/dist/fesm2022/embedpdf-angular-signature.mjs +120 -0
  46. package/dist/fesm2022/embedpdf-angular-signature.mjs.map +1 -0
  47. package/dist/fesm2022/embedpdf-angular-stage.mjs +688 -288
  48. package/dist/fesm2022/embedpdf-angular-stage.mjs.map +1 -1
  49. package/dist/fesm2022/embedpdf-angular-stamp.mjs +169 -0
  50. package/dist/fesm2022/embedpdf-angular-stamp.mjs.map +1 -0
  51. package/dist/fesm2022/embedpdf-angular-testing.mjs +89 -0
  52. package/dist/fesm2022/embedpdf-angular-testing.mjs.map +1 -0
  53. package/dist/fesm2022/embedpdf-angular-toolbar.mjs +1123 -0
  54. package/dist/fesm2022/embedpdf-angular-toolbar.mjs.map +1 -0
  55. package/dist/fesm2022/embedpdf-angular-view-manager.mjs +69 -0
  56. package/dist/fesm2022/embedpdf-angular-view-manager.mjs.map +1 -0
  57. package/dist/fesm2022/embedpdf-angular.mjs +23 -3
  58. package/dist/fesm2022/embedpdf-angular.mjs.map +1 -1
  59. package/dist/form/index.d.ts +79 -0
  60. package/dist/history/index.d.ts +28 -0
  61. package/dist/i18n/index.d.ts +52 -0
  62. package/dist/index.d.ts +20 -0
  63. package/dist/interaction/index.d.ts +58 -0
  64. package/dist/link/index.d.ts +77 -0
  65. package/dist/measurement/index.d.ts +46 -0
  66. package/dist/metadata/index.d.ts +51 -0
  67. package/dist/page-edit/index.d.ts +22 -0
  68. package/dist/page-view/index.d.ts +94 -0
  69. package/dist/redaction/index.d.ts +38 -0
  70. package/dist/render/index.d.ts +45 -6
  71. package/dist/runtime/index.d.ts +579 -199
  72. package/dist/search/index.d.ts +71 -0
  73. package/dist/selection/index.d.ts +141 -0
  74. package/dist/shell/index.d.ts +88 -0
  75. package/dist/signature/index.d.ts +45 -0
  76. package/dist/stage/index.d.ts +242 -141
  77. package/dist/stamp/index.d.ts +58 -0
  78. package/dist/testing/index.d.ts +53 -0
  79. package/dist/toolbar/index.d.ts +257 -0
  80. package/dist/view-manager/index.d.ts +23 -0
  81. package/package.json +135 -14
@@ -0,0 +1,477 @@
1
+ import { selectionState, SelectionToken, selectionPlugin, HANDLE_PAD, HANDLE_BAR, HANDLE_HEAD, SELECTION_DEFAULTS, selectionHandleEndpointsOf, selectionHandleViewOf, armSelectionHandle, selectionHandleGeom } from '@embedpdf/plugin-selection';
2
+ export * from '@embedpdf/plugin-selection';
3
+ import { svgPoints, quadInPixels, paint, mixAccent, samePageBounds, attachSelectionHandle, sameSelectionEndpoints, wireSelectionClipboard } from '@embedpdf/web';
4
+ export { copySelection } from '@embedpdf/web';
5
+ import * as i0 from '@angular/core';
6
+ import { Injectable, computed, effect, untracked, ChangeDetectionStrategy, Component, input, inject, ElementRef, DestroyRef, Directive, signal, output, PLATFORM_ID } from '@angular/core';
7
+ import { pluginService, injectPage, injectKernelHost, CapabilityBinding, injectDocumentScope, devWarn } from '@embedpdf/angular/runtime';
8
+ import { SelectionToken as SelectionToken$1 } from '@embedpdf/plugin-selection/contract/host';
9
+ import { EpdfAnchored, EPDF_PROJECTOR } from '@embedpdf/angular/anchored';
10
+ import { StageToken } from '@embedpdf/plugin-stage/contract';
11
+ import { EpdfStage } from '@embedpdf/angular/stage';
12
+ import { isPlatformBrowser } from '@angular/common';
13
+
14
+ /**
15
+ * The selection plugin's service and feature:
16
+ *
17
+ * withSelection(options) the plugin, for provideEmbedPdf() (it needs withInteraction())
18
+ * inject(EpdfSelection) select from code, read the selected text, the State table as
19
+ * signals (`hasSelection()`, `isSelecting()`, `range()`, `pages()`),
20
+ * `changed$` / `committed$` / `cleared$`, and the settings
21
+ */
22
+ /**
23
+ * Text selection: `select()` and the other methods of the Selecting page, every value of its
24
+ * State table as a signal (`selection.hasSelection()`), its events as streams
25
+ * (`selection.committed$`), and its settings (`selection.settings()`,
26
+ * `selection.updateSettings({ color })`). Without a document the signals read empty and the
27
+ * methods refuse with `not-ready`.
28
+ */
29
+ class EpdfSelection extends pluginService({
30
+ name: 'EpdfSelection',
31
+ feature: 'withSelection()',
32
+ token: SelectionToken,
33
+ state: selectionState,
34
+ methods: [
35
+ 'select',
36
+ 'selectWordAt',
37
+ 'selectLineAt',
38
+ 'selectPage',
39
+ 'selectAll',
40
+ 'extendTo',
41
+ 'clear',
42
+ 'readText',
43
+ 'readTextInRange',
44
+ 'listSegments',
45
+ 'listRects',
46
+ 'getAnchor',
47
+ 'getSnapshot',
48
+ 'getRange',
49
+ 'listSelectedPages',
50
+ 'canSelect',
51
+ 'canCopy',
52
+ ],
53
+ events: ['onChanged', 'onCommitted', 'onCleared'],
54
+ }) {
55
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.4", ngImport: i0, type: EpdfSelection, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
56
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.2.4", ngImport: i0, type: EpdfSelection, providedIn: 'root' });
57
+ }
58
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.4", ngImport: i0, type: EpdfSelection, decorators: [{
59
+ type: Injectable,
60
+ args: [{ providedIn: 'root' }]
61
+ }] });
62
+ /**
63
+ * The selection plugin: selecting text with the pointer, a finger and from code. It works with
64
+ * the interaction plugin, so give `withInteraction()` too:
65
+ * `provideEmbedPdf({ engine }, withStage(), withInteraction(), withSelection())`.
66
+ */
67
+ function withSelection(options) {
68
+ return { plugins: [selectionPlugin(options)], services: [EpdfSelection] };
69
+ }
70
+
71
+ /**
72
+ * `<epdf-selection-layer>`: the highlight of the selected text on one page. It only draws: the
73
+ * pointer goes to the interaction plugin (the Stage and the page view pass it on), and the
74
+ * selection plugin decides what is selected.
75
+ *
76
+ * Each selected line is a polygon of its four corners, placed through the page context, so
77
+ * turned text and turned pages are drawn exactly. The color is the plugin's `color` setting,
78
+ * the viewer's accent at 35% while it's unset, and the `--epdf-text-selection` CSS variable
79
+ * wins over both.
80
+ */
81
+ const NO_SEGMENTS = Object.freeze([]);
82
+ class EpdfSelectionLayer {
83
+ page = injectPage('<epdf-selection-layer>');
84
+ host = injectKernelHost('<epdf-selection-layer>');
85
+ /** The selection plugin of the page's own document, with what layers need of it. */
86
+ selection = new CapabilityBinding(this.host, () => SelectionToken$1, () => this.page.documentId);
87
+ /** This page's selected lines: the same array until the selection on this page changes. */
88
+ segments = this.selection.select((selection) => selection.listSegments(this.page.ref), NO_SEGMENTS);
89
+ /** False while something else draws the selection itself (a highlighter's preview). */
90
+ visible = this.selection.select((selection) => selection.isHighlightVisible(), true);
91
+ color = this.selection.select((selection) => selection.getSettings().color, null);
92
+ /** Each line's corners in the page's pixels, which turn with the page. */
93
+ polygons = computed(() => {
94
+ const transform = this.page.transform();
95
+ return this.segments().map((segment) => svgPoints(quadInPixels(segment.quad, transform)));
96
+ }, ...(ngDevMode ? [{ debugName: "polygons" }] : []));
97
+ /** The CSS variable, then the setting, then the accent (with its own variable) at 35%. */
98
+ fill = computed(() => paint('text-selection', this.color() ?? mixAccent('text-selection', this.host.viewerSettings().accent)), ...(ngDevMode ? [{ debugName: "fill" }] : []));
99
+ constructor() {
100
+ // Read the page's text geometry as soon as the page is shown, so the first press can find
101
+ // the text under it at once. Without permission to select, nothing is read.
102
+ effect(() => {
103
+ const selection = this.selection.capability();
104
+ const page = this.page.ref;
105
+ if (selection)
106
+ untracked(() => void selection.ensureLoaded(page));
107
+ });
108
+ }
109
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.4", ngImport: i0, type: EpdfSelectionLayer, deps: [], target: i0.ɵɵFactoryTarget.Component });
110
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.2.4", type: EpdfSelectionLayer, isStandalone: true, selector: "epdf-selection-layer", ngImport: i0, template: `
111
+ @if (visible() && polygons().length > 0) {
112
+ <svg
113
+ style="position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none"
114
+ >
115
+ @for (points of polygons(); track $index) {
116
+ <!-- The fill goes in style: an SVG attribute doesn't read var(). -->
117
+ <polygon [attr.points]="points" [style.fill]="fill()" />
118
+ }
119
+ </svg>
120
+ }
121
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
122
+ }
123
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.4", ngImport: i0, type: EpdfSelectionLayer, decorators: [{
124
+ type: Component,
125
+ args: [{
126
+ selector: 'epdf-selection-layer',
127
+ changeDetection: ChangeDetectionStrategy.OnPush,
128
+ template: `
129
+ @if (visible() && polygons().length > 0) {
130
+ <svg
131
+ style="position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none"
132
+ >
133
+ @for (points of polygons(); track $index) {
134
+ <!-- The fill goes in style: an SVG attribute doesn't read var(). -->
135
+ <polygon [attr.points]="points" [style.fill]="fill()" />
136
+ }
137
+ </svg>
138
+ }
139
+ `,
140
+ }]
141
+ }], ctorParameters: () => [] });
142
+
143
+ /**
144
+ * `<epdf-selection-menu>`: your UI next to the selected text. Put it inside `<epdf-stage>`,
145
+ * next to the page template, with what the menu holds between its tags:
146
+ *
147
+ * <epdf-stage>
148
+ * <ng-template epdfPage>…</ng-template>
149
+ * <epdf-selection-menu placement="bottom">
150
+ * <button (click)="copy()">Copy</button>
151
+ * </epdf-selection-menu>
152
+ * </epdf-stage>
153
+ *
154
+ * It hides while the user drags and appears when the selection settles (a selection made from
155
+ * code shows at once). One menu for the whole selection: it sits by the selection on the page
156
+ * where it ends. It rides `<epdf-anchored>`, so it moves with the pages in the same frame, and a
157
+ * click in it never reaches the page.
158
+ */
159
+ class EpdfSelectionMenu {
160
+ /** Which side of the selection: `'top'`, `'bottom'`, `'left'` or `'right'`, or a corner. */
161
+ placement = input('top', ...(ngDevMode ? [{ debugName: "placement" }] : []));
162
+ /** Screen pixels between the selection and the menu. */
163
+ gap = input(8, ...(ngDevMode ? [{ debugName: "gap" }] : []));
164
+ /** The selection of the document this part of the template talks to. */
165
+ selection = new CapabilityBinding(injectKernelHost('<epdf-selection-menu>'), () => SelectionToken, injectDocumentScope());
166
+ selecting = this.selection.select((selection) => selection.isSelecting(), false);
167
+ // A fresh object on every read: compared by value, so the menu moves only when the selection
168
+ // did.
169
+ settled = this.selection.select((selection) => selection.getAnchor(), null, samePageBounds);
170
+ /** Where the menu goes; nothing while a drag is still selecting. */
171
+ anchor = computed(() => (this.selecting() ? null : this.settled()), ...(ngDevMode ? [{ debugName: "anchor" }] : []));
172
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.4", ngImport: i0, type: EpdfSelectionMenu, deps: [], target: i0.ɵɵFactoryTarget.Component });
173
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.2.4", type: EpdfSelectionMenu, isStandalone: true, selector: "epdf-selection-menu", inputs: { placement: { classPropertyName: "placement", publicName: "placement", isSignal: true, isRequired: false, transformFunction: null }, gap: { classPropertyName: "gap", publicName: "gap", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
174
+ <epdf-anchored [anchor]="anchor()" [placement]="placement()" [gap]="gap()">
175
+ <ng-content />
176
+ </epdf-anchored>
177
+ `, isInline: true, dependencies: [{ kind: "component", type: EpdfAnchored, selector: "epdf-anchored", inputs: ["anchor", "placement", "gap", "pinned"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
178
+ }
179
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.4", ngImport: i0, type: EpdfSelectionMenu, decorators: [{
180
+ type: Component,
181
+ args: [{
182
+ selector: 'epdf-selection-menu',
183
+ imports: [EpdfAnchored],
184
+ changeDetection: ChangeDetectionStrategy.OnPush,
185
+ template: `
186
+ <epdf-anchored [anchor]="anchor()" [placement]="placement()" [gap]="gap()">
187
+ <ng-content />
188
+ </epdf-anchored>
189
+ `,
190
+ }]
191
+ }] });
192
+
193
+ /**
194
+ * `<epdf-selection-handles>`: the handles at both ends of the selection, as phones draw them, so
195
+ * a finger can grow or shrink it. Put it inside `<epdf-stage>`, next to the selection menu.
196
+ *
197
+ * Each handle is the selection's own edge, a thin bar the height of the text at that end (it
198
+ * turns with turned text and turned pages), with a round grip above the first line at the start
199
+ * and below the last line at the end. Dragging one extends the selection from the other end,
200
+ * through the same gesture a pointer drag uses, so the highlight, the menu and the events all
201
+ * behave the same. A press on a handle never scrolls the Stage.
202
+ *
203
+ * What's decided is the selection plugin's (`selectionHandleViewOf`, `selectionHandleEndpointsOf`,
204
+ * `selectionHandleGeom`, `armSelectionHandle`) and the listener mechanics are `@embedpdf/web`'s
205
+ * (`attachSelectionHandle`); this file keeps
206
+ * the markup and the colors: the plugin's `handles` setting, the accent while its color is
207
+ * unset, and the `--epdf-text-selection-handle` and `--epdf-text-selection-handle-shadow` CSS
208
+ * variables over both.
209
+ */
210
+ const NO_HANDLES = Object.freeze([]);
211
+ /**
212
+ * Binds the drag to one handle element. `arm` is read when a press comes, so it always works
213
+ * with the selection as it is then.
214
+ */
215
+ class EpdfSelectionGrip {
216
+ arm = input.required(...(ngDevMode ? [{ debugName: "arm", alias: 'epdfSelectionGrip' }] : [{
217
+ alias: 'epdfSelectionGrip',
218
+ }]));
219
+ constructor() {
220
+ const element = inject(ElementRef).nativeElement;
221
+ inject(DestroyRef).onDestroy(attachSelectionHandle(element, { arm: () => this.arm()() }));
222
+ }
223
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.4", ngImport: i0, type: EpdfSelectionGrip, deps: [], target: i0.ɵɵFactoryTarget.Directive });
224
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.2.4", type: EpdfSelectionGrip, isStandalone: true, selector: "[epdfSelectionGrip]", inputs: { arm: { classPropertyName: "arm", publicName: "epdfSelectionGrip", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
225
+ }
226
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.4", ngImport: i0, type: EpdfSelectionGrip, decorators: [{
227
+ type: Directive,
228
+ args: [{ selector: '[epdfSelectionGrip]' }]
229
+ }], ctorParameters: () => [] });
230
+ class EpdfSelectionHandles {
231
+ /** The view the handles are drawn over: the Stage they're in, unless you name another. */
232
+ token = input(undefined, ...(ngDevMode ? [{ debugName: "token" }] : []));
233
+ pad = HANDLE_PAD;
234
+ bar = HANDLE_BAR;
235
+ head = HANDLE_HEAD;
236
+ gripWidth = HANDLE_BAR + 2 * HANDLE_PAD;
237
+ host = injectKernelHost('<epdf-selection-handles>');
238
+ enclosingStage = inject(EpdfStage, { optional: true });
239
+ /** How the surface it's in places things: the Stage's camera, or nothing to project through. */
240
+ projection = inject(EPDF_PROJECTOR, { optional: true });
241
+ documentId = injectDocumentScope();
242
+ selection = new CapabilityBinding(this.host, () => SelectionToken$1, this.documentId);
243
+ stage = new CapabilityBinding(this.host, () => this.token() ?? this.enclosingStage?.token() ?? StageToken, this.documentId).capability;
244
+ selecting = this.selection.select((selection) => selection.isSelecting(), false);
245
+ visible = this.selection.select((selection) => selection.isHighlightVisible(), true);
246
+ settings = this.selection.select((selection) => selection.getSettings().handles, SELECTION_DEFAULTS.handles);
247
+ /** Both ends of the selection, compared corner by corner: the same until one moves. */
248
+ endpoints = this.selection.select((selection) => selectionHandleEndpointsOf(selection.getSnapshot()), null, sameSelectionEndpoints);
249
+ /** The handle being dragged: it keeps both handles shown while it selects. */
250
+ dragging = signal(null, ...(ngDevMode ? [{ debugName: "dragging" }] : []));
251
+ /** Each color is its CSS variable first, then the setting; an unset color is the accent. */
252
+ color = computed(() => paint('text-selection-handle', this.settings().color ?? this.host.viewerSettings().accent), ...(ngDevMode ? [{ debugName: "color" }] : []));
253
+ shadow = computed(() => paint('text-selection-handle-shadow', this.settings().shadow), ...(ngDevMode ? [{ debugName: "shadow" }] : []));
254
+ /** Whether this sits over a Stage, the only surface with a camera to place handles through. */
255
+ overStage = computed(() => this.projection?.projector()?.space === 'overlay', ...(ngDevMode ? [{ debugName: "overStage" }] : []));
256
+ handles = computed(() => {
257
+ const stage = this.stage();
258
+ const endpoints = this.endpoints();
259
+ if (!this.overStage() || !stage || !endpoints || !this.visible())
260
+ return NO_HANDLES;
261
+ // Hidden while a drag selects text, like the menu; a handle's own drag keeps them.
262
+ if (this.selecting() && !this.dragging())
263
+ return NO_HANDLES;
264
+ // The camera: the handles move in the same pass as the pages.
265
+ this.projection?.revision();
266
+ const view = selectionHandleViewOf(stage);
267
+ return ['start', 'end'].flatMap((role) => {
268
+ const layout = layoutOf(view, endpoints[role], role);
269
+ return layout ? [layout] : [];
270
+ });
271
+ }, ...(ngDevMode ? [{ debugName: "handles" }] : []));
272
+ armStart = () => this.arm('start');
273
+ armEnd = () => this.arm('end');
274
+ constructor() {
275
+ if (!this.projection)
276
+ warnOutsideStage();
277
+ effect(() => {
278
+ if (this.projection?.projector()?.space === 'client')
279
+ warnOutsideStage();
280
+ });
281
+ }
282
+ /** A press on a handle: start a drag from the other end, with the selection as it is now. */
283
+ arm(role) {
284
+ const stage = untracked(this.stage);
285
+ const endpoints = untracked(this.endpoints);
286
+ const selection = untracked(this.selection.capability);
287
+ if (!stage || !endpoints || !selection)
288
+ return null;
289
+ const armed = armSelectionHandle(selection, selectionHandleViewOf(stage), endpoints, role);
290
+ if (!armed)
291
+ return null;
292
+ this.dragging.set(role);
293
+ return {
294
+ // The point the user grabbed: the middle of the bar.
295
+ base: armed.base,
296
+ session: {
297
+ move: armed.drag.move,
298
+ end: () => {
299
+ armed.drag.end(); // settles: the menu comes back, and committed$ fires
300
+ this.dragging.set(null);
301
+ },
302
+ },
303
+ };
304
+ }
305
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.4", ngImport: i0, type: EpdfSelectionHandles, deps: [], target: i0.ɵɵFactoryTarget.Component });
306
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.2.4", type: EpdfSelectionHandles, isStandalone: true, selector: "epdf-selection-handles", inputs: { token: { classPropertyName: "token", publicName: "token", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
307
+ @for (handle of handles(); track handle.role) {
308
+ <div
309
+ style="position: absolute; touch-action: none; cursor: grab; pointer-events: auto"
310
+ [epdfSelectionGrip]="handle.role === 'start' ? armStart : armEnd"
311
+ [style.left.px]="handle.left"
312
+ [style.top.px]="handle.top"
313
+ [style.width.px]="gripWidth"
314
+ [style.height.px]="handle.height"
315
+ [style.transform]="handle.transform"
316
+ [style.transform-origin]="handle.transformOrigin"
317
+ >
318
+ <!-- The bar: the selection's own edge, as tall as the text at that end. -->
319
+ <div
320
+ style="position: absolute"
321
+ [style.left.px]="pad"
322
+ [style.top.px]="handle.barTop"
323
+ [style.width.px]="bar"
324
+ [style.height.px]="handle.barHeight"
325
+ [style.border-radius.px]="bar / 2"
326
+ [style.background]="color()"
327
+ ></div>
328
+ <!-- The grip: against the bar, above the text at the start, below it at the end. -->
329
+ <div
330
+ style="position: absolute; border-radius: 50%"
331
+ [style.left.px]="pad + bar / 2 - head / 2"
332
+ [style.top.px]="handle.headTop"
333
+ [style.width.px]="head"
334
+ [style.height.px]="head"
335
+ [style.background]="color()"
336
+ [style.box-shadow]="shadow()"
337
+ ></div>
338
+ </div>
339
+ }
340
+ `, isInline: true, dependencies: [{ kind: "directive", type: EpdfSelectionGrip, selector: "[epdfSelectionGrip]", inputs: ["epdfSelectionGrip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
341
+ }
342
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.4", ngImport: i0, type: EpdfSelectionHandles, decorators: [{
343
+ type: Component,
344
+ args: [{
345
+ selector: 'epdf-selection-handles',
346
+ imports: [EpdfSelectionGrip],
347
+ changeDetection: ChangeDetectionStrategy.OnPush,
348
+ template: `
349
+ @for (handle of handles(); track handle.role) {
350
+ <div
351
+ style="position: absolute; touch-action: none; cursor: grab; pointer-events: auto"
352
+ [epdfSelectionGrip]="handle.role === 'start' ? armStart : armEnd"
353
+ [style.left.px]="handle.left"
354
+ [style.top.px]="handle.top"
355
+ [style.width.px]="gripWidth"
356
+ [style.height.px]="handle.height"
357
+ [style.transform]="handle.transform"
358
+ [style.transform-origin]="handle.transformOrigin"
359
+ >
360
+ <!-- The bar: the selection's own edge, as tall as the text at that end. -->
361
+ <div
362
+ style="position: absolute"
363
+ [style.left.px]="pad"
364
+ [style.top.px]="handle.barTop"
365
+ [style.width.px]="bar"
366
+ [style.height.px]="handle.barHeight"
367
+ [style.border-radius.px]="bar / 2"
368
+ [style.background]="color()"
369
+ ></div>
370
+ <!-- The grip: against the bar, above the text at the start, below it at the end. -->
371
+ <div
372
+ style="position: absolute; border-radius: 50%"
373
+ [style.left.px]="pad + bar / 2 - head / 2"
374
+ [style.top.px]="handle.headTop"
375
+ [style.width.px]="head"
376
+ [style.height.px]="head"
377
+ [style.background]="color()"
378
+ [style.box-shadow]="shadow()"
379
+ ></div>
380
+ </div>
381
+ }
382
+ `,
383
+ }]
384
+ }], ctorParameters: () => [] });
385
+ /**
386
+ * A handle laid out upright in its own box (the bar as long as the text is tall, the grip
387
+ * above it at the start or below it at the end), then turned onto the text's edge about the
388
+ * bar's top end: the one point that must sit exactly on the glyph's corner.
389
+ */
390
+ function layoutOf(view, endpoint, role) {
391
+ const geometry = selectionHandleGeom(view, endpoint, role);
392
+ if (!geometry)
393
+ return null; // its page isn't laid out right now
394
+ const barTop = HANDLE_PAD + (role === 'start' ? HANDLE_HEAD : 0);
395
+ const pivotX = HANDLE_PAD + HANDLE_BAR / 2;
396
+ return {
397
+ role,
398
+ left: geometry.bar.from.x - pivotX,
399
+ top: geometry.bar.from.y - barTop,
400
+ height: geometry.length + HANDLE_HEAD + 2 * HANDLE_PAD,
401
+ barTop,
402
+ barHeight: geometry.length,
403
+ headTop: role === 'start' ? HANDLE_PAD : HANDLE_PAD + geometry.length,
404
+ transform: geometry.upright ? null : `rotate(${geometry.rotation}deg)`,
405
+ transformOrigin: geometry.upright ? null : `${pivotX}px ${barTop}px`,
406
+ };
407
+ }
408
+ function warnOutsideStage() {
409
+ devWarn('selection-handles-outside-stage', '<epdf-selection-handles> draws nothing here: put it inside <epdf-stage> ' +
410
+ '(an <epdf-page-view> has no camera to place the handles through).');
411
+ }
412
+
413
+ /**
414
+ * Ctrl+C, Cmd+C and the browser's Copy menu copy the selected text. It draws nothing:
415
+ *
416
+ * <epdf-selection-clipboard /> once next to a document view: anywhere on the page
417
+ * <div tabindex="0" epdfSelectionClipboard> only while focus is inside that element, for a
418
+ * page with more than one viewer
419
+ *
420
+ * It reads the selected text as soon as a selection settles, so the browser's copy event can be
421
+ * answered at once (it can't wait for a read), and copies with the Clipboard API when there's
422
+ * no page selection for the browser to copy. `[prefetch]="false"` reads the text only when
423
+ * someone copies. A selection the user may not copy isn't copied, and `(refused)` fires. The mechanics are `@embedpdf/web`'s, shared by every framework.
424
+ */
425
+ class EpdfSelectionClipboard {
426
+ /** Read the selected text when the selection settles (default true). */
427
+ prefetch = input(undefined, ...(ngDevMode ? [{ debugName: "prefetch" }] : []));
428
+ /** Ctrl+C or the Copy menu met a selection the user may not copy: say so. */
429
+ refused = output();
430
+ selection = new CapabilityBinding(injectKernelHost('<epdf-selection-clipboard>'), () => SelectionToken, injectDocumentScope()).capability;
431
+ constructor() {
432
+ const host = inject(ElementRef).nativeElement;
433
+ if (!isPlatformBrowser(inject(PLATFORM_ID)))
434
+ return;
435
+ // Its own element copies anywhere on the page; another element, only from inside it.
436
+ const target = host.localName === 'epdf-selection-clipboard' ? undefined : host;
437
+ // Wired for the document's selection while there is one; again for the next document.
438
+ effect((onCleanup) => {
439
+ const selection = this.selection();
440
+ const prefetch = this.prefetch();
441
+ if (!selection)
442
+ return;
443
+ onCleanup(wireSelectionClipboard(selection, {
444
+ ...(prefetch === undefined ? {} : { prefetch }),
445
+ ...(target ? { target } : {}),
446
+ onRefused: () => this.refused.emit(),
447
+ }));
448
+ });
449
+ }
450
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.4", ngImport: i0, type: EpdfSelectionClipboard, deps: [], target: i0.ɵɵFactoryTarget.Directive });
451
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.2.4", type: EpdfSelectionClipboard, isStandalone: true, selector: "epdf-selection-clipboard, [epdfSelectionClipboard]", inputs: { prefetch: { classPropertyName: "prefetch", publicName: "prefetch", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { refused: "refused" }, ngImport: i0 });
452
+ }
453
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.4", ngImport: i0, type: EpdfSelectionClipboard, decorators: [{
454
+ type: Directive,
455
+ args: [{ selector: 'epdf-selection-clipboard, [epdfSelectionClipboard]' }]
456
+ }], ctorParameters: () => [] });
457
+
458
+ /**
459
+ * @embedpdf/angular/selection: selecting and copying text.
460
+ *
461
+ * withSelection(options) the plugin, for provideEmbedPdf() (with withInteraction())
462
+ * inject(EpdfSelection) select from code, read the text, the state, the events
463
+ * <epdf-selection-layer> the highlight, in each page
464
+ * <epdf-selection-menu> your menu next to the selection, inside <epdf-stage>
465
+ * <epdf-selection-handles> the handles a finger drags, inside <epdf-stage>
466
+ * <epdf-selection-clipboard> Ctrl+C and the browser's Copy menu
467
+ * <div epdfSelectionClipboard> the same, only while focus is inside that element
468
+ * copySelection(selection) the selected text to the clipboard, from your own button
469
+ */
470
+ // The plugin's types and helpers, so app code has one import for the feature.
471
+
472
+ /**
473
+ * Generated bundle index. Do not edit.
474
+ */
475
+
476
+ export { EpdfSelection, EpdfSelectionClipboard, EpdfSelectionHandles, EpdfSelectionLayer, EpdfSelectionMenu, withSelection };
477
+ //# sourceMappingURL=embedpdf-angular-selection.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedpdf-angular-selection.mjs","sources":["../../selection/src/selection.ts","../../selection/src/selection-layer.ts","../../selection/src/selection-menu.ts","../../selection/src/selection-handles.ts","../../selection/src/selection-clipboard.ts","../../selection/src/public_api.ts","../../selection/src/embedpdf-angular-selection.ts"],"sourcesContent":["/**\n * The selection plugin's service and feature:\n *\n * withSelection(options) the plugin, for provideEmbedPdf() (it needs withInteraction())\n * inject(EpdfSelection) select from code, read the selected text, the State table as\n * signals (`hasSelection()`, `isSelecting()`, `range()`, `pages()`),\n * `changed$` / `committed$` / `cleared$`, and the settings\n */\nimport { Injectable } from '@angular/core';\nimport { pluginService, type EmbedPdfFeature } from '@embedpdf/angular/runtime';\nimport {\n selectionPlugin,\n selectionState,\n SelectionToken,\n type SelectionConfig,\n} from '@embedpdf/plugin-selection';\n\n/**\n * Text selection: `select()` and the other methods of the Selecting page, every value of its\n * State table as a signal (`selection.hasSelection()`), its events as streams\n * (`selection.committed$`), and its settings (`selection.settings()`,\n * `selection.updateSettings({ color })`). Without a document the signals read empty and the\n * methods refuse with `not-ready`.\n */\n@Injectable({ providedIn: 'root' })\nexport class EpdfSelection extends pluginService({\n name: 'EpdfSelection',\n feature: 'withSelection()',\n token: SelectionToken,\n state: selectionState,\n methods: [\n 'select',\n 'selectWordAt',\n 'selectLineAt',\n 'selectPage',\n 'selectAll',\n 'extendTo',\n 'clear',\n 'readText',\n 'readTextInRange',\n 'listSegments',\n 'listRects',\n 'getAnchor',\n 'getSnapshot',\n 'getRange',\n 'listSelectedPages',\n 'canSelect',\n 'canCopy',\n ],\n events: ['onChanged', 'onCommitted', 'onCleared'],\n}) {}\n\n/**\n * The selection plugin: selecting text with the pointer, a finger and from code. It works with\n * the interaction plugin, so give `withInteraction()` too:\n * `provideEmbedPdf({ engine }, withStage(), withInteraction(), withSelection())`.\n */\nexport function withSelection(options?: SelectionConfig): EmbedPdfFeature {\n return { plugins: [selectionPlugin(options)], services: [EpdfSelection] };\n}\n","/**\n * `<epdf-selection-layer>`: the highlight of the selected text on one page. It only draws: the\n * pointer goes to the interaction plugin (the Stage and the page view pass it on), and the\n * selection plugin decides what is selected.\n *\n * Each selected line is a polygon of its four corners, placed through the page context, so\n * turned text and turned pages are drawn exactly. The color is the plugin's `color` setting,\n * the viewer's accent at 35% while it's unset, and the `--epdf-text-selection` CSS variable\n * wins over both.\n */\nimport { ChangeDetectionStrategy, Component, computed, effect, untracked } from '@angular/core';\nimport {\n SelectionToken as SelectionHostToken,\n type SelectionHostCapability,\n type SelectionSegment,\n} from '@embedpdf/plugin-selection/contract/host';\nimport { mixAccent, paint, quadInPixels, svgPoints } from '@embedpdf/web';\nimport { CapabilityBinding, injectKernelHost, injectPage } from '@embedpdf/angular/runtime';\n\nconst NO_SEGMENTS: readonly SelectionSegment[] = Object.freeze([]);\n\n@Component({\n selector: 'epdf-selection-layer',\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n @if (visible() && polygons().length > 0) {\n <svg\n style=\"position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none\"\n >\n @for (points of polygons(); track $index) {\n <!-- The fill goes in style: an SVG attribute doesn't read var(). -->\n <polygon [attr.points]=\"points\" [style.fill]=\"fill()\" />\n }\n </svg>\n }\n `,\n})\nexport class EpdfSelectionLayer {\n private readonly page = injectPage('<epdf-selection-layer>');\n private readonly host = injectKernelHost('<epdf-selection-layer>');\n /** The selection plugin of the page's own document, with what layers need of it. */\n private readonly selection = new CapabilityBinding<SelectionHostCapability>(\n this.host,\n () => SelectionHostToken,\n () => this.page.documentId,\n );\n\n /** This page's selected lines: the same array until the selection on this page changes. */\n private readonly segments = this.selection.select(\n (selection) => selection.listSegments(this.page.ref),\n NO_SEGMENTS,\n );\n /** False while something else draws the selection itself (a highlighter's preview). */\n protected readonly visible = this.selection.select(\n (selection) => selection.isHighlightVisible(),\n true,\n );\n private readonly color = this.selection.select(\n (selection) => selection.getSettings().color,\n null,\n );\n\n /** Each line's corners in the page's pixels, which turn with the page. */\n protected readonly polygons = computed(() => {\n const transform = this.page.transform();\n return this.segments().map((segment) => svgPoints(quadInPixels(segment.quad, transform)));\n });\n /** The CSS variable, then the setting, then the accent (with its own variable) at 35%. */\n protected readonly fill = computed(() =>\n paint(\n 'text-selection',\n this.color() ?? mixAccent('text-selection', this.host.viewerSettings().accent),\n ),\n );\n\n constructor() {\n // Read the page's text geometry as soon as the page is shown, so the first press can find\n // the text under it at once. Without permission to select, nothing is read.\n effect(() => {\n const selection = this.selection.capability();\n const page = this.page.ref;\n if (selection) untracked(() => void selection.ensureLoaded(page));\n });\n }\n}\n","/**\n * `<epdf-selection-menu>`: your UI next to the selected text. Put it inside `<epdf-stage>`,\n * next to the page template, with what the menu holds between its tags:\n *\n * <epdf-stage>\n * <ng-template epdfPage>…</ng-template>\n * <epdf-selection-menu placement=\"bottom\">\n * <button (click)=\"copy()\">Copy</button>\n * </epdf-selection-menu>\n * </epdf-stage>\n *\n * It hides while the user drags and appears when the selection settles (a selection made from\n * code shows at once). One menu for the whole selection: it sits by the selection on the page\n * where it ends. It rides `<epdf-anchored>`, so it moves with the pages in the same frame, and a\n * click in it never reaches the page.\n */\nimport { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';\nimport { SelectionToken } from '@embedpdf/plugin-selection';\nimport { samePageBounds } from '@embedpdf/web';\nimport {\n CapabilityBinding,\n injectDocumentScope,\n injectKernelHost,\n} from '@embedpdf/angular/runtime';\nimport { EpdfAnchored, type AnchoredPlacement } from '@embedpdf/angular/anchored';\n\n@Component({\n selector: 'epdf-selection-menu',\n imports: [EpdfAnchored],\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <epdf-anchored [anchor]=\"anchor()\" [placement]=\"placement()\" [gap]=\"gap()\">\n <ng-content />\n </epdf-anchored>\n `,\n})\nexport class EpdfSelectionMenu {\n /** Which side of the selection: `'top'`, `'bottom'`, `'left'` or `'right'`, or a corner. */\n readonly placement = input<AnchoredPlacement>('top');\n /** Screen pixels between the selection and the menu. */\n readonly gap = input(8);\n\n /** The selection of the document this part of the template talks to. */\n private readonly selection = new CapabilityBinding(\n injectKernelHost('<epdf-selection-menu>'),\n () => SelectionToken,\n injectDocumentScope(),\n );\n private readonly selecting = this.selection.select((selection) => selection.isSelecting(), false);\n // A fresh object on every read: compared by value, so the menu moves only when the selection\n // did.\n private readonly settled = this.selection.select(\n (selection) => selection.getAnchor(),\n null,\n samePageBounds,\n );\n /** Where the menu goes; nothing while a drag is still selecting. */\n protected readonly anchor = computed(() => (this.selecting() ? null : this.settled()));\n}\n","/**\n * `<epdf-selection-handles>`: the handles at both ends of the selection, as phones draw them, so\n * a finger can grow or shrink it. Put it inside `<epdf-stage>`, next to the selection menu.\n *\n * Each handle is the selection's own edge, a thin bar the height of the text at that end (it\n * turns with turned text and turned pages), with a round grip above the first line at the start\n * and below the last line at the end. Dragging one extends the selection from the other end,\n * through the same gesture a pointer drag uses, so the highlight, the menu and the events all\n * behave the same. A press on a handle never scrolls the Stage.\n *\n * What's decided is the selection plugin's (`selectionHandleViewOf`, `selectionHandleEndpointsOf`,\n * `selectionHandleGeom`, `armSelectionHandle`) and the listener mechanics are `@embedpdf/web`'s\n * (`attachSelectionHandle`); this file keeps\n * the markup and the colors: the plugin's `handles` setting, the accent while its color is\n * unset, and the `--epdf-text-selection-handle` and `--epdf-text-selection-handle-shadow` CSS\n * variables over both.\n */\nimport {\n ChangeDetectionStrategy,\n Component,\n computed,\n DestroyRef,\n Directive,\n effect,\n ElementRef,\n inject,\n input,\n signal,\n untracked,\n} from '@angular/core';\nimport type { CapabilityToken } from '@embedpdf/core';\nimport {\n armSelectionHandle,\n HANDLE_BAR,\n HANDLE_HEAD,\n HANDLE_PAD,\n SELECTION_DEFAULTS,\n selectionHandleEndpointsOf,\n selectionHandleGeom,\n selectionHandleViewOf,\n type SelectionHandleEndpoint,\n type SelectionHandleView,\n} from '@embedpdf/plugin-selection';\nimport {\n SelectionToken as SelectionHostToken,\n type SelectionHostCapability,\n} from '@embedpdf/plugin-selection/contract/host';\nimport { StageToken, type StageCapability } from '@embedpdf/plugin-stage/contract';\nimport { attachSelectionHandle, paint, sameSelectionEndpoints } from '@embedpdf/web';\nimport type { SelectionHandleSession } from '@embedpdf/web';\nimport {\n CapabilityBinding,\n devWarn,\n injectDocumentScope,\n injectKernelHost,\n} from '@embedpdf/angular/runtime';\nimport { EPDF_PROJECTOR } from '@embedpdf/angular/anchored';\nimport { EpdfStage } from '@embedpdf/angular/stage';\n\ntype Role = 'start' | 'end';\n\n/** One handle, laid out in the Stage's own box. */\ninterface HandleLayout {\n readonly role: Role;\n readonly left: number;\n readonly top: number;\n readonly height: number;\n readonly barTop: number;\n readonly barHeight: number;\n readonly headTop: number;\n /** Null for upright text: an upright handle carries no transform. */\n readonly transform: string | null;\n readonly transformOrigin: string | null;\n}\n\nconst NO_HANDLES: readonly HandleLayout[] = Object.freeze([]);\n\n/** What a press on a handle starts: the point it grabbed (the bar's middle), and the drag. */\nexport type SelectionGripDrag = {\n readonly base: { readonly x: number; readonly y: number };\n readonly session: SelectionHandleSession;\n} | null;\n\n/**\n * Binds the drag to one handle element. `arm` is read when a press comes, so it always works\n * with the selection as it is then.\n */\n@Directive({ selector: '[epdfSelectionGrip]' })\nexport class EpdfSelectionGrip {\n readonly arm = input.required<() => SelectionGripDrag>({\n alias: 'epdfSelectionGrip',\n });\n\n constructor() {\n const element = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n inject(DestroyRef).onDestroy(attachSelectionHandle(element, { arm: () => this.arm()() }));\n }\n}\n\n@Component({\n selector: 'epdf-selection-handles',\n imports: [EpdfSelectionGrip],\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n @for (handle of handles(); track handle.role) {\n <div\n style=\"position: absolute; touch-action: none; cursor: grab; pointer-events: auto\"\n [epdfSelectionGrip]=\"handle.role === 'start' ? armStart : armEnd\"\n [style.left.px]=\"handle.left\"\n [style.top.px]=\"handle.top\"\n [style.width.px]=\"gripWidth\"\n [style.height.px]=\"handle.height\"\n [style.transform]=\"handle.transform\"\n [style.transform-origin]=\"handle.transformOrigin\"\n >\n <!-- The bar: the selection's own edge, as tall as the text at that end. -->\n <div\n style=\"position: absolute\"\n [style.left.px]=\"pad\"\n [style.top.px]=\"handle.barTop\"\n [style.width.px]=\"bar\"\n [style.height.px]=\"handle.barHeight\"\n [style.border-radius.px]=\"bar / 2\"\n [style.background]=\"color()\"\n ></div>\n <!-- The grip: against the bar, above the text at the start, below it at the end. -->\n <div\n style=\"position: absolute; border-radius: 50%\"\n [style.left.px]=\"pad + bar / 2 - head / 2\"\n [style.top.px]=\"handle.headTop\"\n [style.width.px]=\"head\"\n [style.height.px]=\"head\"\n [style.background]=\"color()\"\n [style.box-shadow]=\"shadow()\"\n ></div>\n </div>\n }\n `,\n})\nexport class EpdfSelectionHandles {\n /** The view the handles are drawn over: the Stage they're in, unless you name another. */\n readonly token = input<CapabilityToken<StageCapability> | undefined>(undefined);\n\n protected readonly pad = HANDLE_PAD;\n protected readonly bar = HANDLE_BAR;\n protected readonly head = HANDLE_HEAD;\n protected readonly gripWidth = HANDLE_BAR + 2 * HANDLE_PAD;\n\n private readonly host = injectKernelHost('<epdf-selection-handles>');\n private readonly enclosingStage = inject(EpdfStage, { optional: true });\n /** How the surface it's in places things: the Stage's camera, or nothing to project through. */\n private readonly projection = inject(EPDF_PROJECTOR, { optional: true });\n private readonly documentId = injectDocumentScope();\n\n private readonly selection = new CapabilityBinding<SelectionHostCapability>(\n this.host,\n () => SelectionHostToken,\n this.documentId,\n );\n private readonly stage = new CapabilityBinding<StageCapability>(\n this.host,\n () => this.token() ?? this.enclosingStage?.token() ?? StageToken,\n this.documentId,\n ).capability;\n\n private readonly selecting = this.selection.select((selection) => selection.isSelecting(), false);\n private readonly visible = this.selection.select(\n (selection) => selection.isHighlightVisible(),\n true,\n );\n private readonly settings = this.selection.select(\n (selection) => selection.getSettings().handles,\n SELECTION_DEFAULTS.handles,\n );\n /** Both ends of the selection, compared corner by corner: the same until one moves. */\n private readonly endpoints = this.selection.select(\n (selection) => selectionHandleEndpointsOf(selection.getSnapshot()),\n null,\n sameSelectionEndpoints,\n );\n /** The handle being dragged: it keeps both handles shown while it selects. */\n private readonly dragging = signal<Role | null>(null);\n\n /** Each color is its CSS variable first, then the setting; an unset color is the accent. */\n protected readonly color = computed(() =>\n paint('text-selection-handle', this.settings().color ?? this.host.viewerSettings().accent),\n );\n protected readonly shadow = computed(() =>\n paint('text-selection-handle-shadow', this.settings().shadow),\n );\n\n /** Whether this sits over a Stage, the only surface with a camera to place handles through. */\n private readonly overStage = computed(() => this.projection?.projector()?.space === 'overlay');\n\n protected readonly handles = computed((): readonly HandleLayout[] => {\n const stage = this.stage();\n const endpoints = this.endpoints();\n if (!this.overStage() || !stage || !endpoints || !this.visible()) return NO_HANDLES;\n // Hidden while a drag selects text, like the menu; a handle's own drag keeps them.\n if (this.selecting() && !this.dragging()) return NO_HANDLES;\n // The camera: the handles move in the same pass as the pages.\n this.projection?.revision();\n const view = selectionHandleViewOf(stage);\n return (['start', 'end'] as const).flatMap((role) => {\n const layout = layoutOf(view, endpoints[role], role);\n return layout ? [layout] : [];\n });\n });\n\n protected readonly armStart = () => this.arm('start');\n protected readonly armEnd = () => this.arm('end');\n\n constructor() {\n if (!this.projection) warnOutsideStage();\n effect(() => {\n if (this.projection?.projector()?.space === 'client') warnOutsideStage();\n });\n }\n\n /** A press on a handle: start a drag from the other end, with the selection as it is now. */\n private arm(role: Role): SelectionGripDrag {\n const stage = untracked(this.stage);\n const endpoints = untracked(this.endpoints);\n const selection = untracked(this.selection.capability);\n if (!stage || !endpoints || !selection) return null;\n const armed = armSelectionHandle(selection, selectionHandleViewOf(stage), endpoints, role);\n if (!armed) return null;\n this.dragging.set(role);\n return {\n // The point the user grabbed: the middle of the bar.\n base: armed.base,\n session: {\n move: armed.drag.move,\n end: () => {\n armed.drag.end(); // settles: the menu comes back, and committed$ fires\n this.dragging.set(null);\n },\n },\n };\n }\n}\n\n/**\n * A handle laid out upright in its own box (the bar as long as the text is tall, the grip\n * above it at the start or below it at the end), then turned onto the text's edge about the\n * bar's top end: the one point that must sit exactly on the glyph's corner.\n */\nfunction layoutOf(\n view: SelectionHandleView,\n endpoint: SelectionHandleEndpoint,\n role: Role,\n): HandleLayout | null {\n const geometry = selectionHandleGeom(view, endpoint, role);\n if (!geometry) return null; // its page isn't laid out right now\n const barTop = HANDLE_PAD + (role === 'start' ? HANDLE_HEAD : 0);\n const pivotX = HANDLE_PAD + HANDLE_BAR / 2;\n return {\n role,\n left: geometry.bar.from.x - pivotX,\n top: geometry.bar.from.y - barTop,\n height: geometry.length + HANDLE_HEAD + 2 * HANDLE_PAD,\n barTop,\n barHeight: geometry.length,\n headTop: role === 'start' ? HANDLE_PAD : HANDLE_PAD + geometry.length,\n transform: geometry.upright ? null : `rotate(${geometry.rotation}deg)`,\n transformOrigin: geometry.upright ? null : `${pivotX}px ${barTop}px`,\n };\n}\n\nfunction warnOutsideStage(): void {\n devWarn(\n 'selection-handles-outside-stage',\n '<epdf-selection-handles> draws nothing here: put it inside <epdf-stage> ' +\n '(an <epdf-page-view> has no camera to place the handles through).',\n );\n}\n","/**\n * Ctrl+C, Cmd+C and the browser's Copy menu copy the selected text. It draws nothing:\n *\n * <epdf-selection-clipboard /> once next to a document view: anywhere on the page\n * <div tabindex=\"0\" epdfSelectionClipboard> only while focus is inside that element, for a\n * page with more than one viewer\n *\n * It reads the selected text as soon as a selection settles, so the browser's copy event can be\n * answered at once (it can't wait for a read), and copies with the Clipboard API when there's\n * no page selection for the browser to copy. `[prefetch]=\"false\"` reads the text only when\n * someone copies. A selection the user may not copy isn't copied, and `(refused)` fires. The mechanics are `@embedpdf/web`'s, shared by every framework.\n */\nimport { isPlatformBrowser } from '@angular/common';\nimport { Directive, effect, ElementRef, inject, input, output, PLATFORM_ID } from '@angular/core';\nimport { SelectionToken } from '@embedpdf/plugin-selection';\nimport { wireSelectionClipboard } from '@embedpdf/web';\nimport {\n CapabilityBinding,\n injectDocumentScope,\n injectKernelHost,\n} from '@embedpdf/angular/runtime';\n\n@Directive({ selector: 'epdf-selection-clipboard, [epdfSelectionClipboard]' })\nexport class EpdfSelectionClipboard {\n /** Read the selected text when the selection settles (default true). */\n readonly prefetch = input<boolean | undefined>(undefined);\n /** Ctrl+C or the Copy menu met a selection the user may not copy: say so. */\n readonly refused = output<void>();\n\n private readonly selection = new CapabilityBinding(\n injectKernelHost('<epdf-selection-clipboard>'),\n () => SelectionToken,\n injectDocumentScope(),\n ).capability;\n\n constructor() {\n const host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n if (!isPlatformBrowser(inject(PLATFORM_ID))) return;\n // Its own element copies anywhere on the page; another element, only from inside it.\n const target = host.localName === 'epdf-selection-clipboard' ? undefined : host;\n // Wired for the document's selection while there is one; again for the next document.\n effect((onCleanup) => {\n const selection = this.selection();\n const prefetch = this.prefetch();\n if (!selection) return;\n onCleanup(\n wireSelectionClipboard(selection, {\n ...(prefetch === undefined ? {} : { prefetch }),\n ...(target ? { target } : {}),\n onRefused: () => this.refused.emit(),\n }),\n );\n });\n }\n}\n","/**\n * @embedpdf/angular/selection: selecting and copying text.\n *\n * withSelection(options) the plugin, for provideEmbedPdf() (with withInteraction())\n * inject(EpdfSelection) select from code, read the text, the state, the events\n * <epdf-selection-layer> the highlight, in each page\n * <epdf-selection-menu> your menu next to the selection, inside <epdf-stage>\n * <epdf-selection-handles> the handles a finger drags, inside <epdf-stage>\n * <epdf-selection-clipboard> Ctrl+C and the browser's Copy menu\n * <div epdfSelectionClipboard> the same, only while focus is inside that element\n * copySelection(selection) the selected text to the clipboard, from your own button\n */\n\n// The plugin's types and helpers, so app code has one import for the feature.\nexport * from '@embedpdf/plugin-selection';\n// The clipboard write lives in @embedpdf/web (the plugin never touches the DOM); re-exported so\n// the whole feature is one import.\nexport { copySelection } from '@embedpdf/web';\nexport * from './selection';\nexport { EpdfSelectionLayer } from './selection-layer';\nexport { EpdfSelectionMenu } from './selection-menu';\nexport { EpdfSelectionHandles } from './selection-handles';\nexport { EpdfSelectionClipboard } from './selection-clipboard';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":["SelectionHostToken"],"mappings":"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"}