@embedpdf/angular 3.0.0-next.15 → 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.
@@ -11,7 +11,7 @@ import * as i0 from '@angular/core';
11
11
  import { Signal, TemplateRef, Injector } from '@angular/core';
12
12
  import { Observable } from 'rxjs';
13
13
  import * as _embedpdf_web from '@embedpdf/web';
14
- import { FramePixels, PictureOrPainting, TextBoxStyle } from '@embedpdf/web';
14
+ import { FramePixels, PictureOrPainting, OwnTextBox } from '@embedpdf/web';
15
15
  import { AnchoredPlacement, EpdfAnchor } from '@embedpdf/angular/anchored';
16
16
 
17
17
  /** `annotation.selection`: what is selected, the verbs that change it as one, and its style panel. */
@@ -487,16 +487,19 @@ declare class EpdfAnnotationLayer {
487
487
 
488
488
  /**
489
489
  * Your own element as the editor of a text box you draw yourself, in a look
490
- * (`<ng-template [epdfAnnotation]="isTextBox" let-annotation>`):
490
+ * (`<ng-template [epdfAnnotation]="isTextBox" let-annotation>`), inside the element that draws
491
+ * the box's frame:
491
492
  *
492
- * <div [epdfRichTextEditor]="annotation" #editor="epdfRichTextEditor"
493
- * class="text-box" [class.editing]="editor.editing()"></div>
493
+ * <div class="text-box" [class.editing]="editor.editing()">
494
+ * <div [epdfRichTextEditor]="annotation" #editor="epdfRichTextEditor"></div>
495
+ * </div>
494
496
  *
495
497
  * It draws the runs, turns typing back into runs, keeps the caret when the style changes, and
496
498
  * handles pasting, input methods and the format shortcuts; `text.toggleFormat()` and
497
499
  * `selection.update()` work on it as on the layer's own box. It gives the element the box's
498
- * body style (font, size, color and alignment), and while someone types it takes the pointer.
499
- * Leave the element empty: the editor fills it.
500
+ * body style (font, size, color and alignment), filling its parent at a legible size
501
+ * (`ownTextBoxOf`), so draw the box's fill, border and padding on the parent; while someone
502
+ * types it takes the pointer. Leave the element empty: the editor fills it.
500
503
  */
501
504
  declare class EpdfRichTextEditor {
502
505
  /** The free text annotation this element edits: the template's `let-annotation`. */
@@ -506,12 +509,12 @@ declare class EpdfRichTextEditor {
506
509
  private readonly lookScale;
507
510
  private readonly view;
508
511
  private readonly pixels;
509
- /** The annotation's text box on the page, or null while there is none. */
512
+ /** The annotation's text box, saved and idle too (this element draws its text), or null. */
510
513
  private readonly item;
511
514
  /** Pixels per point where the element is: in a scaled look, at the annotation's 100% size. */
512
515
  private readonly scale;
513
- /** The box's body style: font, size, color and alignment, or null while there is no box. */
514
- protected readonly look: Signal<TextBoxStyle | null>;
516
+ /** The element's style and the scale its text is laid out at, or null while there is no box. */
517
+ protected readonly own: Signal<OwnTextBox | null>;
515
518
  /** True while someone types in the box. */
516
519
  readonly editing: Signal<boolean>;
517
520
  constructor();
@@ -0,0 +1,29 @@
1
+ import * as _embedpdf_plugin_attachment from '@embedpdf/plugin-attachment';
2
+ export * from '@embedpdf/plugin-attachment';
3
+ import * as _embedpdf_angular_runtime from '@embedpdf/angular/runtime';
4
+ import { EmbedPdfFeature } from '@embedpdf/angular/runtime';
5
+ import * as _embedpdf_core from '@embedpdf/core';
6
+ import * as i0 from '@angular/core';
7
+
8
+ declare const EpdfAttachment_base: _embedpdf_angular_runtime.PluginServiceClass<_embedpdf_plugin_attachment.AttachmentCapability, {
9
+ files: readonly _embedpdf_plugin_attachment.AttachedFile[];
10
+ selected: readonly _embedpdf_plugin_attachment.AttachedFile[];
11
+ status: _embedpdf_core.ResourceStatus;
12
+ canAdd: boolean;
13
+ canDownload: boolean;
14
+ }, "add" | "download" | "select" | "get" | "isPending" | "refresh" | "ensureLoaded" | "canRemove" | "remove" | "reveal", "onResynced" | "onChanged">;
15
+ /**
16
+ * The files of the document in scope (`[epdfDocumentScope]`), else the active one: the State
17
+ * table as signals (`files()`, `selected()`, `status()`, `canAdd()`, `canDownload()`), the
18
+ * reads that take a file (`get()`, `isPending()`, `canRemove()`), the calls that select, add,
19
+ * remove, save and go to files, and the streams `changed$` and `resynced$`. Reading it reads the attachments. With no
20
+ * document the signals read empty, and every call refuses with `not-ready`.
21
+ */
22
+ declare class EpdfAttachment extends EpdfAttachment_base {
23
+ static ɵfac: i0.ɵɵFactoryDeclaration<EpdfAttachment, never>;
24
+ static ɵprov: i0.ɵɵInjectableDeclaration<EpdfAttachment>;
25
+ }
26
+ /** The attachments, for `provideEmbedPdf()`. */
27
+ declare function withAttachment(): EmbedPdfFeature;
28
+
29
+ export { EpdfAttachment, withAttachment };
@@ -1,10 +1,10 @@
1
1
  import { AnnotationToken, annotationState, annotationPlugin, ANNOTATION_DEFAULTS } from '@embedpdf/plugin-annotation';
2
2
  export * from '@embedpdf/plugin-annotation';
3
3
  import * as i0 from '@angular/core';
4
- import { computed, Injectable, inject, DestroyRef, input, ChangeDetectionStrategy, Component, Directive, booleanAttribute, TemplateRef, InjectionToken, effect, untracked, ElementRef, Injector, contentChildren, contentChild, signal, PLATFORM_ID } from '@angular/core';
4
+ import { computed, Injectable, inject, DestroyRef, input, ChangeDetectionStrategy, Component, Directive, booleanAttribute, TemplateRef, InjectionToken, afterRenderEffect, untracked, ElementRef, Injector, contentChildren, contentChild, signal, PLATFORM_ID, effect } from '@angular/core';
5
5
  import { EpdfPluginService, injectDocumentScope, pluginService, CapabilityBinding, injectKernelHost, devWarn, injectPage, EpdfSvgShapes, paintsPagePart, outsideStageError } from '@embedpdf/angular/runtime';
6
6
  import { AnnotationToken as AnnotationToken$1, previewBucket } from '@embedpdf/plugin-annotation/contract/host';
7
- import { enrichCommentThreads, sameAnnotationAnchor, pickRequestedFile, annotationChromePaint, chromeInPixels, sceneViewBox, svgShapesOf, ghostOpacity, rasterInFrame, createTextBoxEditorFollower, textPlateInPixels, textBoxStyleOf, textBoxEditorScaleOf, createShownUrls, editingTextKeyOf, frameInPixels, bakedAppearanceOf, pictureOrPainting, shownAppearance, annotationDrawingOf, lookFrameOf, layerTextBoxesOf, rectInPixels, registerRendererBehaviors, loadAppearanceUrls, loadObjectUrl, sameSelectionAnchor, sameCreationDraftAnchor, sameRotationAnchor, paintDefault, paint } from '@embedpdf/web';
7
+ import { enrichCommentThreads, sameAnnotationAnchor, pickRequestedFile, annotationChromePaint, chromeInPixels, sceneViewBox, svgShapesOf, ghostOpacity, rasterInFrame, createTextBoxEditorFollower, freeTextBoxOf, textBoxEditorScaleOf, ownTextBoxOf, createShownUrls, editingTextKeyOf, frameInPixels, bakedAppearanceOf, pictureOrPainting, shownAppearance, annotationDrawingOf, lookFrameOf, layerTextBoxesOf, rectInPixels, registerRendererBehaviors, loadAppearanceUrls, loadObjectUrl, sameSelectionAnchor, sameCreationDraftAnchor, sameRotationAnchor, paintDefault, paint } from '@embedpdf/web';
8
8
  import { annotationKey } from '@embedpdf/core';
9
9
  import { NgTemplateOutlet, isPlatformBrowser } from '@angular/common';
10
10
  import { scene, MITER_LIMIT, hasLiveDrawing } from '@embedpdf/core-annotation';
@@ -1128,21 +1128,27 @@ const EPDF_LOOK_SCALE = new InjectionToken('EPDF_LOOK_SCALE');
1128
1128
  * Make `element` the editor of the text box `item()` reads, at `scale()` pixels per point: the
1129
1129
  * binding attaches when the plugin is there (again for another document), and redraws only
1130
1130
  * when the text differs. Call it in an injection context; it lets go when the caller goes.
1131
+ *
1132
+ * It follows after the render, not before: when typing starts, the look's frame around the
1133
+ * element stops being inert in that same render, and an element inside an inert one can't take
1134
+ * focus (the editor's `focus()` would do nothing, and the keys would go to the page).
1131
1135
  */
1132
1136
  function bindTextBoxEditor(element, annotation, item, scale) {
1133
1137
  const follower = createTextBoxEditorFollower();
1134
- effect(() => {
1135
- const host = annotation();
1136
- const next = item();
1137
- const at = scale();
1138
- untracked(() => follower.follow(element, host, next, at));
1138
+ afterRenderEffect({
1139
+ write: () => {
1140
+ const host = annotation();
1141
+ const next = item();
1142
+ const at = scale();
1143
+ untracked(() => follower.follow(element, host, next, at));
1144
+ },
1139
1145
  });
1140
1146
  inject(DestroyRef).onDestroy(() => follower.detach());
1141
1147
  }
1142
1148
  /**
1143
1149
  * The layer's own text box for one free text: the engine's text plate (the box inset by its
1144
- * padding), styled like the box's body, with no padding of its own so its edge is the plate's.
1145
- * The box's fill and border are the vector scene's, under it. It takes the pointer only while
1150
+ * padding), styled like the box's body and laid out at a legible size (`freeTextBoxOf`). The
1151
+ * box's fill and border are the vector scene's, under it. It takes the pointer only while
1146
1152
  * someone types in it; otherwise clicks fall through to the shapes (select, move, resize).
1147
1153
  */
1148
1154
  class EpdfFreeTextBox {
@@ -1152,56 +1158,37 @@ class EpdfFreeTextBox {
1152
1158
  outline = input.required(...(ngDevMode ? [{ debugName: "outline" }] : []));
1153
1159
  page = injectPage('[epdfFreeTextBox]');
1154
1160
  pixels = pagePixelsOf(this.page);
1155
- plate = computed(() => textPlateInPixels(this.item(), this.pixels()), ...(ngDevMode ? [{ debugName: "plate" }] : []));
1156
- look = computed(() => textBoxStyleOf(this.item().css, this.plate().scale), ...(ngDevMode ? [{ debugName: "look" }] : []));
1161
+ box = computed(() => freeTextBoxOf(this.item(), this.pixels(), this.outline()), ...(ngDevMode ? [{ debugName: "box" }] : []));
1157
1162
  constructor() {
1158
1163
  const annotation = annotationHostOf(this.page, '[epdfFreeTextBox]').capability;
1159
- bindTextBoxEditor(inject(ElementRef).nativeElement, annotation, this.item, computed(() => this.plate().scale));
1164
+ bindTextBoxEditor(inject(ElementRef).nativeElement, annotation, this.item, computed(() => this.box().scale));
1160
1165
  }
1161
1166
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.4", ngImport: i0, type: EpdfFreeTextBox, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1162
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.2.4", type: EpdfFreeTextBox, isStandalone: true, selector: "[epdfFreeTextBox]", inputs: { item: { classPropertyName: "item", publicName: "epdfFreeTextBox", isSignal: true, isRequired: true, transformFunction: null }, outline: { classPropertyName: "outline", publicName: "outline", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "style.left.px": "plate().left", "style.top.px": "plate().top", "style.width.px": "plate().width", "style.height.px": "plate().height", "style.font-family": "look().fontFamily", "style.font-size": "look().fontSize", "style.color": "look().color", "style.font-weight": "look().fontWeight", "style.font-style": "look().fontStyle", "style.text-decoration": "look().textDecoration", "style.text-align": "look().textAlign", "style.overflow-y": "item().editing ? 'auto' : 'hidden'", "style.outline": "item().editing ? '1px solid ' + outline() : 'none'", "style.cursor": "item().editing ? 'text' : 'default'", "style.transform": "item().rot ? 'rotate(' + item().rot + 'deg)' : null", "style.pointer-events": "item().editing ? 'auto' : 'none'" }, styleAttribute: "position: absolute; box-sizing: border-box; background: transparent; white-space: pre-wrap; overflow-wrap: break-word; overflow-x: hidden; transform-origin: center" }, ngImport: i0 });
1167
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.2.4", type: EpdfFreeTextBox, isStandalone: true, selector: "[epdfFreeTextBox]", inputs: { item: { classPropertyName: "item", publicName: "epdfFreeTextBox", isSignal: true, isRequired: true, transformFunction: null }, outline: { classPropertyName: "outline", publicName: "outline", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "style": "box().style" } }, ngImport: i0 });
1163
1168
  }
1164
1169
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.4", ngImport: i0, type: EpdfFreeTextBox, decorators: [{
1165
1170
  type: Directive,
1166
1171
  args: [{
1167
1172
  selector: '[epdfFreeTextBox]',
1168
- host: {
1169
- style: 'position: absolute; box-sizing: border-box; background: transparent; ' +
1170
- 'white-space: pre-wrap; overflow-wrap: break-word; overflow-x: hidden; transform-origin: center',
1171
- '[style.left.px]': 'plate().left',
1172
- '[style.top.px]': 'plate().top',
1173
- '[style.width.px]': 'plate().width',
1174
- // Fixed to the plate: the box never grows with its text; it scrolls while typing and clips
1175
- // otherwise, where the baked appearance clips.
1176
- '[style.height.px]': 'plate().height',
1177
- '[style.font-family]': 'look().fontFamily',
1178
- '[style.font-size]': 'look().fontSize',
1179
- '[style.color]': 'look().color',
1180
- '[style.font-weight]': 'look().fontWeight',
1181
- '[style.font-style]': 'look().fontStyle',
1182
- '[style.text-decoration]': 'look().textDecoration',
1183
- '[style.text-align]': 'look().textAlign',
1184
- '[style.overflow-y]': "item().editing ? 'auto' : 'hidden'",
1185
- '[style.outline]': "item().editing ? '1px solid ' + outline() : 'none'",
1186
- '[style.cursor]': "item().editing ? 'text' : 'default'",
1187
- // A plain text box turns about its centre, as the baked appearance does.
1188
- '[style.transform]': "item().rot ? 'rotate(' + item().rot + 'deg)' : null",
1189
- '[style.pointer-events]': "item().editing ? 'auto' : 'none'",
1190
- },
1173
+ // Property by property: the editor's own line height on the element stays.
1174
+ host: { '[style]': 'box().style' },
1191
1175
  }]
1192
1176
  }], ctorParameters: () => [] });
1193
1177
  /**
1194
1178
  * Your own element as the editor of a text box you draw yourself, in a look
1195
- * (`<ng-template [epdfAnnotation]="isTextBox" let-annotation>`):
1179
+ * (`<ng-template [epdfAnnotation]="isTextBox" let-annotation>`), inside the element that draws
1180
+ * the box's frame:
1196
1181
  *
1197
- * <div [epdfRichTextEditor]="annotation" #editor="epdfRichTextEditor"
1198
- * class="text-box" [class.editing]="editor.editing()"></div>
1182
+ * <div class="text-box" [class.editing]="editor.editing()">
1183
+ * <div [epdfRichTextEditor]="annotation" #editor="epdfRichTextEditor"></div>
1184
+ * </div>
1199
1185
  *
1200
1186
  * It draws the runs, turns typing back into runs, keeps the caret when the style changes, and
1201
1187
  * handles pasting, input methods and the format shortcuts; `text.toggleFormat()` and
1202
1188
  * `selection.update()` work on it as on the layer's own box. It gives the element the box's
1203
- * body style (font, size, color and alignment), and while someone types it takes the pointer.
1204
- * Leave the element empty: the editor fills it.
1189
+ * body style (font, size, color and alignment), filling its parent at a legible size
1190
+ * (`ownTextBoxOf`), so draw the box's fill, border and padding on the parent; while someone
1191
+ * types it takes the pointer. Leave the element empty: the editor fills it.
1205
1192
  */
1206
1193
  class EpdfRichTextEditor {
1207
1194
  /** The free text annotation this element edits: the template's `let-annotation`. */
@@ -1211,44 +1198,30 @@ class EpdfRichTextEditor {
1211
1198
  lookScale = inject(EPDF_LOOK_SCALE, { optional: true });
1212
1199
  view = pageViewOf(this.page);
1213
1200
  pixels = pagePixelsOf(this.page);
1214
- /** The annotation's text box on the page, or null while there is none. */
1215
- item = this.host.select((annotation) => {
1216
- const key = annotationKey(this.annotation().ref);
1217
- return (annotation
1218
- .listTextItems(this.page.ref, this.view())
1219
- .find((text) => text.ref !== null && annotationKey(text.ref) === key) ?? null);
1220
- }, null);
1201
+ /** The annotation's text box, saved and idle too (this element draws its text), or null. */
1202
+ item = this.host.select((annotation) => annotation.getTextItem(this.annotation().ref, this.view()), null);
1221
1203
  /** Pixels per point where the element is: in a scaled look, at the annotation's 100% size. */
1222
1204
  scale = computed(() => textBoxEditorScaleOf(this.item(), this.pixels(), this.lookScale?.() ?? 1), ...(ngDevMode ? [{ debugName: "scale" }] : []));
1223
- /** The box's body style: font, size, color and alignment, or null while there is no box. */
1224
- look = computed(() => {
1205
+ /** The element's style and the scale its text is laid out at, or null while there is no box. */
1206
+ own = computed(() => {
1225
1207
  const item = this.item();
1226
- return item ? textBoxStyleOf(item.css, this.scale()) : null;
1227
- }, ...(ngDevMode ? [{ debugName: "look" }] : []));
1208
+ return item ? ownTextBoxOf(item, this.scale()) : null;
1209
+ }, ...(ngDevMode ? [{ debugName: "own" }] : []));
1228
1210
  /** True while someone types in the box. */
1229
1211
  editing = computed(() => this.item()?.editing ?? false, ...(ngDevMode ? [{ debugName: "editing" }] : []));
1230
1212
  constructor() {
1231
- bindTextBoxEditor(inject(ElementRef).nativeElement, this.host.capability, this.item, this.scale);
1213
+ bindTextBoxEditor(inject(ElementRef).nativeElement, this.host.capability, this.item, computed(() => this.own()?.scale ?? this.scale()));
1232
1214
  }
1233
1215
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.4", ngImport: i0, type: EpdfRichTextEditor, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1234
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.2.4", type: EpdfRichTextEditor, isStandalone: true, selector: "[epdfRichTextEditor]", inputs: { annotation: { classPropertyName: "annotation", publicName: "epdfRichTextEditor", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "style.font-family": "look()?.fontFamily ?? null", "style.font-size": "look()?.fontSize ?? null", "style.color": "look()?.color ?? null", "style.font-weight": "look()?.fontWeight ?? null", "style.font-style": "look()?.fontStyle ?? null", "style.text-decoration": "look()?.textDecoration ?? null", "style.text-align": "look()?.textAlign ?? null", "style.pointer-events": "editing() ? 'auto' : null" } }, exportAs: ["epdfRichTextEditor"], ngImport: i0 });
1216
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.2.4", type: EpdfRichTextEditor, isStandalone: true, selector: "[epdfRichTextEditor]", inputs: { annotation: { classPropertyName: "annotation", publicName: "epdfRichTextEditor", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "style": "own()?.style ?? null" } }, exportAs: ["epdfRichTextEditor"], ngImport: i0 });
1235
1217
  }
1236
1218
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.4", ngImport: i0, type: EpdfRichTextEditor, decorators: [{
1237
1219
  type: Directive,
1238
1220
  args: [{
1239
1221
  selector: '[epdfRichTextEditor]',
1240
1222
  exportAs: 'epdfRichTextEditor',
1241
- host: {
1242
- '[style.font-family]': 'look()?.fontFamily ?? null',
1243
- '[style.font-size]': 'look()?.fontSize ?? null',
1244
- '[style.color]': 'look()?.color ?? null',
1245
- '[style.font-weight]': 'look()?.fontWeight ?? null',
1246
- '[style.font-style]': 'look()?.fontStyle ?? null',
1247
- '[style.text-decoration]': 'look()?.textDecoration ?? null',
1248
- '[style.text-align]': 'look()?.textAlign ?? null',
1249
- // While typing, the element takes the pointer (the caret, a drag over words).
1250
- '[style.pointer-events]': "editing() ? 'auto' : null",
1251
- },
1223
+ // Property by property: the editor's own line height on the element stays.
1224
+ host: { '[style]': 'own()?.style ?? null' },
1252
1225
  }]
1253
1226
  }], ctorParameters: () => [] });
1254
1227