@embedpdf/plugin-form 2.10.0

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 (174) hide show
  1. package/LICENSE +21 -0
  2. package/dist/index.cjs +2 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.d.ts +1 -0
  5. package/dist/index.js +1789 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/lib/actions.d.ts +33 -0
  8. package/dist/lib/form-plugin.d.ts +59 -0
  9. package/dist/lib/handlers/checkbox.handler.d.ts +3 -0
  10. package/dist/lib/handlers/combobox.handler.d.ts +3 -0
  11. package/dist/lib/handlers/index.d.ts +5 -0
  12. package/dist/lib/handlers/listbox.handler.d.ts +3 -0
  13. package/dist/lib/handlers/radio-button.handler.d.ts +3 -0
  14. package/dist/lib/handlers/text-field.handler.d.ts +3 -0
  15. package/dist/lib/index.d.ts +10 -0
  16. package/dist/lib/manifest.d.ts +4 -0
  17. package/dist/lib/reducer.d.ts +6 -0
  18. package/dist/lib/tools.d.ts +457 -0
  19. package/dist/lib/types.d.ts +98 -0
  20. package/dist/preact/adapter.d.ts +13 -0
  21. package/dist/preact/annotation.d.ts +1 -0
  22. package/dist/preact/core.d.ts +1 -0
  23. package/dist/preact/index.cjs +2 -0
  24. package/dist/preact/index.cjs.map +1 -0
  25. package/dist/preact/index.d.ts +1 -0
  26. package/dist/preact/index.js +1359 -0
  27. package/dist/preact/index.js.map +1 -0
  28. package/dist/react/adapter.d.ts +6 -0
  29. package/dist/react/annotation.d.ts +1 -0
  30. package/dist/react/core.d.ts +1 -0
  31. package/dist/react/index.cjs +2 -0
  32. package/dist/react/index.cjs.map +1 -0
  33. package/dist/react/index.d.ts +1 -0
  34. package/dist/react/index.js +1358 -0
  35. package/dist/react/index.js.map +1 -0
  36. package/dist/shared/components/annotations/form-checkbox.d.ts +12 -0
  37. package/dist/shared/components/annotations/form-combobox.d.ts +12 -0
  38. package/dist/shared/components/annotations/form-listbox.d.ts +12 -0
  39. package/dist/shared/components/annotations/form-radio-button.d.ts +12 -0
  40. package/dist/shared/components/annotations/form-text-field.d.ts +12 -0
  41. package/dist/shared/components/fields/checkbox.d.ts +2 -0
  42. package/dist/shared/components/fields/combobox.d.ts +2 -0
  43. package/dist/shared/components/fields/listbox.d.ts +2 -0
  44. package/dist/shared/components/fields/push-button.d.ts +2 -0
  45. package/dist/shared/components/fields/radio-button.d.ts +2 -0
  46. package/dist/shared/components/fields/style.d.ts +6 -0
  47. package/dist/shared/components/fields/text.d.ts +2 -0
  48. package/dist/shared/components/fill-mode/combobox-fill-mode.d.ts +3 -0
  49. package/dist/shared/components/fill-mode/listbox-fill-mode.d.ts +3 -0
  50. package/dist/shared/components/fill-mode/push-button-fill-mode.d.ts +3 -0
  51. package/dist/shared/components/fill-mode/radio-button-fill-mode.d.ts +3 -0
  52. package/dist/shared/components/fill-mode/text-fill-mode.d.ts +3 -0
  53. package/dist/shared/components/fill-mode/toggle-fill-mode.d.ts +3 -0
  54. package/dist/shared/components/form-renderer-registration.d.ts +5 -0
  55. package/dist/shared/components/form-renderers.d.ts +9 -0
  56. package/dist/shared/components/index.d.ts +2 -0
  57. package/dist/shared/components/render-widget.d.ts +12 -0
  58. package/dist/shared/components/types.d.ts +42 -0
  59. package/dist/shared/hooks/index.d.ts +1 -0
  60. package/dist/shared/hooks/use-form-widget-state.d.ts +12 -0
  61. package/dist/shared/hooks/use-form.d.ts +16 -0
  62. package/dist/shared/index.d.ts +4 -0
  63. package/dist/shared-preact/components/annotations/form-checkbox.d.ts +12 -0
  64. package/dist/shared-preact/components/annotations/form-combobox.d.ts +12 -0
  65. package/dist/shared-preact/components/annotations/form-listbox.d.ts +12 -0
  66. package/dist/shared-preact/components/annotations/form-radio-button.d.ts +12 -0
  67. package/dist/shared-preact/components/annotations/form-text-field.d.ts +12 -0
  68. package/dist/shared-preact/components/fields/checkbox.d.ts +2 -0
  69. package/dist/shared-preact/components/fields/combobox.d.ts +2 -0
  70. package/dist/shared-preact/components/fields/listbox.d.ts +2 -0
  71. package/dist/shared-preact/components/fields/push-button.d.ts +2 -0
  72. package/dist/shared-preact/components/fields/radio-button.d.ts +2 -0
  73. package/dist/shared-preact/components/fields/style.d.ts +6 -0
  74. package/dist/shared-preact/components/fields/text.d.ts +2 -0
  75. package/dist/shared-preact/components/fill-mode/combobox-fill-mode.d.ts +3 -0
  76. package/dist/shared-preact/components/fill-mode/listbox-fill-mode.d.ts +3 -0
  77. package/dist/shared-preact/components/fill-mode/push-button-fill-mode.d.ts +3 -0
  78. package/dist/shared-preact/components/fill-mode/radio-button-fill-mode.d.ts +3 -0
  79. package/dist/shared-preact/components/fill-mode/text-fill-mode.d.ts +3 -0
  80. package/dist/shared-preact/components/fill-mode/toggle-fill-mode.d.ts +3 -0
  81. package/dist/shared-preact/components/form-renderer-registration.d.ts +5 -0
  82. package/dist/shared-preact/components/form-renderers.d.ts +9 -0
  83. package/dist/shared-preact/components/index.d.ts +2 -0
  84. package/dist/shared-preact/components/render-widget.d.ts +12 -0
  85. package/dist/shared-preact/components/types.d.ts +42 -0
  86. package/dist/shared-preact/hooks/index.d.ts +1 -0
  87. package/dist/shared-preact/hooks/use-form-widget-state.d.ts +12 -0
  88. package/dist/shared-preact/hooks/use-form.d.ts +16 -0
  89. package/dist/shared-preact/index.d.ts +4 -0
  90. package/dist/shared-react/components/annotations/form-checkbox.d.ts +12 -0
  91. package/dist/shared-react/components/annotations/form-combobox.d.ts +12 -0
  92. package/dist/shared-react/components/annotations/form-listbox.d.ts +12 -0
  93. package/dist/shared-react/components/annotations/form-radio-button.d.ts +12 -0
  94. package/dist/shared-react/components/annotations/form-text-field.d.ts +12 -0
  95. package/dist/shared-react/components/fields/checkbox.d.ts +2 -0
  96. package/dist/shared-react/components/fields/combobox.d.ts +2 -0
  97. package/dist/shared-react/components/fields/listbox.d.ts +2 -0
  98. package/dist/shared-react/components/fields/push-button.d.ts +2 -0
  99. package/dist/shared-react/components/fields/radio-button.d.ts +2 -0
  100. package/dist/shared-react/components/fields/style.d.ts +6 -0
  101. package/dist/shared-react/components/fields/text.d.ts +2 -0
  102. package/dist/shared-react/components/fill-mode/combobox-fill-mode.d.ts +3 -0
  103. package/dist/shared-react/components/fill-mode/listbox-fill-mode.d.ts +3 -0
  104. package/dist/shared-react/components/fill-mode/push-button-fill-mode.d.ts +3 -0
  105. package/dist/shared-react/components/fill-mode/radio-button-fill-mode.d.ts +3 -0
  106. package/dist/shared-react/components/fill-mode/text-fill-mode.d.ts +3 -0
  107. package/dist/shared-react/components/fill-mode/toggle-fill-mode.d.ts +3 -0
  108. package/dist/shared-react/components/form-renderer-registration.d.ts +5 -0
  109. package/dist/shared-react/components/form-renderers.d.ts +9 -0
  110. package/dist/shared-react/components/index.d.ts +2 -0
  111. package/dist/shared-react/components/render-widget.d.ts +12 -0
  112. package/dist/shared-react/components/types.d.ts +42 -0
  113. package/dist/shared-react/hooks/index.d.ts +1 -0
  114. package/dist/shared-react/hooks/use-form-widget-state.d.ts +12 -0
  115. package/dist/shared-react/hooks/use-form.d.ts +16 -0
  116. package/dist/shared-react/index.d.ts +4 -0
  117. package/dist/svelte/components/FormRendererRegistration.svelte.d.ts +18 -0
  118. package/dist/svelte/components/RenderWidget.svelte.d.ts +11 -0
  119. package/dist/svelte/components/annotations/FormCheckbox.svelte.d.ts +5 -0
  120. package/dist/svelte/components/annotations/FormCombobox.svelte.d.ts +5 -0
  121. package/dist/svelte/components/annotations/FormListbox.svelte.d.ts +5 -0
  122. package/dist/svelte/components/annotations/FormRadioButton.svelte.d.ts +5 -0
  123. package/dist/svelte/components/annotations/FormTextField.svelte.d.ts +5 -0
  124. package/dist/svelte/components/fields/ComboboxField.svelte.d.ts +4 -0
  125. package/dist/svelte/components/fields/ListboxField.svelte.d.ts +4 -0
  126. package/dist/svelte/components/fields/TextField.svelte.d.ts +4 -0
  127. package/dist/svelte/components/fill-mode/ComboboxFillMode.svelte.d.ts +5 -0
  128. package/dist/svelte/components/fill-mode/ListboxFillMode.svelte.d.ts +5 -0
  129. package/dist/svelte/components/fill-mode/RadioButtonFillMode.svelte.d.ts +5 -0
  130. package/dist/svelte/components/fill-mode/TextFillMode.svelte.d.ts +5 -0
  131. package/dist/svelte/components/fill-mode/ToggleFillMode.svelte.d.ts +5 -0
  132. package/dist/svelte/components/form-renderers.d.ts +9 -0
  133. package/dist/svelte/components/previews/CheckboxPreview.svelte.d.ts +9 -0
  134. package/dist/svelte/components/previews/ListboxPreview.svelte.d.ts +9 -0
  135. package/dist/svelte/components/previews/RadioButtonPreview.svelte.d.ts +9 -0
  136. package/dist/svelte/components/previews/TextFieldPreview.svelte.d.ts +9 -0
  137. package/dist/svelte/hooks/index.d.ts +2 -0
  138. package/dist/svelte/hooks/use-form-widget-state.svelte.d.ts +12 -0
  139. package/dist/svelte/hooks/use-form.svelte.d.ts +14 -0
  140. package/dist/svelte/index.cjs +2 -0
  141. package/dist/svelte/index.cjs.map +1 -0
  142. package/dist/svelte/index.d.ts +3 -0
  143. package/dist/svelte/index.js +1567 -0
  144. package/dist/svelte/index.js.map +1 -0
  145. package/dist/vue/components/annotations/form-checkbox.vue.d.ts +6 -0
  146. package/dist/vue/components/annotations/form-combobox.vue.d.ts +6 -0
  147. package/dist/vue/components/annotations/form-listbox.vue.d.ts +6 -0
  148. package/dist/vue/components/annotations/form-radio-button.vue.d.ts +6 -0
  149. package/dist/vue/components/annotations/form-text-field.vue.d.ts +6 -0
  150. package/dist/vue/components/fields/combobox-field.vue.d.ts +4 -0
  151. package/dist/vue/components/fields/listbox-field.vue.d.ts +4 -0
  152. package/dist/vue/components/fields/style.d.ts +6 -0
  153. package/dist/vue/components/fields/text-field.vue.d.ts +4 -0
  154. package/dist/vue/components/fill-mode/combobox-fill-mode.vue.d.ts +6 -0
  155. package/dist/vue/components/fill-mode/listbox-fill-mode.vue.d.ts +6 -0
  156. package/dist/vue/components/fill-mode/radio-button-fill-mode.vue.d.ts +6 -0
  157. package/dist/vue/components/fill-mode/text-fill-mode.vue.d.ts +6 -0
  158. package/dist/vue/components/fill-mode/toggle-fill-mode.vue.d.ts +6 -0
  159. package/dist/vue/components/form-renderer-registration.vue.d.ts +13 -0
  160. package/dist/vue/components/form-renderers.d.ts +3 -0
  161. package/dist/vue/components/previews/checkbox-preview.vue.d.ts +10 -0
  162. package/dist/vue/components/previews/listbox-preview.vue.d.ts +10 -0
  163. package/dist/vue/components/previews/radio-button-preview.vue.d.ts +10 -0
  164. package/dist/vue/components/previews/text-field-preview.vue.d.ts +10 -0
  165. package/dist/vue/components/render-widget.vue.d.ts +15 -0
  166. package/dist/vue/hooks/index.d.ts +2 -0
  167. package/dist/vue/hooks/use-form-widget-state.d.ts +12 -0
  168. package/dist/vue/hooks/use-form.d.ts +12 -0
  169. package/dist/vue/index.cjs +2 -0
  170. package/dist/vue/index.cjs.map +1 -0
  171. package/dist/vue/index.d.ts +3 -0
  172. package/dist/vue/index.js +1643 -0
  173. package/dist/vue/index.js.map +1 -0
  174. package/package.json +84 -0
package/dist/index.js ADDED
@@ -0,0 +1,1789 @@
1
+ import { clamp, BasePlugin, createScopedEmitter } from "@embedpdf/core";
2
+ import { PdfAnnotationSubtype, PdfStandardFont, uuidV4, PDF_FORM_FIELD_FLAG, PDF_FORM_FIELD_TYPE, PdfTaskHelper, PdfErrorCode, Task, isWidgetChecked, TaskSequence } from "@embedpdf/models";
3
+ import { HistoryPlugin } from "@embedpdf/plugin-history";
4
+ import { useState, useClickDetector, defineAnnotationTool } from "@embedpdf/plugin-annotation";
5
+ const FORM_PLUGIN_ID = "form";
6
+ const manifest = {
7
+ id: FORM_PLUGIN_ID,
8
+ name: "Form Plugin",
9
+ version: "1.0.0",
10
+ provides: ["form"],
11
+ requires: ["interaction-manager"],
12
+ optional: ["history", "annotation"],
13
+ defaultConfig: {
14
+ enabled: true
15
+ }
16
+ };
17
+ const INIT_FORM_STATE = "FORM/INIT_STATE";
18
+ const CLEANUP_FORM_STATE = "FORM/CLEANUP_STATE";
19
+ const SELECT_FIELD = "FORM/SELECT_FIELD";
20
+ const DESELECT_FIELD = "FORM/DESELECT_FIELD";
21
+ function initFormState(documentId, state) {
22
+ return { type: INIT_FORM_STATE, payload: { documentId, state } };
23
+ }
24
+ function cleanupFormState(documentId) {
25
+ return { type: CLEANUP_FORM_STATE, payload: documentId };
26
+ }
27
+ function selectField(documentId, annotationId) {
28
+ return { type: SELECT_FIELD, payload: { documentId, annotationId } };
29
+ }
30
+ function deselectField(documentId) {
31
+ return { type: DESELECT_FIELD, payload: documentId };
32
+ }
33
+ const initialDocumentState = {
34
+ selectedFieldId: null
35
+ };
36
+ const initialState = {
37
+ documents: {}
38
+ };
39
+ const reducer = (state = initialState, action) => {
40
+ switch (action.type) {
41
+ case INIT_FORM_STATE:
42
+ return {
43
+ ...state,
44
+ documents: {
45
+ ...state.documents,
46
+ [action.payload.documentId]: action.payload.state
47
+ }
48
+ };
49
+ case CLEANUP_FORM_STATE: {
50
+ const documentId = action.payload;
51
+ const { [documentId]: _, ...remaining } = state.documents;
52
+ return {
53
+ ...state,
54
+ documents: remaining
55
+ };
56
+ }
57
+ case SELECT_FIELD: {
58
+ const { documentId, annotationId } = action.payload;
59
+ const docState = state.documents[documentId];
60
+ if (!docState) return state;
61
+ return {
62
+ ...state,
63
+ documents: {
64
+ ...state.documents,
65
+ [documentId]: {
66
+ ...docState,
67
+ selectedFieldId: annotationId
68
+ }
69
+ }
70
+ };
71
+ }
72
+ case DESELECT_FIELD: {
73
+ const documentId = action.payload;
74
+ const docState = state.documents[documentId];
75
+ if (!docState) return state;
76
+ return {
77
+ ...state,
78
+ documents: {
79
+ ...state.documents,
80
+ [documentId]: {
81
+ ...docState,
82
+ selectedFieldId: null
83
+ }
84
+ }
85
+ };
86
+ }
87
+ default:
88
+ return state;
89
+ }
90
+ };
91
+ const textFieldHandlerFactory = {
92
+ annotationType: PdfAnnotationSubtype.WIDGET,
93
+ create(context) {
94
+ const { pageIndex, onCommit, onPreview, getTool, pageSize } = context;
95
+ const [getStart, setStart] = useState(null);
96
+ const clampToPage = (pos) => ({
97
+ x: clamp(pos.x, 0, pageSize.width),
98
+ y: clamp(pos.y, 0, pageSize.height)
99
+ });
100
+ const getDefaults = () => {
101
+ const tool = getTool();
102
+ if (!tool) return null;
103
+ return {
104
+ ...tool.defaults,
105
+ fontFamily: tool.defaults.fontFamily ?? PdfStandardFont.Helvetica,
106
+ fontSize: tool.defaults.fontSize ?? 12,
107
+ fontColor: tool.defaults.fontColor ?? "#000000",
108
+ strokeColor: tool.defaults.strokeColor ?? "#000000",
109
+ color: tool.defaults.color ?? "#FFFFFF",
110
+ strokeWidth: tool.defaults.strokeWidth ?? 1,
111
+ field: tool.defaults.field
112
+ };
113
+ };
114
+ const buildRect = (start, end) => {
115
+ const minX = Math.min(start.x, end.x);
116
+ const minY = Math.min(start.y, end.y);
117
+ const width = Math.abs(start.x - end.x);
118
+ const height = Math.abs(start.y - end.y);
119
+ return {
120
+ origin: { x: minX, y: minY },
121
+ size: { width, height }
122
+ };
123
+ };
124
+ const buildAnnotation = (rect) => {
125
+ var _a;
126
+ const defaults = getDefaults();
127
+ const fieldName = `TextField_${uuidV4().slice(0, 8)}`;
128
+ return {
129
+ ...defaults,
130
+ type: PdfAnnotationSubtype.WIDGET,
131
+ id: uuidV4(),
132
+ pageIndex,
133
+ rect,
134
+ created: /* @__PURE__ */ new Date(),
135
+ fontFamily: defaults.fontFamily,
136
+ fontSize: defaults.fontSize,
137
+ fontColor: defaults.fontColor,
138
+ strokeColor: defaults.strokeColor,
139
+ color: defaults.color,
140
+ strokeWidth: defaults.strokeWidth,
141
+ field: {
142
+ type: PDF_FORM_FIELD_TYPE.TEXTFIELD,
143
+ flag: ((_a = defaults.field) == null ? void 0 : _a.flag) ?? PDF_FORM_FIELD_FLAG.NONE,
144
+ name: fieldName,
145
+ alternateName: fieldName,
146
+ value: ""
147
+ }
148
+ };
149
+ };
150
+ const clickDetector = useClickDetector({
151
+ getTool,
152
+ onClickDetected: (pos) => {
153
+ const defaults = getDefaults();
154
+ if (!defaults) return;
155
+ const tool = getTool();
156
+ const clickConfig = tool == null ? void 0 : tool.clickBehavior;
157
+ if (!(clickConfig == null ? void 0 : clickConfig.enabled)) return;
158
+ const { width, height } = clickConfig.defaultSize;
159
+ const x = clamp(pos.x - width / 2, 0, pageSize.width - width);
160
+ const y = clamp(pos.y - height / 2, 0, pageSize.height - height);
161
+ const rect = {
162
+ origin: { x, y },
163
+ size: { width, height }
164
+ };
165
+ onCommit(buildAnnotation(rect));
166
+ }
167
+ });
168
+ const getPreview = (current) => {
169
+ const start = getStart();
170
+ if (!start) return null;
171
+ const defaults = getDefaults();
172
+ if (!defaults) return null;
173
+ const rect = buildRect(start, current);
174
+ return {
175
+ type: PdfAnnotationSubtype.WIDGET,
176
+ bounds: rect,
177
+ data: { rect, ...defaults }
178
+ };
179
+ };
180
+ return {
181
+ onPointerDown: (pos, evt) => {
182
+ var _a;
183
+ const clampedPos = clampToPage(pos);
184
+ setStart(clampedPos);
185
+ clickDetector.onStart(clampedPos);
186
+ onPreview(getPreview(clampedPos));
187
+ (_a = evt.setPointerCapture) == null ? void 0 : _a.call(evt);
188
+ },
189
+ onPointerMove: (pos) => {
190
+ const clampedPos = clampToPage(pos);
191
+ clickDetector.onMove(clampedPos);
192
+ if (getStart() && clickDetector.hasMoved()) {
193
+ onPreview(getPreview(clampedPos));
194
+ }
195
+ },
196
+ onPointerUp: (pos, evt) => {
197
+ var _a;
198
+ const start = getStart();
199
+ if (!start) return;
200
+ const clampedPos = clampToPage(pos);
201
+ if (!clickDetector.hasMoved()) {
202
+ clickDetector.onEnd(clampedPos);
203
+ } else {
204
+ const rect = buildRect(start, clampedPos);
205
+ if (rect.size.width > 5 && rect.size.height > 5) {
206
+ onCommit(buildAnnotation(rect));
207
+ }
208
+ }
209
+ setStart(null);
210
+ onPreview(null);
211
+ clickDetector.reset();
212
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
213
+ },
214
+ onPointerLeave: (_, evt) => {
215
+ var _a;
216
+ setStart(null);
217
+ onPreview(null);
218
+ clickDetector.reset();
219
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
220
+ },
221
+ onPointerCancel: (_, evt) => {
222
+ var _a;
223
+ setStart(null);
224
+ onPreview(null);
225
+ clickDetector.reset();
226
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
227
+ }
228
+ };
229
+ }
230
+ };
231
+ const checkboxHandlerFactory = {
232
+ annotationType: PdfAnnotationSubtype.WIDGET,
233
+ create(context) {
234
+ const { pageIndex, onCommit, onPreview, getTool, pageSize } = context;
235
+ const [getStart, setStart] = useState(null);
236
+ const clampToPage = (pos) => ({
237
+ x: clamp(pos.x, 0, pageSize.width),
238
+ y: clamp(pos.y, 0, pageSize.height)
239
+ });
240
+ const getDefaults = () => {
241
+ const tool = getTool();
242
+ if (!tool) return null;
243
+ return {
244
+ ...tool.defaults,
245
+ strokeColor: tool.defaults.strokeColor ?? "#000000",
246
+ color: tool.defaults.color ?? "#FFFFFF",
247
+ strokeWidth: tool.defaults.strokeWidth ?? 1,
248
+ field: tool.defaults.field
249
+ };
250
+ };
251
+ const buildRect = (start, end) => {
252
+ const minX = Math.min(start.x, end.x);
253
+ const minY = Math.min(start.y, end.y);
254
+ const width = Math.abs(start.x - end.x);
255
+ const height = Math.abs(start.y - end.y);
256
+ return {
257
+ origin: { x: minX, y: minY },
258
+ size: { width, height }
259
+ };
260
+ };
261
+ const buildAnnotation = (rect) => {
262
+ var _a;
263
+ const defaults = getDefaults();
264
+ const fieldName = `Checkbox_${uuidV4().slice(0, 8)}`;
265
+ return {
266
+ ...defaults,
267
+ type: PdfAnnotationSubtype.WIDGET,
268
+ id: uuidV4(),
269
+ pageIndex,
270
+ rect,
271
+ created: /* @__PURE__ */ new Date(),
272
+ strokeColor: defaults.strokeColor,
273
+ color: defaults.color,
274
+ strokeWidth: defaults.strokeWidth,
275
+ exportValue: "Yes",
276
+ field: {
277
+ type: PDF_FORM_FIELD_TYPE.CHECKBOX,
278
+ flag: ((_a = defaults.field) == null ? void 0 : _a.flag) ?? PDF_FORM_FIELD_FLAG.NONE,
279
+ name: fieldName,
280
+ alternateName: fieldName,
281
+ value: "Off"
282
+ }
283
+ };
284
+ };
285
+ const clickDetector = useClickDetector({
286
+ getTool,
287
+ onClickDetected: (pos) => {
288
+ const defaults = getDefaults();
289
+ if (!defaults) return;
290
+ const tool = getTool();
291
+ const clickConfig = tool == null ? void 0 : tool.clickBehavior;
292
+ if (!(clickConfig == null ? void 0 : clickConfig.enabled)) return;
293
+ const { width, height } = clickConfig.defaultSize;
294
+ const x = clamp(pos.x - width / 2, 0, pageSize.width - width);
295
+ const y = clamp(pos.y - height / 2, 0, pageSize.height - height);
296
+ const rect = {
297
+ origin: { x, y },
298
+ size: { width, height }
299
+ };
300
+ onCommit(buildAnnotation(rect));
301
+ }
302
+ });
303
+ const getPreview = (current) => {
304
+ const start = getStart();
305
+ if (!start) return null;
306
+ const defaults = getDefaults();
307
+ if (!defaults) return null;
308
+ const rect = buildRect(start, current);
309
+ return {
310
+ type: PdfAnnotationSubtype.WIDGET,
311
+ bounds: rect,
312
+ data: { rect, ...defaults }
313
+ };
314
+ };
315
+ return {
316
+ onPointerDown: (pos, evt) => {
317
+ var _a;
318
+ const clampedPos = clampToPage(pos);
319
+ setStart(clampedPos);
320
+ clickDetector.onStart(clampedPos);
321
+ onPreview(getPreview(clampedPos));
322
+ (_a = evt.setPointerCapture) == null ? void 0 : _a.call(evt);
323
+ },
324
+ onPointerMove: (pos) => {
325
+ const clampedPos = clampToPage(pos);
326
+ clickDetector.onMove(clampedPos);
327
+ if (getStart() && clickDetector.hasMoved()) {
328
+ onPreview(getPreview(clampedPos));
329
+ }
330
+ },
331
+ onPointerUp: (pos, evt) => {
332
+ var _a;
333
+ const start = getStart();
334
+ if (!start) return;
335
+ const clampedPos = clampToPage(pos);
336
+ if (!clickDetector.hasMoved()) {
337
+ clickDetector.onEnd(clampedPos);
338
+ } else {
339
+ const rect = buildRect(start, clampedPos);
340
+ if (rect.size.width > 5 && rect.size.height > 5) {
341
+ onCommit(buildAnnotation(rect));
342
+ }
343
+ }
344
+ setStart(null);
345
+ onPreview(null);
346
+ clickDetector.reset();
347
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
348
+ },
349
+ onPointerLeave: (_, evt) => {
350
+ var _a;
351
+ setStart(null);
352
+ onPreview(null);
353
+ clickDetector.reset();
354
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
355
+ },
356
+ onPointerCancel: (_, evt) => {
357
+ var _a;
358
+ setStart(null);
359
+ onPreview(null);
360
+ clickDetector.reset();
361
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
362
+ }
363
+ };
364
+ }
365
+ };
366
+ const radioButtonHandlerFactory = {
367
+ annotationType: PdfAnnotationSubtype.WIDGET,
368
+ create(context) {
369
+ const { pageIndex, onCommit, onPreview, getTool, pageSize } = context;
370
+ const [getStart, setStart] = useState(null);
371
+ const clampToPage = (pos) => ({
372
+ x: clamp(pos.x, 0, pageSize.width),
373
+ y: clamp(pos.y, 0, pageSize.height)
374
+ });
375
+ const getDefaults = () => {
376
+ const tool = getTool();
377
+ if (!tool) return null;
378
+ return {
379
+ ...tool.defaults,
380
+ strokeColor: tool.defaults.strokeColor ?? "#000000",
381
+ color: tool.defaults.color ?? "#FFFFFF",
382
+ strokeWidth: tool.defaults.strokeWidth ?? 1,
383
+ field: tool.defaults.field
384
+ };
385
+ };
386
+ const buildRect = (start, end) => {
387
+ const dx = end.x - start.x;
388
+ const dy = end.y - start.y;
389
+ const side = Math.max(Math.abs(dx), Math.abs(dy));
390
+ const sx = dx < 0 ? -side : side;
391
+ const sy = dy < 0 ? -side : side;
392
+ const minX = Math.min(start.x, start.x + sx);
393
+ const minY = Math.min(start.y, start.y + sy);
394
+ return {
395
+ origin: { x: minX, y: minY },
396
+ size: { width: side, height: side }
397
+ };
398
+ };
399
+ const buildAnnotation = (rect) => {
400
+ var _a;
401
+ const defaults = getDefaults();
402
+ const fieldName = `RadioButton_${uuidV4().slice(0, 8)}`;
403
+ const id = uuidV4();
404
+ return {
405
+ ...defaults,
406
+ type: PdfAnnotationSubtype.WIDGET,
407
+ id,
408
+ pageIndex,
409
+ rect,
410
+ created: /* @__PURE__ */ new Date(),
411
+ strokeColor: defaults.strokeColor,
412
+ color: defaults.color,
413
+ strokeWidth: defaults.strokeWidth,
414
+ exportValue: id,
415
+ field: {
416
+ type: PDF_FORM_FIELD_TYPE.RADIOBUTTON,
417
+ flag: ((_a = defaults.field) == null ? void 0 : _a.flag) ?? PDF_FORM_FIELD_FLAG.BUTTON_RADIO | PDF_FORM_FIELD_FLAG.BUTTON_NOTOGGLETOOFF,
418
+ name: fieldName,
419
+ alternateName: fieldName,
420
+ value: "Off",
421
+ options: []
422
+ }
423
+ };
424
+ };
425
+ const clickDetector = useClickDetector({
426
+ getTool,
427
+ onClickDetected: (pos) => {
428
+ const defaults = getDefaults();
429
+ if (!defaults) return;
430
+ const tool = getTool();
431
+ const clickConfig = tool == null ? void 0 : tool.clickBehavior;
432
+ if (!(clickConfig == null ? void 0 : clickConfig.enabled)) return;
433
+ const { width, height } = clickConfig.defaultSize;
434
+ const x = clamp(pos.x - width / 2, 0, pageSize.width - width);
435
+ const y = clamp(pos.y - height / 2, 0, pageSize.height - height);
436
+ const rect = {
437
+ origin: { x, y },
438
+ size: { width, height }
439
+ };
440
+ onCommit(buildAnnotation(rect));
441
+ }
442
+ });
443
+ const getPreview = (current) => {
444
+ const start = getStart();
445
+ if (!start) return null;
446
+ const defaults = getDefaults();
447
+ if (!defaults) return null;
448
+ const rect = buildRect(start, current);
449
+ return {
450
+ type: PdfAnnotationSubtype.WIDGET,
451
+ bounds: rect,
452
+ data: { rect, ...defaults }
453
+ };
454
+ };
455
+ return {
456
+ onPointerDown: (pos, evt) => {
457
+ var _a;
458
+ const clampedPos = clampToPage(pos);
459
+ setStart(clampedPos);
460
+ clickDetector.onStart(clampedPos);
461
+ onPreview(getPreview(clampedPos));
462
+ (_a = evt.setPointerCapture) == null ? void 0 : _a.call(evt);
463
+ },
464
+ onPointerMove: (pos) => {
465
+ const clampedPos = clampToPage(pos);
466
+ clickDetector.onMove(clampedPos);
467
+ if (getStart() && clickDetector.hasMoved()) {
468
+ onPreview(getPreview(clampedPos));
469
+ }
470
+ },
471
+ onPointerUp: (pos, evt) => {
472
+ var _a;
473
+ const start = getStart();
474
+ if (!start) return;
475
+ const clampedPos = clampToPage(pos);
476
+ if (!clickDetector.hasMoved()) {
477
+ clickDetector.onEnd(clampedPos);
478
+ } else {
479
+ const rect = buildRect(start, clampedPos);
480
+ if (rect.size.width > 5 && rect.size.height > 5) {
481
+ onCommit(buildAnnotation(rect));
482
+ }
483
+ }
484
+ setStart(null);
485
+ onPreview(null);
486
+ clickDetector.reset();
487
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
488
+ },
489
+ onPointerLeave: (_, evt) => {
490
+ var _a;
491
+ setStart(null);
492
+ onPreview(null);
493
+ clickDetector.reset();
494
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
495
+ },
496
+ onPointerCancel: (_, evt) => {
497
+ var _a;
498
+ setStart(null);
499
+ onPreview(null);
500
+ clickDetector.reset();
501
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
502
+ }
503
+ };
504
+ }
505
+ };
506
+ const comboboxHandlerFactory = {
507
+ annotationType: PdfAnnotationSubtype.WIDGET,
508
+ create(context) {
509
+ const { pageIndex, onCommit, onPreview, getTool, pageSize } = context;
510
+ const [getStart, setStart] = useState(null);
511
+ const clampToPage = (pos) => ({
512
+ x: clamp(pos.x, 0, pageSize.width),
513
+ y: clamp(pos.y, 0, pageSize.height)
514
+ });
515
+ const getDefaults = () => {
516
+ const tool = getTool();
517
+ if (!tool) return null;
518
+ return {
519
+ ...tool.defaults,
520
+ fontFamily: tool.defaults.fontFamily ?? PdfStandardFont.Helvetica,
521
+ fontSize: tool.defaults.fontSize ?? 12,
522
+ fontColor: tool.defaults.fontColor ?? "#000000",
523
+ strokeColor: tool.defaults.strokeColor ?? "#000000",
524
+ color: tool.defaults.color ?? "#FFFFFF",
525
+ strokeWidth: tool.defaults.strokeWidth ?? 1,
526
+ field: tool.defaults.field
527
+ };
528
+ };
529
+ const buildRect = (start, end) => {
530
+ const minX = Math.min(start.x, end.x);
531
+ const minY = Math.min(start.y, end.y);
532
+ const width = Math.abs(start.x - end.x);
533
+ const height = Math.abs(start.y - end.y);
534
+ return {
535
+ origin: { x: minX, y: minY },
536
+ size: { width, height }
537
+ };
538
+ };
539
+ const buildAnnotation = (rect) => {
540
+ var _a;
541
+ const defaults = getDefaults();
542
+ const fieldName = `Combobox_${uuidV4().slice(0, 8)}`;
543
+ return {
544
+ ...defaults,
545
+ type: PdfAnnotationSubtype.WIDGET,
546
+ id: uuidV4(),
547
+ pageIndex,
548
+ rect,
549
+ created: /* @__PURE__ */ new Date(),
550
+ fontFamily: defaults.fontFamily,
551
+ fontSize: defaults.fontSize,
552
+ fontColor: defaults.fontColor,
553
+ strokeColor: defaults.strokeColor,
554
+ color: defaults.color,
555
+ strokeWidth: defaults.strokeWidth,
556
+ field: {
557
+ type: PDF_FORM_FIELD_TYPE.COMBOBOX,
558
+ flag: ((_a = defaults.field) == null ? void 0 : _a.flag) ?? PDF_FORM_FIELD_FLAG.NONE,
559
+ name: fieldName,
560
+ alternateName: fieldName,
561
+ value: "",
562
+ options: [
563
+ { label: "Option 1", isSelected: true },
564
+ { label: "Option 2", isSelected: false },
565
+ { label: "Option 3", isSelected: false }
566
+ ]
567
+ }
568
+ };
569
+ };
570
+ const clickDetector = useClickDetector({
571
+ getTool,
572
+ onClickDetected: (pos) => {
573
+ const defaults = getDefaults();
574
+ if (!defaults) return;
575
+ const tool = getTool();
576
+ const clickConfig = tool == null ? void 0 : tool.clickBehavior;
577
+ if (!(clickConfig == null ? void 0 : clickConfig.enabled)) return;
578
+ const { width, height } = clickConfig.defaultSize;
579
+ const x = clamp(pos.x - width / 2, 0, pageSize.width - width);
580
+ const y = clamp(pos.y - height / 2, 0, pageSize.height - height);
581
+ const rect = {
582
+ origin: { x, y },
583
+ size: { width, height }
584
+ };
585
+ onCommit(buildAnnotation(rect));
586
+ }
587
+ });
588
+ const getPreview = (current) => {
589
+ const start = getStart();
590
+ if (!start) return null;
591
+ const defaults = getDefaults();
592
+ if (!defaults) return null;
593
+ const rect = buildRect(start, current);
594
+ return {
595
+ type: PdfAnnotationSubtype.WIDGET,
596
+ bounds: rect,
597
+ data: { rect, ...defaults }
598
+ };
599
+ };
600
+ return {
601
+ onPointerDown: (pos, evt) => {
602
+ var _a;
603
+ const clampedPos = clampToPage(pos);
604
+ setStart(clampedPos);
605
+ clickDetector.onStart(clampedPos);
606
+ onPreview(getPreview(clampedPos));
607
+ (_a = evt.setPointerCapture) == null ? void 0 : _a.call(evt);
608
+ },
609
+ onPointerMove: (pos) => {
610
+ const clampedPos = clampToPage(pos);
611
+ clickDetector.onMove(clampedPos);
612
+ if (getStart() && clickDetector.hasMoved()) {
613
+ onPreview(getPreview(clampedPos));
614
+ }
615
+ },
616
+ onPointerUp: (pos, evt) => {
617
+ var _a;
618
+ const start = getStart();
619
+ if (!start) return;
620
+ const clampedPos = clampToPage(pos);
621
+ if (!clickDetector.hasMoved()) {
622
+ clickDetector.onEnd(clampedPos);
623
+ } else {
624
+ const rect = buildRect(start, clampedPos);
625
+ if (rect.size.width > 5 && rect.size.height > 5) {
626
+ onCommit(buildAnnotation(rect));
627
+ }
628
+ }
629
+ setStart(null);
630
+ onPreview(null);
631
+ clickDetector.reset();
632
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
633
+ },
634
+ onPointerLeave: (_, evt) => {
635
+ var _a;
636
+ setStart(null);
637
+ onPreview(null);
638
+ clickDetector.reset();
639
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
640
+ },
641
+ onPointerCancel: (_, evt) => {
642
+ var _a;
643
+ setStart(null);
644
+ onPreview(null);
645
+ clickDetector.reset();
646
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
647
+ }
648
+ };
649
+ }
650
+ };
651
+ const listboxHandlerFactory = {
652
+ annotationType: PdfAnnotationSubtype.WIDGET,
653
+ create(context) {
654
+ const { pageIndex, onCommit, onPreview, getTool, pageSize } = context;
655
+ const [getStart, setStart] = useState(null);
656
+ const clampToPage = (pos) => ({
657
+ x: clamp(pos.x, 0, pageSize.width),
658
+ y: clamp(pos.y, 0, pageSize.height)
659
+ });
660
+ const getDefaults = () => {
661
+ const tool = getTool();
662
+ if (!tool) return null;
663
+ return {
664
+ ...tool.defaults,
665
+ fontFamily: tool.defaults.fontFamily ?? PdfStandardFont.Helvetica,
666
+ fontSize: tool.defaults.fontSize ?? 12,
667
+ fontColor: tool.defaults.fontColor ?? "#000000",
668
+ strokeColor: tool.defaults.strokeColor ?? "#000000",
669
+ color: tool.defaults.color ?? "#FFFFFF",
670
+ strokeWidth: tool.defaults.strokeWidth ?? 1,
671
+ field: tool.defaults.field
672
+ };
673
+ };
674
+ const buildRect = (start, end) => {
675
+ const minX = Math.min(start.x, end.x);
676
+ const minY = Math.min(start.y, end.y);
677
+ const width = Math.abs(start.x - end.x);
678
+ const height = Math.abs(start.y - end.y);
679
+ return {
680
+ origin: { x: minX, y: minY },
681
+ size: { width, height }
682
+ };
683
+ };
684
+ const buildAnnotation = (rect) => {
685
+ var _a;
686
+ const defaults = getDefaults();
687
+ const fieldName = `Listbox_${uuidV4().slice(0, 8)}`;
688
+ return {
689
+ ...defaults,
690
+ type: PdfAnnotationSubtype.WIDGET,
691
+ id: uuidV4(),
692
+ pageIndex,
693
+ rect,
694
+ created: /* @__PURE__ */ new Date(),
695
+ fontFamily: defaults.fontFamily,
696
+ fontSize: defaults.fontSize,
697
+ fontColor: defaults.fontColor,
698
+ strokeColor: defaults.strokeColor,
699
+ color: defaults.color,
700
+ strokeWidth: defaults.strokeWidth,
701
+ field: {
702
+ type: PDF_FORM_FIELD_TYPE.LISTBOX,
703
+ flag: ((_a = defaults.field) == null ? void 0 : _a.flag) ?? PDF_FORM_FIELD_FLAG.NONE,
704
+ name: fieldName,
705
+ alternateName: fieldName,
706
+ value: "",
707
+ options: [
708
+ { label: "Option 1", isSelected: true },
709
+ { label: "Option 2", isSelected: false },
710
+ { label: "Option 3", isSelected: false }
711
+ ]
712
+ }
713
+ };
714
+ };
715
+ const clickDetector = useClickDetector({
716
+ getTool,
717
+ onClickDetected: (pos) => {
718
+ const defaults = getDefaults();
719
+ if (!defaults) return;
720
+ const tool = getTool();
721
+ const clickConfig = tool == null ? void 0 : tool.clickBehavior;
722
+ if (!(clickConfig == null ? void 0 : clickConfig.enabled)) return;
723
+ const { width, height } = clickConfig.defaultSize;
724
+ const x = clamp(pos.x - width / 2, 0, pageSize.width - width);
725
+ const y = clamp(pos.y - height / 2, 0, pageSize.height - height);
726
+ const rect = {
727
+ origin: { x, y },
728
+ size: { width, height }
729
+ };
730
+ onCommit(buildAnnotation(rect));
731
+ }
732
+ });
733
+ const getPreview = (current) => {
734
+ const start = getStart();
735
+ if (!start) return null;
736
+ const defaults = getDefaults();
737
+ if (!defaults) return null;
738
+ const rect = buildRect(start, current);
739
+ return {
740
+ type: PdfAnnotationSubtype.WIDGET,
741
+ bounds: rect,
742
+ data: { rect, ...defaults }
743
+ };
744
+ };
745
+ return {
746
+ onPointerDown: (pos, evt) => {
747
+ var _a;
748
+ const clampedPos = clampToPage(pos);
749
+ setStart(clampedPos);
750
+ clickDetector.onStart(clampedPos);
751
+ onPreview(getPreview(clampedPos));
752
+ (_a = evt.setPointerCapture) == null ? void 0 : _a.call(evt);
753
+ },
754
+ onPointerMove: (pos) => {
755
+ const clampedPos = clampToPage(pos);
756
+ clickDetector.onMove(clampedPos);
757
+ if (getStart() && clickDetector.hasMoved()) {
758
+ onPreview(getPreview(clampedPos));
759
+ }
760
+ },
761
+ onPointerUp: (pos, evt) => {
762
+ var _a;
763
+ const start = getStart();
764
+ if (!start) return;
765
+ const clampedPos = clampToPage(pos);
766
+ if (!clickDetector.hasMoved()) {
767
+ clickDetector.onEnd(clampedPos);
768
+ } else {
769
+ const rect = buildRect(start, clampedPos);
770
+ if (rect.size.width > 5 && rect.size.height > 5) {
771
+ onCommit(buildAnnotation(rect));
772
+ }
773
+ }
774
+ setStart(null);
775
+ onPreview(null);
776
+ clickDetector.reset();
777
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
778
+ },
779
+ onPointerLeave: (_, evt) => {
780
+ var _a;
781
+ setStart(null);
782
+ onPreview(null);
783
+ clickDetector.reset();
784
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
785
+ },
786
+ onPointerCancel: (_, evt) => {
787
+ var _a;
788
+ setStart(null);
789
+ onPreview(null);
790
+ clickDetector.reset();
791
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
792
+ }
793
+ };
794
+ }
795
+ };
796
+ const formTextFieldTool = defineAnnotationTool({
797
+ id: "formTextField",
798
+ name: "Text Field",
799
+ labelKey: "form.textfield",
800
+ categories: ["annotation", "form"],
801
+ matchScore: (a) => {
802
+ var _a;
803
+ if (a.type !== PdfAnnotationSubtype.WIDGET) return 0;
804
+ const widget = a;
805
+ return ((_a = widget.field) == null ? void 0 : _a.type) === PDF_FORM_FIELD_TYPE.TEXTFIELD ? 10 : 0;
806
+ },
807
+ interaction: {
808
+ exclusive: false,
809
+ cursor: "crosshair",
810
+ isDraggable: true,
811
+ isResizable: true,
812
+ isRotatable: false,
813
+ isGroupDraggable: true,
814
+ isGroupResizable: false,
815
+ isGroupRotatable: false
816
+ },
817
+ defaults: {
818
+ type: PdfAnnotationSubtype.WIDGET,
819
+ fontFamily: PdfStandardFont.Helvetica,
820
+ fontSize: 12,
821
+ fontColor: "#000000",
822
+ strokeColor: "#000000",
823
+ color: "#FFFFFF",
824
+ strokeWidth: 1,
825
+ field: {
826
+ flag: PDF_FORM_FIELD_FLAG.NONE,
827
+ name: "TextField",
828
+ alternateName: "TextField",
829
+ value: "",
830
+ type: PDF_FORM_FIELD_TYPE.TEXTFIELD
831
+ }
832
+ },
833
+ behavior: {
834
+ useAppearanceStream: false
835
+ },
836
+ clickBehavior: {
837
+ enabled: true,
838
+ defaultSize: { width: 150, height: 24 }
839
+ },
840
+ pointerHandler: textFieldHandlerFactory
841
+ });
842
+ const formCheckboxTool = defineAnnotationTool({
843
+ id: "formCheckbox",
844
+ name: "Checkbox",
845
+ labelKey: "form.checkbox",
846
+ categories: ["annotation", "form"],
847
+ matchScore: (a) => {
848
+ var _a;
849
+ if (a.type !== PdfAnnotationSubtype.WIDGET) return 0;
850
+ const widget = a;
851
+ return ((_a = widget.field) == null ? void 0 : _a.type) === PDF_FORM_FIELD_TYPE.CHECKBOX ? 10 : 0;
852
+ },
853
+ interaction: {
854
+ exclusive: false,
855
+ cursor: "crosshair",
856
+ isDraggable: true,
857
+ isResizable: true,
858
+ isRotatable: false,
859
+ isGroupDraggable: true,
860
+ isGroupResizable: false,
861
+ isGroupRotatable: false
862
+ },
863
+ defaults: {
864
+ type: PdfAnnotationSubtype.WIDGET,
865
+ strokeColor: "#000000",
866
+ color: "#FFFFFF",
867
+ strokeWidth: 1,
868
+ field: {
869
+ flag: PDF_FORM_FIELD_FLAG.NONE,
870
+ name: "Checkbox",
871
+ alternateName: "Checkbox",
872
+ value: "Off",
873
+ type: PDF_FORM_FIELD_TYPE.CHECKBOX
874
+ }
875
+ },
876
+ behavior: {
877
+ useAppearanceStream: false
878
+ },
879
+ clickBehavior: {
880
+ enabled: true,
881
+ defaultSize: { width: 20, height: 20 }
882
+ },
883
+ pointerHandler: checkboxHandlerFactory
884
+ });
885
+ const formRadioButtonTool = defineAnnotationTool({
886
+ id: "formRadioButton",
887
+ name: "Radio Button",
888
+ labelKey: "form.radiobutton",
889
+ categories: ["annotation", "form"],
890
+ matchScore: (a) => {
891
+ var _a;
892
+ if (a.type !== PdfAnnotationSubtype.WIDGET) return 0;
893
+ const widget = a;
894
+ return ((_a = widget.field) == null ? void 0 : _a.type) === PDF_FORM_FIELD_TYPE.RADIOBUTTON ? 10 : 0;
895
+ },
896
+ interaction: {
897
+ exclusive: false,
898
+ cursor: "crosshair",
899
+ isDraggable: true,
900
+ isResizable: true,
901
+ isRotatable: false,
902
+ lockAspectRatio: true,
903
+ isGroupDraggable: true,
904
+ isGroupResizable: false,
905
+ isGroupRotatable: false
906
+ },
907
+ defaults: {
908
+ type: PdfAnnotationSubtype.WIDGET,
909
+ strokeColor: "#000000",
910
+ color: "#FFFFFF",
911
+ strokeWidth: 1,
912
+ field: {
913
+ flag: PDF_FORM_FIELD_FLAG.BUTTON_RADIO | PDF_FORM_FIELD_FLAG.BUTTON_NOTOGGLETOOFF,
914
+ name: "RadioButton",
915
+ alternateName: "RadioButton",
916
+ value: "Off",
917
+ type: PDF_FORM_FIELD_TYPE.RADIOBUTTON,
918
+ options: []
919
+ }
920
+ },
921
+ behavior: {
922
+ useAppearanceStream: false
923
+ },
924
+ clickBehavior: {
925
+ enabled: true,
926
+ defaultSize: { width: 20, height: 20 }
927
+ },
928
+ pointerHandler: radioButtonHandlerFactory
929
+ });
930
+ const formComboboxTool = defineAnnotationTool({
931
+ id: "formCombobox",
932
+ name: "Combo Box",
933
+ labelKey: "form.combobox",
934
+ categories: ["annotation", "form"],
935
+ matchScore: (a) => {
936
+ var _a;
937
+ if (a.type !== PdfAnnotationSubtype.WIDGET) return 0;
938
+ const widget = a;
939
+ return ((_a = widget.field) == null ? void 0 : _a.type) === PDF_FORM_FIELD_TYPE.COMBOBOX ? 10 : 0;
940
+ },
941
+ interaction: {
942
+ exclusive: false,
943
+ cursor: "crosshair",
944
+ isDraggable: true,
945
+ isResizable: true,
946
+ isRotatable: false,
947
+ isGroupDraggable: true,
948
+ isGroupResizable: false,
949
+ isGroupRotatable: false
950
+ },
951
+ defaults: {
952
+ type: PdfAnnotationSubtype.WIDGET,
953
+ fontFamily: PdfStandardFont.Helvetica,
954
+ fontSize: 12,
955
+ fontColor: "#000000",
956
+ strokeColor: "#000000",
957
+ color: "#FFFFFF",
958
+ strokeWidth: 1,
959
+ field: {
960
+ flag: PDF_FORM_FIELD_FLAG.NONE,
961
+ name: "ComboBox",
962
+ alternateName: "ComboBox",
963
+ value: "",
964
+ type: PDF_FORM_FIELD_TYPE.COMBOBOX,
965
+ options: [
966
+ { label: "Option 1", isSelected: true },
967
+ { label: "Option 2", isSelected: false },
968
+ { label: "Option 3", isSelected: false }
969
+ ]
970
+ }
971
+ },
972
+ behavior: {
973
+ useAppearanceStream: false
974
+ },
975
+ clickBehavior: {
976
+ enabled: true,
977
+ defaultSize: { width: 200, height: 40 }
978
+ },
979
+ pointerHandler: comboboxHandlerFactory
980
+ });
981
+ const formListboxTool = defineAnnotationTool({
982
+ id: "formListbox",
983
+ name: "List Box",
984
+ labelKey: "form.listbox",
985
+ categories: ["annotation", "form"],
986
+ matchScore: (a) => {
987
+ var _a;
988
+ if (a.type !== PdfAnnotationSubtype.WIDGET) return 0;
989
+ const widget = a;
990
+ return ((_a = widget.field) == null ? void 0 : _a.type) === PDF_FORM_FIELD_TYPE.LISTBOX ? 10 : 0;
991
+ },
992
+ interaction: {
993
+ exclusive: false,
994
+ cursor: "crosshair",
995
+ isDraggable: true,
996
+ isResizable: true,
997
+ isRotatable: false,
998
+ isGroupDraggable: true,
999
+ isGroupResizable: false,
1000
+ isGroupRotatable: false
1001
+ },
1002
+ defaults: {
1003
+ type: PdfAnnotationSubtype.WIDGET,
1004
+ fontFamily: PdfStandardFont.Helvetica,
1005
+ fontSize: 12,
1006
+ fontColor: "#000000",
1007
+ strokeColor: "#000000",
1008
+ color: "#FFFFFF",
1009
+ strokeWidth: 1,
1010
+ field: {
1011
+ flag: PDF_FORM_FIELD_FLAG.NONE,
1012
+ name: "ListBox",
1013
+ alternateName: "ListBox",
1014
+ value: "",
1015
+ type: PDF_FORM_FIELD_TYPE.LISTBOX,
1016
+ options: [
1017
+ { label: "Option 1", isSelected: true },
1018
+ { label: "Option 2", isSelected: false },
1019
+ { label: "Option 3", isSelected: false }
1020
+ ]
1021
+ }
1022
+ },
1023
+ behavior: {
1024
+ useAppearanceStream: false
1025
+ },
1026
+ clickBehavior: {
1027
+ enabled: true,
1028
+ defaultSize: { width: 150, height: 150 }
1029
+ },
1030
+ pointerHandler: listboxHandlerFactory
1031
+ });
1032
+ const formTools = [
1033
+ formTextFieldTool,
1034
+ formCheckboxTool,
1035
+ formRadioButtonTool,
1036
+ formComboboxTool,
1037
+ formListboxTool
1038
+ ];
1039
+ const _FormPlugin = class _FormPlugin extends BasePlugin {
1040
+ constructor(id, registry, _config) {
1041
+ var _a, _b;
1042
+ super(id, registry);
1043
+ this.FORM_HISTORY_TOPIC = "form-fields";
1044
+ this.annotation = null;
1045
+ this.history = null;
1046
+ this.state$ = createScopedEmitter(
1047
+ (documentId, state) => ({ documentId, state })
1048
+ );
1049
+ this.fieldValueChange$ = createScopedEmitter((_, event) => event, { cache: false });
1050
+ this.formReady$ = createScopedEmitter(
1051
+ (documentId, fields) => ({ documentId, fields }),
1052
+ { cache: false }
1053
+ );
1054
+ this.fieldGroupIndex = /* @__PURE__ */ new Map();
1055
+ this.fieldNameIndex = /* @__PURE__ */ new Map();
1056
+ this.orderedFieldIndex = /* @__PURE__ */ new Map();
1057
+ this.propagationInProgress = /* @__PURE__ */ new Set();
1058
+ this.annotation = ((_a = registry.getPlugin("annotation")) == null ? void 0 : _a.provides()) ?? null;
1059
+ this.history = ((_b = registry.getPlugin(HistoryPlugin.id)) == null ? void 0 : _b.provides()) ?? null;
1060
+ if (this.annotation) {
1061
+ for (const tool of formTools) {
1062
+ this.annotation.addTool(tool);
1063
+ }
1064
+ this.annotation.onAnnotationEvent((event) => this.handleAnnotationEvent(event));
1065
+ }
1066
+ }
1067
+ async initialize() {
1068
+ }
1069
+ onDocumentLoadingStarted(documentId) {
1070
+ this.dispatch(initFormState(documentId, { ...initialDocumentState }));
1071
+ }
1072
+ onDocumentClosed(documentId) {
1073
+ this.dispatch(cleanupFormState(documentId));
1074
+ this.fieldGroupIndex.delete(documentId);
1075
+ this.fieldNameIndex.delete(documentId);
1076
+ this.orderedFieldIndex.delete(documentId);
1077
+ this.state$.clearScope(documentId);
1078
+ this.fieldValueChange$.clearScope(documentId);
1079
+ this.formReady$.clearScope(documentId);
1080
+ }
1081
+ onStoreUpdated(prev, next) {
1082
+ for (const documentId in next.documents) {
1083
+ const prevDoc = prev.documents[documentId];
1084
+ const nextDoc = next.documents[documentId];
1085
+ if (prevDoc !== nextDoc) {
1086
+ this.state$.emit(documentId, nextDoc);
1087
+ }
1088
+ }
1089
+ }
1090
+ buildCapability() {
1091
+ return {
1092
+ getPageFormAnnoWidgets: (pageIndex, documentId) => this.getPageFormAnnoWidgets(pageIndex, documentId),
1093
+ setFormFieldValues: (pageIndex, annotation, newField, documentId) => this.setFormFieldValues(pageIndex, annotation, newField, documentId),
1094
+ renameField: (annotationId, name, documentId) => this.renameFieldMethod(annotationId, name, documentId),
1095
+ shareField: (annotationId, targetAnnotationId, documentId) => this.shareFieldMethod(annotationId, targetAnnotationId, documentId),
1096
+ renderWidget: (options, documentId) => this.renderWidget(options, documentId),
1097
+ selectField: (annotationId, documentId) => this.selectFieldMethod(annotationId, documentId),
1098
+ deselectField: (documentId) => this.deselectFieldMethod(documentId),
1099
+ getSelectedFieldId: (documentId) => this.getSelectedFieldId(documentId),
1100
+ selectNextField: (documentId) => this.selectNextFieldMethod(documentId),
1101
+ selectPreviousField: (documentId) => this.selectPreviousFieldMethod(documentId),
1102
+ activateField: (documentId) => this.activateFieldMethod(documentId),
1103
+ getState: (documentId) => this.getDocumentState(documentId),
1104
+ getFieldGroup: (annotationId, documentId) => this.getFieldGroup(annotationId, documentId),
1105
+ getFieldSiblings: (annotationId, documentId) => this.getFieldSiblings(annotationId, documentId),
1106
+ getFormValues: (documentId) => this.getFormValuesMethod(documentId),
1107
+ getFormFields: (documentId) => this.getFormFieldsMethod(documentId),
1108
+ setFormValues: (values, documentId) => this.setFormValuesMethod(values, documentId),
1109
+ forDocument: (documentId) => this.createFormScope(documentId),
1110
+ onStateChange: this.state$.onGlobal,
1111
+ onFieldValueChange: this.fieldValueChange$.onGlobal,
1112
+ onFormReady: this.formReady$.onGlobal
1113
+ };
1114
+ }
1115
+ createFormScope(documentId) {
1116
+ return {
1117
+ getPageFormAnnoWidgets: (pageIndex) => this.getPageFormAnnoWidgets(pageIndex, documentId),
1118
+ setFormFieldValues: (pageIndex, annotation, newField) => this.setFormFieldValues(pageIndex, annotation, newField, documentId),
1119
+ renameField: (annotationId, name) => this.renameFieldMethod(annotationId, name, documentId),
1120
+ shareField: (annotationId, targetAnnotationId) => this.shareFieldMethod(annotationId, targetAnnotationId, documentId),
1121
+ renderWidget: (options) => this.renderWidget(options, documentId),
1122
+ selectField: (annotationId) => this.selectFieldMethod(annotationId, documentId),
1123
+ deselectField: () => this.deselectFieldMethod(documentId),
1124
+ getSelectedFieldId: () => this.getSelectedFieldId(documentId),
1125
+ selectNextField: () => this.selectNextFieldMethod(documentId),
1126
+ selectPreviousField: () => this.selectPreviousFieldMethod(documentId),
1127
+ activateField: () => this.activateFieldMethod(documentId),
1128
+ getState: () => this.getDocumentState(documentId),
1129
+ getFieldGroup: (annotationId) => this.getFieldGroup(annotationId, documentId),
1130
+ getFieldSiblings: (annotationId) => this.getFieldSiblings(annotationId, documentId),
1131
+ getFormValues: () => this.getFormValuesMethod(documentId),
1132
+ getFormFields: () => this.getFormFieldsMethod(documentId),
1133
+ setFormValues: (values) => this.setFormValuesMethod(values, documentId),
1134
+ onStateChange: this.state$.forScope(documentId),
1135
+ onFieldValueChange: this.fieldValueChange$.forScope(documentId),
1136
+ onFormReady: this.formReady$.forScope(documentId)
1137
+ };
1138
+ }
1139
+ handleAnnotationEvent(event) {
1140
+ switch (event.type) {
1141
+ case "loaded":
1142
+ this.buildFieldGroupIndex(event.documentId);
1143
+ this.formReady$.emit(event.documentId, this.getFormFieldsMethod(event.documentId));
1144
+ break;
1145
+ case "create":
1146
+ case "delete": {
1147
+ if (event.annotation.type !== PdfAnnotationSubtype.WIDGET) break;
1148
+ this.buildFieldGroupIndex(event.documentId);
1149
+ break;
1150
+ }
1151
+ case "update": {
1152
+ if (!event.committed) break;
1153
+ const anno = event.annotation;
1154
+ if (anno.type !== PdfAnnotationSubtype.WIDGET) break;
1155
+ if (this.propagationInProgress.has(anno.id)) {
1156
+ this.propagationInProgress.delete(anno.id);
1157
+ break;
1158
+ }
1159
+ const patch = event.patch;
1160
+ this.buildFieldGroupIndex(event.documentId);
1161
+ this.propagateFieldLevelChanges(event.documentId, anno, patch);
1162
+ break;
1163
+ }
1164
+ }
1165
+ }
1166
+ propagateFieldLevelChanges(documentId, annotation, patch) {
1167
+ if (!this.annotation || !patch.field) return;
1168
+ const fieldPatch = patch.field;
1169
+ const siblings = this.getFieldSiblings(annotation.id, documentId);
1170
+ if (siblings.length === 0) return;
1171
+ const siblingPatches = [];
1172
+ for (const sibling of siblings) {
1173
+ this.propagationInProgress.add(sibling.annotationId);
1174
+ siblingPatches.push({
1175
+ pageIndex: sibling.pageIndex,
1176
+ id: sibling.annotationId,
1177
+ patch: { field: { ...fieldPatch } }
1178
+ });
1179
+ }
1180
+ this.annotation.forDocument(documentId).updateAnnotations(siblingPatches);
1181
+ }
1182
+ buildFieldGroupIndex(documentId) {
1183
+ if (!this.annotation) return;
1184
+ const annoState = this.annotation.forDocument(documentId).getState();
1185
+ if (!annoState) return;
1186
+ const idx = /* @__PURE__ */ new Map();
1187
+ const allWidgets = [];
1188
+ for (const [pageStr, uids] of Object.entries(annoState.pages)) {
1189
+ const pageIndex = Number(pageStr);
1190
+ for (const uid of uids) {
1191
+ const tracked = annoState.byUid[uid];
1192
+ if (!tracked || tracked.object.type !== PdfAnnotationSubtype.WIDGET) continue;
1193
+ const widget = tracked.object;
1194
+ const entry = { annotationId: uid, pageIndex };
1195
+ allWidgets.push({ entry, widget });
1196
+ const fieldKey = this.getFieldKey(widget.field);
1197
+ if (!fieldKey) continue;
1198
+ const group = idx.get(fieldKey) ?? [];
1199
+ group.push(entry);
1200
+ idx.set(fieldKey, group);
1201
+ }
1202
+ }
1203
+ this.fieldGroupIndex.set(documentId, idx);
1204
+ const nameIdx = /* @__PURE__ */ new Map();
1205
+ for (const { entry, widget } of allWidgets) {
1206
+ const name = widget.field.name.trim();
1207
+ if (!name) continue;
1208
+ const group = nameIdx.get(name) ?? [];
1209
+ group.push(entry);
1210
+ nameIdx.set(name, group);
1211
+ }
1212
+ this.fieldNameIndex.set(documentId, nameIdx);
1213
+ const navigable = allWidgets.filter(
1214
+ ({ widget }) => !(widget.field.flag & PDF_FORM_FIELD_FLAG.READONLY)
1215
+ );
1216
+ this.orderedFieldIndex.set(
1217
+ documentId,
1218
+ navigable.map(({ entry }) => entry)
1219
+ );
1220
+ }
1221
+ getDocumentState(documentId) {
1222
+ const id = documentId ?? this.getActiveDocumentId();
1223
+ return this.state.documents[id] ?? { ...initialDocumentState };
1224
+ }
1225
+ // ─────────────────────────────────────────────────────────
1226
+ // Field Group Index
1227
+ // ─────────────────────────────────────────────────────────
1228
+ getDocIndex(documentId) {
1229
+ let idx = this.fieldGroupIndex.get(documentId);
1230
+ if (!idx) {
1231
+ idx = /* @__PURE__ */ new Map();
1232
+ this.fieldGroupIndex.set(documentId, idx);
1233
+ }
1234
+ return idx;
1235
+ }
1236
+ getFieldKey(field) {
1237
+ if (typeof field.fieldObjectId === "number" && field.fieldObjectId > 0) {
1238
+ return `field:${field.fieldObjectId}`;
1239
+ }
1240
+ const normalizedName = field.name.trim();
1241
+ if (!normalizedName) return null;
1242
+ return `legacy:${field.type}:${normalizedName}`;
1243
+ }
1244
+ resolveWidgetAnnotation(annotationId, documentId) {
1245
+ if (!this.annotation) return null;
1246
+ const annoState = this.annotation.forDocument(documentId).getState();
1247
+ const tracked = annoState == null ? void 0 : annoState.byUid[annotationId];
1248
+ if (!tracked || tracked.object.type !== PdfAnnotationSubtype.WIDGET) {
1249
+ return null;
1250
+ }
1251
+ return tracked.object;
1252
+ }
1253
+ getFieldGroup(annotationId, documentId) {
1254
+ const docId = documentId ?? this.getActiveDocumentId();
1255
+ const widget = this.resolveWidgetAnnotation(annotationId, docId);
1256
+ if (!widget) return [];
1257
+ const fieldKey = this.getFieldKey(widget.field);
1258
+ if (!fieldKey) {
1259
+ return [{ annotationId: widget.id, pageIndex: widget.pageIndex }];
1260
+ }
1261
+ return this.getDocIndex(docId).get(fieldKey) ?? [
1262
+ { annotationId: widget.id, pageIndex: widget.pageIndex }
1263
+ ];
1264
+ }
1265
+ getFieldSiblings(annotationId, documentId) {
1266
+ return this.getFieldGroup(annotationId, documentId).filter(
1267
+ (e) => e.annotationId !== annotationId
1268
+ );
1269
+ }
1270
+ // ─────────────────────────────────────────────────────────
1271
+ // Form Values API
1272
+ // ─────────────────────────────────────────────────────────
1273
+ getFormValuesMethod(documentId) {
1274
+ const docId = documentId ?? this.getActiveDocumentId();
1275
+ const nameIdx = this.fieldNameIndex.get(docId);
1276
+ if (!nameIdx) return {};
1277
+ const values = {};
1278
+ for (const [name, entries] of nameIdx) {
1279
+ const widget = this.resolveWidgetAnnotation(entries[0].annotationId, docId);
1280
+ if (widget) {
1281
+ values[name] = widget.field.value;
1282
+ }
1283
+ }
1284
+ return values;
1285
+ }
1286
+ getFormFieldsMethod(documentId) {
1287
+ const docId = documentId ?? this.getActiveDocumentId();
1288
+ const nameIdx = this.fieldNameIndex.get(docId);
1289
+ if (!nameIdx) return [];
1290
+ const fields = [];
1291
+ for (const [name, entries] of nameIdx) {
1292
+ const widget = this.resolveWidgetAnnotation(entries[0].annotationId, docId);
1293
+ if (!widget) continue;
1294
+ fields.push({
1295
+ name,
1296
+ type: widget.field.type,
1297
+ value: widget.field.value,
1298
+ readOnly: !!(widget.field.flag & PDF_FORM_FIELD_FLAG.READONLY),
1299
+ ..."options" in widget.field && widget.field.options ? { options: widget.field.options } : {}
1300
+ });
1301
+ }
1302
+ return fields;
1303
+ }
1304
+ setFormValuesMethod(values, documentId) {
1305
+ const docId = documentId ?? this.getActiveDocumentId();
1306
+ const nameIdx = this.fieldNameIndex.get(docId);
1307
+ if (!nameIdx) {
1308
+ return PdfTaskHelper.reject({
1309
+ code: PdfErrorCode.NotFound,
1310
+ message: "no form fields indexed for this document"
1311
+ });
1312
+ }
1313
+ const entries = Object.entries(values);
1314
+ if (entries.length === 0) {
1315
+ return PdfTaskHelper.resolve(true);
1316
+ }
1317
+ const resultTask = new Task();
1318
+ let pending = entries.length;
1319
+ let failed = false;
1320
+ const onComplete = () => {
1321
+ pending--;
1322
+ if (pending === 0 && !failed) {
1323
+ resultTask.resolve(true);
1324
+ }
1325
+ };
1326
+ const onError = (err) => {
1327
+ if (!failed) {
1328
+ failed = true;
1329
+ resultTask.reject(err);
1330
+ }
1331
+ };
1332
+ for (const [name, value] of entries) {
1333
+ const fieldEntries = nameIdx.get(name);
1334
+ if (!fieldEntries || fieldEntries.length === 0) {
1335
+ onComplete();
1336
+ continue;
1337
+ }
1338
+ let targetEntry = fieldEntries[0];
1339
+ let widget = this.resolveWidgetAnnotation(targetEntry.annotationId, docId);
1340
+ if (!widget) {
1341
+ onComplete();
1342
+ continue;
1343
+ }
1344
+ if (widget.field.type === PDF_FORM_FIELD_TYPE.RADIOBUTTON || widget.field.type === PDF_FORM_FIELD_TYPE.CHECKBOX) {
1345
+ for (const entry of fieldEntries) {
1346
+ const w = this.resolveWidgetAnnotation(entry.annotationId, docId);
1347
+ if (w && w.exportValue === value) {
1348
+ widget = w;
1349
+ targetEntry = entry;
1350
+ break;
1351
+ }
1352
+ }
1353
+ }
1354
+ this.setFormFieldValues(
1355
+ targetEntry.pageIndex,
1356
+ widget,
1357
+ this.buildImportField(widget, value),
1358
+ docId
1359
+ ).wait(
1360
+ () => onComplete(),
1361
+ (error) => onError(error.reason)
1362
+ );
1363
+ }
1364
+ return resultTask;
1365
+ }
1366
+ buildImportField(widget, value) {
1367
+ const field = widget.field;
1368
+ if ((field.type === PDF_FORM_FIELD_TYPE.COMBOBOX || field.type === PDF_FORM_FIELD_TYPE.LISTBOX) && "options" in field) {
1369
+ return {
1370
+ ...field,
1371
+ value,
1372
+ options: field.options.map((opt) => ({
1373
+ ...opt,
1374
+ isSelected: opt.label === value
1375
+ }))
1376
+ };
1377
+ }
1378
+ if (field.type === PDF_FORM_FIELD_TYPE.CHECKBOX) {
1379
+ const normalizedValue = value === "Off" ? "Off" : widget.exportValue ?? "Yes";
1380
+ return { ...field, value: normalizedValue };
1381
+ }
1382
+ return { ...field, value };
1383
+ }
1384
+ isToggleField(field) {
1385
+ return field.type === PDF_FORM_FIELD_TYPE.CHECKBOX || field.type === PDF_FORM_FIELD_TYPE.RADIOBUTTON;
1386
+ }
1387
+ shouldRegenerateWidgetAppearances(field) {
1388
+ return !this.isToggleField(field);
1389
+ }
1390
+ getFieldBatchTarget(batch) {
1391
+ const entries = [...batch.values()];
1392
+ const checkedToggleEntry = entries.find(
1393
+ (entry) => this.isToggleField(entry.widget.field) && isWidgetChecked(entry.widget)
1394
+ );
1395
+ return checkedToggleEntry ?? entries[0];
1396
+ }
1397
+ async readFieldWidgets(doc, groupEntries, seq, regenerateAppearances) {
1398
+ const pageSet = new Set(groupEntries.map((entry) => entry.pageIndex));
1399
+ const memberIds = new Set(groupEntries.map((entry) => entry.annotationId));
1400
+ const batch = /* @__PURE__ */ new Map();
1401
+ for (const pageIndex of pageSet) {
1402
+ const page = doc.pages.find((entry) => entry.index === pageIndex);
1403
+ if (!page) continue;
1404
+ const pageMemberIds = groupEntries.filter((entry) => entry.pageIndex === pageIndex).map((entry) => entry.annotationId);
1405
+ if (regenerateAppearances) {
1406
+ await seq.run(() => this.engine.regenerateWidgetAppearances(doc, page, pageMemberIds));
1407
+ }
1408
+ const widgets = await seq.run(() => this.engine.getPageAnnoWidgets(doc, page));
1409
+ for (const widget of widgets) {
1410
+ if (memberIds.has(widget.id)) {
1411
+ batch.set(widget.id, { widget, pageIndex });
1412
+ }
1413
+ }
1414
+ }
1415
+ return batch;
1416
+ }
1417
+ syncFieldBatch(documentId, batch, options = {}) {
1418
+ if (!this.annotation) return;
1419
+ for (const [id, { widget, pageIndex }] of batch) {
1420
+ this.annotation.syncAnnotationObject(id, widget, documentId);
1421
+ this.annotation.invalidatePageAppearances(pageIndex, documentId);
1422
+ if (options.emitFieldValueChanges) {
1423
+ this.fieldValueChange$.emit(documentId, {
1424
+ documentId,
1425
+ pageIndex,
1426
+ annotationId: id,
1427
+ widget
1428
+ });
1429
+ }
1430
+ }
1431
+ this.buildFieldGroupIndex(documentId);
1432
+ }
1433
+ resolveWidgetPage(annotationId, documentId, doc) {
1434
+ const widget = this.resolveWidgetAnnotation(annotationId, documentId);
1435
+ if (!widget) return null;
1436
+ const page = doc.pages.find((entry) => entry.index === widget.pageIndex);
1437
+ if (!page) return null;
1438
+ return { widget, page };
1439
+ }
1440
+ getPageFormAnnoWidgets(pageIndex, documentId) {
1441
+ const docState = this.getCoreDocumentOrThrow(documentId);
1442
+ const doc = docState.document;
1443
+ if (!doc) {
1444
+ return PdfTaskHelper.reject({
1445
+ code: PdfErrorCode.DocNotOpen,
1446
+ message: "document is not open"
1447
+ });
1448
+ }
1449
+ const page = doc.pages.find((p) => p.index === pageIndex);
1450
+ if (!page) {
1451
+ return PdfTaskHelper.reject({
1452
+ code: PdfErrorCode.NotFound,
1453
+ message: "page does not exist"
1454
+ });
1455
+ }
1456
+ return this.engine.getPageAnnoWidgets(doc, page);
1457
+ }
1458
+ setFormFieldValues(pageIndex, annotation, newField, documentId) {
1459
+ const docId = documentId ?? this.getActiveDocumentId();
1460
+ const coreDoc = this.getCoreDocumentOrThrow(docId);
1461
+ const doc = coreDoc.document;
1462
+ if (!doc) {
1463
+ return PdfTaskHelper.reject({
1464
+ code: PdfErrorCode.DocNotOpen,
1465
+ message: "document is not open"
1466
+ });
1467
+ }
1468
+ const page = doc.pages.find((p) => p.index === pageIndex);
1469
+ if (!page) {
1470
+ return PdfTaskHelper.reject({
1471
+ code: PdfErrorCode.NotFound,
1472
+ message: "page does not exist"
1473
+ });
1474
+ }
1475
+ const resultTask = new Task();
1476
+ const seq = new TaskSequence(resultTask);
1477
+ seq.execute(
1478
+ async () => {
1479
+ const groupEntries = this.getFieldGroup(annotation.id, docId);
1480
+ const beforeEntries = await this.readFieldWidgets(doc, groupEntries, seq, false);
1481
+ await seq.run(() => this.engine.setFormFieldState(doc, page, annotation, newField));
1482
+ const afterEntries = await this.readFieldWidgets(
1483
+ doc,
1484
+ groupEntries,
1485
+ seq,
1486
+ this.shouldRegenerateWidgetAppearances(newField)
1487
+ );
1488
+ let isFirstExecution = true;
1489
+ const applyToEngine = async (batch) => {
1490
+ const target = this.getFieldBatchTarget(batch);
1491
+ if (!target) return;
1492
+ const pg = doc.pages.find((p) => p.index === target.pageIndex);
1493
+ if (!pg) return;
1494
+ await new Promise((resolve) => {
1495
+ this.engine.setFormFieldState(doc, pg, target.widget, target.widget.field).wait(
1496
+ () => resolve(),
1497
+ () => resolve()
1498
+ );
1499
+ });
1500
+ if (this.shouldRegenerateWidgetAppearances(target.widget.field)) {
1501
+ for (const pi of new Set([...batch.values()].map((entry) => entry.pageIndex))) {
1502
+ const p = doc.pages.find((pp) => pp.index === pi);
1503
+ if (!p) continue;
1504
+ const ids = [...batch.entries()].filter(([, entry]) => entry.pageIndex === pi).map(([id]) => id);
1505
+ await new Promise((resolve) => {
1506
+ this.engine.regenerateWidgetAppearances(doc, p, ids).wait(
1507
+ () => resolve(),
1508
+ () => resolve()
1509
+ );
1510
+ });
1511
+ }
1512
+ }
1513
+ };
1514
+ const command = {
1515
+ execute: () => {
1516
+ const skipEngine = isFirstExecution;
1517
+ isFirstExecution = false;
1518
+ if (skipEngine) {
1519
+ this.syncFieldBatch(docId, afterEntries, { emitFieldValueChanges: true });
1520
+ } else {
1521
+ applyToEngine(afterEntries).then(
1522
+ () => this.syncFieldBatch(docId, afterEntries, { emitFieldValueChanges: true })
1523
+ );
1524
+ }
1525
+ },
1526
+ undo: () => {
1527
+ applyToEngine(beforeEntries).then(
1528
+ () => this.syncFieldBatch(docId, beforeEntries, { emitFieldValueChanges: true })
1529
+ );
1530
+ }
1531
+ };
1532
+ if (this.history) {
1533
+ this.history.forDocument(docId).register(command, this.FORM_HISTORY_TOPIC);
1534
+ } else {
1535
+ command.execute();
1536
+ }
1537
+ resultTask.resolve(true);
1538
+ },
1539
+ (err) => ({ code: PdfErrorCode.Unknown, message: String(err) })
1540
+ );
1541
+ return resultTask;
1542
+ }
1543
+ findConflictingFieldGroups(normalizedName, sourceAnnotationId, documentId) {
1544
+ const result = /* @__PURE__ */ new Map();
1545
+ if (!this.annotation) return result;
1546
+ const annoState = this.annotation.forDocument(documentId).getState();
1547
+ if (!annoState) return result;
1548
+ const sourceFieldKey = (() => {
1549
+ const w = this.resolveWidgetAnnotation(sourceAnnotationId, documentId);
1550
+ return w ? this.getFieldKey(w.field) : null;
1551
+ })();
1552
+ for (const [pageStr, uids] of Object.entries(annoState.pages)) {
1553
+ const pageIndex = Number(pageStr);
1554
+ for (const uid of uids) {
1555
+ const tracked = annoState.byUid[uid];
1556
+ if (!tracked || tracked.object.type !== PdfAnnotationSubtype.WIDGET) continue;
1557
+ const widget = tracked.object;
1558
+ if (widget.field.name.trim() !== normalizedName) continue;
1559
+ const fieldKey = this.getFieldKey(widget.field);
1560
+ if (!fieldKey || fieldKey === sourceFieldKey) continue;
1561
+ if (!result.has(fieldKey)) {
1562
+ result.set(fieldKey, { entries: [], widget });
1563
+ }
1564
+ result.get(fieldKey).entries.push({ annotationId: uid, pageIndex });
1565
+ }
1566
+ }
1567
+ return result;
1568
+ }
1569
+ renameFieldMethod(annotationId, name, documentId) {
1570
+ const docId = documentId ?? this.getActiveDocumentId();
1571
+ const normalizedName = name.trim();
1572
+ if (!normalizedName) {
1573
+ return PdfTaskHelper.reject({
1574
+ code: PdfErrorCode.Unknown,
1575
+ message: "Field name must not be empty."
1576
+ });
1577
+ }
1578
+ const coreDoc = this.getCoreDocumentOrThrow(docId);
1579
+ const doc = coreDoc.document;
1580
+ if (!doc) {
1581
+ return PdfTaskHelper.reject({
1582
+ code: PdfErrorCode.DocNotOpen,
1583
+ message: "document is not open"
1584
+ });
1585
+ }
1586
+ const source = this.resolveWidgetPage(annotationId, docId, doc);
1587
+ if (!source) {
1588
+ return PdfTaskHelper.reject({
1589
+ code: PdfErrorCode.NotFound,
1590
+ message: "widget annotation not found"
1591
+ });
1592
+ }
1593
+ if (source.widget.field.name.trim() === normalizedName) {
1594
+ return PdfTaskHelper.resolve({ outcome: "no-op" });
1595
+ }
1596
+ const conflicts = this.findConflictingFieldGroups(normalizedName, annotationId, docId);
1597
+ if (conflicts.size > 0) {
1598
+ if (conflicts.size > 1) {
1599
+ return PdfTaskHelper.reject({
1600
+ code: PdfErrorCode.Unknown,
1601
+ message: "That field name is used by multiple fields. Choose a unique name."
1602
+ });
1603
+ }
1604
+ const [, match] = [...conflicts.entries()][0];
1605
+ if (match.widget.field.type !== source.widget.field.type) {
1606
+ return PdfTaskHelper.reject({
1607
+ code: PdfErrorCode.Unknown,
1608
+ message: "That field name is already used by a different widget type."
1609
+ });
1610
+ }
1611
+ return PdfTaskHelper.resolve({
1612
+ outcome: "conflict",
1613
+ targetAnnotationId: match.entries[0].annotationId,
1614
+ fieldName: normalizedName
1615
+ });
1616
+ }
1617
+ const resultTask = new Task();
1618
+ const seq = new TaskSequence(resultTask);
1619
+ seq.execute(
1620
+ async () => {
1621
+ const groupEntries = this.getFieldGroup(annotationId, docId);
1622
+ await seq.run(
1623
+ () => this.engine.renameWidgetField(doc, source.page, source.widget, normalizedName)
1624
+ );
1625
+ const syncedEntries = await this.readFieldWidgets(doc, groupEntries, seq, false);
1626
+ this.syncFieldBatch(docId, syncedEntries);
1627
+ resultTask.resolve({ outcome: "renamed" });
1628
+ },
1629
+ (err) => ({ code: PdfErrorCode.Unknown, message: String(err) })
1630
+ );
1631
+ return resultTask;
1632
+ }
1633
+ shareFieldMethod(annotationId, targetAnnotationId, documentId) {
1634
+ const docId = documentId ?? this.getActiveDocumentId();
1635
+ if (annotationId === targetAnnotationId) {
1636
+ return PdfTaskHelper.resolve(true);
1637
+ }
1638
+ const coreDoc = this.getCoreDocumentOrThrow(docId);
1639
+ const doc = coreDoc.document;
1640
+ if (!doc) {
1641
+ return PdfTaskHelper.reject({
1642
+ code: PdfErrorCode.DocNotOpen,
1643
+ message: "document is not open"
1644
+ });
1645
+ }
1646
+ const source = this.resolveWidgetPage(annotationId, docId, doc);
1647
+ const target = this.resolveWidgetPage(targetAnnotationId, docId, doc);
1648
+ if (!source || !target) {
1649
+ return PdfTaskHelper.reject({
1650
+ code: PdfErrorCode.NotFound,
1651
+ message: "widget annotation not found"
1652
+ });
1653
+ }
1654
+ if (source.widget.field.type !== target.widget.field.type) {
1655
+ return PdfTaskHelper.reject({
1656
+ code: PdfErrorCode.Unknown,
1657
+ message: "cannot share fields with different widget types"
1658
+ });
1659
+ }
1660
+ if (source.widget.field.fieldObjectId && target.widget.field.fieldObjectId && source.widget.field.fieldObjectId === target.widget.field.fieldObjectId) {
1661
+ return PdfTaskHelper.resolve(true);
1662
+ }
1663
+ const affectedEntryMap = /* @__PURE__ */ new Map();
1664
+ for (const entry of this.getFieldGroup(annotationId, docId)) {
1665
+ affectedEntryMap.set(entry.annotationId, entry);
1666
+ }
1667
+ for (const entry of this.getFieldGroup(targetAnnotationId, docId)) {
1668
+ affectedEntryMap.set(entry.annotationId, entry);
1669
+ }
1670
+ const affectedEntries = [...affectedEntryMap.values()];
1671
+ const resultTask = new Task();
1672
+ const seq = new TaskSequence(resultTask);
1673
+ seq.execute(
1674
+ async () => {
1675
+ await seq.run(
1676
+ () => this.engine.shareWidgetField(doc, source.page, source.widget, target.page, target.widget)
1677
+ );
1678
+ const syncedEntries = await this.readFieldWidgets(
1679
+ doc,
1680
+ affectedEntries,
1681
+ seq,
1682
+ this.shouldRegenerateWidgetAppearances(target.widget.field)
1683
+ );
1684
+ this.syncFieldBatch(docId, syncedEntries);
1685
+ resultTask.resolve(true);
1686
+ },
1687
+ (err) => ({ code: PdfErrorCode.Unknown, message: String(err) })
1688
+ );
1689
+ return resultTask;
1690
+ }
1691
+ selectFieldMethod(annotationId, documentId) {
1692
+ const docId = documentId ?? this.getActiveDocumentId();
1693
+ this.dispatch(selectField(docId, annotationId));
1694
+ }
1695
+ deselectFieldMethod(documentId) {
1696
+ const docId = documentId ?? this.getActiveDocumentId();
1697
+ this.dispatch(deselectField(docId));
1698
+ }
1699
+ getSelectedFieldId(documentId) {
1700
+ return this.getDocumentState(documentId).selectedFieldId;
1701
+ }
1702
+ selectNextFieldMethod(documentId) {
1703
+ const docId = documentId ?? this.getActiveDocumentId();
1704
+ const ordered = this.orderedFieldIndex.get(docId);
1705
+ if (!ordered || ordered.length === 0) return;
1706
+ const currentId = this.getSelectedFieldId(docId);
1707
+ let nextIndex = 0;
1708
+ if (currentId) {
1709
+ const currentIndex = ordered.findIndex((e) => e.annotationId === currentId);
1710
+ nextIndex = currentIndex >= 0 ? (currentIndex + 1) % ordered.length : 0;
1711
+ }
1712
+ const next = ordered[nextIndex];
1713
+ this.dispatch(selectField(docId, next.annotationId));
1714
+ }
1715
+ selectPreviousFieldMethod(documentId) {
1716
+ const docId = documentId ?? this.getActiveDocumentId();
1717
+ const ordered = this.orderedFieldIndex.get(docId);
1718
+ if (!ordered || ordered.length === 0) return;
1719
+ const currentId = this.getSelectedFieldId(docId);
1720
+ let prevIndex = ordered.length - 1;
1721
+ if (currentId) {
1722
+ const currentIndex = ordered.findIndex((e) => e.annotationId === currentId);
1723
+ prevIndex = currentIndex >= 0 ? (currentIndex - 1 + ordered.length) % ordered.length : ordered.length - 1;
1724
+ }
1725
+ const prev = ordered[prevIndex];
1726
+ this.dispatch(selectField(docId, prev.annotationId));
1727
+ }
1728
+ activateFieldMethod(documentId) {
1729
+ const docId = documentId ?? this.getActiveDocumentId();
1730
+ const selectedId = this.getSelectedFieldId(docId);
1731
+ if (!selectedId) return;
1732
+ const widget = this.resolveWidgetAnnotation(selectedId, docId);
1733
+ if (!widget) return;
1734
+ const field = widget.field;
1735
+ if (field.type === PDF_FORM_FIELD_TYPE.CHECKBOX) {
1736
+ const checked = isWidgetChecked(widget);
1737
+ const newValue = checked ? "Off" : widget.exportValue ?? "Yes";
1738
+ this.setFormFieldValues(widget.pageIndex, widget, { ...field, value: newValue }, docId);
1739
+ } else if (field.type === PDF_FORM_FIELD_TYPE.RADIOBUTTON) {
1740
+ if (!isWidgetChecked(widget) && widget.exportValue) {
1741
+ this.setFormFieldValues(
1742
+ widget.pageIndex,
1743
+ widget,
1744
+ { ...field, value: widget.exportValue },
1745
+ docId
1746
+ );
1747
+ }
1748
+ }
1749
+ }
1750
+ renderWidget(options, documentId) {
1751
+ if (!this.annotation) {
1752
+ return PdfTaskHelper.reject({
1753
+ code: PdfErrorCode.NotFound,
1754
+ message: "annotation plugin not found"
1755
+ });
1756
+ }
1757
+ const id = documentId ?? this.getActiveDocumentId();
1758
+ return this.annotation.forDocument(id).renderAnnotation(options);
1759
+ }
1760
+ async destroy() {
1761
+ this.state$.clear();
1762
+ this.fieldValueChange$.clear();
1763
+ this.formReady$.clear();
1764
+ super.destroy();
1765
+ }
1766
+ };
1767
+ _FormPlugin.id = "form";
1768
+ let FormPlugin = _FormPlugin;
1769
+ const FormPluginPackage = {
1770
+ manifest,
1771
+ create: (registry, config) => new FormPlugin(FORM_PLUGIN_ID, registry, config),
1772
+ reducer,
1773
+ initialState
1774
+ };
1775
+ export {
1776
+ FORM_PLUGIN_ID,
1777
+ FormPlugin,
1778
+ FormPluginPackage,
1779
+ formCheckboxTool,
1780
+ formComboboxTool,
1781
+ formListboxTool,
1782
+ formRadioButtonTool,
1783
+ formTextFieldTool,
1784
+ formTools,
1785
+ initialDocumentState,
1786
+ initialState,
1787
+ manifest
1788
+ };
1789
+ //# sourceMappingURL=index.js.map