@embedpdf/plugin-link 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.
@@ -1,9 +1,10 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_contract = require("../contract-CaaMtYBR.cjs");
2
+ const require_contract = require("../contract-DXB_v4as.cjs");
3
3
  //#region src/host-contract.ts
4
4
  /** @embedpdf/plugin-link/contract/host: the host lens, the public capability plus what a framework binding supplies. */
5
5
  const LinkToken = (0, require("@embedpdf/core").createHostToken)(require_contract.LinkToken);
6
6
  //#endregion
7
7
  exports.LinkToken = LinkToken;
8
+ exports.resolveLinkTarget = require_contract.resolveLinkTarget;
8
9
 
9
10
  //# sourceMappingURL=host.cjs.map
@@ -1,3 +1,3 @@
1
- import { a as LinkCapability, c as PageDestination, i as LinkActivation, l as PdfLinkTarget, n as LinkActivateContext, o as LinkLoadedEvent, r as LinkActivatedEvent, s as LinkResolution, t as Link } from "../contract-C8by3cQG.cjs";
2
- import { n as LinkToken, r as UriOpener, t as LinkHostCapability } from "../host-contract-WJZHqcPp.cjs";
3
- export { Link, LinkActivateContext, LinkActivatedEvent, LinkActivation, LinkCapability, LinkHostCapability, LinkLoadedEvent, LinkResolution, LinkToken, type PageDestination, type PdfLinkTarget, UriOpener };
1
+ import { a as LinkCapability, c as PageDestination, i as LinkActivation, l as PdfLinkTarget, n as LinkActivateContext, o as LinkLoadedEvent, r as LinkActivatedEvent, s as LinkResolution, t as Link, u as resolveLinkTarget } from "../contract-B4x0DFCT.cjs";
2
+ import { n as LinkToken, r as UriOpener, t as LinkHostCapability } from "../host-contract-c0QOjhO6.cjs";
3
+ export { Link, LinkActivateContext, LinkActivatedEvent, LinkActivation, LinkCapability, LinkHostCapability, LinkLoadedEvent, LinkResolution, LinkToken, type PageDestination, type PdfLinkTarget, UriOpener, resolveLinkTarget };
@@ -1,3 +1,3 @@
1
- import { a as LinkCapability, c as PageDestination, i as LinkActivation, l as PdfLinkTarget, n as LinkActivateContext, o as LinkLoadedEvent, r as LinkActivatedEvent, s as LinkResolution, t as Link } from "../contract-BL4jWtGT.js";
2
- import { n as LinkToken, r as UriOpener, t as LinkHostCapability } from "../host-contract-BEEpcMUN.js";
3
- export { Link, LinkActivateContext, LinkActivatedEvent, LinkActivation, LinkCapability, LinkHostCapability, LinkLoadedEvent, LinkResolution, LinkToken, type PageDestination, type PdfLinkTarget, UriOpener };
1
+ import { a as LinkCapability, c as PageDestination, i as LinkActivation, l as PdfLinkTarget, n as LinkActivateContext, o as LinkLoadedEvent, r as LinkActivatedEvent, s as LinkResolution, t as Link, u as resolveLinkTarget } from "../contract-DyTXDEwb.js";
2
+ import { n as LinkToken, r as UriOpener, t as LinkHostCapability } from "../host-contract-DNwp7dlr.js";
3
+ export { Link, LinkActivateContext, LinkActivatedEvent, LinkActivation, LinkCapability, LinkHostCapability, LinkLoadedEvent, LinkResolution, LinkToken, type PageDestination, type PdfLinkTarget, UriOpener, resolveLinkTarget };
@@ -1,9 +1,9 @@
1
- import { t as LinkToken$1 } from "../contract-D0k-EtjB.js";
1
+ import { n as LinkToken$1, t as resolveLinkTarget } from "../contract-CJ9mhj7i.js";
2
2
  import { createHostToken } from "@embedpdf/core";
3
3
  //#region src/host-contract.ts
4
4
  /** @embedpdf/plugin-link/contract/host: the host lens, the public capability plus what a framework binding supplies. */
5
5
  const LinkToken = createHostToken(LinkToken$1);
6
6
  //#endregion
7
- export { LinkToken };
7
+ export { LinkToken, resolveLinkTarget };
8
8
 
9
9
  //# sourceMappingURL=host.js.map
@@ -58,6 +58,13 @@ type LinkResolution = {
58
58
  kind: 'reported';
59
59
  target: PdfLinkTarget;
60
60
  };
61
+ /**
62
+ * What activating a target would do, by the rule every link and outline item
63
+ * follows: a `goto` to a page `hasPage` knows is its destination, one to a
64
+ * page the document doesn't have is reported; a website and a named verb are
65
+ * handed on; anything else is reported.
66
+ */
67
+ declare function resolveLinkTarget(target: PdfLinkTarget, hasPage: (page: PageRef) => boolean): LinkResolution;
61
68
  interface LinkActivateContext {
62
69
  /** The link's `/A` tree when it has one; the actions plugin runs it instead of the target. */
63
70
  activate?: PdfActionTree;
@@ -132,5 +139,5 @@ interface LinkCapability {
132
139
  readonly onLoaded: EventHook<LinkLoadedEvent>;
133
140
  }
134
141
  //#endregion
135
- export { LinkCapability as a, PageDestination as c, LinkActivation as i, PdfLinkTarget as l, LinkActivateContext as n, LinkLoadedEvent as o, LinkActivatedEvent as r, LinkResolution as s, Link as t, LinkToken as u };
136
- //# sourceMappingURL=contract-C8by3cQG.d.cts.map
142
+ export { LinkCapability as a, PageDestination as c, LinkToken as d, LinkActivation as i, PdfLinkTarget as l, LinkActivateContext as n, LinkLoadedEvent as o, LinkActivatedEvent as r, LinkResolution as s, Link as t, resolveLinkTarget as u };
143
+ //# sourceMappingURL=contract-B4x0DFCT.d.cts.map
@@ -0,0 +1,46 @@
1
+ import { createCapabilityToken } from "@embedpdf/core";
2
+ //#region src/token.ts
3
+ /** The package token, created once here: `contract.ts` re-exports it and
4
+ * `host-contract.ts` widens it to the host capability. */
5
+ const LinkToken = createCapabilityToken("link", {
6
+ hint: `add linkPlugin() from '@embedpdf/plugin-link' to your plugins list`,
7
+ promises: {
8
+ listAllLinks: true,
9
+ ensureLoaded: true
10
+ }
11
+ });
12
+ //#endregion
13
+ //#region src/contract.ts
14
+ /**
15
+ * What activating a target would do, by the rule every link and outline item
16
+ * follows: a `goto` to a page `hasPage` knows is its destination, one to a
17
+ * page the document doesn't have is reported; a website and a named verb are
18
+ * handed on; anything else is reported.
19
+ */
20
+ function resolveLinkTarget(target, hasPage) {
21
+ switch (target.kind) {
22
+ case "goto": return hasPage(target.destination.page) ? {
23
+ kind: "destination",
24
+ destination: target.destination
25
+ } : {
26
+ kind: "reported",
27
+ target
28
+ };
29
+ case "uri": return {
30
+ kind: "uri",
31
+ uri: target.uri
32
+ };
33
+ case "named": return {
34
+ kind: "named",
35
+ name: target.name
36
+ };
37
+ default: return {
38
+ kind: "reported",
39
+ target
40
+ };
41
+ }
42
+ }
43
+ //#endregion
44
+ export { LinkToken as n, resolveLinkTarget as t };
45
+
46
+ //# sourceMappingURL=contract-CJ9mhj7i.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract-CJ9mhj7i.js","names":[],"sources":["../src/token.ts","../src/contract.ts"],"sourcesContent":["/** The package token, created once here: `contract.ts` re-exports it and\n * `host-contract.ts` widens it to the host capability. */\nimport { createCapabilityToken } from '@embedpdf/core';\n\nimport type { LinkCapability } from './contract';\n\nexport const LinkToken = createCapabilityToken<LinkCapability>('link', {\n hint: `add linkPlugin() from '@embedpdf/plugin-link' to your plugins list`,\n // Without a document, an adapter's stand-in rejects these with `not-ready`, as the\n // capability would; the type asks for every member that returns a promise.\n promises: {\n listAllLinks: true,\n ensureLoaded: true,\n },\n});\n","/** @embedpdf/plugin-link/contract: the public link vocabulary. */\nimport type { EventHook, OperationOptions, PageRef, ResourceStatus } from '@embedpdf/core';\nimport type { Point } from '@embedpdf/core-geometry';\nimport type {\n AnnotationRef,\n PageDestination,\n PdfActionTree,\n PdfLinkTarget,\n} from '@embedpdf/engine-core/runtime';\nimport type { ActionDispatchResult } from '@embedpdf/plugin-actions/contract';\nimport type { LinkNavItem } from '@embedpdf/plugin-annotation/contract';\nimport type { StageCapability } from '@embedpdf/plugin-stage/contract';\n\nexport { LinkToken } from './token';\n\n/**\n * A clickable link area: page-space `bounds`, its target, and its annotation\n * (when it is one). The target and `/A` tree are as the annotation holds\n * them, their destinations in page space.\n */\nexport type Link = LinkNavItem;\nexport type { PageDestination, PdfLinkTarget };\n\n/**\n * What activation did: `revealed` (the view went to a page), `uri` (a website\n * opened), `dispatched` (the actions plugin runs the link's action), or\n * `reported` (a link it won't follow). `destination`, `named` and a `uri`\n * with no framework to open it are handed to the caller to perform.\n */\nexport type LinkActivation =\n | { outcome: 'revealed' }\n | { outcome: 'destination'; destination: PageDestination }\n | { outcome: 'uri'; uri: string }\n | { outcome: 'named'; name: string }\n | { outcome: 'reported'; target: PdfLinkTarget }\n | { outcome: 'dispatched'; dispatch: Promise<ActionDispatchResult> }\n | { outcome: 'none' };\n\n/**\n * What activating a target would do, with no side effect. A `goto` to a page\n * of this document is its destination, ready for `stage.goToDestination`;\n * one to a page the document doesn't have is reported.\n */\nexport type LinkResolution =\n | { kind: 'destination'; destination: PageDestination }\n | { kind: 'uri'; uri: string }\n | { kind: 'named'; name: string }\n | { kind: 'reported'; target: PdfLinkTarget };\n\n/**\n * What activating a target would do, by the rule every link and outline item\n * follows: a `goto` to a page `hasPage` knows is its destination, one to a\n * page the document doesn't have is reported; a website and a named verb are\n * handed on; anything else is reported.\n */\nexport function resolveLinkTarget(\n target: PdfLinkTarget,\n hasPage: (page: PageRef) => boolean,\n): LinkResolution {\n switch (target.kind) {\n case 'goto':\n return hasPage(target.destination.page)\n ? { kind: 'destination', destination: target.destination }\n : { kind: 'reported', target };\n case 'uri':\n return { kind: 'uri', uri: target.uri };\n case 'named':\n return { kind: 'named', name: target.name };\n default:\n return { kind: 'reported', target };\n }\n}\n\nexport interface LinkActivateContext {\n /** The link's `/A` tree when it has one; the actions plugin runs it instead of the target. */\n activate?: PdfActionTree;\n ref?: AnnotationRef;\n page?: PageRef;\n /**\n * The view the link was followed in: a page destination moves this Stage.\n * Defaults to the main view.\n */\n stage?: StageCapability;\n}\n\n/** A link target was activated through this capability. */\nexport interface LinkActivatedEvent {\n readonly target: PdfLinkTarget;\n readonly activation: LinkActivation;\n}\n/** A page's links were read from the engine. */\nexport interface LinkLoadedEvent {\n readonly page: PageRef;\n}\n\nexport interface LinkCapability {\n /**\n * Clickable areas on a page (its ref or its index), page space.\n * Reference-stable per page while unchanged; empty for a page that isn't in\n * the document.\n */\n listLinks(page: PageRef | number): readonly Link[];\n /** One link by its stable id, or null. */\n getLink(page: PageRef | number, linkId: string): Link | null;\n /** The topmost (smallest) link under a page point, or null. */\n getLinkAt(page: PageRef | number, point: Point): Link | null;\n /**\n * Every link in the document; loads pages as needed. Rejects when a page's\n * read fails, and `operation-cancelled` when `signal` fires.\n */\n listAllLinks(options?: OperationOptions): Promise<readonly Link[]>;\n /**\n * Load a page's links. Resolves at once when the annotation plugin owns\n * them; rejects when the read fails, which `getStatus(page)` then reports,\n * `not-found` for a page that isn't in the document, and\n * `operation-cancelled` when `signal` fires.\n */\n ensureLoaded(page: PageRef | number, options?: OperationOptions): Promise<void>;\n /** The page's links were read and are current. Always true with the annotation plugin. */\n isLoaded(page: PageRef | number): boolean;\n /** Load state of a page's links: `idle`, `loading`, `ready`, `error` or `forbidden`. */\n getStatus(page: PageRef | number): ResourceStatus;\n /** What activation would do, with no side effect. */\n resolve(target: PdfLinkTarget): LinkResolution;\n /**\n * Follow a link, or a link's target, as a click does, and return what\n * happened at once (the user's gesture is still on the stack, so a website\n * can open in a new tab). A `goto` moves the Stage, by its `scrollBehavior`\n * setting; a website opens through the framework (an `http`, `https`,\n * `mailto` or `tel` address only); a link with an `/A` tree dispatches\n * through the actions plugin. Fires `onActivated`.\n */\n activate(target: PdfLinkTarget | Link, context?: LinkActivateContext): LinkActivation;\n /**\n * Hit test, then activate. Null when no link is there; throws `not-found`\n * for a page that isn't in the document.\n */\n activateAt(\n page: PageRef | number,\n point: Point,\n context?: LinkActivateContext,\n ): LinkActivation | null;\n /** A human label for tooltips. */\n getLabel(link: Link | PdfLinkTarget): string;\n /** After the built-in handling of any activation. */\n readonly onActivated: EventHook<LinkActivatedEvent>;\n /**\n * A page's links were read, first or again after an annotation change on\n * it. Never fires for a failed read, nor while the annotation plugin owns the links.\n */\n readonly onLoaded: EventHook<LinkLoadedEvent>;\n}\n"],"mappings":";;;;AAMA,MAAa,YAAY,sBAAsC,QAAQ;CACrE,MAAM;CAGN,UAAU;EACR,cAAc;EACd,cAAc;CAChB;AACF,CAAC;;;;;;;;;ACyCD,SAAgB,kBACd,QACA,SACgB;CAChB,QAAQ,OAAO,MAAf;EACE,KAAK,QACH,OAAO,QAAQ,OAAO,YAAY,IAAI,IAClC;GAAE,MAAM;GAAe,aAAa,OAAO;EAAY,IACvD;GAAE,MAAM;GAAY;EAAO;EACjC,KAAK,OACH,OAAO;GAAE,MAAM;GAAO,KAAK,OAAO;EAAI;EACxC,KAAK,SACH,OAAO;GAAE,MAAM;GAAS,MAAM,OAAO;EAAK;EAC5C,SACE,OAAO;GAAE,MAAM;GAAY;EAAO;CACtC;AACF"}
@@ -0,0 +1,56 @@
1
+ //#region src/token.ts
2
+ /** The package token, created once here: `contract.ts` re-exports it and
3
+ * `host-contract.ts` widens it to the host capability. */
4
+ const LinkToken = (0, require("@embedpdf/core").createCapabilityToken)("link", {
5
+ hint: `add linkPlugin() from '@embedpdf/plugin-link' to your plugins list`,
6
+ promises: {
7
+ listAllLinks: true,
8
+ ensureLoaded: true
9
+ }
10
+ });
11
+ //#endregion
12
+ //#region src/contract.ts
13
+ /**
14
+ * What activating a target would do, by the rule every link and outline item
15
+ * follows: a `goto` to a page `hasPage` knows is its destination, one to a
16
+ * page the document doesn't have is reported; a website and a named verb are
17
+ * handed on; anything else is reported.
18
+ */
19
+ function resolveLinkTarget(target, hasPage) {
20
+ switch (target.kind) {
21
+ case "goto": return hasPage(target.destination.page) ? {
22
+ kind: "destination",
23
+ destination: target.destination
24
+ } : {
25
+ kind: "reported",
26
+ target
27
+ };
28
+ case "uri": return {
29
+ kind: "uri",
30
+ uri: target.uri
31
+ };
32
+ case "named": return {
33
+ kind: "named",
34
+ name: target.name
35
+ };
36
+ default: return {
37
+ kind: "reported",
38
+ target
39
+ };
40
+ }
41
+ }
42
+ //#endregion
43
+ Object.defineProperty(exports, "LinkToken", {
44
+ enumerable: true,
45
+ get: function() {
46
+ return LinkToken;
47
+ }
48
+ });
49
+ Object.defineProperty(exports, "resolveLinkTarget", {
50
+ enumerable: true,
51
+ get: function() {
52
+ return resolveLinkTarget;
53
+ }
54
+ });
55
+
56
+ //# sourceMappingURL=contract-DXB_v4as.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract-DXB_v4as.cjs","names":[],"sources":["../src/token.ts","../src/contract.ts"],"sourcesContent":["/** The package token, created once here: `contract.ts` re-exports it and\n * `host-contract.ts` widens it to the host capability. */\nimport { createCapabilityToken } from '@embedpdf/core';\n\nimport type { LinkCapability } from './contract';\n\nexport const LinkToken = createCapabilityToken<LinkCapability>('link', {\n hint: `add linkPlugin() from '@embedpdf/plugin-link' to your plugins list`,\n // Without a document, an adapter's stand-in rejects these with `not-ready`, as the\n // capability would; the type asks for every member that returns a promise.\n promises: {\n listAllLinks: true,\n ensureLoaded: true,\n },\n});\n","/** @embedpdf/plugin-link/contract: the public link vocabulary. */\nimport type { EventHook, OperationOptions, PageRef, ResourceStatus } from '@embedpdf/core';\nimport type { Point } from '@embedpdf/core-geometry';\nimport type {\n AnnotationRef,\n PageDestination,\n PdfActionTree,\n PdfLinkTarget,\n} from '@embedpdf/engine-core/runtime';\nimport type { ActionDispatchResult } from '@embedpdf/plugin-actions/contract';\nimport type { LinkNavItem } from '@embedpdf/plugin-annotation/contract';\nimport type { StageCapability } from '@embedpdf/plugin-stage/contract';\n\nexport { LinkToken } from './token';\n\n/**\n * A clickable link area: page-space `bounds`, its target, and its annotation\n * (when it is one). The target and `/A` tree are as the annotation holds\n * them, their destinations in page space.\n */\nexport type Link = LinkNavItem;\nexport type { PageDestination, PdfLinkTarget };\n\n/**\n * What activation did: `revealed` (the view went to a page), `uri` (a website\n * opened), `dispatched` (the actions plugin runs the link's action), or\n * `reported` (a link it won't follow). `destination`, `named` and a `uri`\n * with no framework to open it are handed to the caller to perform.\n */\nexport type LinkActivation =\n | { outcome: 'revealed' }\n | { outcome: 'destination'; destination: PageDestination }\n | { outcome: 'uri'; uri: string }\n | { outcome: 'named'; name: string }\n | { outcome: 'reported'; target: PdfLinkTarget }\n | { outcome: 'dispatched'; dispatch: Promise<ActionDispatchResult> }\n | { outcome: 'none' };\n\n/**\n * What activating a target would do, with no side effect. A `goto` to a page\n * of this document is its destination, ready for `stage.goToDestination`;\n * one to a page the document doesn't have is reported.\n */\nexport type LinkResolution =\n | { kind: 'destination'; destination: PageDestination }\n | { kind: 'uri'; uri: string }\n | { kind: 'named'; name: string }\n | { kind: 'reported'; target: PdfLinkTarget };\n\n/**\n * What activating a target would do, by the rule every link and outline item\n * follows: a `goto` to a page `hasPage` knows is its destination, one to a\n * page the document doesn't have is reported; a website and a named verb are\n * handed on; anything else is reported.\n */\nexport function resolveLinkTarget(\n target: PdfLinkTarget,\n hasPage: (page: PageRef) => boolean,\n): LinkResolution {\n switch (target.kind) {\n case 'goto':\n return hasPage(target.destination.page)\n ? { kind: 'destination', destination: target.destination }\n : { kind: 'reported', target };\n case 'uri':\n return { kind: 'uri', uri: target.uri };\n case 'named':\n return { kind: 'named', name: target.name };\n default:\n return { kind: 'reported', target };\n }\n}\n\nexport interface LinkActivateContext {\n /** The link's `/A` tree when it has one; the actions plugin runs it instead of the target. */\n activate?: PdfActionTree;\n ref?: AnnotationRef;\n page?: PageRef;\n /**\n * The view the link was followed in: a page destination moves this Stage.\n * Defaults to the main view.\n */\n stage?: StageCapability;\n}\n\n/** A link target was activated through this capability. */\nexport interface LinkActivatedEvent {\n readonly target: PdfLinkTarget;\n readonly activation: LinkActivation;\n}\n/** A page's links were read from the engine. */\nexport interface LinkLoadedEvent {\n readonly page: PageRef;\n}\n\nexport interface LinkCapability {\n /**\n * Clickable areas on a page (its ref or its index), page space.\n * Reference-stable per page while unchanged; empty for a page that isn't in\n * the document.\n */\n listLinks(page: PageRef | number): readonly Link[];\n /** One link by its stable id, or null. */\n getLink(page: PageRef | number, linkId: string): Link | null;\n /** The topmost (smallest) link under a page point, or null. */\n getLinkAt(page: PageRef | number, point: Point): Link | null;\n /**\n * Every link in the document; loads pages as needed. Rejects when a page's\n * read fails, and `operation-cancelled` when `signal` fires.\n */\n listAllLinks(options?: OperationOptions): Promise<readonly Link[]>;\n /**\n * Load a page's links. Resolves at once when the annotation plugin owns\n * them; rejects when the read fails, which `getStatus(page)` then reports,\n * `not-found` for a page that isn't in the document, and\n * `operation-cancelled` when `signal` fires.\n */\n ensureLoaded(page: PageRef | number, options?: OperationOptions): Promise<void>;\n /** The page's links were read and are current. Always true with the annotation plugin. */\n isLoaded(page: PageRef | number): boolean;\n /** Load state of a page's links: `idle`, `loading`, `ready`, `error` or `forbidden`. */\n getStatus(page: PageRef | number): ResourceStatus;\n /** What activation would do, with no side effect. */\n resolve(target: PdfLinkTarget): LinkResolution;\n /**\n * Follow a link, or a link's target, as a click does, and return what\n * happened at once (the user's gesture is still on the stack, so a website\n * can open in a new tab). A `goto` moves the Stage, by its `scrollBehavior`\n * setting; a website opens through the framework (an `http`, `https`,\n * `mailto` or `tel` address only); a link with an `/A` tree dispatches\n * through the actions plugin. Fires `onActivated`.\n */\n activate(target: PdfLinkTarget | Link, context?: LinkActivateContext): LinkActivation;\n /**\n * Hit test, then activate. Null when no link is there; throws `not-found`\n * for a page that isn't in the document.\n */\n activateAt(\n page: PageRef | number,\n point: Point,\n context?: LinkActivateContext,\n ): LinkActivation | null;\n /** A human label for tooltips. */\n getLabel(link: Link | PdfLinkTarget): string;\n /** After the built-in handling of any activation. */\n readonly onActivated: EventHook<LinkActivatedEvent>;\n /**\n * A page's links were read, first or again after an annotation change on\n * it. Never fires for a failed read, nor while the annotation plugin owns the links.\n */\n readonly onLoaded: EventHook<LinkLoadedEvent>;\n}\n"],"mappings":";;;AAMA,MAAa,aAAA,2BAAA,CAAA,CAAA,sBAAA,CAAkD,QAAQ;CACrE,MAAM;CAGN,UAAU;EACR,cAAc;EACd,cAAc;CAChB;AACF,CAAC;;;;;;;;;ACyCD,SAAgB,kBACd,QACA,SACgB;CAChB,QAAQ,OAAO,MAAf;EACE,KAAK,QACH,OAAO,QAAQ,OAAO,YAAY,IAAI,IAClC;GAAE,MAAM;GAAe,aAAa,OAAO;EAAY,IACvD;GAAE,MAAM;GAAY;EAAO;EACjC,KAAK,OACH,OAAO;GAAE,MAAM;GAAO,KAAK,OAAO;EAAI;EACxC,KAAK,SACH,OAAO;GAAE,MAAM;GAAS,MAAM,OAAO;EAAK;EAC5C,SACE,OAAO;GAAE,MAAM;GAAY;EAAO;CACtC;AACF"}
@@ -58,6 +58,13 @@ type LinkResolution = {
58
58
  kind: 'reported';
59
59
  target: PdfLinkTarget;
60
60
  };
61
+ /**
62
+ * What activating a target would do, by the rule every link and outline item
63
+ * follows: a `goto` to a page `hasPage` knows is its destination, one to a
64
+ * page the document doesn't have is reported; a website and a named verb are
65
+ * handed on; anything else is reported.
66
+ */
67
+ declare function resolveLinkTarget(target: PdfLinkTarget, hasPage: (page: PageRef) => boolean): LinkResolution;
61
68
  interface LinkActivateContext {
62
69
  /** The link's `/A` tree when it has one; the actions plugin runs it instead of the target. */
63
70
  activate?: PdfActionTree;
@@ -132,5 +139,5 @@ interface LinkCapability {
132
139
  readonly onLoaded: EventHook<LinkLoadedEvent>;
133
140
  }
134
141
  //#endregion
135
- export { LinkCapability as a, PageDestination as c, LinkActivation as i, PdfLinkTarget as l, LinkActivateContext as n, LinkLoadedEvent as o, LinkActivatedEvent as r, LinkResolution as s, Link as t, LinkToken as u };
136
- //# sourceMappingURL=contract-BL4jWtGT.d.ts.map
142
+ export { LinkCapability as a, PageDestination as c, LinkToken as d, LinkActivation as i, PdfLinkTarget as l, LinkActivateContext as n, LinkLoadedEvent as o, LinkActivatedEvent as r, LinkResolution as s, Link as t, resolveLinkTarget as u };
143
+ //# sourceMappingURL=contract-DyTXDEwb.d.ts.map
package/dist/contract.cjs CHANGED
@@ -1,3 +1,4 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_contract = require("./contract-CaaMtYBR.cjs");
2
+ const require_contract = require("./contract-DXB_v4as.cjs");
3
3
  exports.LinkToken = require_contract.LinkToken;
4
+ exports.resolveLinkTarget = require_contract.resolveLinkTarget;
@@ -1,2 +1,2 @@
1
- import { a as LinkCapability, c as PageDestination, i as LinkActivation, l as PdfLinkTarget, n as LinkActivateContext, o as LinkLoadedEvent, r as LinkActivatedEvent, s as LinkResolution, t as Link, u as LinkToken } from "./contract-C8by3cQG.cjs";
2
- export { Link, LinkActivateContext, LinkActivatedEvent, LinkActivation, LinkCapability, LinkLoadedEvent, LinkResolution, LinkToken, type PageDestination, type PdfLinkTarget };
1
+ import { a as LinkCapability, c as PageDestination, d as LinkToken, i as LinkActivation, l as PdfLinkTarget, n as LinkActivateContext, o as LinkLoadedEvent, r as LinkActivatedEvent, s as LinkResolution, t as Link, u as resolveLinkTarget } from "./contract-B4x0DFCT.cjs";
2
+ export { Link, LinkActivateContext, LinkActivatedEvent, LinkActivation, LinkCapability, LinkLoadedEvent, LinkResolution, LinkToken, type PageDestination, type PdfLinkTarget, resolveLinkTarget };
@@ -1,2 +1,2 @@
1
- import { a as LinkCapability, c as PageDestination, i as LinkActivation, l as PdfLinkTarget, n as LinkActivateContext, o as LinkLoadedEvent, r as LinkActivatedEvent, s as LinkResolution, t as Link, u as LinkToken } from "./contract-BL4jWtGT.js";
2
- export { Link, LinkActivateContext, LinkActivatedEvent, LinkActivation, LinkCapability, LinkLoadedEvent, LinkResolution, LinkToken, type PageDestination, type PdfLinkTarget };
1
+ import { a as LinkCapability, c as PageDestination, d as LinkToken, i as LinkActivation, l as PdfLinkTarget, n as LinkActivateContext, o as LinkLoadedEvent, r as LinkActivatedEvent, s as LinkResolution, t as Link, u as resolveLinkTarget } from "./contract-DyTXDEwb.js";
2
+ export { Link, LinkActivateContext, LinkActivatedEvent, LinkActivation, LinkCapability, LinkLoadedEvent, LinkResolution, LinkToken, type PageDestination, type PdfLinkTarget, resolveLinkTarget };
package/dist/contract.js CHANGED
@@ -1,2 +1,2 @@
1
- import { t as LinkToken } from "./contract-D0k-EtjB.js";
2
- export { LinkToken };
1
+ import { n as LinkToken, t as resolveLinkTarget } from "./contract-CJ9mhj7i.js";
2
+ export { LinkToken, resolveLinkTarget };
@@ -1,4 +1,4 @@
1
- import { a as LinkCapability } from "./contract-BL4jWtGT.js";
1
+ import { a as LinkCapability } from "./contract-DyTXDEwb.js";
2
2
  import { Unsubscribe } from "@embedpdf/core";
3
3
  //#region src/host-contract.d.ts
4
4
  /**
@@ -20,4 +20,4 @@ interface LinkHostCapability extends LinkCapability {
20
20
  declare const LinkToken: import("@embedpdf/core").CapabilityToken<LinkHostCapability>;
21
21
  //#endregion
22
22
  export { LinkToken as n, UriOpener as r, LinkHostCapability as t };
23
- //# sourceMappingURL=host-contract-BEEpcMUN.d.ts.map
23
+ //# sourceMappingURL=host-contract-DNwp7dlr.d.ts.map
@@ -1,4 +1,4 @@
1
- import { a as LinkCapability } from "./contract-C8by3cQG.cjs";
1
+ import { a as LinkCapability } from "./contract-B4x0DFCT.cjs";
2
2
  import { Unsubscribe } from "@embedpdf/core";
3
3
  //#region src/host-contract.d.ts
4
4
  /**
@@ -20,4 +20,4 @@ interface LinkHostCapability extends LinkCapability {
20
20
  declare const LinkToken: import("@embedpdf/core").CapabilityToken<LinkHostCapability>;
21
21
  //#endregion
22
22
  export { LinkToken as n, UriOpener as r, LinkHostCapability as t };
23
- //# sourceMappingURL=host-contract-WJZHqcPp.d.cts.map
23
+ //# sourceMappingURL=host-contract-c0QOjhO6.d.cts.map
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_contract = require("./contract-CaaMtYBR.cjs");
2
+ const require_contract = require("./contract-DXB_v4as.cjs");
3
3
  const require_contract_host = require("./contract/host.cjs");
4
4
  let _embedpdf_core = require("@embedpdf/core");
5
5
  let _embedpdf_plugin_actions_contract = require("@embedpdf/plugin-actions/contract");
@@ -106,29 +106,7 @@ function createLinkController(ctx) {
106
106
  await ctx.cancellable(options?.signal, pages.ensureLoaded(ref));
107
107
  };
108
108
  const uriOpeners = [];
109
- const resolve = (target) => {
110
- switch (target.kind) {
111
- case "goto": return ctx.getPage(target.destination.page) ? {
112
- kind: "destination",
113
- destination: target.destination
114
- } : {
115
- kind: "reported",
116
- target
117
- };
118
- case "uri": return {
119
- kind: "uri",
120
- uri: target.uri
121
- };
122
- case "named": return {
123
- kind: "named",
124
- name: target.name
125
- };
126
- default: return {
127
- kind: "reported",
128
- target
129
- };
130
- }
131
- };
109
+ const resolve = (target) => require_contract.resolveLinkTarget(target, (page) => ctx.getPage(page) !== null);
132
110
  const perform = (target, context) => {
133
111
  const actions = ctx.tryGet(_embedpdf_plugin_actions_contract.ActionsToken);
134
112
  if (actions && context?.activate) return {
@@ -275,5 +253,6 @@ const linkPlugin = () => (0, _embedpdf_core.definePlugin)({
275
253
  //#endregion
276
254
  exports.LinkToken = require_contract.LinkToken;
277
255
  exports.linkPlugin = linkPlugin;
256
+ exports.resolveLinkTarget = require_contract.resolveLinkTarget;
278
257
 
279
258
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["AnnotationToken","InteractionToken","AnnotationHostToken","PluginError","ActionsToken","StageToken","InteractionToken","LinkToken","InteractionToken","StageToken","AnnotationToken","ActionsToken"],"sources":["../src/connect.ts","../src/source.ts","../src/controller.ts","../src/link.plugin.ts"],"sourcesContent":["/** The link plugin's wiring to its siblings, run from the controller's `connect`. */\nimport type { PluginContext } from '@embedpdf/core';\nimport { AnnotationToken } from '@embedpdf/plugin-annotation/contract/host';\nimport { InteractionToken } from '@embedpdf/plugin-interaction/contract/host';\n\n/**\n * Links are annotations: while a navigation tool is active the link layer\n * owns their input (its anchors take the clicks), so the annotation plane\n * stands down for them. A link still shows as the file draws it.\n */\nexport function connectLink(ctx: PluginContext<void>): void {\n const annotation = ctx.tryGet(AnnotationToken);\n if (!annotation) return;\n const interaction = ctx.get(InteractionToken);\n ctx.cleanup(\n annotation.registerBehavior({\n id: 'link-nav',\n matches: (target) => target.subtype === 'link',\n engaged: () => interaction.activeToolEnables('link-nav'),\n }),\n );\n}\n","/**\n * The stand-alone source, used when no annotation plugin is installed: the\n * clickable areas among one page's annotations, in page space.\n */\nimport { annotationKey, type Annotation } from '@embedpdf/engine-core/runtime';\n\nimport type { Link } from './contract';\n\n/** The visible link annotations of a page that have a target. */\nexport function linksOf(annotations: readonly Annotation[]): readonly Link[] {\n const links: Link[] = [];\n for (const dto of annotations) {\n if (dto.subtype !== 'link' || dto.target == null) continue;\n if (dto.hidden || dto.noView) continue;\n links.push({\n id: annotationKey(dto.ref),\n bounds: dto.rect,\n target: dto.target,\n ...(dto.actions?.activate ? { activate: dto.actions.activate } : {}),\n ...(dto.actions?.cursorEnter?.root || dto.actions?.cursorExit?.root\n ? {\n hoverEvents: {\n enter: Boolean(dto.actions?.cursorEnter?.root),\n exit: Boolean(dto.actions?.cursorExit?.root),\n },\n }\n : {}),\n ref: dto.ref,\n attached: dto.reply?.type === 'group',\n });\n }\n return links;\n}\n","import {\n PluginError,\n type PluginContext,\n type DocumentEvent,\n type OperationOptions,\n type PageRef,\n} from '@embedpdf/core';\nimport type { Point } from '@embedpdf/core-geometry';\nimport type { PdfLinkTarget } from '@embedpdf/engine-core/runtime';\nimport { ActionsToken } from '@embedpdf/plugin-actions/contract';\nimport { AnnotationToken as AnnotationHostToken } from '@embedpdf/plugin-annotation/contract/host';\nimport { InteractionToken } from '@embedpdf/plugin-interaction/contract/host';\nimport { StageToken } from '@embedpdf/plugin-stage/contract';\n\nimport { connectLink } from './connect';\nimport type {\n Link,\n LinkActivateContext,\n LinkActivatedEvent,\n LinkActivation,\n LinkLoadedEvent,\n LinkResolution,\n} from './contract';\nimport type { LinkHostCapability, UriOpener } from './host-contract';\nimport { linksOf } from './source';\n\nconst EMPTY: readonly Link[] = Object.freeze([]);\n\nconst isLink = (value: PdfLinkTarget | Link): value is Link =>\n 'target' in value && 'bounds' in value;\nconst contains = (\n bounds: { x: number; y: number; width: number; height: number },\n point: Point,\n): boolean =>\n point.x >= bounds.x &&\n point.x <= bounds.x + bounds.width &&\n point.y >= bounds.y &&\n point.y <= bounds.y + bounds.height;\n\n/** The pages whose annotation lists an event changed, each once. */\nfunction pagesChangedBy(event: DocumentEvent): readonly PageRef[] | null {\n switch (event.type) {\n case 'annotations.created':\n return [event.annotation.page];\n case 'annotations.updated':\n return [event.annotation.page];\n case 'annotations.deleted':\n case 'annotations.reordered':\n return [event.page];\n // These can remove annotations, links included, from the pages they applied to.\n case 'redaction.applied':\n case 'pages.flattened':\n return event.results\n .filter((result) => result.status === 'applied')\n .map((result) => result.page);\n case 'annotations.flattened':\n return event.results.some((result) => result.status === 'applied') ? [event.page] : null;\n default:\n return null;\n }\n}\n\n/**\n * The link controller. Two sources for the clickable areas: the annotation\n * plugin's folded model when it is installed (always current), else a page\n * mirror of this plugin's own per-page reads, re-read when a confirmed\n * change (an annotation write, a redaction, a flatten) touches a loaded page. Activation is pure resolution\n * (`resolve`) plus the one side effect this plugin owns, a stage reveal;\n * everything else is reported to the host, which keeps the user gesture.\n */\nexport function createLinkController(ctx: PluginContext<void>) {\n const annotationHost = () => ctx.tryGet(AnnotationHostToken);\n const activated = ctx.events.source<LinkActivatedEvent>();\n const loaded = ctx.events.source<LinkLoadedEvent>();\n\n const pages = ctx.pageMirror<readonly Link[]>({\n name: 'links',\n load: async (doc, page) => {\n if (!ctx.getPage(page)) {\n throw new PluginError(\n 'not-found',\n 'link',\n `page ${page.objectNumber} is not in this document`,\n );\n }\n const snapshot = await doc.page(page).annotations.list();\n return linksOf(snapshot.annotations);\n },\n affected: pagesChangedBy,\n changed: ({ page, cause }) => {\n if (cause === 'load') loaded.emit({ page });\n },\n });\n\n // Reads take a page's ref or its index; a page that isn't there has no links.\n const listLinks = (pageArgument: PageRef | number): readonly Link[] => {\n const page = ctx.getPage(pageArgument)?.ref;\n if (!page) return EMPTY;\n const host = annotationHost();\n if (host) return host.listLinkItems(page);\n return pages.get(page) ?? EMPTY;\n };\n\n const ensureLoaded = async (\n pageArgument: PageRef | number,\n options?: OperationOptions,\n ): Promise<void> => {\n const { ref } = ctx.pageOf(pageArgument);\n // With the annotation plugin installed, its model owns the data.\n if (annotationHost()) return;\n await ctx.cancellable(options?.signal, pages.ensureLoaded(ref));\n };\n\n // The framework's website openers, the latest first: the plugin never opens one itself.\n const uriOpeners: UriOpener[] = [];\n\n const resolve = (target: PdfLinkTarget): LinkResolution => {\n switch (target.kind) {\n case 'goto':\n // A page the document doesn't have can't be shown.\n return ctx.getPage(target.destination.page)\n ? { kind: 'destination', destination: target.destination }\n : { kind: 'reported', target };\n case 'uri':\n return { kind: 'uri', uri: target.uri };\n case 'named':\n return { kind: 'named', name: target.name };\n default:\n return { kind: 'reported', target };\n }\n };\n\n const perform = (target: PdfLinkTarget, context?: LinkActivateContext): LinkActivation => {\n const actions = ctx.tryGet(ActionsToken);\n if (actions && context?.activate) {\n const dispatch = actions.execute(context.activate, {\n origin: 'user',\n source: { kind: 'link', annotation: context.ref, page: context.page },\n event: { scope: 'activate' },\n });\n return { outcome: 'dispatched', dispatch };\n }\n const resolution = resolve(target);\n switch (resolution.kind) {\n case 'destination': {\n // The view the link was followed in, by its own scroll behavior.\n const stage = context?.stage ?? ctx.tryGet(StageToken);\n if (!stage) return { outcome: 'destination', destination: resolution.destination };\n stage.goToDestination(resolution.destination);\n return { outcome: 'revealed' };\n }\n case 'uri': {\n const open = uriOpeners[0];\n if (!open || open(resolution.uri)) return { outcome: 'uri', uri: resolution.uri };\n return { outcome: 'reported', target };\n }\n case 'named':\n return { outcome: 'named', name: resolution.name };\n default:\n return { outcome: 'reported', target };\n }\n };\n\n const activate = (input: PdfLinkTarget | Link, context?: LinkActivateContext): LinkActivation => {\n const target = isLink(input) ? input.target : input;\n const linkContext: LinkActivateContext | undefined = isLink(input)\n ? { activate: input.activate, ref: input.ref, ...context }\n : context;\n const activation = perform(target, linkContext);\n activated.emit({ target, activation });\n return activation;\n };\n\n const getLinkAt = (page: PageRef | number, point: Point): Link | null => {\n let best: Link | null = null;\n for (const link of listLinks(page)) {\n if (!contains(link.bounds, point)) continue;\n if (\n !best ||\n link.bounds.width * link.bounds.height < best.bounds.width * best.bounds.height\n ) {\n best = link;\n }\n }\n return best;\n };\n\n const getLabel = (input: Link | PdfLinkTarget): string => {\n const target = isLink(input) ? input.target : input;\n switch (target.kind) {\n case 'uri':\n return target.uri;\n case 'goto':\n return 'Go to destination';\n case 'named':\n return target.name;\n default:\n return 'Link';\n }\n };\n\n const api: LinkHostCapability = {\n listLinks,\n getLink: (page, linkId) => listLinks(page).find((link) => link.id === linkId) ?? null,\n getLinkAt,\n listAllLinks: async (options) => {\n const layouts = ctx.document()?.pages ?? [];\n await ctx.cancellable(\n options?.signal,\n Promise.all(layouts.map((layout) => ensureLoaded(layout.ref, options))),\n );\n return layouts.flatMap((layout) => listLinks(layout.ref));\n },\n ensureLoaded,\n isLoaded: (page) => {\n const ref = ctx.getPage(page)?.ref;\n return !!ref && (annotationHost() !== null || pages.getStatus(ref) === 'ready');\n },\n getStatus: (page) => {\n const ref = ctx.getPage(page)?.ref;\n if (!ref) return 'idle';\n return annotationHost() ? 'ready' : pages.getStatus(ref);\n },\n resolve,\n activate,\n activateAt: (pageArgument, point, context) => {\n const page = ctx.pageOf(pageArgument).ref;\n const link = getLinkAt(page, point);\n return link ? activate(link, { page, ...context }) : null;\n },\n getLabel,\n onActivated: activated.on,\n onLoaded: loaded.on,\n registerUriOpener: (opener) => {\n uriOpeners.unshift(opener);\n return () => {\n const index = uriOpeners.indexOf(opener);\n if (index >= 0) uriOpeners.splice(index, 1);\n };\n },\n isNavigationEngaged: () => ctx.tryGet(InteractionToken)?.activeToolEnables('link-nav') ?? false,\n };\n\n return {\n api,\n connect() {\n connectLink(ctx);\n },\n };\n}\n","import { definePlugin } from '@embedpdf/core';\nimport { ActionsToken } from '@embedpdf/plugin-actions/contract';\nimport { AnnotationToken } from '@embedpdf/plugin-annotation/contract';\nimport { InteractionToken } from '@embedpdf/plugin-interaction/contract';\nimport { StageToken } from '@embedpdf/plugin-stage/contract';\n\nimport { createLinkController } from './controller';\nimport { LinkToken } from './host-contract';\n\n/**\n * Clickable link regions and their activation. Document-scoped; needs the\n * interaction hub (the navigation tool tag), optionally the stage (reveal),\n * the annotation plugin (the folded link model) and actions (`/A` trees).\n */\nexport const linkPlugin = () =>\n definePlugin({\n id: 'link',\n token: LinkToken,\n scope: 'document',\n requires: [InteractionToken],\n optional: [StageToken, AnnotationToken, ActionsToken],\n create: createLinkController,\n });\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["AnnotationToken","InteractionToken","AnnotationHostToken","PluginError","resolveLinkTarget","ActionsToken","StageToken","InteractionToken","LinkToken","InteractionToken","StageToken","AnnotationToken","ActionsToken"],"sources":["../src/connect.ts","../src/source.ts","../src/controller.ts","../src/link.plugin.ts"],"sourcesContent":["/** The link plugin's wiring to its siblings, run from the controller's `connect`. */\nimport type { PluginContext } from '@embedpdf/core';\nimport { AnnotationToken } from '@embedpdf/plugin-annotation/contract/host';\nimport { InteractionToken } from '@embedpdf/plugin-interaction/contract/host';\n\n/**\n * Links are annotations: while a navigation tool is active the link layer\n * owns their input (its anchors take the clicks), so the annotation plane\n * stands down for them. A link still shows as the file draws it.\n */\nexport function connectLink(ctx: PluginContext<void>): void {\n const annotation = ctx.tryGet(AnnotationToken);\n if (!annotation) return;\n const interaction = ctx.get(InteractionToken);\n ctx.cleanup(\n annotation.registerBehavior({\n id: 'link-nav',\n matches: (target) => target.subtype === 'link',\n engaged: () => interaction.activeToolEnables('link-nav'),\n }),\n );\n}\n","/**\n * The stand-alone source, used when no annotation plugin is installed: the\n * clickable areas among one page's annotations, in page space.\n */\nimport { annotationKey, type Annotation } from '@embedpdf/engine-core/runtime';\n\nimport type { Link } from './contract';\n\n/** The visible link annotations of a page that have a target. */\nexport function linksOf(annotations: readonly Annotation[]): readonly Link[] {\n const links: Link[] = [];\n for (const dto of annotations) {\n if (dto.subtype !== 'link' || dto.target == null) continue;\n if (dto.hidden || dto.noView) continue;\n links.push({\n id: annotationKey(dto.ref),\n bounds: dto.rect,\n target: dto.target,\n ...(dto.actions?.activate ? { activate: dto.actions.activate } : {}),\n ...(dto.actions?.cursorEnter?.root || dto.actions?.cursorExit?.root\n ? {\n hoverEvents: {\n enter: Boolean(dto.actions?.cursorEnter?.root),\n exit: Boolean(dto.actions?.cursorExit?.root),\n },\n }\n : {}),\n ref: dto.ref,\n attached: dto.reply?.type === 'group',\n });\n }\n return links;\n}\n","import {\n PluginError,\n type PluginContext,\n type DocumentEvent,\n type OperationOptions,\n type PageRef,\n} from '@embedpdf/core';\nimport type { Point } from '@embedpdf/core-geometry';\nimport type { PdfLinkTarget } from '@embedpdf/engine-core/runtime';\nimport { ActionsToken } from '@embedpdf/plugin-actions/contract';\nimport { AnnotationToken as AnnotationHostToken } from '@embedpdf/plugin-annotation/contract/host';\nimport { InteractionToken } from '@embedpdf/plugin-interaction/contract/host';\nimport { StageToken } from '@embedpdf/plugin-stage/contract';\n\nimport { connectLink } from './connect';\nimport {\n resolveLinkTarget,\n type Link,\n type LinkActivateContext,\n type LinkActivatedEvent,\n type LinkActivation,\n type LinkLoadedEvent,\n type LinkResolution,\n} from './contract';\nimport type { LinkHostCapability, UriOpener } from './host-contract';\nimport { linksOf } from './source';\n\nconst EMPTY: readonly Link[] = Object.freeze([]);\n\nconst isLink = (value: PdfLinkTarget | Link): value is Link =>\n 'target' in value && 'bounds' in value;\nconst contains = (\n bounds: { x: number; y: number; width: number; height: number },\n point: Point,\n): boolean =>\n point.x >= bounds.x &&\n point.x <= bounds.x + bounds.width &&\n point.y >= bounds.y &&\n point.y <= bounds.y + bounds.height;\n\n/** The pages whose annotation lists an event changed, each once. */\nfunction pagesChangedBy(event: DocumentEvent): readonly PageRef[] | null {\n switch (event.type) {\n case 'annotations.created':\n return [event.annotation.page];\n case 'annotations.updated':\n return [event.annotation.page];\n case 'annotations.deleted':\n case 'annotations.reordered':\n return [event.page];\n // These can remove annotations, links included, from the pages they applied to.\n case 'redaction.applied':\n case 'pages.flattened':\n return event.results\n .filter((result) => result.status === 'applied')\n .map((result) => result.page);\n case 'annotations.flattened':\n return event.results.some((result) => result.status === 'applied') ? [event.page] : null;\n default:\n return null;\n }\n}\n\n/**\n * The link controller. Two sources for the clickable areas: the annotation\n * plugin's folded model when it is installed (always current), else a page\n * mirror of this plugin's own per-page reads, re-read when a confirmed\n * change (an annotation write, a redaction, a flatten) touches a loaded page. Activation is pure resolution\n * (`resolve`) plus the one side effect this plugin owns, a stage reveal;\n * everything else is reported to the host, which keeps the user gesture.\n */\nexport function createLinkController(ctx: PluginContext<void>) {\n const annotationHost = () => ctx.tryGet(AnnotationHostToken);\n const activated = ctx.events.source<LinkActivatedEvent>();\n const loaded = ctx.events.source<LinkLoadedEvent>();\n\n const pages = ctx.pageMirror<readonly Link[]>({\n name: 'links',\n load: async (doc, page) => {\n if (!ctx.getPage(page)) {\n throw new PluginError(\n 'not-found',\n 'link',\n `page ${page.objectNumber} is not in this document`,\n );\n }\n const snapshot = await doc.page(page).annotations.list();\n return linksOf(snapshot.annotations);\n },\n affected: pagesChangedBy,\n changed: ({ page, cause }) => {\n if (cause === 'load') loaded.emit({ page });\n },\n });\n\n // Reads take a page's ref or its index; a page that isn't there has no links.\n const listLinks = (pageArgument: PageRef | number): readonly Link[] => {\n const page = ctx.getPage(pageArgument)?.ref;\n if (!page) return EMPTY;\n const host = annotationHost();\n if (host) return host.listLinkItems(page);\n return pages.get(page) ?? EMPTY;\n };\n\n const ensureLoaded = async (\n pageArgument: PageRef | number,\n options?: OperationOptions,\n ): Promise<void> => {\n const { ref } = ctx.pageOf(pageArgument);\n // With the annotation plugin installed, its model owns the data.\n if (annotationHost()) return;\n await ctx.cancellable(options?.signal, pages.ensureLoaded(ref));\n };\n\n // The framework's website openers, the latest first: the plugin never opens one itself.\n const uriOpeners: UriOpener[] = [];\n\n // A page the document doesn't have can't be shown.\n const resolve = (target: PdfLinkTarget): LinkResolution =>\n resolveLinkTarget(target, (page) => ctx.getPage(page) !== null);\n\n const perform = (target: PdfLinkTarget, context?: LinkActivateContext): LinkActivation => {\n const actions = ctx.tryGet(ActionsToken);\n if (actions && context?.activate) {\n const dispatch = actions.execute(context.activate, {\n origin: 'user',\n source: { kind: 'link', annotation: context.ref, page: context.page },\n event: { scope: 'activate' },\n });\n return { outcome: 'dispatched', dispatch };\n }\n const resolution = resolve(target);\n switch (resolution.kind) {\n case 'destination': {\n // The view the link was followed in, by its own scroll behavior.\n const stage = context?.stage ?? ctx.tryGet(StageToken);\n if (!stage) return { outcome: 'destination', destination: resolution.destination };\n stage.goToDestination(resolution.destination);\n return { outcome: 'revealed' };\n }\n case 'uri': {\n const open = uriOpeners[0];\n if (!open || open(resolution.uri)) return { outcome: 'uri', uri: resolution.uri };\n return { outcome: 'reported', target };\n }\n case 'named':\n return { outcome: 'named', name: resolution.name };\n default:\n return { outcome: 'reported', target };\n }\n };\n\n const activate = (input: PdfLinkTarget | Link, context?: LinkActivateContext): LinkActivation => {\n const target = isLink(input) ? input.target : input;\n const linkContext: LinkActivateContext | undefined = isLink(input)\n ? { activate: input.activate, ref: input.ref, ...context }\n : context;\n const activation = perform(target, linkContext);\n activated.emit({ target, activation });\n return activation;\n };\n\n const getLinkAt = (page: PageRef | number, point: Point): Link | null => {\n let best: Link | null = null;\n for (const link of listLinks(page)) {\n if (!contains(link.bounds, point)) continue;\n if (\n !best ||\n link.bounds.width * link.bounds.height < best.bounds.width * best.bounds.height\n ) {\n best = link;\n }\n }\n return best;\n };\n\n const getLabel = (input: Link | PdfLinkTarget): string => {\n const target = isLink(input) ? input.target : input;\n switch (target.kind) {\n case 'uri':\n return target.uri;\n case 'goto':\n return 'Go to destination';\n case 'named':\n return target.name;\n default:\n return 'Link';\n }\n };\n\n const api: LinkHostCapability = {\n listLinks,\n getLink: (page, linkId) => listLinks(page).find((link) => link.id === linkId) ?? null,\n getLinkAt,\n listAllLinks: async (options) => {\n const layouts = ctx.document()?.pages ?? [];\n await ctx.cancellable(\n options?.signal,\n Promise.all(layouts.map((layout) => ensureLoaded(layout.ref, options))),\n );\n return layouts.flatMap((layout) => listLinks(layout.ref));\n },\n ensureLoaded,\n isLoaded: (page) => {\n const ref = ctx.getPage(page)?.ref;\n return !!ref && (annotationHost() !== null || pages.getStatus(ref) === 'ready');\n },\n getStatus: (page) => {\n const ref = ctx.getPage(page)?.ref;\n if (!ref) return 'idle';\n return annotationHost() ? 'ready' : pages.getStatus(ref);\n },\n resolve,\n activate,\n activateAt: (pageArgument, point, context) => {\n const page = ctx.pageOf(pageArgument).ref;\n const link = getLinkAt(page, point);\n return link ? activate(link, { page, ...context }) : null;\n },\n getLabel,\n onActivated: activated.on,\n onLoaded: loaded.on,\n registerUriOpener: (opener) => {\n uriOpeners.unshift(opener);\n return () => {\n const index = uriOpeners.indexOf(opener);\n if (index >= 0) uriOpeners.splice(index, 1);\n };\n },\n isNavigationEngaged: () => ctx.tryGet(InteractionToken)?.activeToolEnables('link-nav') ?? false,\n };\n\n return {\n api,\n connect() {\n connectLink(ctx);\n },\n };\n}\n","import { definePlugin } from '@embedpdf/core';\nimport { ActionsToken } from '@embedpdf/plugin-actions/contract';\nimport { AnnotationToken } from '@embedpdf/plugin-annotation/contract';\nimport { InteractionToken } from '@embedpdf/plugin-interaction/contract';\nimport { StageToken } from '@embedpdf/plugin-stage/contract';\n\nimport { createLinkController } from './controller';\nimport { LinkToken } from './host-contract';\n\n/**\n * Clickable link regions and their activation. Document-scoped; needs the\n * interaction hub (the navigation tool tag), optionally the stage (reveal),\n * the annotation plugin (the folded link model) and actions (`/A` trees).\n */\nexport const linkPlugin = () =>\n definePlugin({\n id: 'link',\n token: LinkToken,\n scope: 'document',\n requires: [InteractionToken],\n optional: [StageToken, AnnotationToken, ActionsToken],\n create: createLinkController,\n });\n"],"mappings":"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"}
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { a as LinkCapability, c as PageDestination, i as LinkActivation, l as PdfLinkTarget, n as LinkActivateContext, o as LinkLoadedEvent, r as LinkActivatedEvent, s as LinkResolution, t as Link, u as LinkToken } from "./contract-C8by3cQG.cjs";
2
- import { t as LinkHostCapability } from "./host-contract-WJZHqcPp.cjs";
1
+ import { a as LinkCapability, c as PageDestination, d as LinkToken, i as LinkActivation, l as PdfLinkTarget, n as LinkActivateContext, o as LinkLoadedEvent, r as LinkActivatedEvent, s as LinkResolution, t as Link, u as resolveLinkTarget } from "./contract-B4x0DFCT.cjs";
2
+ import { t as LinkHostCapability } from "./host-contract-c0QOjhO6.cjs";
3
3
  //#region src/link.plugin.d.ts
4
4
  /**
5
5
  * Clickable link regions and their activation. Document-scoped; needs the
@@ -8,5 +8,5 @@ import { t as LinkHostCapability } from "./host-contract-WJZHqcPp.cjs";
8
8
  */
9
9
  declare const linkPlugin: () => import("@embedpdf/core").PluginDef<void, LinkHostCapability, import("@embedpdf/core").NoSettings>;
10
10
  //#endregion
11
- export { Link, LinkActivateContext, LinkActivatedEvent, LinkActivation, LinkCapability, LinkLoadedEvent, LinkResolution, LinkToken, type PageDestination, type PdfLinkTarget, linkPlugin };
11
+ export { Link, LinkActivateContext, LinkActivatedEvent, LinkActivation, LinkCapability, LinkLoadedEvent, LinkResolution, LinkToken, type PageDestination, type PdfLinkTarget, linkPlugin, resolveLinkTarget };
12
12
  //# sourceMappingURL=index.d.cts.map
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { a as LinkCapability, c as PageDestination, i as LinkActivation, l as PdfLinkTarget, n as LinkActivateContext, o as LinkLoadedEvent, r as LinkActivatedEvent, s as LinkResolution, t as Link, u as LinkToken } from "./contract-BL4jWtGT.js";
2
- import { t as LinkHostCapability } from "./host-contract-BEEpcMUN.js";
1
+ import { a as LinkCapability, c as PageDestination, d as LinkToken, i as LinkActivation, l as PdfLinkTarget, n as LinkActivateContext, o as LinkLoadedEvent, r as LinkActivatedEvent, s as LinkResolution, t as Link, u as resolveLinkTarget } from "./contract-DyTXDEwb.js";
2
+ import { t as LinkHostCapability } from "./host-contract-DNwp7dlr.js";
3
3
  //#region src/link.plugin.d.ts
4
4
  /**
5
5
  * Clickable link regions and their activation. Document-scoped; needs the
@@ -8,5 +8,5 @@ import { t as LinkHostCapability } from "./host-contract-BEEpcMUN.js";
8
8
  */
9
9
  declare const linkPlugin: () => import("@embedpdf/core").PluginDef<void, LinkHostCapability, import("@embedpdf/core").NoSettings>;
10
10
  //#endregion
11
- export { Link, LinkActivateContext, LinkActivatedEvent, LinkActivation, LinkCapability, LinkLoadedEvent, LinkResolution, LinkToken, type PageDestination, type PdfLinkTarget, linkPlugin };
11
+ export { Link, LinkActivateContext, LinkActivatedEvent, LinkActivation, LinkCapability, LinkLoadedEvent, LinkResolution, LinkToken, type PageDestination, type PdfLinkTarget, linkPlugin, resolveLinkTarget };
12
12
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as LinkToken } from "./contract-D0k-EtjB.js";
1
+ import { n as LinkToken, t as resolveLinkTarget } from "./contract-CJ9mhj7i.js";
2
2
  import { LinkToken as LinkToken$1 } from "./contract/host.js";
3
3
  import { PluginError, definePlugin } from "@embedpdf/core";
4
4
  import { ActionsToken } from "@embedpdf/plugin-actions/contract";
@@ -105,29 +105,7 @@ function createLinkController(ctx) {
105
105
  await ctx.cancellable(options?.signal, pages.ensureLoaded(ref));
106
106
  };
107
107
  const uriOpeners = [];
108
- const resolve = (target) => {
109
- switch (target.kind) {
110
- case "goto": return ctx.getPage(target.destination.page) ? {
111
- kind: "destination",
112
- destination: target.destination
113
- } : {
114
- kind: "reported",
115
- target
116
- };
117
- case "uri": return {
118
- kind: "uri",
119
- uri: target.uri
120
- };
121
- case "named": return {
122
- kind: "named",
123
- name: target.name
124
- };
125
- default: return {
126
- kind: "reported",
127
- target
128
- };
129
- }
130
- };
108
+ const resolve = (target) => resolveLinkTarget(target, (page) => ctx.getPage(page) !== null);
131
109
  const perform = (target, context) => {
132
110
  const actions = ctx.tryGet(ActionsToken);
133
111
  if (actions && context?.activate) return {
@@ -272,6 +250,6 @@ const linkPlugin = () => definePlugin({
272
250
  create: createLinkController
273
251
  });
274
252
  //#endregion
275
- export { LinkToken, linkPlugin };
253
+ export { LinkToken, linkPlugin, resolveLinkTarget };
276
254
 
277
255
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["AnnotationToken","InteractionToken","AnnotationHostToken","InteractionToken","LinkToken"],"sources":["../src/connect.ts","../src/source.ts","../src/controller.ts","../src/link.plugin.ts"],"sourcesContent":["/** The link plugin's wiring to its siblings, run from the controller's `connect`. */\nimport type { PluginContext } from '@embedpdf/core';\nimport { AnnotationToken } from '@embedpdf/plugin-annotation/contract/host';\nimport { InteractionToken } from '@embedpdf/plugin-interaction/contract/host';\n\n/**\n * Links are annotations: while a navigation tool is active the link layer\n * owns their input (its anchors take the clicks), so the annotation plane\n * stands down for them. A link still shows as the file draws it.\n */\nexport function connectLink(ctx: PluginContext<void>): void {\n const annotation = ctx.tryGet(AnnotationToken);\n if (!annotation) return;\n const interaction = ctx.get(InteractionToken);\n ctx.cleanup(\n annotation.registerBehavior({\n id: 'link-nav',\n matches: (target) => target.subtype === 'link',\n engaged: () => interaction.activeToolEnables('link-nav'),\n }),\n );\n}\n","/**\n * The stand-alone source, used when no annotation plugin is installed: the\n * clickable areas among one page's annotations, in page space.\n */\nimport { annotationKey, type Annotation } from '@embedpdf/engine-core/runtime';\n\nimport type { Link } from './contract';\n\n/** The visible link annotations of a page that have a target. */\nexport function linksOf(annotations: readonly Annotation[]): readonly Link[] {\n const links: Link[] = [];\n for (const dto of annotations) {\n if (dto.subtype !== 'link' || dto.target == null) continue;\n if (dto.hidden || dto.noView) continue;\n links.push({\n id: annotationKey(dto.ref),\n bounds: dto.rect,\n target: dto.target,\n ...(dto.actions?.activate ? { activate: dto.actions.activate } : {}),\n ...(dto.actions?.cursorEnter?.root || dto.actions?.cursorExit?.root\n ? {\n hoverEvents: {\n enter: Boolean(dto.actions?.cursorEnter?.root),\n exit: Boolean(dto.actions?.cursorExit?.root),\n },\n }\n : {}),\n ref: dto.ref,\n attached: dto.reply?.type === 'group',\n });\n }\n return links;\n}\n","import {\n PluginError,\n type PluginContext,\n type DocumentEvent,\n type OperationOptions,\n type PageRef,\n} from '@embedpdf/core';\nimport type { Point } from '@embedpdf/core-geometry';\nimport type { PdfLinkTarget } from '@embedpdf/engine-core/runtime';\nimport { ActionsToken } from '@embedpdf/plugin-actions/contract';\nimport { AnnotationToken as AnnotationHostToken } from '@embedpdf/plugin-annotation/contract/host';\nimport { InteractionToken } from '@embedpdf/plugin-interaction/contract/host';\nimport { StageToken } from '@embedpdf/plugin-stage/contract';\n\nimport { connectLink } from './connect';\nimport type {\n Link,\n LinkActivateContext,\n LinkActivatedEvent,\n LinkActivation,\n LinkLoadedEvent,\n LinkResolution,\n} from './contract';\nimport type { LinkHostCapability, UriOpener } from './host-contract';\nimport { linksOf } from './source';\n\nconst EMPTY: readonly Link[] = Object.freeze([]);\n\nconst isLink = (value: PdfLinkTarget | Link): value is Link =>\n 'target' in value && 'bounds' in value;\nconst contains = (\n bounds: { x: number; y: number; width: number; height: number },\n point: Point,\n): boolean =>\n point.x >= bounds.x &&\n point.x <= bounds.x + bounds.width &&\n point.y >= bounds.y &&\n point.y <= bounds.y + bounds.height;\n\n/** The pages whose annotation lists an event changed, each once. */\nfunction pagesChangedBy(event: DocumentEvent): readonly PageRef[] | null {\n switch (event.type) {\n case 'annotations.created':\n return [event.annotation.page];\n case 'annotations.updated':\n return [event.annotation.page];\n case 'annotations.deleted':\n case 'annotations.reordered':\n return [event.page];\n // These can remove annotations, links included, from the pages they applied to.\n case 'redaction.applied':\n case 'pages.flattened':\n return event.results\n .filter((result) => result.status === 'applied')\n .map((result) => result.page);\n case 'annotations.flattened':\n return event.results.some((result) => result.status === 'applied') ? [event.page] : null;\n default:\n return null;\n }\n}\n\n/**\n * The link controller. Two sources for the clickable areas: the annotation\n * plugin's folded model when it is installed (always current), else a page\n * mirror of this plugin's own per-page reads, re-read when a confirmed\n * change (an annotation write, a redaction, a flatten) touches a loaded page. Activation is pure resolution\n * (`resolve`) plus the one side effect this plugin owns, a stage reveal;\n * everything else is reported to the host, which keeps the user gesture.\n */\nexport function createLinkController(ctx: PluginContext<void>) {\n const annotationHost = () => ctx.tryGet(AnnotationHostToken);\n const activated = ctx.events.source<LinkActivatedEvent>();\n const loaded = ctx.events.source<LinkLoadedEvent>();\n\n const pages = ctx.pageMirror<readonly Link[]>({\n name: 'links',\n load: async (doc, page) => {\n if (!ctx.getPage(page)) {\n throw new PluginError(\n 'not-found',\n 'link',\n `page ${page.objectNumber} is not in this document`,\n );\n }\n const snapshot = await doc.page(page).annotations.list();\n return linksOf(snapshot.annotations);\n },\n affected: pagesChangedBy,\n changed: ({ page, cause }) => {\n if (cause === 'load') loaded.emit({ page });\n },\n });\n\n // Reads take a page's ref or its index; a page that isn't there has no links.\n const listLinks = (pageArgument: PageRef | number): readonly Link[] => {\n const page = ctx.getPage(pageArgument)?.ref;\n if (!page) return EMPTY;\n const host = annotationHost();\n if (host) return host.listLinkItems(page);\n return pages.get(page) ?? EMPTY;\n };\n\n const ensureLoaded = async (\n pageArgument: PageRef | number,\n options?: OperationOptions,\n ): Promise<void> => {\n const { ref } = ctx.pageOf(pageArgument);\n // With the annotation plugin installed, its model owns the data.\n if (annotationHost()) return;\n await ctx.cancellable(options?.signal, pages.ensureLoaded(ref));\n };\n\n // The framework's website openers, the latest first: the plugin never opens one itself.\n const uriOpeners: UriOpener[] = [];\n\n const resolve = (target: PdfLinkTarget): LinkResolution => {\n switch (target.kind) {\n case 'goto':\n // A page the document doesn't have can't be shown.\n return ctx.getPage(target.destination.page)\n ? { kind: 'destination', destination: target.destination }\n : { kind: 'reported', target };\n case 'uri':\n return { kind: 'uri', uri: target.uri };\n case 'named':\n return { kind: 'named', name: target.name };\n default:\n return { kind: 'reported', target };\n }\n };\n\n const perform = (target: PdfLinkTarget, context?: LinkActivateContext): LinkActivation => {\n const actions = ctx.tryGet(ActionsToken);\n if (actions && context?.activate) {\n const dispatch = actions.execute(context.activate, {\n origin: 'user',\n source: { kind: 'link', annotation: context.ref, page: context.page },\n event: { scope: 'activate' },\n });\n return { outcome: 'dispatched', dispatch };\n }\n const resolution = resolve(target);\n switch (resolution.kind) {\n case 'destination': {\n // The view the link was followed in, by its own scroll behavior.\n const stage = context?.stage ?? ctx.tryGet(StageToken);\n if (!stage) return { outcome: 'destination', destination: resolution.destination };\n stage.goToDestination(resolution.destination);\n return { outcome: 'revealed' };\n }\n case 'uri': {\n const open = uriOpeners[0];\n if (!open || open(resolution.uri)) return { outcome: 'uri', uri: resolution.uri };\n return { outcome: 'reported', target };\n }\n case 'named':\n return { outcome: 'named', name: resolution.name };\n default:\n return { outcome: 'reported', target };\n }\n };\n\n const activate = (input: PdfLinkTarget | Link, context?: LinkActivateContext): LinkActivation => {\n const target = isLink(input) ? input.target : input;\n const linkContext: LinkActivateContext | undefined = isLink(input)\n ? { activate: input.activate, ref: input.ref, ...context }\n : context;\n const activation = perform(target, linkContext);\n activated.emit({ target, activation });\n return activation;\n };\n\n const getLinkAt = (page: PageRef | number, point: Point): Link | null => {\n let best: Link | null = null;\n for (const link of listLinks(page)) {\n if (!contains(link.bounds, point)) continue;\n if (\n !best ||\n link.bounds.width * link.bounds.height < best.bounds.width * best.bounds.height\n ) {\n best = link;\n }\n }\n return best;\n };\n\n const getLabel = (input: Link | PdfLinkTarget): string => {\n const target = isLink(input) ? input.target : input;\n switch (target.kind) {\n case 'uri':\n return target.uri;\n case 'goto':\n return 'Go to destination';\n case 'named':\n return target.name;\n default:\n return 'Link';\n }\n };\n\n const api: LinkHostCapability = {\n listLinks,\n getLink: (page, linkId) => listLinks(page).find((link) => link.id === linkId) ?? null,\n getLinkAt,\n listAllLinks: async (options) => {\n const layouts = ctx.document()?.pages ?? [];\n await ctx.cancellable(\n options?.signal,\n Promise.all(layouts.map((layout) => ensureLoaded(layout.ref, options))),\n );\n return layouts.flatMap((layout) => listLinks(layout.ref));\n },\n ensureLoaded,\n isLoaded: (page) => {\n const ref = ctx.getPage(page)?.ref;\n return !!ref && (annotationHost() !== null || pages.getStatus(ref) === 'ready');\n },\n getStatus: (page) => {\n const ref = ctx.getPage(page)?.ref;\n if (!ref) return 'idle';\n return annotationHost() ? 'ready' : pages.getStatus(ref);\n },\n resolve,\n activate,\n activateAt: (pageArgument, point, context) => {\n const page = ctx.pageOf(pageArgument).ref;\n const link = getLinkAt(page, point);\n return link ? activate(link, { page, ...context }) : null;\n },\n getLabel,\n onActivated: activated.on,\n onLoaded: loaded.on,\n registerUriOpener: (opener) => {\n uriOpeners.unshift(opener);\n return () => {\n const index = uriOpeners.indexOf(opener);\n if (index >= 0) uriOpeners.splice(index, 1);\n };\n },\n isNavigationEngaged: () => ctx.tryGet(InteractionToken)?.activeToolEnables('link-nav') ?? false,\n };\n\n return {\n api,\n connect() {\n connectLink(ctx);\n },\n };\n}\n","import { definePlugin } from '@embedpdf/core';\nimport { ActionsToken } from '@embedpdf/plugin-actions/contract';\nimport { AnnotationToken } from '@embedpdf/plugin-annotation/contract';\nimport { InteractionToken } from '@embedpdf/plugin-interaction/contract';\nimport { StageToken } from '@embedpdf/plugin-stage/contract';\n\nimport { createLinkController } from './controller';\nimport { LinkToken } from './host-contract';\n\n/**\n * Clickable link regions and their activation. Document-scoped; needs the\n * interaction hub (the navigation tool tag), optionally the stage (reveal),\n * the annotation plugin (the folded link model) and actions (`/A` trees).\n */\nexport const linkPlugin = () =>\n definePlugin({\n id: 'link',\n token: LinkToken,\n scope: 'document',\n requires: [InteractionToken],\n optional: [StageToken, AnnotationToken, ActionsToken],\n create: createLinkController,\n });\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["AnnotationToken","InteractionToken","AnnotationHostToken","InteractionToken","LinkToken"],"sources":["../src/connect.ts","../src/source.ts","../src/controller.ts","../src/link.plugin.ts"],"sourcesContent":["/** The link plugin's wiring to its siblings, run from the controller's `connect`. */\nimport type { PluginContext } from '@embedpdf/core';\nimport { AnnotationToken } from '@embedpdf/plugin-annotation/contract/host';\nimport { InteractionToken } from '@embedpdf/plugin-interaction/contract/host';\n\n/**\n * Links are annotations: while a navigation tool is active the link layer\n * owns their input (its anchors take the clicks), so the annotation plane\n * stands down for them. A link still shows as the file draws it.\n */\nexport function connectLink(ctx: PluginContext<void>): void {\n const annotation = ctx.tryGet(AnnotationToken);\n if (!annotation) return;\n const interaction = ctx.get(InteractionToken);\n ctx.cleanup(\n annotation.registerBehavior({\n id: 'link-nav',\n matches: (target) => target.subtype === 'link',\n engaged: () => interaction.activeToolEnables('link-nav'),\n }),\n );\n}\n","/**\n * The stand-alone source, used when no annotation plugin is installed: the\n * clickable areas among one page's annotations, in page space.\n */\nimport { annotationKey, type Annotation } from '@embedpdf/engine-core/runtime';\n\nimport type { Link } from './contract';\n\n/** The visible link annotations of a page that have a target. */\nexport function linksOf(annotations: readonly Annotation[]): readonly Link[] {\n const links: Link[] = [];\n for (const dto of annotations) {\n if (dto.subtype !== 'link' || dto.target == null) continue;\n if (dto.hidden || dto.noView) continue;\n links.push({\n id: annotationKey(dto.ref),\n bounds: dto.rect,\n target: dto.target,\n ...(dto.actions?.activate ? { activate: dto.actions.activate } : {}),\n ...(dto.actions?.cursorEnter?.root || dto.actions?.cursorExit?.root\n ? {\n hoverEvents: {\n enter: Boolean(dto.actions?.cursorEnter?.root),\n exit: Boolean(dto.actions?.cursorExit?.root),\n },\n }\n : {}),\n ref: dto.ref,\n attached: dto.reply?.type === 'group',\n });\n }\n return links;\n}\n","import {\n PluginError,\n type PluginContext,\n type DocumentEvent,\n type OperationOptions,\n type PageRef,\n} from '@embedpdf/core';\nimport type { Point } from '@embedpdf/core-geometry';\nimport type { PdfLinkTarget } from '@embedpdf/engine-core/runtime';\nimport { ActionsToken } from '@embedpdf/plugin-actions/contract';\nimport { AnnotationToken as AnnotationHostToken } from '@embedpdf/plugin-annotation/contract/host';\nimport { InteractionToken } from '@embedpdf/plugin-interaction/contract/host';\nimport { StageToken } from '@embedpdf/plugin-stage/contract';\n\nimport { connectLink } from './connect';\nimport {\n resolveLinkTarget,\n type Link,\n type LinkActivateContext,\n type LinkActivatedEvent,\n type LinkActivation,\n type LinkLoadedEvent,\n type LinkResolution,\n} from './contract';\nimport type { LinkHostCapability, UriOpener } from './host-contract';\nimport { linksOf } from './source';\n\nconst EMPTY: readonly Link[] = Object.freeze([]);\n\nconst isLink = (value: PdfLinkTarget | Link): value is Link =>\n 'target' in value && 'bounds' in value;\nconst contains = (\n bounds: { x: number; y: number; width: number; height: number },\n point: Point,\n): boolean =>\n point.x >= bounds.x &&\n point.x <= bounds.x + bounds.width &&\n point.y >= bounds.y &&\n point.y <= bounds.y + bounds.height;\n\n/** The pages whose annotation lists an event changed, each once. */\nfunction pagesChangedBy(event: DocumentEvent): readonly PageRef[] | null {\n switch (event.type) {\n case 'annotations.created':\n return [event.annotation.page];\n case 'annotations.updated':\n return [event.annotation.page];\n case 'annotations.deleted':\n case 'annotations.reordered':\n return [event.page];\n // These can remove annotations, links included, from the pages they applied to.\n case 'redaction.applied':\n case 'pages.flattened':\n return event.results\n .filter((result) => result.status === 'applied')\n .map((result) => result.page);\n case 'annotations.flattened':\n return event.results.some((result) => result.status === 'applied') ? [event.page] : null;\n default:\n return null;\n }\n}\n\n/**\n * The link controller. Two sources for the clickable areas: the annotation\n * plugin's folded model when it is installed (always current), else a page\n * mirror of this plugin's own per-page reads, re-read when a confirmed\n * change (an annotation write, a redaction, a flatten) touches a loaded page. Activation is pure resolution\n * (`resolve`) plus the one side effect this plugin owns, a stage reveal;\n * everything else is reported to the host, which keeps the user gesture.\n */\nexport function createLinkController(ctx: PluginContext<void>) {\n const annotationHost = () => ctx.tryGet(AnnotationHostToken);\n const activated = ctx.events.source<LinkActivatedEvent>();\n const loaded = ctx.events.source<LinkLoadedEvent>();\n\n const pages = ctx.pageMirror<readonly Link[]>({\n name: 'links',\n load: async (doc, page) => {\n if (!ctx.getPage(page)) {\n throw new PluginError(\n 'not-found',\n 'link',\n `page ${page.objectNumber} is not in this document`,\n );\n }\n const snapshot = await doc.page(page).annotations.list();\n return linksOf(snapshot.annotations);\n },\n affected: pagesChangedBy,\n changed: ({ page, cause }) => {\n if (cause === 'load') loaded.emit({ page });\n },\n });\n\n // Reads take a page's ref or its index; a page that isn't there has no links.\n const listLinks = (pageArgument: PageRef | number): readonly Link[] => {\n const page = ctx.getPage(pageArgument)?.ref;\n if (!page) return EMPTY;\n const host = annotationHost();\n if (host) return host.listLinkItems(page);\n return pages.get(page) ?? EMPTY;\n };\n\n const ensureLoaded = async (\n pageArgument: PageRef | number,\n options?: OperationOptions,\n ): Promise<void> => {\n const { ref } = ctx.pageOf(pageArgument);\n // With the annotation plugin installed, its model owns the data.\n if (annotationHost()) return;\n await ctx.cancellable(options?.signal, pages.ensureLoaded(ref));\n };\n\n // The framework's website openers, the latest first: the plugin never opens one itself.\n const uriOpeners: UriOpener[] = [];\n\n // A page the document doesn't have can't be shown.\n const resolve = (target: PdfLinkTarget): LinkResolution =>\n resolveLinkTarget(target, (page) => ctx.getPage(page) !== null);\n\n const perform = (target: PdfLinkTarget, context?: LinkActivateContext): LinkActivation => {\n const actions = ctx.tryGet(ActionsToken);\n if (actions && context?.activate) {\n const dispatch = actions.execute(context.activate, {\n origin: 'user',\n source: { kind: 'link', annotation: context.ref, page: context.page },\n event: { scope: 'activate' },\n });\n return { outcome: 'dispatched', dispatch };\n }\n const resolution = resolve(target);\n switch (resolution.kind) {\n case 'destination': {\n // The view the link was followed in, by its own scroll behavior.\n const stage = context?.stage ?? ctx.tryGet(StageToken);\n if (!stage) return { outcome: 'destination', destination: resolution.destination };\n stage.goToDestination(resolution.destination);\n return { outcome: 'revealed' };\n }\n case 'uri': {\n const open = uriOpeners[0];\n if (!open || open(resolution.uri)) return { outcome: 'uri', uri: resolution.uri };\n return { outcome: 'reported', target };\n }\n case 'named':\n return { outcome: 'named', name: resolution.name };\n default:\n return { outcome: 'reported', target };\n }\n };\n\n const activate = (input: PdfLinkTarget | Link, context?: LinkActivateContext): LinkActivation => {\n const target = isLink(input) ? input.target : input;\n const linkContext: LinkActivateContext | undefined = isLink(input)\n ? { activate: input.activate, ref: input.ref, ...context }\n : context;\n const activation = perform(target, linkContext);\n activated.emit({ target, activation });\n return activation;\n };\n\n const getLinkAt = (page: PageRef | number, point: Point): Link | null => {\n let best: Link | null = null;\n for (const link of listLinks(page)) {\n if (!contains(link.bounds, point)) continue;\n if (\n !best ||\n link.bounds.width * link.bounds.height < best.bounds.width * best.bounds.height\n ) {\n best = link;\n }\n }\n return best;\n };\n\n const getLabel = (input: Link | PdfLinkTarget): string => {\n const target = isLink(input) ? input.target : input;\n switch (target.kind) {\n case 'uri':\n return target.uri;\n case 'goto':\n return 'Go to destination';\n case 'named':\n return target.name;\n default:\n return 'Link';\n }\n };\n\n const api: LinkHostCapability = {\n listLinks,\n getLink: (page, linkId) => listLinks(page).find((link) => link.id === linkId) ?? null,\n getLinkAt,\n listAllLinks: async (options) => {\n const layouts = ctx.document()?.pages ?? [];\n await ctx.cancellable(\n options?.signal,\n Promise.all(layouts.map((layout) => ensureLoaded(layout.ref, options))),\n );\n return layouts.flatMap((layout) => listLinks(layout.ref));\n },\n ensureLoaded,\n isLoaded: (page) => {\n const ref = ctx.getPage(page)?.ref;\n return !!ref && (annotationHost() !== null || pages.getStatus(ref) === 'ready');\n },\n getStatus: (page) => {\n const ref = ctx.getPage(page)?.ref;\n if (!ref) return 'idle';\n return annotationHost() ? 'ready' : pages.getStatus(ref);\n },\n resolve,\n activate,\n activateAt: (pageArgument, point, context) => {\n const page = ctx.pageOf(pageArgument).ref;\n const link = getLinkAt(page, point);\n return link ? activate(link, { page, ...context }) : null;\n },\n getLabel,\n onActivated: activated.on,\n onLoaded: loaded.on,\n registerUriOpener: (opener) => {\n uriOpeners.unshift(opener);\n return () => {\n const index = uriOpeners.indexOf(opener);\n if (index >= 0) uriOpeners.splice(index, 1);\n };\n },\n isNavigationEngaged: () => ctx.tryGet(InteractionToken)?.activeToolEnables('link-nav') ?? false,\n };\n\n return {\n api,\n connect() {\n connectLink(ctx);\n },\n };\n}\n","import { definePlugin } from '@embedpdf/core';\nimport { ActionsToken } from '@embedpdf/plugin-actions/contract';\nimport { AnnotationToken } from '@embedpdf/plugin-annotation/contract';\nimport { InteractionToken } from '@embedpdf/plugin-interaction/contract';\nimport { StageToken } from '@embedpdf/plugin-stage/contract';\n\nimport { createLinkController } from './controller';\nimport { LinkToken } from './host-contract';\n\n/**\n * Clickable link regions and their activation. Document-scoped; needs the\n * interaction hub (the navigation tool tag), optionally the stage (reveal),\n * the annotation plugin (the folded link model) and actions (`/A` trees).\n */\nexport const linkPlugin = () =>\n definePlugin({\n id: 'link',\n token: LinkToken,\n scope: 'document',\n requires: [InteractionToken],\n optional: [StageToken, AnnotationToken, ActionsToken],\n create: createLinkController,\n });\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@embedpdf/plugin-link",
3
- "version": "3.0.0-next.15",
3
+ "version": "3.0.0-next.16",
4
4
  "private": false,
5
5
  "description": "The navigation plane for PDF link annotations: per-page clickable link areas + one activate() entry point (GoTo → stage reveal, URI → framework opener). Works standalone in viewer deployments; with the annotation plugin present it reads the folded model (no double fetch) and a Behavior hands links to the editing plane when the link tool is active.",
6
6
  "type": "module",
@@ -26,14 +26,14 @@
26
26
  "dist"
27
27
  ],
28
28
  "dependencies": {
29
- "@embedpdf/core-annotation": "3.0.0-next.15",
30
- "@embedpdf/core-geometry": "3.0.0-next.15",
31
- "@embedpdf/core": "3.0.0-next.15",
32
- "@embedpdf/plugin-interaction": "3.0.0-next.15",
33
- "@embedpdf/plugin-annotation": "3.0.0-next.15",
34
- "@embedpdf/plugin-stage": "3.0.0-next.15",
35
- "@embedpdf/engine-core": "3.0.0-next.15",
36
- "@embedpdf/plugin-actions": "3.0.0-next.15"
29
+ "@embedpdf/core-annotation": "3.0.0-next.16",
30
+ "@embedpdf/core": "3.0.0-next.16",
31
+ "@embedpdf/plugin-annotation": "3.0.0-next.16",
32
+ "@embedpdf/plugin-interaction": "3.0.0-next.16",
33
+ "@embedpdf/plugin-stage": "3.0.0-next.16",
34
+ "@embedpdf/core-geometry": "3.0.0-next.16",
35
+ "@embedpdf/plugin-actions": "3.0.0-next.16",
36
+ "@embedpdf/engine-core": "3.0.0-next.16"
37
37
  },
38
38
  "devDependencies": {
39
39
  "typescript": "^5.0.0",
@@ -1,19 +0,0 @@
1
- //#region src/token.ts
2
- /** The package token, created once here: `contract.ts` re-exports it and
3
- * `host-contract.ts` widens it to the host capability. */
4
- const LinkToken = (0, require("@embedpdf/core").createCapabilityToken)("link", {
5
- hint: `add linkPlugin() from '@embedpdf/plugin-link' to your plugins list`,
6
- promises: {
7
- listAllLinks: true,
8
- ensureLoaded: true
9
- }
10
- });
11
- //#endregion
12
- Object.defineProperty(exports, "LinkToken", {
13
- enumerable: true,
14
- get: function() {
15
- return LinkToken;
16
- }
17
- });
18
-
19
- //# sourceMappingURL=contract-CaaMtYBR.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"contract-CaaMtYBR.cjs","names":[],"sources":["../src/token.ts"],"sourcesContent":["/** The package token, created once here: `contract.ts` re-exports it and\n * `host-contract.ts` widens it to the host capability. */\nimport { createCapabilityToken } from '@embedpdf/core';\n\nimport type { LinkCapability } from './contract';\n\nexport const LinkToken = createCapabilityToken<LinkCapability>('link', {\n hint: `add linkPlugin() from '@embedpdf/plugin-link' to your plugins list`,\n // Without a document, an adapter's stand-in rejects these with `not-ready`, as the\n // capability would; the type asks for every member that returns a promise.\n promises: {\n listAllLinks: true,\n ensureLoaded: true,\n },\n});\n"],"mappings":";;;AAMA,MAAa,aAAA,2BAAA,CAAA,CAAA,sBAAA,CAAkD,QAAQ;CACrE,MAAM;CAGN,UAAU;EACR,cAAc;EACd,cAAc;CAChB;AACF,CAAC"}
@@ -1,15 +0,0 @@
1
- import { createCapabilityToken } from "@embedpdf/core";
2
- //#region src/token.ts
3
- /** The package token, created once here: `contract.ts` re-exports it and
4
- * `host-contract.ts` widens it to the host capability. */
5
- const LinkToken = createCapabilityToken("link", {
6
- hint: `add linkPlugin() from '@embedpdf/plugin-link' to your plugins list`,
7
- promises: {
8
- listAllLinks: true,
9
- ensureLoaded: true
10
- }
11
- });
12
- //#endregion
13
- export { LinkToken as t };
14
-
15
- //# sourceMappingURL=contract-D0k-EtjB.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"contract-D0k-EtjB.js","names":[],"sources":["../src/token.ts"],"sourcesContent":["/** The package token, created once here: `contract.ts` re-exports it and\n * `host-contract.ts` widens it to the host capability. */\nimport { createCapabilityToken } from '@embedpdf/core';\n\nimport type { LinkCapability } from './contract';\n\nexport const LinkToken = createCapabilityToken<LinkCapability>('link', {\n hint: `add linkPlugin() from '@embedpdf/plugin-link' to your plugins list`,\n // Without a document, an adapter's stand-in rejects these with `not-ready`, as the\n // capability would; the type asks for every member that returns a promise.\n promises: {\n listAllLinks: true,\n ensureLoaded: true,\n },\n});\n"],"mappings":";;;;AAMA,MAAa,YAAY,sBAAsC,QAAQ;CACrE,MAAM;CAGN,UAAU;EACR,cAAc;EACd,cAAc;CAChB;AACF,CAAC"}