@embedpdf/plugin-redaction 2.3.0 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/dist/index.cjs +1 -1
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js +748 -105
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/actions.d.ts +25 -1
  6. package/dist/lib/index.d.ts +1 -0
  7. package/dist/lib/redaction-plugin.d.ts +98 -2
  8. package/dist/lib/tools.d.ts +28 -0
  9. package/dist/lib/types.d.ts +38 -11
  10. package/dist/preact/adapter.d.ts +4 -4
  11. package/dist/preact/annotation.d.ts +1 -0
  12. package/dist/preact/index.cjs +1 -1
  13. package/dist/preact/index.cjs.map +1 -1
  14. package/dist/preact/index.js +187 -11
  15. package/dist/preact/index.js.map +1 -1
  16. package/dist/react/annotation.d.ts +1 -0
  17. package/dist/react/index.cjs +1 -1
  18. package/dist/react/index.cjs.map +1 -1
  19. package/dist/react/index.js +187 -11
  20. package/dist/react/index.js.map +1 -1
  21. package/dist/shared/components/annotations/index.d.ts +2 -0
  22. package/dist/shared/components/annotations/redact-area.d.ts +18 -0
  23. package/dist/shared/components/annotations/redact-highlight.d.ts +18 -0
  24. package/dist/shared/components/index.d.ts +3 -0
  25. package/dist/shared/components/redact-renderer-registration.d.ts +5 -0
  26. package/dist/shared/components/redact-renderers.d.ts +7 -0
  27. package/dist/shared/index.d.ts +1 -0
  28. package/dist/shared-preact/components/annotations/index.d.ts +2 -0
  29. package/dist/shared-preact/components/annotations/redact-area.d.ts +18 -0
  30. package/dist/shared-preact/components/annotations/redact-highlight.d.ts +18 -0
  31. package/dist/shared-preact/components/index.d.ts +3 -0
  32. package/dist/shared-preact/components/redact-renderer-registration.d.ts +5 -0
  33. package/dist/shared-preact/components/redact-renderers.d.ts +7 -0
  34. package/dist/shared-preact/index.d.ts +1 -0
  35. package/dist/shared-react/components/annotations/index.d.ts +2 -0
  36. package/dist/shared-react/components/annotations/redact-area.d.ts +18 -0
  37. package/dist/shared-react/components/annotations/redact-highlight.d.ts +18 -0
  38. package/dist/shared-react/components/index.d.ts +3 -0
  39. package/dist/shared-react/components/redact-renderer-registration.d.ts +5 -0
  40. package/dist/shared-react/components/redact-renderers.d.ts +7 -0
  41. package/dist/shared-react/index.d.ts +1 -0
  42. package/dist/svelte/components/RedactRendererRegistration.svelte.d.ts +7 -0
  43. package/dist/svelte/components/annotations/RedactArea.svelte.d.ts +5 -0
  44. package/dist/svelte/components/annotations/RedactHighlight.svelte.d.ts +5 -0
  45. package/dist/svelte/components/annotations/index.d.ts +2 -0
  46. package/dist/svelte/components/index.d.ts +3 -0
  47. package/dist/svelte/components/redact-renderers.d.ts +7 -0
  48. package/dist/svelte/index.cjs +1 -1
  49. package/dist/svelte/index.cjs.map +1 -1
  50. package/dist/svelte/index.d.ts +1 -0
  51. package/dist/svelte/index.js +270 -22
  52. package/dist/svelte/index.js.map +1 -1
  53. package/dist/vue/components/annotations/index.d.ts +2 -0
  54. package/dist/vue/components/annotations/redact-area.vue.d.ts +6 -0
  55. package/dist/vue/components/annotations/redact-highlight.vue.d.ts +6 -0
  56. package/dist/vue/components/index.d.ts +3 -0
  57. package/dist/vue/components/redact-renderer-registration.vue.d.ts +13 -0
  58. package/dist/vue/components/redact-renderers.d.ts +7 -0
  59. package/dist/vue/components/types.d.ts +1 -1
  60. package/dist/vue/hooks/use-redaction.d.ts +2 -2
  61. package/dist/vue/index.cjs +1 -1
  62. package/dist/vue/index.cjs.map +1 -1
  63. package/dist/vue/index.d.ts +2 -1
  64. package/dist/vue/index.js +264 -59
  65. package/dist/vue/index.js.map +1 -1
  66. package/package.json +13 -9
@@ -7,6 +7,14 @@ export declare class RedactionPlugin extends BasePlugin<RedactionPluginConfig, R
7
7
  private config;
8
8
  private selectionCapability;
9
9
  private interactionManagerCapability;
10
+ private annotationCapability;
11
+ private historyCapability;
12
+ /**
13
+ * Determines which mode to use:
14
+ * - true: Annotation mode (new) - uses REDACT annotations as pending state
15
+ * - false: Legacy mode (deprecated) - uses internal pending state
16
+ */
17
+ private readonly useAnnotationMode;
10
18
  private readonly redactionSelection$;
11
19
  private readonly pending$;
12
20
  private readonly selected$;
@@ -14,14 +22,52 @@ export declare class RedactionPlugin extends BasePlugin<RedactionPluginConfig, R
14
22
  private readonly events$;
15
23
  private readonly documentUnsubscribers;
16
24
  constructor(id: string, registry: PluginRegistry, config: RedactionPluginConfig);
25
+ /**
26
+ * Setup redaction modes - registers all interaction modes for redaction.
27
+ * Works for both annotation mode and legacy mode.
28
+ */
29
+ private setupRedactionModes;
30
+ /**
31
+ * Setup mode change listener - handles all redaction modes
32
+ */
33
+ private setupModeChangeListener;
17
34
  protected onDocumentLoadingStarted(documentId: string): void;
18
35
  protected onDocumentLoaded(documentId: string): void;
19
36
  protected onDocumentClosed(documentId: string): void;
20
37
  initialize(_config: RedactionPluginConfig): Promise<void>;
21
38
  protected buildCapability(): RedactionCapability;
22
39
  private createRedactionScope;
40
+ /**
41
+ * Get pending redactions derived from annotation plugin (annotation mode only)
42
+ */
43
+ private getPendingFromAnnotations;
23
44
  private getDocumentState;
24
45
  private getDocumentStateOrThrow;
46
+ /**
47
+ * Sync internal state when REDACT annotation is created.
48
+ * Called from annotation event listener in annotation mode.
49
+ */
50
+ private syncFromAnnotationCreate;
51
+ /**
52
+ * Sync internal state when REDACT annotation is updated (moved/resized/color changed).
53
+ * Called from annotation event listener in annotation mode.
54
+ */
55
+ private syncFromAnnotationUpdate;
56
+ /**
57
+ * Sync internal state when REDACT annotation is deleted.
58
+ * Called from annotation event listener in annotation mode.
59
+ */
60
+ private syncFromAnnotationDelete;
61
+ /**
62
+ * Sync internal state from existing REDACT annotations after initial load.
63
+ * Called when annotation plugin emits 'loaded' event.
64
+ */
65
+ private syncFromAnnotationLoad;
66
+ /**
67
+ * Sync selection state from annotation plugin's selected REDACT annotation.
68
+ * Called when annotation plugin state changes.
69
+ */
70
+ private syncSelectionFromAnnotation;
25
71
  private addPendingItems;
26
72
  private removePendingItem;
27
73
  private clearPendingItems;
@@ -34,13 +80,63 @@ export declare class RedactionPlugin extends BasePlugin<RedactionPluginConfig, R
34
80
  private enableMarqueeRedact;
35
81
  private toggleMarqueeRedact;
36
82
  private isMarqueeRedactActive;
37
- private startRedactionMode;
38
- private endRedactionMode;
83
+ private enableRedact;
84
+ private toggleRedact;
85
+ private isRedactActive;
86
+ private endRedact;
39
87
  onRedactionSelectionChange(documentId: string, callback: (formattedSelection: FormattedSelection[]) => void): import('@embedpdf/core').Unsubscribe;
88
+ /**
89
+ * Get the stroke color for redaction previews.
90
+ * In annotation mode: returns tool's defaults.strokeColor
91
+ * In legacy mode: returns hardcoded red
92
+ */
93
+ getPreviewStrokeColor(): string;
40
94
  registerMarqueeOnPage(opts: RegisterMarqueeOnPageOptions): () => void;
41
95
  private queueCurrentSelectionAsPending;
42
96
  private commitPendingOne;
97
+ /**
98
+ * Legacy commit single redaction using redactTextInRects
99
+ */
100
+ private commitPendingOneLegacy;
101
+ /**
102
+ * Annotation mode: Apply single redaction using engine.applyRedaction
103
+ */
104
+ private applyRedactionAnnotationMode;
43
105
  private commitAllPending;
106
+ /**
107
+ * Legacy commit all redactions using redactTextInRects
108
+ */
109
+ private commitAllPendingLegacy;
110
+ /**
111
+ * Annotation mode: Apply all redactions using engine.applyAllRedactions per page
112
+ */
113
+ private applyAllRedactionsAnnotationMode;
114
+ /**
115
+ * Create REDACT annotations from text selection (annotation mode only)
116
+ * @returns Array of annotation IDs that were created
117
+ */
118
+ private createRedactAnnotationsFromSelection;
119
+ /**
120
+ * Create legacy RedactionItems from text selection (legacy mode only)
121
+ */
122
+ private createLegacyRedactionsFromSelection;
123
+ /**
124
+ * Unified method to create redactions from text selection.
125
+ * Delegates to annotation mode or legacy mode helper based on configuration.
126
+ */
127
+ private createRedactionsFromSelection;
128
+ /**
129
+ * Create a REDACT annotation from an area/marquee selection (annotation mode only)
130
+ */
131
+ private createRedactAnnotationFromArea;
132
+ /**
133
+ * Convert a RedactionItem to a PdfRedactAnnoObject
134
+ */
135
+ private redactionItemToAnnotation;
136
+ /**
137
+ * Convert a PdfRedactAnnoObject to a RedactionItem
138
+ */
139
+ private annotationToRedactionItem;
44
140
  private emitPendingChange;
45
141
  private emitSelectedChange;
46
142
  private emitStateChange;
@@ -0,0 +1,28 @@
1
+ import { PdfAnnotationObject, PdfRedactAnnoObject } from '@embedpdf/models';
2
+ import { AnnotationTool } from '@embedpdf/plugin-annotation';
3
+ /**
4
+ * Unified Redact tool - handles both text-based and area-based redactions.
5
+ * Dynamically determines isDraggable/isResizable based on whether it has segmentRects.
6
+ */
7
+ export declare const redactTool: AnnotationTool<PdfRedactAnnoObject>;
8
+ export declare const redactTools: {
9
+ id: string;
10
+ name: string;
11
+ matchScore: (annotation: PdfAnnotationObject) => number;
12
+ defaults: Partial<PdfRedactAnnoObject>;
13
+ interaction: {
14
+ mode?: string;
15
+ exclusive: boolean;
16
+ cursor?: string;
17
+ textSelection?: boolean;
18
+ isDraggable?: import('@embedpdf/plugin-annotation').DynamicBooleanProp;
19
+ isResizable?: import('@embedpdf/plugin-annotation').DynamicBooleanProp;
20
+ lockAspectRatio?: import('@embedpdf/plugin-annotation').DynamicBooleanProp;
21
+ isGroupDraggable?: import('@embedpdf/plugin-annotation').DynamicBooleanProp;
22
+ isGroupResizable?: import('@embedpdf/plugin-annotation').DynamicBooleanProp;
23
+ };
24
+ behavior?: {
25
+ deactivateToolAfterCreate?: boolean;
26
+ selectAfterCreate?: boolean;
27
+ };
28
+ }[];
@@ -1,7 +1,20 @@
1
1
  import { BasePluginConfig, EventHook } from '@embedpdf/core';
2
2
  import { PdfErrorReason, Rect, Task } from '@embedpdf/models';
3
3
  export declare enum RedactionMode {
4
+ /**
5
+ * Unified redaction mode - supports both text selection and area marquee simultaneously.
6
+ * Available when annotation plugin is present.
7
+ */
8
+ Redact = "redact",
9
+ /**
10
+ * Area-based redactions only (marquee selection).
11
+ * For backwards compatibility with existing code.
12
+ */
4
13
  MarqueeRedact = "marqueeRedact",
14
+ /**
15
+ * Text-based redactions only (text selection).
16
+ * For backwards compatibility with existing code.
17
+ */
5
18
  RedactSelection = "redactSelection"
6
19
  }
7
20
  export interface SelectedRedaction {
@@ -19,18 +32,22 @@ export interface RedactionState {
19
32
  documents: Record<string, RedactionDocumentState>;
20
33
  activeDocumentId: string | null;
21
34
  }
22
- export type RedactionItem = {
35
+ export type RedactionSource = 'annotation' | 'legacy';
36
+ interface RedactionItemBase {
23
37
  id: string;
24
- kind: 'text';
25
38
  page: number;
26
39
  rect: Rect;
40
+ source: RedactionSource;
41
+ markColor: string;
42
+ redactionColor: string;
43
+ }
44
+ export type RedactionItem = (RedactionItemBase & {
45
+ kind: 'text';
27
46
  rects: Rect[];
28
- } | {
29
- id: string;
47
+ text?: string;
48
+ }) | (RedactionItemBase & {
30
49
  kind: 'area';
31
- page: number;
32
- rect: Rect;
33
- };
50
+ });
34
51
  export interface MarqueeRedactCallback {
35
52
  onPreview?: (rect: Rect | null) => void;
36
53
  onCommit?: (rect: Rect) => void;
@@ -43,6 +60,11 @@ export interface RegisterMarqueeOnPageOptions {
43
60
  }
44
61
  export interface RedactionPluginConfig extends BasePluginConfig {
45
62
  drawBlackBoxes: boolean;
63
+ /**
64
+ * When true, use annotation-based redactions (requires annotation plugin).
65
+ * When false (default), use legacy internal pending state.
66
+ */
67
+ useAnnotationMode?: boolean;
46
68
  }
47
69
  export type RedactionEvent = {
48
70
  type: 'add';
@@ -76,6 +98,10 @@ export interface StateChangeEvent {
76
98
  }
77
99
  export interface RedactionScope {
78
100
  queueCurrentSelectionAsPending(): Task<boolean, PdfErrorReason>;
101
+ enableRedact(): void;
102
+ toggleRedact(): void;
103
+ isRedactActive(): boolean;
104
+ endRedact(): void;
79
105
  enableMarqueeRedact(): void;
80
106
  toggleMarqueeRedact(): void;
81
107
  isMarqueeRedactActive(): boolean;
@@ -87,8 +113,6 @@ export interface RedactionScope {
87
113
  clearPending(): void;
88
114
  commitAllPending(): Task<boolean, PdfErrorReason>;
89
115
  commitPending(page: number, id: string): Task<boolean, PdfErrorReason>;
90
- endRedaction(): void;
91
- startRedaction(): void;
92
116
  selectPending(page: number, id: string): void;
93
117
  getSelectedPending(): SelectedRedaction | null;
94
118
  deselectPending(): void;
@@ -100,6 +124,10 @@ export interface RedactionScope {
100
124
  }
101
125
  export interface RedactionCapability {
102
126
  queueCurrentSelectionAsPending(): Task<boolean, PdfErrorReason>;
127
+ enableRedact(): void;
128
+ toggleRedact(): void;
129
+ isRedactActive(): boolean;
130
+ endRedact(): void;
103
131
  enableMarqueeRedact(): void;
104
132
  toggleMarqueeRedact(): void;
105
133
  isMarqueeRedactActive(): boolean;
@@ -111,8 +139,6 @@ export interface RedactionCapability {
111
139
  clearPending(): void;
112
140
  commitAllPending(): Task<boolean, PdfErrorReason>;
113
141
  commitPending(page: number, id: string): Task<boolean, PdfErrorReason>;
114
- endRedaction(): void;
115
- startRedaction(): void;
116
142
  selectPending(page: number, id: string): void;
117
143
  getSelectedPending(): SelectedRedaction | null;
118
144
  deselectPending(): void;
@@ -123,3 +149,4 @@ export interface RedactionCapability {
123
149
  onRedactionEvent: EventHook<RedactionEvent>;
124
150
  onStateChange: EventHook<StateChangeEvent>;
125
151
  }
152
+ export {};
@@ -4,7 +4,7 @@ export { useEffect, useRef, useState, useMemo, useCallback } from 'preact/hooks'
4
4
  export type { ComponentChildren as ReactNode } from 'preact';
5
5
  export type HTMLAttributes<T = any> = import('preact').JSX.HTMLAttributes<T extends EventTarget ? T : never>;
6
6
  export type CSSProperties = import('preact').JSX.CSSProperties;
7
- export type MouseEvent<T = Element> = JSX.TargetedMouseEvent<T extends EventTarget ? T : never>;
8
- export type PointerEvent<T = Element> = JSX.TargetedPointerEvent<T extends EventTarget ? T : never>;
9
- export type ChangeEvent<T = Element> = JSX.TargetedInputEvent<T extends EventTarget ? T : never>;
10
- export type TouchEvent<T = Element> = JSX.TargetedTouchEvent<T extends EventTarget ? T : never>;
7
+ export type MouseEvent<T = Element, _E = unknown> = JSX.TargetedMouseEvent<T extends EventTarget ? T : never>;
8
+ export type PointerEvent<T = Element, _E = unknown> = JSX.TargetedPointerEvent<T extends EventTarget ? T : never>;
9
+ export type ChangeEvent<T = Element, _E = unknown> = JSX.TargetedInputEvent<T extends EventTarget ? T : never>;
10
+ export type TouchEvent<T = Element, _E = unknown> = JSX.TargetedTouchEvent<T extends EventTarget ? T : never>;
@@ -0,0 +1 @@
1
+ export * from '@embedpdf/plugin-annotation/preact';
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core/preact"),t=require("@embedpdf/plugin-redaction"),n=require("preact"),i=require("preact/hooks"),o=require("preact/jsx-runtime"),r=require("@embedpdf/utils/preact"),s=require("@embedpdf/models"),d=()=>e.usePlugin(t.RedactionPlugin.id),l=()=>e.useCapability(t.RedactionPlugin.id),a=({documentId:t,pageIndex:n,scale:r,className:s,stroke:l="red",fill:a="transparent"})=>{const{plugin:c}=d(),u=e.useDocumentState(t),[p,g]=i.useState(null),x=i.useMemo(()=>void 0!==r?r:(null==u?void 0:u.scale)??1,[r,null==u?void 0:u.scale]);return i.useEffect(()=>{if(c&&t)return c.registerMarqueeOnPage({documentId:t,pageIndex:n,scale:x,callback:{onPreview:g}})},[c,t,n,x]),p?o.jsx("div",{style:{position:"absolute",pointerEvents:"none",left:p.origin.x*x,top:p.origin.y*x,width:p.size.width*x,height:p.size.height*x,border:`1px solid ${l}`,background:a,boxSizing:"border-box"},className:s}):null};function c({color:e="#FFFF00",opacity:t=1,border:n="1px solid red",rects:i,rect:r,scale:s,onClick:d,style:l,...a}){return o.jsx(o.Fragment,{children:i.map((i,c)=>o.jsx("div",{onPointerDown:d,onTouchStart:d,style:{position:"absolute",border:n,left:(r?i.origin.x-r.origin.x:i.origin.x)*s,top:(r?i.origin.y-r.origin.y:i.origin.y)*s,width:i.size.width*s,height:i.size.height*s,background:e,opacity:t,pointerEvents:d?"auto":"none",cursor:d?"pointer":"default",zIndex:d?1:void 0,...l},...a},c))})}function u({documentId:e,pageIndex:t,scale:n}){const{plugin:r}=d(),[s,l]=i.useState([]),[a,u]=i.useState(null);return i.useEffect(()=>{if(r)return r.onRedactionSelectionChange(e,e=>{const n=e.find(e=>e.pageIndex===t);l((null==n?void 0:n.segmentRects)??[]),u((null==n?void 0:n.rect)??null)})},[r,e,t]),a?o.jsx("div",{style:{mixBlendMode:"normal",pointerEvents:"none",position:"absolute",inset:0},children:o.jsx(c,{color:"transparent",opacity:1,rects:s,scale:n,border:"1px solid red"})}):null}function p({documentId:e,pageIndex:t,scale:d,bboxStroke:a="rgba(0,0,0,0.8)",rotation:u=s.Rotation.Degree0,selectionMenu:p}){const{provides:g}=l(),[x,h]=i.useState([]),[m,f]=i.useState(null);i.useEffect(()=>{if(!g)return;const n=g.forDocument(e),i=n.getState();h(i.pending[t]??[]),f(i.selected&&i.selected.page===t?i.selected.id:null);const o=n.onPendingChange(e=>h(e[t]??[])),r=n.onSelectedChange(e=>{f(e&&e.page===t?e.id:null)});return()=>{null==o||o(),null==r||r()}},[g,e,t]);const b=i.useCallback((n,i)=>{n.stopPropagation(),g&&g.forDocument(e).selectPending(t,i)},[g,e,t]);return x.length?o.jsx("div",{style:{position:"absolute",inset:0,pointerEvents:"none"},children:x.map(e=>{if("area"===e.kind){const i=e.rect;return o.jsxs(n.Fragment,{children:[o.jsx("div",{style:{position:"absolute",left:i.origin.x*d,top:i.origin.y*d,width:i.size.width*d,height:i.size.height*d,background:"transparent",outline:m===e.id?`1px solid ${a}`:"none",outlineOffset:"2px",border:"1px solid red",pointerEvents:"auto",cursor:"pointer"},onPointerDown:t=>b(t,e.id),onTouchStart:t=>b(t,e.id)}),p&&o.jsx(r.CounterRotate,{rect:{origin:{x:i.origin.x*d,y:i.origin.y*d},size:{width:i.size.width*d,height:i.size.height*d}},rotation:u,children:n=>p({...n,context:{type:"redaction",item:e,pageIndex:t},selected:m===e.id,placement:{suggestTop:!1}})})]},e.id)}const i=e.rect;return o.jsxs(n.Fragment,{children:[o.jsx("div",{style:{position:"absolute",left:i.origin.x*d,top:i.origin.y*d,width:i.size.width*d,height:i.size.height*d,background:"transparent",outline:m===e.id?`1px solid ${a}`:"none",outlineOffset:"2px",pointerEvents:"auto",cursor:m===e.id?"pointer":"default"},children:o.jsx(c,{rect:i,rects:e.rects,color:"transparent",border:"1px solid red",scale:d,onClick:t=>b(t,e.id)})}),p&&o.jsx(r.CounterRotate,{rect:{origin:{x:i.origin.x*d,y:i.origin.y*d},size:{width:i.size.width*d,height:i.size.height*d}},rotation:u,children:n=>p({...n,context:{type:"redaction",item:e,pageIndex:t},selected:m===e.id,placement:{suggestTop:!1}})})]},e.id)})}):null}exports.RedactionLayer=({documentId:t,pageIndex:r,scale:d,rotation:l,selectionMenu:c})=>{const g=e.useDocumentState(t),x=i.useMemo(()=>void 0!==d?d:(null==g?void 0:g.scale)??1,[d,null==g?void 0:g.scale]),h=i.useMemo(()=>void 0!==l?l:(null==g?void 0:g.rotation)??s.Rotation.Degree0,[l,null==g?void 0:g.rotation]);return o.jsxs(n.Fragment,{children:[o.jsx(p,{documentId:t,pageIndex:r,scale:x,rotation:h,selectionMenu:c}),o.jsx(a,{documentId:t,pageIndex:r,scale:x}),o.jsx(u,{documentId:t,pageIndex:r,scale:x})]})},exports.useRedaction=e=>{const{provides:n}=l(),[o,r]=i.useState(t.initialDocumentState),s=i.useMemo(()=>n?n.forDocument(e):null,[n,e]);return i.useEffect(()=>{if(!s)return void r(t.initialDocumentState);try{r(s.getState())}catch(e){r(t.initialDocumentState)}return s.onStateChange(e=>{r(e)})},[s]),{state:o,provides:s}},exports.useRedactionCapability=l,exports.useRedactionPlugin=d,Object.keys(t).forEach(e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>t[e]})});
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core"),t=require("@embedpdf/plugin-redaction"),n=require("@embedpdf/plugin-annotation/preact"),o=require("preact/jsx-runtime"),i=require("@embedpdf/models"),r=require("preact"),s=require("preact/hooks"),l=require("@embedpdf/core/preact"),a=require("@embedpdf/utils/preact");function d({annotation:e,isSelected:t,scale:n,onClick:r,style:l}){const[a,d]=s.useState(!1),{object:c}=e,u=c.segmentRects??[],g=c.rect,p=c.strokeColor??"#FF0000",x=c.color??"#000000",f=c.opacity??1,h=c.fontColor??c.overlayColor??"#FFFFFF",m=c.overlayText,y=c.overlayTextRepeat??!1,v=c.fontSize??12,b=c.fontFamily??i.PdfStandardFont.Helvetica,S=c.textAlign??i.PdfTextAlignment.Center,j=()=>{if(!m)return null;if(!y)return m;return Array(10).fill(m).join(" ")};return o.jsx("div",{onMouseEnter:()=>d(!0),onMouseLeave:()=>d(!1),style:{position:"absolute",inset:0},children:u.map((e,t)=>o.jsx("div",{onPointerDown:r,onTouchStart:r,style:{position:"absolute",left:(g?e.origin.x-g.origin.x:e.origin.x)*n,top:(g?e.origin.y-g.origin.y:e.origin.y)*n,width:e.size.width*n,height:e.size.height*n,background:a?x:"transparent",border:a?"none":`2px solid ${p}`,opacity:a?f:1,boxSizing:"border-box",pointerEvents:"auto",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:S===i.PdfTextAlignment.Left?"flex-start":S===i.PdfTextAlignment.Right?"flex-end":"center",overflow:"hidden",...l},children:a&&m&&o.jsx("span",{style:{color:h,fontSize:Math.min(v*n,e.size.height*n*.8),fontFamily:i.standardFontCss(b),textAlign:i.textAlignmentToCss(S),whiteSpace:y?"normal":"nowrap",overflow:"hidden",textOverflow:"ellipsis",lineHeight:1},children:j()})},t))})}function c({annotation:e,isSelected:t,scale:n,onClick:r,style:l}){const[a,d]=s.useState(!1),{object:c}=e,u=c.strokeColor??"#FF0000",g=c.color??"#000000",p=c.opacity??1,x=c.fontColor??c.overlayColor??"#FFFFFF",f=c.overlayText,h=c.overlayTextRepeat??!1,m=c.fontSize??12,y=c.fontFamily??i.PdfStandardFont.Helvetica,v=c.textAlign??i.PdfTextAlignment.Center;return o.jsx("div",{onPointerDown:t?void 0:r,onTouchStart:t?void 0:r,onMouseEnter:()=>d(!0),onMouseLeave:()=>d(!1),style:{position:"absolute",inset:0,background:a?g:"transparent",border:a?"none":`2px solid ${u}`,opacity:a?p:1,boxSizing:"border-box",pointerEvents:"auto",cursor:t?"move":"pointer",display:"flex",alignItems:"center",justifyContent:v===i.PdfTextAlignment.Left?"flex-start":v===i.PdfTextAlignment.Right?"flex-end":"center",overflow:"hidden",...l},children:a&&f&&o.jsx("span",{style:{color:x,fontSize:m*n,fontFamily:i.standardFontCss(y),textAlign:i.textAlignmentToCss(v),whiteSpace:h?"normal":"nowrap",overflow:"hidden",textOverflow:"ellipsis",padding:"4px"},children:(()=>{if(!f)return null;if(!h)return f;return Array(10).fill(f).join(" ")})()})})}const u=[n.createRenderer({id:"redactHighlight",matches:e=>{var t;return e.type===i.PdfAnnotationSubtype.REDACT&&"segmentRects"in e&&((null==(t=e.segmentRects)?void 0:t.length)??0)>0},render:e=>o.jsx(d,{...e})}),n.createRenderer({id:"redactArea",matches:e=>{var t;return!(e.type!==i.PdfAnnotationSubtype.REDACT||"segmentRects"in e&&(null==(t=e.segmentRects)?void 0:t.length))},render:e=>o.jsx(c,{...e})})];function g(){return n.useRegisterRenderers(u),null}const p=()=>l.usePlugin(t.RedactionPlugin.id),x=()=>l.useCapability(t.RedactionPlugin.id),f=({documentId:e,pageIndex:t,scale:n,className:i,stroke:r,fill:a="transparent"})=>{const{plugin:d}=p(),c=l.useDocumentState(e),[u,g]=s.useState(null),x=s.useMemo(()=>void 0!==n?n:(null==c?void 0:c.scale)??1,[n,null==c?void 0:c.scale]),f=r??(null==d?void 0:d.getPreviewStrokeColor())??"red";return s.useEffect(()=>{if(d&&e)return d.registerMarqueeOnPage({documentId:e,pageIndex:t,scale:x,callback:{onPreview:g}})},[d,e,t,x]),u?o.jsx("div",{style:{position:"absolute",pointerEvents:"none",left:u.origin.x*x,top:u.origin.y*x,width:u.size.width*x,height:u.size.height*x,border:`1px solid ${f}`,background:a,boxSizing:"border-box"},className:i}):null};function h({color:e="#FFFF00",opacity:t=1,border:n="1px solid red",rects:i,rect:r,scale:s,onClick:l,style:a,...d}){return o.jsx(o.Fragment,{children:i.map((i,c)=>o.jsx("div",{onPointerDown:l,onTouchStart:l,style:{position:"absolute",border:n,left:(r?i.origin.x-r.origin.x:i.origin.x)*s,top:(r?i.origin.y-r.origin.y:i.origin.y)*s,width:i.size.width*s,height:i.size.height*s,background:e,opacity:t,pointerEvents:l?"auto":"none",cursor:l?"pointer":"default",zIndex:l?1:void 0,...a},...d},c))})}function m({documentId:e,pageIndex:t,scale:n}){const{plugin:i}=p(),[r,l]=s.useState([]),[a,d]=s.useState(null),c=(null==i?void 0:i.getPreviewStrokeColor())??"red";return s.useEffect(()=>{if(i)return i.onRedactionSelectionChange(e,e=>{const n=e.find(e=>e.pageIndex===t);l((null==n?void 0:n.segmentRects)??[]),d((null==n?void 0:n.rect)??null)})},[i,e,t]),a?o.jsx("div",{style:{mixBlendMode:"normal",pointerEvents:"none",position:"absolute",inset:0},children:o.jsx(h,{color:"transparent",opacity:1,rects:r,scale:n,border:`1px solid ${c}`})}):null}function y({documentId:e,pageIndex:t,scale:n,bboxStroke:l="rgba(0,0,0,0.8)",rotation:d=i.Rotation.Degree0,selectionMenu:c}){const{provides:u}=x(),[g,p]=s.useState([]),[f,m]=s.useState(null);s.useEffect(()=>{if(!u)return;const n=u.forDocument(e),o=n.getState();p((o.pending[t]??[]).filter(e=>"legacy"===e.source)),m(o.selected&&o.selected.page===t?o.selected.id:null);const i=n.onPendingChange(e=>{p((e[t]??[]).filter(e=>"legacy"===e.source))}),r=n.onSelectedChange(e=>{m(e&&e.page===t?e.id:null)});return()=>{null==i||i(),null==r||r()}},[u,e,t]);const y=s.useCallback((n,o)=>{n.stopPropagation(),u&&u.forDocument(e).selectPending(t,o)},[u,e,t]);return g.length?o.jsx("div",{style:{position:"absolute",inset:0,pointerEvents:"none"},children:g.map(e=>{if("area"===e.kind){const i=e.rect;return o.jsxs(r.Fragment,{children:[o.jsx("div",{style:{position:"absolute",left:i.origin.x*n,top:i.origin.y*n,width:i.size.width*n,height:i.size.height*n,background:"transparent",outline:f===e.id?`1px solid ${l}`:"none",outlineOffset:"2px",border:`1px solid ${e.markColor}`,pointerEvents:"auto",cursor:"pointer"},onPointerDown:t=>y(t,e.id),onTouchStart:t=>y(t,e.id)}),c&&o.jsx(a.CounterRotate,{rect:{origin:{x:i.origin.x*n,y:i.origin.y*n},size:{width:i.size.width*n,height:i.size.height*n}},rotation:d,children:n=>c({...n,context:{type:"redaction",item:e,pageIndex:t},selected:f===e.id,placement:{suggestTop:!1}})})]},e.id)}const i=e.rect;return o.jsxs(r.Fragment,{children:[o.jsx("div",{style:{position:"absolute",left:i.origin.x*n,top:i.origin.y*n,width:i.size.width*n,height:i.size.height*n,background:"transparent",outline:f===e.id?`1px solid ${l}`:"none",outlineOffset:"2px",pointerEvents:"auto",cursor:f===e.id?"pointer":"default"},children:o.jsx(h,{rect:i,rects:e.rects,color:"transparent",border:`1px solid ${e.markColor}`,scale:n,onClick:t=>y(t,e.id)})}),c&&o.jsx(a.CounterRotate,{rect:{origin:{x:i.origin.x*n,y:i.origin.y*n},size:{width:i.size.width*n,height:i.size.height*n}},rotation:d,children:n=>c({...n,context:{type:"redaction",item:e,pageIndex:t},selected:f===e.id,placement:{suggestTop:!1}})})]},e.id)})}):null}const v=e.createPluginPackage(t.RedactionPluginPackage).addUtility(g).build();exports.RedactArea=c,exports.RedactHighlight=d,exports.RedactRendererRegistration=g,exports.RedactionLayer=({documentId:e,pageIndex:t,scale:n,rotation:a,selectionMenu:d})=>{const c=l.useDocumentState(e),u=s.useMemo(()=>void 0!==n?n:(null==c?void 0:c.scale)??1,[n,null==c?void 0:c.scale]),g=s.useMemo(()=>void 0!==a?a:(null==c?void 0:c.rotation)??i.Rotation.Degree0,[a,null==c?void 0:c.rotation]);return o.jsxs(r.Fragment,{children:[o.jsx(y,{documentId:e,pageIndex:t,scale:u,rotation:g,selectionMenu:d}),o.jsx(f,{documentId:e,pageIndex:t,scale:u}),o.jsx(m,{documentId:e,pageIndex:t,scale:u})]})},exports.RedactionPluginPackage=v,exports.redactRenderers=u,exports.useRedaction=e=>{const{provides:n}=x(),[o,i]=s.useState(t.initialDocumentState),r=s.useMemo(()=>n?n.forDocument(e):null,[n,e]);return s.useEffect(()=>{if(!r)return void i(t.initialDocumentState);try{i(r.getState())}catch(e){i(t.initialDocumentState)}return r.onStateChange(e=>{i(e)})},[r]),{state:o,provides:r}},exports.useRedactionCapability=x,exports.useRedactionPlugin=p,Object.keys(t).forEach(e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>t[e]})});
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../src/shared/hooks/use-redaction.ts","../../src/shared/components/marquee-redact.tsx","../../src/shared/components/highlight.tsx","../../src/shared/components/selection-redact.tsx","../../src/shared/components/pending-redactions.tsx","../../src/shared/components/redaction-layer.tsx"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport {\n initialDocumentState,\n RedactionPlugin,\n RedactionDocumentState,\n RedactionScope,\n} from '@embedpdf/plugin-redaction';\nimport { useState, useEffect, useMemo } from '@framework';\n\nexport const useRedactionPlugin = () => usePlugin<RedactionPlugin>(RedactionPlugin.id);\nexport const useRedactionCapability = () => useCapability<RedactionPlugin>(RedactionPlugin.id);\n\nexport const useRedaction = (\n documentId: string,\n): {\n state: RedactionDocumentState;\n provides: RedactionScope | null;\n} => {\n const { provides } = useRedactionCapability();\n const [state, setState] = useState<RedactionDocumentState>(initialDocumentState);\n\n const scope = useMemo(\n () => (provides ? provides.forDocument(documentId) : null),\n [provides, documentId],\n );\n\n useEffect(() => {\n if (!scope) {\n setState(initialDocumentState);\n return;\n }\n\n // Set initial state\n try {\n setState(scope.getState());\n } catch (e) {\n // Handle case where state might not be ready\n setState(initialDocumentState);\n }\n\n // Subscribe to changes\n const unsubscribe = scope.onStateChange((newState) => {\n setState(newState);\n });\n\n return unsubscribe;\n }, [scope]);\n\n return {\n state,\n provides: scope,\n };\n};\n","import { useEffect, useMemo, useState } from '@framework';\nimport { useDocumentState } from '@embedpdf/core/@framework';\nimport { Rect } from '@embedpdf/models';\n\nimport { useRedactionPlugin } from '../hooks/use-redaction';\n\ninterface MarqueeRedactProps {\n /** The ID of the document */\n documentId: string;\n /** Index of the page this layer lives on */\n pageIndex: number;\n /** Scale of the page */\n scale?: number;\n /** Optional CSS class applied to the marquee rectangle */\n className?: string;\n /** Stroke / fill colours (defaults below) */\n stroke?: string;\n fill?: string;\n}\n\nexport const MarqueeRedact = ({\n documentId,\n pageIndex,\n scale: scaleOverride,\n className,\n stroke = 'red',\n fill = 'transparent',\n}: MarqueeRedactProps) => {\n const { plugin: redactionPlugin } = useRedactionPlugin();\n const documentState = useDocumentState(documentId);\n\n const [rect, setRect] = useState<Rect | null>(null);\n\n const scale = useMemo(() => {\n if (scaleOverride !== undefined) return scaleOverride;\n return documentState?.scale ?? 1;\n }, [scaleOverride, documentState?.scale]);\n\n useEffect(() => {\n if (!redactionPlugin || !documentId) return;\n return redactionPlugin.registerMarqueeOnPage({\n documentId,\n pageIndex,\n scale,\n callback: {\n onPreview: setRect,\n },\n });\n }, [redactionPlugin, documentId, pageIndex, scale]);\n\n if (!rect) return null;\n\n return (\n <div\n style={{\n position: 'absolute',\n pointerEvents: 'none',\n left: rect.origin.x * scale,\n top: rect.origin.y * scale,\n width: rect.size.width * scale,\n height: rect.size.height * scale,\n border: `1px solid ${stroke}`,\n background: fill,\n boxSizing: 'border-box',\n }}\n className={className}\n />\n );\n};\n","import { HTMLAttributes, CSSProperties, MouseEvent, TouchEvent } from '@framework';\nimport { Rect } from '@embedpdf/models';\n\ntype HighlightProps = Omit<HTMLAttributes<HTMLDivElement>, 'style'> & {\n color?: string;\n opacity?: number;\n border?: string;\n rects: Rect[];\n rect?: Rect;\n scale: number;\n onClick?: (e: MouseEvent<HTMLDivElement> | TouchEvent<HTMLDivElement>) => void;\n style?: CSSProperties;\n};\n\nexport function Highlight({\n color = '#FFFF00',\n opacity = 1,\n border = '1px solid red',\n rects,\n rect,\n scale,\n onClick,\n style,\n ...props\n}: HighlightProps) {\n return (\n <>\n {rects.map((b, i) => (\n <div\n key={i}\n onPointerDown={onClick}\n onTouchStart={onClick}\n style={{\n position: 'absolute',\n border,\n left: (rect ? b.origin.x - rect.origin.x : b.origin.x) * scale,\n top: (rect ? b.origin.y - rect.origin.y : b.origin.y) * scale,\n width: b.size.width * scale,\n height: b.size.height * scale,\n background: color,\n opacity: opacity,\n pointerEvents: onClick ? 'auto' : 'none',\n cursor: onClick ? 'pointer' : 'default',\n zIndex: onClick ? 1 : undefined,\n ...style,\n }}\n {...props}\n />\n ))}\n </>\n );\n}\n","import { Rect } from '@embedpdf/models';\nimport { useEffect, useState } from '@framework';\nimport { useRedactionPlugin } from '../hooks';\nimport { Highlight } from './highlight';\n\ninterface SelectionRedactProps {\n documentId: string;\n pageIndex: number;\n scale: number;\n}\n\nexport function SelectionRedact({ documentId, pageIndex, scale }: SelectionRedactProps) {\n const { plugin: redactionPlugin } = useRedactionPlugin();\n const [rects, setRects] = useState<Array<Rect>>([]);\n const [boundingRect, setBoundingRect] = useState<Rect | null>(null);\n\n useEffect(() => {\n if (!redactionPlugin) return;\n return redactionPlugin.onRedactionSelectionChange(documentId, (formattedSelection) => {\n const selection = formattedSelection.find((s) => s.pageIndex === pageIndex);\n setRects(selection?.segmentRects ?? []);\n setBoundingRect(selection?.rect ?? null);\n });\n }, [redactionPlugin, documentId, pageIndex]);\n\n if (!boundingRect) return null;\n\n return (\n <div\n style={{\n mixBlendMode: 'normal',\n pointerEvents: 'none',\n position: 'absolute',\n inset: 0,\n }}\n >\n <Highlight\n color={'transparent'}\n opacity={1}\n rects={rects}\n scale={scale}\n border=\"1px solid red\"\n />\n </div>\n );\n}\n","import { Fragment, useEffect, useState, useCallback, MouseEvent, TouchEvent } from '@framework';\nimport { CounterRotate } from '@embedpdf/utils/@framework';\nimport { useRedactionCapability } from '../hooks';\nimport { RedactionItem } from '@embedpdf/plugin-redaction';\nimport { Highlight } from './highlight';\nimport { RedactionSelectionMenuRenderFn } from './types';\nimport { Rotation } from '@embedpdf/models';\n\ninterface PendingRedactionsProps {\n documentId: string;\n pageIndex: number;\n scale: number;\n rotation: Rotation;\n bboxStroke?: string;\n selectionMenu?: RedactionSelectionMenuRenderFn;\n}\n\nexport function PendingRedactions({\n documentId,\n pageIndex,\n scale,\n bboxStroke = 'rgba(0,0,0,0.8)',\n rotation = Rotation.Degree0,\n selectionMenu,\n}: PendingRedactionsProps) {\n const { provides: redaction } = useRedactionCapability();\n const [items, setItems] = useState<RedactionItem[]>([]);\n const [selectedId, setSelectedId] = useState<string | null>(null);\n\n useEffect(() => {\n if (!redaction) return;\n\n // Use document-scoped hooks so we only receive events for this document\n const scoped = redaction.forDocument(documentId);\n\n // Initialize with current state\n const currentState = scoped.getState();\n setItems(currentState.pending[pageIndex] ?? []);\n setSelectedId(\n currentState.selected && currentState.selected.page === pageIndex\n ? currentState.selected.id\n : null,\n );\n\n // Subscribe to future changes\n const off1 = scoped.onPendingChange((map) => setItems(map[pageIndex] ?? []));\n const off2 = scoped.onSelectedChange((sel) => {\n setSelectedId(sel && sel.page === pageIndex ? sel.id : null);\n });\n\n return () => {\n off1?.();\n off2?.();\n };\n }, [redaction, documentId, pageIndex]);\n\n const select = useCallback(\n (e: MouseEvent | TouchEvent, id: string) => {\n e.stopPropagation();\n if (!redaction) return;\n redaction.forDocument(documentId).selectPending(pageIndex, id);\n },\n [redaction, documentId, pageIndex],\n );\n\n if (!items.length) return null;\n\n return (\n <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>\n {items.map((it) => {\n if (it.kind === 'area') {\n const r = it.rect;\n return (\n <Fragment key={it.id}>\n <div\n style={{\n position: 'absolute',\n left: r.origin.x * scale,\n top: r.origin.y * scale,\n width: r.size.width * scale,\n height: r.size.height * scale,\n background: 'transparent',\n outline: selectedId === it.id ? `1px solid ${bboxStroke}` : 'none',\n outlineOffset: '2px',\n border: `1px solid red`,\n pointerEvents: 'auto',\n cursor: 'pointer',\n }}\n onPointerDown={(e) => select(e, it.id)}\n onTouchStart={(e) => select(e, it.id)}\n />\n {selectionMenu && (\n <CounterRotate\n rect={{\n origin: { x: r.origin.x * scale, y: r.origin.y * scale },\n size: { width: r.size.width * scale, height: r.size.height * scale },\n }}\n rotation={rotation}\n >\n {(props) =>\n selectionMenu({\n ...props,\n context: {\n type: 'redaction',\n item: it,\n pageIndex,\n },\n selected: selectedId === it.id,\n placement: {\n suggestTop: false,\n },\n })\n }\n </CounterRotate>\n )}\n </Fragment>\n );\n }\n\n const b = it.rect;\n return (\n <Fragment key={it.id}>\n <div\n style={{\n position: 'absolute',\n left: b.origin.x * scale,\n top: b.origin.y * scale,\n width: b.size.width * scale,\n height: b.size.height * scale,\n background: 'transparent',\n outline: selectedId === it.id ? `1px solid ${bboxStroke}` : 'none',\n outlineOffset: '2px',\n pointerEvents: 'auto',\n cursor: selectedId === it.id ? 'pointer' : 'default',\n }}\n >\n <Highlight\n rect={b}\n rects={it.rects}\n color=\"transparent\"\n border=\"1px solid red\"\n scale={scale}\n onClick={(e) => select(e, it.id)}\n />\n </div>\n {selectionMenu && (\n <CounterRotate\n rect={{\n origin: { x: b.origin.x * scale, y: b.origin.y * scale },\n size: { width: b.size.width * scale, height: b.size.height * scale },\n }}\n rotation={rotation}\n >\n {(props) =>\n selectionMenu({\n ...props,\n context: {\n type: 'redaction',\n item: it,\n pageIndex,\n },\n selected: selectedId === it.id,\n placement: {\n suggestTop: false,\n },\n })\n }\n </CounterRotate>\n )}\n </Fragment>\n );\n })}\n </div>\n );\n}\n","import { Fragment, useMemo } from '@framework';\nimport { useDocumentState } from '@embedpdf/core/@framework';\nimport { MarqueeRedact } from './marquee-redact';\nimport { SelectionRedact } from './selection-redact';\nimport { PendingRedactions } from './pending-redactions';\nimport { Rotation } from '@embedpdf/models';\nimport { RedactionSelectionMenuRenderFn } from './types';\n\ninterface RedactionLayerProps {\n /** The ID of the document this layer belongs to */\n documentId: string;\n /** Index of the page this layer lives on */\n pageIndex: number;\n /** Current render scale for this page */\n scale?: number;\n /** Page rotation (for counter-rotating menus, etc.) */\n rotation?: Rotation;\n /** Optional menu renderer for a selected redaction */\n selectionMenu?: RedactionSelectionMenuRenderFn;\n}\n\nexport const RedactionLayer = ({\n documentId,\n pageIndex,\n scale,\n rotation,\n selectionMenu,\n}: RedactionLayerProps) => {\n const documentState = useDocumentState(documentId);\n\n const actualScale = useMemo(() => {\n if (scale !== undefined) return scale;\n return documentState?.scale ?? 1;\n }, [scale, documentState?.scale]);\n\n const actualRotation = useMemo(() => {\n if (rotation !== undefined) return rotation;\n return documentState?.rotation ?? Rotation.Degree0;\n }, [rotation, documentState?.rotation]);\n\n return (\n <Fragment>\n <PendingRedactions\n documentId={documentId}\n pageIndex={pageIndex}\n scale={actualScale}\n rotation={actualRotation}\n selectionMenu={selectionMenu}\n />\n <MarqueeRedact documentId={documentId} pageIndex={pageIndex} scale={actualScale} />\n <SelectionRedact documentId={documentId} pageIndex={pageIndex} scale={actualScale} />\n </Fragment>\n );\n};\n"],"names":["useRedactionPlugin","usePlugin","RedactionPlugin","id","useRedactionCapability","useCapability","MarqueeRedact","documentId","pageIndex","scale","scaleOverride","className","stroke","fill","plugin","redactionPlugin","documentState","useDocumentState","rect","setRect","useState","useMemo","useEffect","registerMarqueeOnPage","callback","onPreview","jsx","style","position","pointerEvents","left","origin","x","top","y","width","size","height","border","background","boxSizing","Highlight","color","opacity","rects","onClick","props","Fragment","children","map","b","i","onPointerDown","onTouchStart","cursor","zIndex","SelectionRedact","setRects","boundingRect","setBoundingRect","onRedactionSelectionChange","formattedSelection","selection","find","s","segmentRects","mixBlendMode","inset","PendingRedactions","bboxStroke","rotation","Rotation","Degree0","selectionMenu","provides","redaction","items","setItems","selectedId","setSelectedId","scoped","forDocument","currentState","getState","pending","selected","page","off1","onPendingChange","off2","onSelectedChange","sel","select","useCallback","e","stopPropagation","selectPending","length","it","kind","r","outline","outlineOffset","CounterRotate","context","type","item","placement","suggestTop","actualScale","actualRotation","state","setState","initialDocumentState","scope","onStateChange","newState"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../../src/shared/components/annotations/redact-highlight.tsx","../../src/shared/components/annotations/redact-area.tsx","../../src/shared/components/redact-renderers.tsx","../../src/shared/components/redact-renderer-registration.tsx","../../src/shared/hooks/use-redaction.ts","../../src/shared/components/marquee-redact.tsx","../../src/shared/components/highlight.tsx","../../src/shared/components/selection-redact.tsx","../../src/shared/components/pending-redactions.tsx","../../src/shared/components/redaction-layer.tsx","../../src/shared/index.ts"],"sourcesContent":["import { CSSProperties, MouseEvent, TouchEvent, useState } from '@framework';\nimport {\n PdfRedactAnnoObject,\n PdfStandardFont,\n PdfTextAlignment,\n Rect,\n standardFontCss,\n textAlignmentToCss,\n} from '@embedpdf/models';\nimport { TrackedAnnotation } from '@embedpdf/plugin-annotation';\n\nexport interface RedactHighlightProps {\n annotation: TrackedAnnotation<PdfRedactAnnoObject>;\n isSelected: boolean;\n scale: number;\n pageIndex: number;\n onClick: (e: MouseEvent<Element> | TouchEvent<Element>) => void;\n style?: CSSProperties;\n}\n\n/**\n * Renders a text-based redact annotation using QuadPoints/segmentRects.\n * Default: shows strokeColor (C) border only, no fill.\n * Hovered: shows redaction preview with color (IC) as background fill + overlayText.\n * Selected: no border (AnnotationContainer handles selection styling).\n */\nexport function RedactHighlight({\n annotation,\n isSelected,\n scale,\n onClick,\n style,\n}: RedactHighlightProps) {\n const [isHovered, setIsHovered] = useState(false);\n const { object } = annotation;\n\n const segmentRects = object.segmentRects ?? [];\n const rect = object.rect;\n\n // C - Border/stroke color\n const strokeColor = object.strokeColor ?? '#FF0000';\n // IC - Interior color (background fill when redaction is applied)\n const color = object.color ?? '#000000';\n // CA - Opacity (0-1)\n const opacity = object.opacity ?? 1;\n // OC - Overlay text color (Adobe extension), fallback to fontColor\n const textColor = object.fontColor ?? object.overlayColor ?? '#FFFFFF';\n // Overlay text properties\n const overlayText = object.overlayText;\n const overlayTextRepeat = object.overlayTextRepeat ?? false;\n const fontSize = object.fontSize ?? 12;\n const fontFamily = object.fontFamily ?? PdfStandardFont.Helvetica;\n const textAlign = object.textAlign ?? PdfTextAlignment.Center;\n\n // Calculate how many times to repeat text (approximate)\n const renderOverlayText = () => {\n if (!overlayText) return null;\n if (!overlayTextRepeat) return overlayText;\n // Repeat text multiple times to fill the space\n const reps = 10; // Enough repetitions to fill most containers\n return Array(reps).fill(overlayText).join(' ');\n };\n\n return (\n <div\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n style={{ position: 'absolute', inset: 0 }}\n >\n {segmentRects.map((b: Rect, i: number) => (\n <div\n key={i}\n onPointerDown={onClick}\n onTouchStart={onClick}\n style={{\n position: 'absolute',\n left: (rect ? b.origin.x - rect.origin.x : b.origin.x) * scale,\n top: (rect ? b.origin.y - rect.origin.y : b.origin.y) * scale,\n width: b.size.width * scale,\n height: b.size.height * scale,\n // Default: transparent background with strokeColor (C) border\n // Hovered: color (IC) background fill, no border\n // Selected: no border (container handles it)\n background: isHovered ? color : 'transparent',\n border: !isHovered ? `2px solid ${strokeColor}` : 'none',\n opacity: isHovered ? opacity : 1,\n boxSizing: 'border-box',\n pointerEvents: 'auto',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent:\n textAlign === PdfTextAlignment.Left\n ? 'flex-start'\n : textAlign === PdfTextAlignment.Right\n ? 'flex-end'\n : 'center',\n overflow: 'hidden',\n ...style,\n }}\n >\n {isHovered && overlayText && (\n <span\n style={{\n color: textColor,\n fontSize: Math.min(fontSize * scale, b.size.height * scale * 0.8),\n fontFamily: standardFontCss(fontFamily),\n textAlign: textAlignmentToCss(textAlign),\n whiteSpace: overlayTextRepeat ? 'normal' : 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n lineHeight: 1,\n }}\n >\n {renderOverlayText()}\n </span>\n )}\n </div>\n ))}\n </div>\n );\n}\n","import { CSSProperties, MouseEvent, TouchEvent, useState } from '@framework';\nimport {\n PdfRedactAnnoObject,\n PdfStandardFont,\n PdfTextAlignment,\n standardFontCss,\n textAlignmentToCss,\n} from '@embedpdf/models';\nimport { TrackedAnnotation } from '@embedpdf/plugin-annotation';\n\nexport interface RedactAreaProps {\n annotation: TrackedAnnotation<PdfRedactAnnoObject>;\n isSelected: boolean;\n scale: number;\n pageIndex: number;\n onClick: (e: MouseEvent<Element> | TouchEvent<Element>) => void;\n style?: CSSProperties;\n}\n\n/**\n * Renders an area-based redact annotation (marquee redaction).\n * Default: shows strokeColor (C) border only, no fill.\n * Hovered: shows redaction preview with color (IC) as background fill + overlayText.\n * Selected: no border (AnnotationContainer handles selection styling).\n */\nexport function RedactArea({ annotation, isSelected, scale, onClick, style }: RedactAreaProps) {\n const [isHovered, setIsHovered] = useState(false);\n const { object } = annotation;\n\n // C - Border/stroke color\n const strokeColor = object.strokeColor ?? '#FF0000';\n // IC - Interior color (background fill when redaction is applied)\n const color = object.color ?? '#000000';\n // CA - Opacity (0-1)\n const opacity = object.opacity ?? 1;\n // OC - Overlay text color (Adobe extension), fallback to fontColor\n const textColor = object.fontColor ?? object.overlayColor ?? '#FFFFFF';\n // Overlay text properties\n const overlayText = object.overlayText;\n const overlayTextRepeat = object.overlayTextRepeat ?? false;\n const fontSize = object.fontSize ?? 12;\n const fontFamily = object.fontFamily ?? PdfStandardFont.Helvetica;\n const textAlign = object.textAlign ?? PdfTextAlignment.Center;\n\n // Calculate how many times to repeat text (approximate)\n const renderOverlayText = () => {\n if (!overlayText) return null;\n if (!overlayTextRepeat) return overlayText;\n // Repeat text multiple times to fill the space\n const reps = 10; // Enough repetitions to fill most containers\n return Array(reps).fill(overlayText).join(' ');\n };\n\n return (\n <div\n onPointerDown={!isSelected ? onClick : undefined}\n onTouchStart={!isSelected ? onClick : undefined}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n style={{\n position: 'absolute',\n inset: 0,\n // Default: transparent background with strokeColor (C) border\n // Hovered: color (IC) background fill, no border\n // Selected: no border (container handles it)\n background: isHovered ? color : 'transparent',\n border: !isHovered ? `2px solid ${strokeColor}` : 'none',\n opacity: isHovered ? opacity : 1,\n boxSizing: 'border-box',\n pointerEvents: 'auto',\n cursor: isSelected ? 'move' : 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent:\n textAlign === PdfTextAlignment.Left\n ? 'flex-start'\n : textAlign === PdfTextAlignment.Right\n ? 'flex-end'\n : 'center',\n overflow: 'hidden',\n ...style,\n }}\n >\n {isHovered && overlayText && (\n <span\n style={{\n color: textColor,\n fontSize: fontSize * scale,\n fontFamily: standardFontCss(fontFamily),\n textAlign: textAlignmentToCss(textAlign),\n whiteSpace: overlayTextRepeat ? 'normal' : 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n padding: '4px',\n }}\n >\n {renderOverlayText()}\n </span>\n )}\n </div>\n );\n}\n","import { PdfAnnotationSubtype, PdfRedactAnnoObject } from '@embedpdf/models';\nimport { createRenderer, BoxedAnnotationRenderer } from '@embedpdf/plugin-annotation/@framework';\nimport { RedactHighlight } from './annotations/redact-highlight';\nimport { RedactArea } from './annotations/redact-area';\n\n/**\n * Boxed annotation renderers for Redact annotations.\n * Type safety is enforced at definition time via createRenderer.\n * These are automatically registered with the annotation plugin via context.\n */\nexport const redactRenderers: BoxedAnnotationRenderer[] = [\n createRenderer<PdfRedactAnnoObject>({\n id: 'redactHighlight',\n matches: (a): a is PdfRedactAnnoObject =>\n a.type === PdfAnnotationSubtype.REDACT &&\n 'segmentRects' in a &&\n (a.segmentRects?.length ?? 0) > 0,\n render: (props) => <RedactHighlight {...props} />,\n }),\n createRenderer<PdfRedactAnnoObject>({\n id: 'redactArea',\n matches: (a): a is PdfRedactAnnoObject =>\n a.type === PdfAnnotationSubtype.REDACT &&\n (!('segmentRects' in a) || !(a.segmentRects?.length ?? 0)),\n render: (props) => <RedactArea {...props} />,\n }),\n];\n","import { useRegisterRenderers } from '@embedpdf/plugin-annotation/@framework';\nimport { redactRenderers } from '../components/redact-renderers';\n\n/**\n * Utility component that registers redact renderers once at app level.\n * Added via addUtility() so it mounts once, not per-page.\n */\nexport function RedactRendererRegistration() {\n useRegisterRenderers(redactRenderers);\n return null;\n}\n","import { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport {\n initialDocumentState,\n RedactionPlugin,\n RedactionDocumentState,\n RedactionScope,\n} from '@embedpdf/plugin-redaction';\nimport { useState, useEffect, useMemo } from '@framework';\n\nexport const useRedactionPlugin = () => usePlugin<RedactionPlugin>(RedactionPlugin.id);\nexport const useRedactionCapability = () => useCapability<RedactionPlugin>(RedactionPlugin.id);\n\nexport const useRedaction = (\n documentId: string,\n): {\n state: RedactionDocumentState;\n provides: RedactionScope | null;\n} => {\n const { provides } = useRedactionCapability();\n const [state, setState] = useState<RedactionDocumentState>(initialDocumentState);\n\n const scope = useMemo(\n () => (provides ? provides.forDocument(documentId) : null),\n [provides, documentId],\n );\n\n useEffect(() => {\n if (!scope) {\n setState(initialDocumentState);\n return;\n }\n\n // Set initial state\n try {\n setState(scope.getState());\n } catch (e) {\n // Handle case where state might not be ready\n setState(initialDocumentState);\n }\n\n // Subscribe to changes\n const unsubscribe = scope.onStateChange((newState) => {\n setState(newState);\n });\n\n return unsubscribe;\n }, [scope]);\n\n return {\n state,\n provides: scope,\n };\n};\n","import { useEffect, useMemo, useState } from '@framework';\nimport { useDocumentState } from '@embedpdf/core/@framework';\nimport { Rect } from '@embedpdf/models';\n\nimport { useRedactionPlugin } from '../hooks/use-redaction';\n\ninterface MarqueeRedactProps {\n /** The ID of the document */\n documentId: string;\n /** Index of the page this layer lives on */\n pageIndex: number;\n /** Scale of the page */\n scale?: number;\n /** Optional CSS class applied to the marquee rectangle */\n className?: string;\n /** Stroke / fill colours (defaults below) */\n stroke?: string;\n fill?: string;\n}\n\nexport const MarqueeRedact = ({\n documentId,\n pageIndex,\n scale: scaleOverride,\n className,\n stroke,\n fill = 'transparent',\n}: MarqueeRedactProps) => {\n const { plugin: redactionPlugin } = useRedactionPlugin();\n const documentState = useDocumentState(documentId);\n\n const [rect, setRect] = useState<Rect | null>(null);\n\n const scale = useMemo(() => {\n if (scaleOverride !== undefined) return scaleOverride;\n return documentState?.scale ?? 1;\n }, [scaleOverride, documentState?.scale]);\n\n // Get stroke color from plugin (annotation mode uses tool defaults, legacy uses red)\n // Allow prop override for backwards compatibility\n const strokeColor = stroke ?? redactionPlugin?.getPreviewStrokeColor() ?? 'red';\n\n useEffect(() => {\n if (!redactionPlugin || !documentId) return;\n return redactionPlugin.registerMarqueeOnPage({\n documentId,\n pageIndex,\n scale,\n callback: {\n onPreview: setRect,\n },\n });\n }, [redactionPlugin, documentId, pageIndex, scale]);\n\n if (!rect) return null;\n\n return (\n <div\n style={{\n position: 'absolute',\n pointerEvents: 'none',\n left: rect.origin.x * scale,\n top: rect.origin.y * scale,\n width: rect.size.width * scale,\n height: rect.size.height * scale,\n border: `1px solid ${strokeColor}`,\n background: fill,\n boxSizing: 'border-box',\n }}\n className={className}\n />\n );\n};\n","import { HTMLAttributes, CSSProperties, MouseEvent, TouchEvent } from '@framework';\nimport { Rect } from '@embedpdf/models';\n\ntype HighlightProps = Omit<HTMLAttributes<HTMLDivElement>, 'style'> & {\n color?: string;\n opacity?: number;\n border?: string;\n rects: Rect[];\n rect?: Rect;\n scale: number;\n onClick?: (e: MouseEvent<HTMLDivElement> | TouchEvent<HTMLDivElement>) => void;\n style?: CSSProperties;\n};\n\nexport function Highlight({\n color = '#FFFF00',\n opacity = 1,\n border = '1px solid red',\n rects,\n rect,\n scale,\n onClick,\n style,\n ...props\n}: HighlightProps) {\n return (\n <>\n {rects.map((b, i) => (\n <div\n key={i}\n onPointerDown={onClick}\n onTouchStart={onClick}\n style={{\n position: 'absolute',\n border,\n left: (rect ? b.origin.x - rect.origin.x : b.origin.x) * scale,\n top: (rect ? b.origin.y - rect.origin.y : b.origin.y) * scale,\n width: b.size.width * scale,\n height: b.size.height * scale,\n background: color,\n opacity: opacity,\n pointerEvents: onClick ? 'auto' : 'none',\n cursor: onClick ? 'pointer' : 'default',\n zIndex: onClick ? 1 : undefined,\n ...style,\n }}\n {...props}\n />\n ))}\n </>\n );\n}\n","import { Rect } from '@embedpdf/models';\nimport { useEffect, useState } from '@framework';\nimport { useRedactionPlugin } from '../hooks';\nimport { Highlight } from './highlight';\n\ninterface SelectionRedactProps {\n documentId: string;\n pageIndex: number;\n scale: number;\n}\n\nexport function SelectionRedact({ documentId, pageIndex, scale }: SelectionRedactProps) {\n const { plugin: redactionPlugin } = useRedactionPlugin();\n const [rects, setRects] = useState<Array<Rect>>([]);\n const [boundingRect, setBoundingRect] = useState<Rect | null>(null);\n\n // Get stroke color from plugin (annotation mode uses tool defaults, legacy uses red)\n const strokeColor = redactionPlugin?.getPreviewStrokeColor() ?? 'red';\n\n useEffect(() => {\n if (!redactionPlugin) return;\n return redactionPlugin.onRedactionSelectionChange(documentId, (formattedSelection) => {\n const selection = formattedSelection.find((s) => s.pageIndex === pageIndex);\n setRects(selection?.segmentRects ?? []);\n setBoundingRect(selection?.rect ?? null);\n });\n }, [redactionPlugin, documentId, pageIndex]);\n\n if (!boundingRect) return null;\n\n return (\n <div\n style={{\n mixBlendMode: 'normal',\n pointerEvents: 'none',\n position: 'absolute',\n inset: 0,\n }}\n >\n <Highlight\n color={'transparent'}\n opacity={1}\n rects={rects}\n scale={scale}\n border={`1px solid ${strokeColor}`}\n />\n </div>\n );\n}\n","import { Fragment, useEffect, useState, useCallback, MouseEvent, TouchEvent } from '@framework';\nimport { CounterRotate } from '@embedpdf/utils/@framework';\nimport { useRedactionCapability } from '../hooks';\nimport { RedactionItem } from '@embedpdf/plugin-redaction';\nimport { Highlight } from './highlight';\nimport { RedactionSelectionMenuRenderFn } from './types';\nimport { Rotation } from '@embedpdf/models';\n\ninterface PendingRedactionsProps {\n documentId: string;\n pageIndex: number;\n scale: number;\n rotation: Rotation;\n bboxStroke?: string;\n selectionMenu?: RedactionSelectionMenuRenderFn;\n}\n\nexport function PendingRedactions({\n documentId,\n pageIndex,\n scale,\n bboxStroke = 'rgba(0,0,0,0.8)',\n rotation = Rotation.Degree0,\n selectionMenu,\n}: PendingRedactionsProps) {\n const { provides: redaction } = useRedactionCapability();\n const [items, setItems] = useState<RedactionItem[]>([]);\n const [selectedId, setSelectedId] = useState<string | null>(null);\n\n useEffect(() => {\n if (!redaction) return;\n\n // Use document-scoped hooks so we only receive events for this document\n const scoped = redaction.forDocument(documentId);\n\n // Initialize with current state - only show legacy mode items\n const currentState = scoped.getState();\n setItems((currentState.pending[pageIndex] ?? []).filter((it) => it.source === 'legacy'));\n setSelectedId(\n currentState.selected && currentState.selected.page === pageIndex\n ? currentState.selected.id\n : null,\n );\n\n // Subscribe to future changes - only show legacy mode items\n const off1 = scoped.onPendingChange((map) => {\n setItems((map[pageIndex] ?? []).filter((it) => it.source === 'legacy'));\n });\n const off2 = scoped.onSelectedChange((sel) => {\n setSelectedId(sel && sel.page === pageIndex ? sel.id : null);\n });\n\n return () => {\n off1?.();\n off2?.();\n };\n }, [redaction, documentId, pageIndex]);\n\n const select = useCallback(\n (e: MouseEvent | TouchEvent, id: string) => {\n e.stopPropagation();\n if (!redaction) return;\n redaction.forDocument(documentId).selectPending(pageIndex, id);\n },\n [redaction, documentId, pageIndex],\n );\n\n if (!items.length) return null;\n\n return (\n <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>\n {items.map((it) => {\n if (it.kind === 'area') {\n const r = it.rect;\n return (\n <Fragment key={it.id}>\n <div\n style={{\n position: 'absolute',\n left: r.origin.x * scale,\n top: r.origin.y * scale,\n width: r.size.width * scale,\n height: r.size.height * scale,\n background: 'transparent',\n outline: selectedId === it.id ? `1px solid ${bboxStroke}` : 'none',\n outlineOffset: '2px',\n border: `1px solid ${it.markColor}`,\n pointerEvents: 'auto',\n cursor: 'pointer',\n }}\n onPointerDown={(e) => select(e, it.id)}\n onTouchStart={(e) => select(e, it.id)}\n />\n {selectionMenu && (\n <CounterRotate\n rect={{\n origin: { x: r.origin.x * scale, y: r.origin.y * scale },\n size: { width: r.size.width * scale, height: r.size.height * scale },\n }}\n rotation={rotation}\n >\n {(props) =>\n selectionMenu({\n ...props,\n context: {\n type: 'redaction',\n item: it,\n pageIndex,\n },\n selected: selectedId === it.id,\n placement: {\n suggestTop: false,\n },\n })\n }\n </CounterRotate>\n )}\n </Fragment>\n );\n }\n\n const b = it.rect;\n return (\n <Fragment key={it.id}>\n <div\n style={{\n position: 'absolute',\n left: b.origin.x * scale,\n top: b.origin.y * scale,\n width: b.size.width * scale,\n height: b.size.height * scale,\n background: 'transparent',\n outline: selectedId === it.id ? `1px solid ${bboxStroke}` : 'none',\n outlineOffset: '2px',\n pointerEvents: 'auto',\n cursor: selectedId === it.id ? 'pointer' : 'default',\n }}\n >\n <Highlight\n rect={b}\n rects={it.rects}\n color=\"transparent\"\n border={`1px solid ${it.markColor}`}\n scale={scale}\n onClick={(e) => select(e, it.id)}\n />\n </div>\n {selectionMenu && (\n <CounterRotate\n rect={{\n origin: { x: b.origin.x * scale, y: b.origin.y * scale },\n size: { width: b.size.width * scale, height: b.size.height * scale },\n }}\n rotation={rotation}\n >\n {(props) =>\n selectionMenu({\n ...props,\n context: {\n type: 'redaction',\n item: it,\n pageIndex,\n },\n selected: selectedId === it.id,\n placement: {\n suggestTop: false,\n },\n })\n }\n </CounterRotate>\n )}\n </Fragment>\n );\n })}\n </div>\n );\n}\n","import { Fragment, useMemo } from '@framework';\nimport { useDocumentState } from '@embedpdf/core/@framework';\nimport { MarqueeRedact } from './marquee-redact';\nimport { SelectionRedact } from './selection-redact';\nimport { PendingRedactions } from './pending-redactions';\nimport { Rotation } from '@embedpdf/models';\nimport { RedactionSelectionMenuRenderFn } from './types';\n\ninterface RedactionLayerProps {\n /** The ID of the document this layer belongs to */\n documentId: string;\n /** Index of the page this layer lives on */\n pageIndex: number;\n /** Current render scale for this page */\n scale?: number;\n /** Page rotation (for counter-rotating menus, etc.) */\n rotation?: Rotation;\n /** Optional menu renderer for a selected redaction */\n selectionMenu?: RedactionSelectionMenuRenderFn;\n}\n\nexport const RedactionLayer = ({\n documentId,\n pageIndex,\n scale,\n rotation,\n selectionMenu,\n}: RedactionLayerProps) => {\n const documentState = useDocumentState(documentId);\n\n const actualScale = useMemo(() => {\n if (scale !== undefined) return scale;\n return documentState?.scale ?? 1;\n }, [scale, documentState?.scale]);\n\n const actualRotation = useMemo(() => {\n if (rotation !== undefined) return rotation;\n return documentState?.rotation ?? Rotation.Degree0;\n }, [rotation, documentState?.rotation]);\n\n return (\n <Fragment>\n <PendingRedactions\n documentId={documentId}\n pageIndex={pageIndex}\n scale={actualScale}\n rotation={actualRotation}\n selectionMenu={selectionMenu}\n />\n <MarqueeRedact documentId={documentId} pageIndex={pageIndex} scale={actualScale} />\n <SelectionRedact documentId={documentId} pageIndex={pageIndex} scale={actualScale} />\n </Fragment>\n );\n};\n","import { createPluginPackage } from '@embedpdf/core';\nimport { RedactionPluginPackage as BaseRedactionPackage } from '@embedpdf/plugin-redaction';\nimport { RedactRendererRegistration } from './components/redact-renderer-registration';\n\nexport * from './hooks';\nexport * from './components';\nexport * from '@embedpdf/plugin-redaction';\n\n// Automatically register redact renderers when plugin is loaded\nexport const RedactionPluginPackage = createPluginPackage(BaseRedactionPackage)\n .addUtility(RedactRendererRegistration)\n .build();\n"],"names":["RedactHighlight","annotation","isSelected","scale","onClick","style","isHovered","setIsHovered","useState","object","segmentRects","rect","strokeColor","color","opacity","textColor","fontColor","overlayColor","overlayText","overlayTextRepeat","fontSize","fontFamily","PdfStandardFont","Helvetica","textAlign","PdfTextAlignment","Center","renderOverlayText","Array","fill","join","jsx","onMouseEnter","onMouseLeave","position","inset","children","map","b","i","onPointerDown","onTouchStart","left","origin","x","top","y","width","size","height","background","border","boxSizing","pointerEvents","cursor","display","alignItems","justifyContent","Left","Right","overflow","Math","min","standardFontCss","textAlignmentToCss","whiteSpace","textOverflow","lineHeight","RedactArea","padding","redactRenderers","createRenderer","id","matches","a","type","PdfAnnotationSubtype","REDACT","_a","length","render","props","RedactRendererRegistration","useRegisterRenderers","useRedactionPlugin","usePlugin","RedactionPlugin","useRedactionCapability","useCapability","MarqueeRedact","documentId","pageIndex","scaleOverride","className","stroke","plugin","redactionPlugin","documentState","useDocumentState","setRect","useMemo","getPreviewStrokeColor","useEffect","registerMarqueeOnPage","callback","onPreview","Highlight","rects","Fragment","zIndex","SelectionRedact","setRects","boundingRect","setBoundingRect","onRedactionSelectionChange","formattedSelection","selection","find","s","mixBlendMode","PendingRedactions","bboxStroke","rotation","Rotation","Degree0","selectionMenu","provides","redaction","items","setItems","selectedId","setSelectedId","scoped","forDocument","currentState","getState","pending","filter","it","source","selected","page","off1","onPendingChange","off2","onSelectedChange","sel","select","useCallback","e","stopPropagation","selectPending","kind","r","outline","outlineOffset","markColor","CounterRotate","context","item","placement","suggestTop","RedactionPluginPackage","createPluginPackage","BaseRedactionPackage","addUtility","build","actualScale","actualRotation","state","setState","initialDocumentState","scope","onStateChange","newState"],"mappings":"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"}