@bigbinary/neeto-pdf-frontend 1.0.2 → 1.0.3

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 (64) hide show
  1. package/dist/.ready +1 -1
  2. package/dist/AttachmentCard-Blp45MKz.js +64 -0
  3. package/dist/AttachmentCard-Blp45MKz.js.map +1 -0
  4. package/dist/AttachmentCard-CbDrjY7P.js +67 -0
  5. package/dist/AttachmentCard-CbDrjY7P.js.map +1 -0
  6. package/dist/FilenameUtilities-DFEKeP7n.js +150 -0
  7. package/dist/FilenameUtilities-DFEKeP7n.js.map +1 -0
  8. package/dist/{FilenameUtilities-BRCCinT2.js → FilenameUtilities-Di7TmEIR.js} +9 -184
  9. package/dist/FilenameUtilities-Di7TmEIR.js.map +1 -0
  10. package/dist/FilenameUtilities-SpduImYz.js +139 -0
  11. package/dist/FilenameUtilities-SpduImYz.js.map +1 -0
  12. package/dist/{FilenameUtilities-DHtvZ32y.js → FilenameUtilities-Xttn7r8R.js} +2 -177
  13. package/dist/FilenameUtilities-Xttn7r8R.js.map +1 -0
  14. package/dist/IconBlock-BZvD1k7W.js +17 -0
  15. package/dist/IconBlock-BZvD1k7W.js.map +1 -0
  16. package/dist/IconBlock-Cte1G732.js +15 -0
  17. package/dist/IconBlock-Cte1G732.js.map +1 -0
  18. package/dist/PdfDocumentsPage.js +2 -1
  19. package/dist/PdfDocumentsPage.js.map +1 -1
  20. package/dist/PdfEditorPage.js +3 -146
  21. package/dist/PdfEditorPage.js.map +1 -1
  22. package/dist/cjs/PdfDocumentsPage.js +2 -1
  23. package/dist/cjs/PdfDocumentsPage.js.map +1 -1
  24. package/dist/cjs/PdfEditorPage.js +12 -155
  25. package/dist/cjs/PdfEditorPage.js.map +1 -1
  26. package/dist/cjs/index.js +3 -1
  27. package/dist/cjs/index.js.map +1 -1
  28. package/dist/cjs/v2/PdfAttachmentSelector.js +95 -0
  29. package/dist/cjs/v2/PdfAttachmentSelector.js.map +1 -0
  30. package/dist/cjs/v2/PdfAttachmentsPreview.js +45 -0
  31. package/dist/cjs/v2/PdfAttachmentsPreview.js.map +1 -0
  32. package/dist/cjs/v2/PdfDocumentsPage.js +555 -0
  33. package/dist/cjs/v2/PdfDocumentsPage.js.map +1 -0
  34. package/dist/cjs/v2/PdfEditorPage.js +1920 -0
  35. package/dist/cjs/v2/PdfEditorPage.js.map +1 -0
  36. package/dist/cjs/v2/index.js +67 -0
  37. package/dist/cjs/v2/index.js.map +1 -0
  38. package/dist/constants-DDj0SAA-.js +8 -0
  39. package/dist/constants-DDj0SAA-.js.map +1 -0
  40. package/dist/constants-MHmmvZDo.js +5 -0
  41. package/dist/constants-MHmmvZDo.js.map +1 -0
  42. package/dist/index.js +3 -1
  43. package/dist/index.js.map +1 -1
  44. package/dist/pdf_documents-PKt4xiTc.js +181 -0
  45. package/dist/pdf_documents-PKt4xiTc.js.map +1 -0
  46. package/dist/pdf_documents-j2CBlJrR.js +179 -0
  47. package/dist/pdf_documents-j2CBlJrR.js.map +1 -0
  48. package/dist/pdf_mapping_schema-CS6f9Kug.js +149 -0
  49. package/dist/pdf_mapping_schema-CS6f9Kug.js.map +1 -0
  50. package/dist/pdf_mapping_schema-Co4FN4KU.js +147 -0
  51. package/dist/pdf_mapping_schema-Co4FN4KU.js.map +1 -0
  52. package/dist/v2/PdfAttachmentSelector.js +93 -0
  53. package/dist/v2/PdfAttachmentSelector.js.map +1 -0
  54. package/dist/v2/PdfAttachmentsPreview.js +43 -0
  55. package/dist/v2/PdfAttachmentsPreview.js.map +1 -0
  56. package/dist/v2/PdfDocumentsPage.js +553 -0
  57. package/dist/v2/PdfDocumentsPage.js.map +1 -0
  58. package/dist/v2/PdfEditorPage.js +1899 -0
  59. package/dist/v2/PdfEditorPage.js.map +1 -0
  60. package/dist/v2/index.js +58 -0
  61. package/dist/v2/index.js.map +1 -0
  62. package/package.json +13 -1
  63. package/dist/FilenameUtilities-BRCCinT2.js.map +0 -1
  64. package/dist/FilenameUtilities-DHtvZ32y.js.map +0 -1
@@ -0,0 +1,1899 @@
1
+ import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
2
+ import { useRef, useState, useMemo, useEffect, createElement } from 'react';
3
+ import { Spinner, Typography, Select, Input, ColorPicker, Button, Toastr } from '@bigbinary/neeto-atoms';
4
+ import { createPortal } from 'react-dom';
5
+ import { useTranslation } from 'react-i18next';
6
+ import _asyncToGenerator from '@babel/runtime/helpers/asyncToGenerator';
7
+ import _regeneratorRuntime from '@babel/runtime/regenerator';
8
+ import _defineProperty from '@babel/runtime/helpers/defineProperty';
9
+ import classNames from 'classnames';
10
+ import { findBy, findById, removeById } from '@bigbinary/neeto-cist';
11
+ import Calendar from '@bigbinary/neeto-icons/Calendar';
12
+ import Hash from '@bigbinary/neeto-icons/Hash';
13
+ import TextLines from '@bigbinary/neeto-icons/TextLines';
14
+ import { p as pdfMappingSchema } from '../pdf_mapping_schema-Co4FN4KU.js';
15
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
16
+ import * as pdfjsLib from 'pdfjs-dist';
17
+ import _objectWithoutProperties from '@babel/runtime/helpers/objectWithoutProperties';
18
+ import { withT } from '@bigbinary/neeto-commons-frontend/v2/react-utils';
19
+ import CenterAlign from '@bigbinary/neeto-icons/CenterAlign';
20
+ import Delete from '@bigbinary/neeto-icons/Delete';
21
+ import Folder from '@bigbinary/neeto-icons/Folder';
22
+ import LeftAlign from '@bigbinary/neeto-icons/LeftAlign';
23
+ import RightAlign from '@bigbinary/neeto-icons/RightAlign';
24
+ import Search from '@bigbinary/neeto-icons/Search';
25
+ import Drag from '@bigbinary/neeto-icons/Drag';
26
+ import logger from 'js-logger';
27
+ import { h as buildOutputFilename, i as useFetchPdfDocument, u as useUpdatePdfDocument, g as getPdfDocumentApiErrorMessage, d as buildOutputFilenameTemplate } from '../FilenameUtilities-SpduImYz.js';
28
+ import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray';
29
+ import { append } from 'ramda';
30
+ import Left from '@bigbinary/neeto-icons/Left';
31
+ import Right from '@bigbinary/neeto-icons/Right';
32
+ import _typeof from '@babel/runtime/helpers/typeof';
33
+ import { dateFormat } from '@bigbinary/neeto-commons-frontend/v2/utils';
34
+ import Download from '@bigbinary/neeto-icons/Download';
35
+ import LeftArrow from '@bigbinary/neeto-icons/LeftArrow';
36
+ import Minus from '@bigbinary/neeto-icons/Minus';
37
+ import Plus from '@bigbinary/neeto-icons/Plus';
38
+ import NavigationHeader from '@bigbinary/neeto-molecules/v2/NavigationHeader';
39
+ import '@tanstack/react-query';
40
+ import '../pdf_documents-j2CBlJrR.js';
41
+ import 'axios';
42
+
43
+ var mappingDefaults = pdfMappingSchema.defaults;
44
+
45
+ // CSS pixels per PDF point (96dpi / 72dpi). `renderScale = CSS_PX_PER_PT * zoom`
46
+ // maps a page's intrinsic point dimensions to on-screen pixels, and font sizes
47
+ // (stored in points) to pixels. Keeping geometry in point-fractions keeps
48
+ // mappings resolution independent.
49
+ var CSS_PX_PER_PT = 96 / 72;
50
+ var ZOOM = {
51
+ MIN: 0.5,
52
+ MAX: 2,
53
+ STEP: 0.1,
54
+ DEFAULT: 1
55
+ };
56
+ var PDF_CANVAS = {
57
+ MAX_DISPLAY_SIZE: 1400,
58
+ MAX_RENDER_SIZE: 8192,
59
+ MAX_RENDER_PIXELS: 16000000
60
+ };
61
+ var EDITOR_MODES = {
62
+ MAP: "map",
63
+ PREVIEW: "preview"
64
+ };
65
+ var PDF_LOAD_INITIAL_STATE = {
66
+ pages: [],
67
+ isLoading: true,
68
+ error: null
69
+ };
70
+ var EMPTY_MAPPINGS = [];
71
+ var FIELD_SOURCES = {
72
+ ANSWER: pdfMappingSchema.enums.sources[0],
73
+ SYSTEM: pdfMappingSchema.enums.sources[1]
74
+ };
75
+ var DRAG_KINDS = {
76
+ MOVE: "move",
77
+ RESIZE: "resize"
78
+ };
79
+ var ALIGNMENTS = {
80
+ LEFT: pdfMappingSchema.enums.alignments[0],
81
+ CENTER: pdfMappingSchema.enums.alignments[1],
82
+ RIGHT: pdfMappingSchema.enums.alignments[2]
83
+ };
84
+ var FORM_THEME_COLOR = "rgb(var(--neeto-form-answer-color, 0, 128, 104))";
85
+ var FORM_THEME_BACKGROUND = "rgba(var(--neeto-form-answer-color, 0, 128, 104), 0.08)";
86
+ var RESIZE_HANDLES = [{
87
+ key: "top-left",
88
+ x: "left",
89
+ y: "top",
90
+ className: "-left-1.5 -top-1.5 cursor-nwse-resize"
91
+ }, {
92
+ key: "top-right",
93
+ x: "right",
94
+ y: "top",
95
+ className: "-right-1.5 -top-1.5 cursor-nesw-resize"
96
+ }, {
97
+ key: "bottom-left",
98
+ x: "left",
99
+ y: "bottom",
100
+ className: "-left-1.5 -bottom-1.5 cursor-nesw-resize"
101
+ }, {
102
+ key: "bottom-right",
103
+ x: "right",
104
+ y: "bottom",
105
+ className: "-right-1.5 -bottom-1.5 cursor-nwse-resize"
106
+ }];
107
+
108
+ // Curated, PDF/web-safe fonts. The JSON schema also supplies the server-side
109
+ // variants so client/server rendering cannot drift when the list changes.
110
+ var FONTS = pdfMappingSchema.fonts.map(function (_ref) {
111
+ var label = _ref.label,
112
+ stack = _ref.stack,
113
+ value = _ref.value;
114
+ return {
115
+ value: value,
116
+ label: label,
117
+ stack: stack
118
+ };
119
+ });
120
+
121
+ // Maps a curated font to pdf-lib StandardFont variant names, indexed by
122
+ // (bold ? 1 : 0) + (italic ? 2 : 0).
123
+ var STANDARD_FONT_VARIANTS = Object.fromEntries(pdfMappingSchema.fonts.map(function (_ref2) {
124
+ var clientVariants = _ref2.client_variants,
125
+ value = _ref2.value;
126
+ return [value, clientVariants];
127
+ }));
128
+ var DEFAULT_FONT_SIZE = mappingDefaults.style.font_size;
129
+ var DEFAULT_DISPLAY_FONT_SIZE = DEFAULT_FONT_SIZE * CSS_PX_PER_PT;
130
+ var FONT_SIZE_LIMITS = pdfMappingSchema.ranges.font_size;
131
+ var DEFAULT_STYLE = {
132
+ font: mappingDefaults.style.font,
133
+ fontSize: DEFAULT_FONT_SIZE,
134
+ color: mappingDefaults.style.color,
135
+ bold: mappingDefaults.style.bold,
136
+ italic: mappingDefaults.style.italic,
137
+ underline: mappingDefaults.style.underline,
138
+ align: mappingDefaults.style.align
139
+ };
140
+
141
+ // Default placement box as a fraction of the page (top-left origin).
142
+ var DEFAULT_BOX = mappingDefaults.box;
143
+ var MIN_BOX = {
144
+ width: 0.03,
145
+ height: 0.012
146
+ };
147
+ var SYSTEM_FIELD_KEYS = {
148
+ FORM_NAME: "form_name",
149
+ SUBMISSION_ID: "submission_id",
150
+ SUBMISSION_DATE: "submission_date"
151
+ };
152
+
153
+ // System fields are not form questions; they resolve from submission metadata.
154
+ var SYSTEM_FIELDS = [{
155
+ key: SYSTEM_FIELD_KEYS.FORM_NAME,
156
+ labelKey: "neetoPdf.pdfDocuments.editor.systemFields.formName",
157
+ icon: TextLines
158
+ }, {
159
+ key: SYSTEM_FIELD_KEYS.SUBMISSION_ID,
160
+ labelKey: "neetoPdf.pdfDocuments.editor.systemFields.submissionId",
161
+ icon: Hash
162
+ }, {
163
+ key: SYSTEM_FIELD_KEYS.SUBMISSION_DATE,
164
+ labelKey: "neetoPdf.pdfDocuments.editor.systemFields.submissionDate",
165
+ icon: Calendar
166
+ }];
167
+
168
+ var clamp = function clamp(value, min, max) {
169
+ return Math.min(Math.max(value, min), max);
170
+ };
171
+ var getPdfPageDisplayScale = function getPdfPageDisplayScale(_ref) {
172
+ var heightPt = _ref.heightPt,
173
+ rawScale = _ref.rawScale,
174
+ widthPt = _ref.widthPt;
175
+ var maxPageSize = Math.max(widthPt, heightPt);
176
+ if (!maxPageSize) return rawScale;
177
+ var zoom = rawScale / CSS_PX_PER_PT;
178
+ var baseScale = Math.min(CSS_PX_PER_PT, PDF_CANVAS.MAX_DISPLAY_SIZE / maxPageSize);
179
+ return baseScale * zoom;
180
+ };
181
+ var getDefaultFontSizeForScale = function getDefaultFontSizeForScale(scale) {
182
+ if (!scale || Number.isNaN(scale)) return DEFAULT_STYLE.fontSize;
183
+ return clamp(Math.round(DEFAULT_DISPLAY_FONT_SIZE / scale), FONT_SIZE_LIMITS.min, FONT_SIZE_LIMITS.max);
184
+ };
185
+ var getFontStack = function getFontStack(font) {
186
+ var _findBy;
187
+ return ((_findBy = findBy({
188
+ value: font
189
+ }, FONTS)) === null || _findBy === void 0 ? void 0 : _findBy.stack) || FONTS[0].stack;
190
+ };
191
+
192
+ function ownKeys$3(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
193
+ function _objectSpread$3(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$3(Object(t), true).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$3(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
194
+ var getJustifyContent = function getJustifyContent(align) {
195
+ if (align === "center") return "center";
196
+ if (align === "right") return "flex-end";
197
+ return "flex-start";
198
+ };
199
+ var PlacedField = function PlacedField(_ref) {
200
+ var mapping = _ref.mapping,
201
+ mode = _ref.mode,
202
+ isSelected = _ref.isSelected,
203
+ scale = _ref.scale,
204
+ pageWidthPx = _ref.pageWidthPx,
205
+ pageHeightPx = _ref.pageHeightPx,
206
+ previewValue = _ref.previewValue,
207
+ onSelect = _ref.onSelect,
208
+ onChange = _ref.onChange;
209
+ var dragRef = useRef(null);
210
+ var draftPatchRef = useRef(null);
211
+ var _useState = useState(null),
212
+ _useState2 = _slicedToArray(_useState, 2),
213
+ draftPatch = _useState2[0],
214
+ setDraftPatch = _useState2[1];
215
+ var isPreview = mode === EDITOR_MODES.PREVIEW;
216
+ var displayMapping = draftPatch ? _objectSpread$3(_objectSpread$3({}, mapping), draftPatch) : mapping;
217
+ var style = {
218
+ left: "".concat(displayMapping.x * pageWidthPx, "px"),
219
+ top: "".concat(displayMapping.y * pageHeightPx, "px"),
220
+ width: "".concat(displayMapping.width * pageWidthPx, "px"),
221
+ height: "".concat(displayMapping.height * pageHeightPx, "px")
222
+ };
223
+ var selectedStyle = isSelected ? {
224
+ borderColor: FORM_THEME_COLOR,
225
+ backgroundColor: FORM_THEME_BACKGROUND
226
+ } : {};
227
+ var textStyle = {
228
+ fontFamily: getFontStack(displayMapping.font),
229
+ fontSize: "".concat(displayMapping.fontSize * scale, "px"),
230
+ color: displayMapping.color,
231
+ fontWeight: displayMapping.bold ? 700 : 400,
232
+ fontStyle: displayMapping.italic ? "italic" : "normal",
233
+ textDecoration: displayMapping.underline ? "underline" : "none",
234
+ textAlign: displayMapping.align,
235
+ justifyContent: getJustifyContent(displayMapping.align)
236
+ };
237
+ var getResizePatch = function getResizePatch(_ref2) {
238
+ var drag = _ref2.drag,
239
+ dxFrac = _ref2.dxFrac,
240
+ dyFrac = _ref2.dyFrac;
241
+ var patch = {};
242
+ var originRight = drag.originX + drag.originWidth;
243
+ var originBottom = drag.originY + drag.originHeight;
244
+ if (drag.handle.x === "left") {
245
+ var x = clamp(drag.originX + dxFrac, 0, originRight - MIN_BOX.width);
246
+ patch.x = x;
247
+ patch.width = originRight - x;
248
+ } else {
249
+ patch.width = clamp(drag.originWidth + dxFrac, MIN_BOX.width, 1 - drag.originX);
250
+ }
251
+ if (drag.handle.y === "top") {
252
+ var y = clamp(drag.originY + dyFrac, 0, originBottom - MIN_BOX.height);
253
+ patch.y = y;
254
+ patch.height = originBottom - y;
255
+ } else {
256
+ patch.height = clamp(drag.originHeight + dyFrac, MIN_BOX.height, 1 - drag.originY);
257
+ }
258
+ return patch;
259
+ };
260
+ var handlePointerMove = function handlePointerMove(event) {
261
+ var drag = dragRef.current;
262
+ if (!drag) return;
263
+ var dxFrac = (event.clientX - drag.startX) / pageWidthPx;
264
+ var dyFrac = (event.clientY - drag.startY) / pageHeightPx;
265
+ var patch = drag.kind === DRAG_KINDS.MOVE ? {
266
+ x: clamp(drag.originX + dxFrac, 0, 1 - mapping.width),
267
+ y: clamp(drag.originY + dyFrac, 0, 1 - mapping.height)
268
+ } : getResizePatch({
269
+ drag: drag,
270
+ dxFrac: dxFrac,
271
+ dyFrac: dyFrac
272
+ });
273
+ draftPatchRef.current = patch;
274
+ setDraftPatch(patch);
275
+ };
276
+ var startDrag = function startDrag(event, kind) {
277
+ var handle = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
278
+ if (isPreview) return;
279
+ event.stopPropagation();
280
+ event.preventDefault();
281
+ onSelect(mapping.id);
282
+ event.currentTarget.setPointerCapture(event.pointerId);
283
+ dragRef.current = {
284
+ kind: kind,
285
+ handle: handle,
286
+ startX: event.clientX,
287
+ startY: event.clientY,
288
+ originX: mapping.x,
289
+ originY: mapping.y,
290
+ originWidth: mapping.width,
291
+ originHeight: mapping.height
292
+ };
293
+ draftPatchRef.current = null;
294
+ setDraftPatch(null);
295
+ };
296
+ var endDrag = function endDrag(event) {
297
+ var _event$currentTarget$, _event$currentTarget;
298
+ if (!dragRef.current) return;
299
+ (_event$currentTarget$ = (_event$currentTarget = event.currentTarget).releasePointerCapture) === null || _event$currentTarget$ === void 0 || _event$currentTarget$.call(_event$currentTarget, event.pointerId);
300
+ dragRef.current = null;
301
+ if (draftPatchRef.current) onChange(mapping.id, draftPatchRef.current);
302
+ draftPatchRef.current = null;
303
+ setDraftPatch(null);
304
+ };
305
+ var renderResizeHandle = function renderResizeHandle(handle) {
306
+ return /*#__PURE__*/jsx("span", {
307
+ style: {
308
+ backgroundColor: FORM_THEME_COLOR
309
+ },
310
+ className: classNames("rounded-full border-background absolute h-3 w-3 border-2", handle.className),
311
+ onPointerCancel: endDrag,
312
+ onPointerDown: function onPointerDown(event) {
313
+ return startDrag(event, DRAG_KINDS.RESIZE, handle);
314
+ },
315
+ onPointerMove: handlePointerMove,
316
+ onPointerUp: endDrag
317
+ }, handle.key);
318
+ };
319
+ if (isPreview) {
320
+ return /*#__PURE__*/jsx("div", {
321
+ style: style,
322
+ className: "pointer-events-none absolute flex items-center",
323
+ children: /*#__PURE__*/jsx("span", {
324
+ className: "w-full overflow-hidden leading-tight whitespace-pre-wrap",
325
+ style: textStyle,
326
+ children: previewValue
327
+ })
328
+ });
329
+ }
330
+ return /*#__PURE__*/jsxs("div", {
331
+ style: _objectSpread$3(_objectSpread$3({}, style), selectedStyle),
332
+ className: classNames("rounded-sm absolute flex cursor-move items-center border transition-colors select-none", {
333
+ "z-10": isSelected,
334
+ "border-border bg-opacity-40 bg-background border-dashed": !isSelected
335
+ }),
336
+ onPointerCancel: endDrag,
337
+ onPointerDown: function onPointerDown(event) {
338
+ return startDrag(event, DRAG_KINDS.MOVE);
339
+ },
340
+ onPointerMove: handlePointerMove,
341
+ onPointerUp: endDrag,
342
+ children: [/*#__PURE__*/jsx("span", {
343
+ className: "flex w-full items-center gap-1 overflow-hidden px-1 leading-tight",
344
+ style: textStyle,
345
+ children: /*#__PURE__*/jsx("span", {
346
+ className: "truncate",
347
+ children: displayMapping.label
348
+ })
349
+ }), isSelected && RESIZE_HANDLES.map(renderResizeHandle)]
350
+ });
351
+ };
352
+
353
+ var getRenderPixelRatio = function getRenderPixelRatio(viewport) {
354
+ var dpr = window.devicePixelRatio || 1;
355
+ var widthRatio = PDF_CANVAS.MAX_RENDER_SIZE / viewport.width;
356
+ var heightRatio = PDF_CANVAS.MAX_RENDER_SIZE / viewport.height;
357
+ var pixelRatio = Math.sqrt(PDF_CANVAS.MAX_RENDER_PIXELS / (viewport.width * viewport.height));
358
+ return Math.min(dpr, widthRatio, heightRatio, pixelRatio);
359
+ };
360
+ var PdfPage = function PdfPage(_ref) {
361
+ var pageDescriptor = _ref.pageDescriptor,
362
+ rawScale = _ref.scale,
363
+ mappings = _ref.mappings,
364
+ selectedId = _ref.selectedId,
365
+ mode = _ref.mode,
366
+ resolveValue = _ref.resolveValue,
367
+ onSelect = _ref.onSelect,
368
+ onChange = _ref.onChange,
369
+ onDropField = _ref.onDropField,
370
+ onScaleChange = _ref.onScaleChange;
371
+ var page = pageDescriptor.page,
372
+ pageNumber = pageDescriptor.pageNumber,
373
+ widthPt = pageDescriptor.widthPt,
374
+ heightPt = pageDescriptor.heightPt;
375
+ var canvasRef = useRef(null);
376
+ var overlayRef = useRef(null);
377
+ var scale = useMemo(function () {
378
+ return getPdfPageDisplayScale({
379
+ heightPt: heightPt,
380
+ rawScale: rawScale,
381
+ widthPt: widthPt
382
+ });
383
+ }, [heightPt, rawScale, widthPt]);
384
+ var defaultMappingScale = useMemo(function () {
385
+ return getPdfPageDisplayScale({
386
+ heightPt: heightPt,
387
+ rawScale: CSS_PX_PER_PT,
388
+ widthPt: widthPt
389
+ });
390
+ }, [heightPt, widthPt]);
391
+ var viewport = useMemo(function () {
392
+ return page.getViewport({
393
+ scale: scale
394
+ });
395
+ }, [page, scale]);
396
+ var pageWidthPx = viewport.width;
397
+ var pageHeightPx = viewport.height;
398
+ useEffect(function () {
399
+ onScaleChange(pageNumber, defaultMappingScale);
400
+ }, [defaultMappingScale, onScaleChange, pageNumber]);
401
+ useEffect(function () {
402
+ var canvas = canvasRef.current;
403
+ if (!canvas) return undefined;
404
+ var renderPixelRatio = getRenderPixelRatio(viewport);
405
+ canvas.width = Math.floor(viewport.width * renderPixelRatio);
406
+ canvas.height = Math.floor(viewport.height * renderPixelRatio);
407
+ canvas.style.width = "".concat(viewport.width, "px");
408
+ canvas.style.height = "".concat(viewport.height, "px");
409
+ var renderTask = page.render({
410
+ canvasContext: canvas.getContext("2d"),
411
+ viewport: viewport,
412
+ transform: renderPixelRatio !== 1 ? [renderPixelRatio, 0, 0, renderPixelRatio, 0, 0] : undefined
413
+ });
414
+ var render = /*#__PURE__*/function () {
415
+ var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
416
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
417
+ while (1) switch (_context.prev = _context.next) {
418
+ case 0:
419
+ _context.prev = 0;
420
+ _context.next = 3;
421
+ return renderTask.promise;
422
+ case 3:
423
+ _context.next = 7;
424
+ break;
425
+ case 5:
426
+ _context.prev = 5;
427
+ _context.t0 = _context["catch"](0);
428
+ case 7:
429
+ case "end":
430
+ return _context.stop();
431
+ }
432
+ }, _callee, null, [[0, 5]]);
433
+ }));
434
+ return function render() {
435
+ return _ref2.apply(this, arguments);
436
+ };
437
+ }();
438
+ render();
439
+ return function () {
440
+ return renderTask.cancel();
441
+ };
442
+ }, [page, scale, viewport]);
443
+ var handleDrop = function handleDrop(event) {
444
+ event.preventDefault();
445
+ var rect = overlayRef.current.getBoundingClientRect();
446
+ var xFrac = clamp((event.clientX - rect.left) / rect.width, 0, 1);
447
+ var yFrac = clamp((event.clientY - rect.top) / rect.height, 0, 1);
448
+ onDropField({
449
+ pageNumber: pageNumber,
450
+ scale: defaultMappingScale,
451
+ x: xFrac,
452
+ y: yFrac
453
+ });
454
+ };
455
+ var handleDragOver = function handleDragOver(event) {
456
+ event.preventDefault();
457
+ event.dataTransfer.dropEffect = "copy";
458
+ };
459
+ return /*#__PURE__*/jsxs("div", {
460
+ className: "shadow-md bg-background relative",
461
+ style: {
462
+ width: "".concat(pageWidthPx, "px"),
463
+ height: "".concat(pageHeightPx, "px")
464
+ },
465
+ children: [/*#__PURE__*/jsx("canvas", {
466
+ ref: canvasRef
467
+ }), /*#__PURE__*/jsx("div", {
468
+ className: "absolute inset-0",
469
+ ref: overlayRef,
470
+ onDragOver: handleDragOver,
471
+ onDrop: handleDrop,
472
+ onPointerDown: function onPointerDown() {
473
+ return onSelect(null);
474
+ },
475
+ children: mappings.map(function (mapping) {
476
+ return /*#__PURE__*/createElement(PlacedField, {
477
+ mapping: mapping,
478
+ mode: mode,
479
+ onChange: onChange,
480
+ onSelect: onSelect,
481
+ pageHeightPx: pageHeightPx,
482
+ pageWidthPx: pageWidthPx,
483
+ scale: scale,
484
+ isSelected: mapping.id === selectedId,
485
+ key: mapping.id,
486
+ previewValue: mode === EDITOR_MODES.PREVIEW ? resolveValue(mapping) : null
487
+ });
488
+ })
489
+ })]
490
+ });
491
+ };
492
+
493
+ // The worker is vendored into public/ (see the sync:pdf-worker script) so it is
494
+ // served as a static asset with a JS MIME type. pdf.js always loads it as a
495
+ // module worker. Its version must stay in sync with pdfjs-dist.
496
+ pdfjsLib.GlobalWorkerOptions.workerSrc = "/pdf.worker.min.js";
497
+
498
+ // Loads a PDF via pdf.js and returns one descriptor per page:
499
+ // { pageNumber, page (PDFPageProxy), widthPt, heightPt }. Dimensions are in PDF
500
+ // points (viewport scale 1), which the canvas scales by CSS_PX_PER_PT * zoom.
501
+ var usePdfDocument = function usePdfDocument(url) {
502
+ var _useState = useState(PDF_LOAD_INITIAL_STATE),
503
+ _useState2 = _slicedToArray(_useState, 2),
504
+ state = _useState2[0],
505
+ setState = _useState2[1];
506
+ useEffect(function () {
507
+ if (!url) return undefined;
508
+ var isCancelled = false;
509
+ var pdf;
510
+ setState(PDF_LOAD_INITIAL_STATE);
511
+ var loadingTask = pdfjsLib.getDocument({
512
+ url: url
513
+ });
514
+ var loadPages = /*#__PURE__*/function () {
515
+ var _ref = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
516
+ var pages, pageNumber, page, viewport;
517
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
518
+ while (1) switch (_context.prev = _context.next) {
519
+ case 0:
520
+ _context.prev = 0;
521
+ _context.next = 3;
522
+ return loadingTask.promise;
523
+ case 3:
524
+ pdf = _context.sent;
525
+ pages = [];
526
+ pageNumber = 1;
527
+ case 6:
528
+ if (!(pageNumber <= pdf.numPages)) {
529
+ _context.next = 15;
530
+ break;
531
+ }
532
+ _context.next = 9;
533
+ return pdf.getPage(pageNumber);
534
+ case 9:
535
+ page = _context.sent;
536
+ viewport = page.getViewport({
537
+ scale: 1
538
+ });
539
+ pages.push({
540
+ pageNumber: pageNumber,
541
+ page: page,
542
+ widthPt: viewport.width,
543
+ heightPt: viewport.height
544
+ });
545
+ case 12:
546
+ pageNumber += 1;
547
+ _context.next = 6;
548
+ break;
549
+ case 15:
550
+ if (!isCancelled) setState({
551
+ pages: pages,
552
+ isLoading: false,
553
+ error: null
554
+ });
555
+ _context.next = 21;
556
+ break;
557
+ case 18:
558
+ _context.prev = 18;
559
+ _context.t0 = _context["catch"](0);
560
+ if (!isCancelled) setState({
561
+ pages: [],
562
+ isLoading: false,
563
+ error: _context.t0
564
+ });
565
+ case 21:
566
+ case "end":
567
+ return _context.stop();
568
+ }
569
+ }, _callee, null, [[0, 18]]);
570
+ }));
571
+ return function loadPages() {
572
+ return _ref.apply(this, arguments);
573
+ };
574
+ }();
575
+ loadPages();
576
+ return function () {
577
+ var _loadingTask$destroy, _pdf, _pdf$destroy;
578
+ isCancelled = true;
579
+ (_loadingTask$destroy = loadingTask.destroy) === null || _loadingTask$destroy === void 0 || _loadingTask$destroy.call(loadingTask);
580
+ (_pdf = pdf) === null || _pdf === void 0 || (_pdf$destroy = _pdf.destroy) === null || _pdf$destroy === void 0 || _pdf$destroy.call(_pdf);
581
+ };
582
+ }, [url]);
583
+ return state;
584
+ };
585
+
586
+ var Canvas = function Canvas(_ref) {
587
+ var templateUrl = _ref.templateUrl,
588
+ zoom = _ref.zoom,
589
+ mappings = _ref.mappings,
590
+ selectedId = _ref.selectedId,
591
+ mode = _ref.mode,
592
+ resolveValue = _ref.resolveValue,
593
+ onSelect = _ref.onSelect,
594
+ onChange = _ref.onChange,
595
+ onDropField = _ref.onDropField,
596
+ onPageScaleChange = _ref.onPageScaleChange;
597
+ var _useTranslation = useTranslation(),
598
+ t = _useTranslation.t;
599
+ var _usePdfDocument = usePdfDocument(templateUrl),
600
+ pages = _usePdfDocument.pages,
601
+ isLoading = _usePdfDocument.isLoading,
602
+ error = _usePdfDocument.error;
603
+ var scale = CSS_PX_PER_PT * zoom;
604
+ var mappingsByPage = useMemo(function () {
605
+ return mappings.reduce(function (groupedMappings, mapping) {
606
+ var pageMappings = groupedMappings.get(mapping.page) || [];
607
+ pageMappings.push(mapping);
608
+ groupedMappings.set(mapping.page, pageMappings);
609
+ return groupedMappings;
610
+ }, new Map());
611
+ }, [mappings]);
612
+ if (isLoading) {
613
+ return /*#__PURE__*/jsx("div", {
614
+ className: "flex h-full w-full items-center justify-center",
615
+ children: /*#__PURE__*/jsx(Spinner, {})
616
+ });
617
+ }
618
+ if (error || !templateUrl) {
619
+ return /*#__PURE__*/jsx("div", {
620
+ className: "flex h-full w-full items-center justify-center p-8",
621
+ children: /*#__PURE__*/jsx(Typography, {
622
+ className: "text-muted-foreground",
623
+ variant: "body2",
624
+ children: t("neetoPdf.pdfDocuments.editor.renderError")
625
+ })
626
+ });
627
+ }
628
+ return /*#__PURE__*/jsx("div", {
629
+ className: "bg-muted absolute inset-0 overflow-auto",
630
+ children: /*#__PURE__*/jsx("div", {
631
+ className: "flex min-h-full min-w-full w-max flex-col items-center gap-6 p-8",
632
+ children: pages.map(function (pageDescriptor) {
633
+ return /*#__PURE__*/createElement(PdfPage, {
634
+ mode: mode,
635
+ onChange: onChange,
636
+ onDropField: onDropField,
637
+ onSelect: onSelect,
638
+ pageDescriptor: pageDescriptor,
639
+ resolveValue: resolveValue,
640
+ scale: scale,
641
+ selectedId: selectedId,
642
+ key: pageDescriptor.pageNumber,
643
+ mappings: mappingsByPage.get(pageDescriptor.pageNumber) || EMPTY_MAPPINGS,
644
+ onScaleChange: onPageScaleChange
645
+ });
646
+ })
647
+ })
648
+ });
649
+ };
650
+
651
+ var _excluded = ["isActive", "onClick", "className", "children"];
652
+ function ownKeys$2(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
653
+ function _objectSpread$2(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$2(Object(t), true).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$2(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
654
+ var ToggleButton = function ToggleButton(_ref) {
655
+ var isActive = _ref.isActive,
656
+ onClick = _ref.onClick,
657
+ className = _ref.className,
658
+ children = _ref.children,
659
+ rest = _objectWithoutProperties(_ref, _excluded);
660
+ return /*#__PURE__*/jsx("button", _objectSpread$2(_objectSpread$2({
661
+ onClick: onClick,
662
+ type: "button",
663
+ className: classNames("border-border flex h-8 items-center justify-center border text-sm first:rounded-l-md last:rounded-r-md", className, {
664
+ "bg-foreground text-background": isActive,
665
+ "bg-background text-foreground hover:bg-muted": !isActive
666
+ })
667
+ }, rest), {}, {
668
+ children: children
669
+ }));
670
+ };
671
+ var EmptyState = withT(function (_ref2) {
672
+ var t = _ref2.t;
673
+ return /*#__PURE__*/jsxs("div", {
674
+ className: "flex h-full flex-col items-center justify-center gap-2 p-8 text-center",
675
+ children: [/*#__PURE__*/jsx(Folder, {
676
+ className: "text-muted-foreground",
677
+ size: 32
678
+ }), /*#__PURE__*/jsx(Typography, {
679
+ variant: "body2",
680
+ weight: "medium",
681
+ children: t("neetoPdf.pdfDocuments.editor.field.emptyTitle")
682
+ }), /*#__PURE__*/jsx(Typography, {
683
+ className: "text-muted-foreground",
684
+ variant: "body3",
685
+ children: t("neetoPdf.pdfDocuments.editor.field.emptyDescription")
686
+ })]
687
+ });
688
+ });
689
+ var renderFontOptionLabel = function renderFontOptionLabel(_ref3) {
690
+ var label = _ref3.label,
691
+ stack = _ref3.stack;
692
+ return /*#__PURE__*/jsx("span", {
693
+ style: {
694
+ fontFamily: stack
695
+ },
696
+ children: label
697
+ });
698
+ };
699
+ var sanitizeFontSize = function sanitizeFontSize(value) {
700
+ var fontSize = Number(value);
701
+ if (Number.isNaN(fontSize)) return FONT_SIZE_LIMITS.min;
702
+ return Math.min(Math.max(fontSize, FONT_SIZE_LIMITS.min), FONT_SIZE_LIMITS.max);
703
+ };
704
+ var FieldPanel = withT(function (_ref4) {
705
+ var t = _ref4.t,
706
+ mapping = _ref4.mapping,
707
+ _onChange = _ref4.onChange,
708
+ onRemove = _ref4.onRemove;
709
+ return mapping ? /*#__PURE__*/jsxs("div", {
710
+ className: "border-border bg-background flex h-full w-72 shrink-0 flex-col overflow-y-auto border-l p-4",
711
+ children: [/*#__PURE__*/jsx("div", {
712
+ className: "mb-4 flex place-content-between items-center gap-2",
713
+ children: /*#__PURE__*/jsx(Typography, {
714
+ className: "truncate",
715
+ "data-testid": "field-header",
716
+ variant: "h3",
717
+ children: mapping.label
718
+ })
719
+ }), /*#__PURE__*/jsxs("div", {
720
+ className: "grow space-y-5",
721
+ children: [/*#__PURE__*/jsxs("div", {
722
+ className: "space-y-1",
723
+ children: [/*#__PURE__*/jsx(Typography, {
724
+ className: "text-foreground",
725
+ variant: "body3",
726
+ children: t("neetoPdf.pdfDocuments.editor.field.font")
727
+ }), /*#__PURE__*/jsx(Select, {
728
+ formatOptionLabel: renderFontOptionLabel,
729
+ isSearchable: false,
730
+ options: FONTS,
731
+ size: "small",
732
+ value: mapping.font,
733
+ onChange: function onChange(font) {
734
+ return _onChange(mapping.id, {
735
+ font: font
736
+ });
737
+ }
738
+ })]
739
+ }), /*#__PURE__*/jsxs("div", {
740
+ className: "flex gap-4",
741
+ children: [/*#__PURE__*/jsxs("div", {
742
+ className: "min-w-0 flex-1 space-y-1",
743
+ children: [/*#__PURE__*/jsx(Typography, {
744
+ className: "text-foreground",
745
+ variant: "body3",
746
+ children: t("neetoPdf.pdfDocuments.editor.field.size")
747
+ }), /*#__PURE__*/jsx(Input, {
748
+ max: FONT_SIZE_LIMITS.max,
749
+ min: FONT_SIZE_LIMITS.min,
750
+ size: "small",
751
+ type: "number",
752
+ value: mapping.fontSize,
753
+ onChange: function onChange(event) {
754
+ return _onChange(mapping.id, {
755
+ fontSize: sanitizeFontSize(event.target.value)
756
+ });
757
+ }
758
+ })]
759
+ }), /*#__PURE__*/jsxs("div", {
760
+ className: "space-y-1",
761
+ children: [/*#__PURE__*/jsx(Typography, {
762
+ className: "text-foreground",
763
+ variant: "body3",
764
+ children: t("neetoPdf.pdfDocuments.editor.field.format")
765
+ }), /*#__PURE__*/jsxs("div", {
766
+ className: "flex",
767
+ children: [/*#__PURE__*/jsx(ToggleButton, {
768
+ "aria-label": "bold",
769
+ className: "w-9",
770
+ isActive: mapping.bold,
771
+ onClick: function onClick() {
772
+ return _onChange(mapping.id, {
773
+ bold: !mapping.bold
774
+ });
775
+ },
776
+ children: /*#__PURE__*/jsx("span", {
777
+ className: "font-bold",
778
+ children: "B"
779
+ })
780
+ }), /*#__PURE__*/jsx(ToggleButton, {
781
+ "aria-label": "italic",
782
+ className: "w-9",
783
+ isActive: mapping.italic,
784
+ onClick: function onClick() {
785
+ return _onChange(mapping.id, {
786
+ italic: !mapping.italic
787
+ });
788
+ },
789
+ children: /*#__PURE__*/jsx("span", {
790
+ className: "italic",
791
+ children: "I"
792
+ })
793
+ }), /*#__PURE__*/jsx(ToggleButton, {
794
+ "aria-label": "underline",
795
+ className: "w-9",
796
+ isActive: mapping.underline,
797
+ onClick: function onClick() {
798
+ return _onChange(mapping.id, {
799
+ underline: !mapping.underline
800
+ });
801
+ },
802
+ children: /*#__PURE__*/jsx("span", {
803
+ className: "underline",
804
+ children: "U"
805
+ })
806
+ })]
807
+ })]
808
+ })]
809
+ }), /*#__PURE__*/jsxs("div", {
810
+ className: "space-y-1",
811
+ children: [/*#__PURE__*/jsx(Typography, {
812
+ className: "text-foreground",
813
+ variant: "body3",
814
+ children: t("neetoPdf.pdfDocuments.editor.field.fontColor")
815
+ }), /*#__PURE__*/jsx(ColorPicker, {
816
+ showHexValue: true,
817
+ color: mapping.color,
818
+ size: "small",
819
+ onChange: function onChange(_ref5) {
820
+ var hex = _ref5.hex;
821
+ return _onChange(mapping.id, {
822
+ color: hex
823
+ });
824
+ }
825
+ })]
826
+ }), /*#__PURE__*/jsxs("div", {
827
+ className: "space-y-1",
828
+ children: [/*#__PURE__*/jsx(Typography, {
829
+ className: "text-foreground",
830
+ variant: "body3",
831
+ children: t("neetoPdf.pdfDocuments.editor.field.alignment")
832
+ }), /*#__PURE__*/jsxs("div", {
833
+ className: "flex w-full",
834
+ children: [/*#__PURE__*/jsx(ToggleButton, {
835
+ "aria-label": "align-left",
836
+ className: "flex-1",
837
+ isActive: mapping.align === ALIGNMENTS.LEFT,
838
+ onClick: function onClick() {
839
+ return _onChange(mapping.id, {
840
+ align: ALIGNMENTS.LEFT
841
+ });
842
+ },
843
+ children: /*#__PURE__*/jsx(LeftAlign, {
844
+ size: 16
845
+ })
846
+ }), /*#__PURE__*/jsx(ToggleButton, {
847
+ "aria-label": "align-center",
848
+ className: "flex-1",
849
+ isActive: mapping.align === ALIGNMENTS.CENTER,
850
+ onClick: function onClick() {
851
+ return _onChange(mapping.id, {
852
+ align: ALIGNMENTS.CENTER
853
+ });
854
+ },
855
+ children: /*#__PURE__*/jsx(CenterAlign, {
856
+ size: 16
857
+ })
858
+ }), /*#__PURE__*/jsx(ToggleButton, {
859
+ "aria-label": "align-right",
860
+ className: "flex-1",
861
+ isActive: mapping.align === ALIGNMENTS.RIGHT,
862
+ onClick: function onClick() {
863
+ return _onChange(mapping.id, {
864
+ align: ALIGNMENTS.RIGHT
865
+ });
866
+ },
867
+ children: /*#__PURE__*/jsx(RightAlign, {
868
+ size: 16
869
+ })
870
+ })]
871
+ })]
872
+ })]
873
+ }), /*#__PURE__*/jsx(Button, {
874
+ fullWidth: true,
875
+ className: "mt-4",
876
+ icon: Delete,
877
+ label: t("neetoPdf.pdfDocuments.editor.field.remove"),
878
+ variant: "destructive",
879
+ onClick: function onClick() {
880
+ return onRemove(mapping.id);
881
+ }
882
+ })]
883
+ }) : /*#__PURE__*/jsx("div", {
884
+ className: "border-border bg-background flex h-full w-72 shrink-0 flex-col border-l",
885
+ children: /*#__PURE__*/jsx(EmptyState, {})
886
+ });
887
+ });
888
+
889
+ var FieldCard = function FieldCard(_ref) {
890
+ var field = _ref.field,
891
+ onPlace = _ref.onPlace,
892
+ onDragStart = _ref.onDragStart,
893
+ onDragEnd = _ref.onDragEnd;
894
+ var Icon = field.icon;
895
+ var handleDragStart = function handleDragStart(event) {
896
+ event.dataTransfer.effectAllowed = "copy";
897
+ event.dataTransfer.setData("text/plain", field.key);
898
+ onDragStart(field);
899
+ };
900
+ return /*#__PURE__*/jsxs("div", {
901
+ onDragEnd: onDragEnd,
902
+ draggable: true,
903
+ className: "border-border bg-background hover:bg-muted rounded-lg relative mb-2 flex h-10 cursor-pointer items-center gap-2 border p-3 transition-all duration-300 ease-in-out",
904
+ "data-testid": "add-".concat(field.key, "-field"),
905
+ onClick: function onClick() {
906
+ return onPlace(field);
907
+ },
908
+ onDragStart: handleDragStart,
909
+ children: [/*#__PURE__*/jsx("span", {
910
+ className: "absolute end-full top-1/2 me-0.5 flex-shrink-0 -translate-y-1/2 cursor-grab",
911
+ "data-testid": "drag-handle",
912
+ children: /*#__PURE__*/jsx(Drag, {
913
+ className: "text-muted-foreground hover:text-muted-foreground transition-all duration-300 ease-in-out",
914
+ size: 16
915
+ })
916
+ }), /*#__PURE__*/jsxs("div", {
917
+ className: "flex flex-grow items-center gap-2 overflow-hidden",
918
+ children: [Icon && /*#__PURE__*/jsx("div", {
919
+ className: "flex-shrink-0",
920
+ children: /*#__PURE__*/jsx(Icon, {})
921
+ }), /*#__PURE__*/jsx(Typography, {
922
+ className: "truncate leading-4",
923
+ variant: "body2",
924
+ children: field.label
925
+ })]
926
+ })]
927
+ });
928
+ };
929
+
930
+ var Section = function Section(_ref) {
931
+ var title = _ref.title,
932
+ children = _ref.children;
933
+ if (!(children !== null && children !== void 0 && children.length)) return null;
934
+ return /*#__PURE__*/jsxs(Fragment, {
935
+ children: [/*#__PURE__*/jsx(Typography, {
936
+ className: "mt-1 mb-3",
937
+ variant: "h3",
938
+ children: title
939
+ }), children]
940
+ });
941
+ };
942
+ var FieldsPanel = function FieldsPanel(_ref2) {
943
+ var answerFields = _ref2.answerFields,
944
+ systemFields = _ref2.systemFields,
945
+ onPlace = _ref2.onPlace,
946
+ onDragStartField = _ref2.onDragStartField,
947
+ onDragEndField = _ref2.onDragEndField;
948
+ var _useTranslation = useTranslation(),
949
+ t = _useTranslation.t;
950
+ var _useState = useState(""),
951
+ _useState2 = _slicedToArray(_useState, 2),
952
+ searchTerm = _useState2[0],
953
+ setSearchTerm = _useState2[1];
954
+ var query = searchTerm.trim().toLowerCase();
955
+ var matches = function matches(field) {
956
+ return field.label.toLowerCase().includes(query);
957
+ };
958
+ var filteredAnswers = query ? answerFields.filter(matches) : answerFields;
959
+ var filteredSystem = query ? systemFields.filter(matches) : systemFields;
960
+ var renderField = function renderField(field) {
961
+ return /*#__PURE__*/createElement(FieldCard, {
962
+ field: field,
963
+ onPlace: onPlace,
964
+ key: "".concat(field.source, "-").concat(field.key),
965
+ onDragEnd: onDragEndField,
966
+ onDragStart: onDragStartField
967
+ });
968
+ };
969
+ return /*#__PURE__*/jsxs("div", {
970
+ className: "border-border bg-muted flex h-full w-[360px] shrink-0 flex-col border-r",
971
+ children: [/*#__PURE__*/jsx("div", {
972
+ className: "p-6 pb-1",
973
+ children: /*#__PURE__*/jsx(Typography, {
974
+ lineHeight: "normal",
975
+ variant: "h3",
976
+ weight: "semibold",
977
+ children: t("neetoPdf.pdfDocuments.editor.addNewElement")
978
+ })
979
+ }), /*#__PURE__*/jsxs("div", {
980
+ className: "mb-1 px-6",
981
+ children: [/*#__PURE__*/jsx(Typography, {
982
+ className: "mb-3",
983
+ variant: "body3",
984
+ children: t("neetoPdf.pdfDocuments.editor.addNewElementDescription")
985
+ }), /*#__PURE__*/jsx(Input, {
986
+ autoFocus: true,
987
+ "data-testid": "elements-panel-search-field",
988
+ placeholder: t("neetoPdf.pdfDocuments.editor.searchElements"),
989
+ prefix: /*#__PURE__*/jsx(Search, {}),
990
+ type: "search",
991
+ value: searchTerm,
992
+ onChange: function onChange(event) {
993
+ return setSearchTerm(event.target.value);
994
+ }
995
+ })]
996
+ }), /*#__PURE__*/jsxs("div", {
997
+ className: "grow overflow-y-auto px-6 pb-2",
998
+ "data-testid": "elements-container",
999
+ children: [/*#__PURE__*/jsx(Section, {
1000
+ title: t("neetoPdf.pdfDocuments.editor.answers"),
1001
+ children: filteredAnswers.map(renderField)
1002
+ }), /*#__PURE__*/jsx(Section, {
1003
+ title: t("neetoPdf.pdfDocuments.editor.system"),
1004
+ children: filteredSystem.map(renderField)
1005
+ }), filteredAnswers.length === 0 && filteredSystem.length === 0 ? /*#__PURE__*/jsx(Typography, {
1006
+ className: "text-foreground text-md flex h-full items-center justify-center",
1007
+ weight: "bold",
1008
+ children: t("neetoPdf.pdfDocuments.editor.noFields")
1009
+ }) : null]
1010
+ })]
1011
+ });
1012
+ };
1013
+
1014
+ // pdf-lib StandardFonts only support WinAnsi encoding and single-line text, so
1015
+ // collapse whitespace and drop characters they cannot encode.
1016
+ var sanitizeForPdf = function sanitizeForPdf(text) {
1017
+ return text.replace(/\s+/g, " ").trim().replace(/[^\x20-\x7E\xA0-\xFF]/g, "").trim();
1018
+ };
1019
+ var hexToRgbComponents = function hexToRgbComponents(hex) {
1020
+ var value = (hex || DEFAULT_STYLE.color).replace("#", "");
1021
+ var full = value.length === 3 ? value.split("").map(function (_char) {
1022
+ return _char + _char;
1023
+ }).join("") : value;
1024
+ var _int = parseInt(full, 16);
1025
+ return {
1026
+ r: (_int >> 16 & 255) / 255,
1027
+ g: (_int >> 8 & 255) / 255,
1028
+ b: (_int & 255) / 255
1029
+ };
1030
+ };
1031
+ var standardFontName = function standardFontName(font, bold, italic) {
1032
+ var variants = STANDARD_FONT_VARIANTS[font] || STANDARD_FONT_VARIANTS.Helvetica;
1033
+ return variants[(bold ? 1 : 0) + (italic ? 2 : 0)];
1034
+ };
1035
+ var triggerBlobDownload = function triggerBlobDownload(bytes, fileName) {
1036
+ var blob = new Blob([bytes], {
1037
+ type: "application/pdf"
1038
+ });
1039
+ var url = URL.createObjectURL(blob);
1040
+ var link = window.document.createElement("a");
1041
+ link.href = url;
1042
+ link.download = fileName;
1043
+ window.document.body.appendChild(link);
1044
+ link.click();
1045
+ link.remove();
1046
+ URL.revokeObjectURL(url);
1047
+ };
1048
+
1049
+ // Stamp the resolved values for one submission onto the template PDF (client
1050
+ // side, via pdf-lib) and trigger a browser download. pdf-lib is imported lazily
1051
+ // so it only loads on the first download.
1052
+ var downloadFilledPdf = /*#__PURE__*/function () {
1053
+ var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2(_ref) {
1054
+ var templateUrl, mappings, valueFor, fileName, pdfLibModule, PDFDocument, StandardFonts, rgb, response, bytes, pdfDoc, pages, fontNames, embeddedFonts;
1055
+ return _regeneratorRuntime.wrap(function _callee2$(_context2) {
1056
+ while (1) switch (_context2.prev = _context2.next) {
1057
+ case 0:
1058
+ templateUrl = _ref.templateUrl, mappings = _ref.mappings, valueFor = _ref.valueFor, fileName = _ref.fileName;
1059
+ _context2.next = 3;
1060
+ return import('pdf-lib');
1061
+ case 3:
1062
+ pdfLibModule = _context2.sent;
1063
+ PDFDocument = pdfLibModule.PDFDocument, StandardFonts = pdfLibModule.StandardFonts, rgb = pdfLibModule.rgb;
1064
+ _context2.next = 7;
1065
+ return fetch(templateUrl);
1066
+ case 7:
1067
+ response = _context2.sent;
1068
+ if (response.ok) {
1069
+ _context2.next = 10;
1070
+ break;
1071
+ }
1072
+ throw new Error("Failed to fetch template PDF (".concat(response.status, ")"));
1073
+ case 10:
1074
+ _context2.next = 12;
1075
+ return response.arrayBuffer();
1076
+ case 12:
1077
+ bytes = _context2.sent;
1078
+ _context2.next = 15;
1079
+ return PDFDocument.load(bytes, {
1080
+ ignoreEncryption: true
1081
+ });
1082
+ case 15:
1083
+ pdfDoc = _context2.sent;
1084
+ pages = pdfDoc.getPages();
1085
+ fontNames = _toConsumableArray(new Set(mappings.map(function (mapping) {
1086
+ return standardFontName(mapping.font, mapping.bold, mapping.italic);
1087
+ })));
1088
+ _context2.t0 = Object;
1089
+ _context2.next = 21;
1090
+ return Promise.all(fontNames.map(/*#__PURE__*/function () {
1091
+ var _ref3 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee(name) {
1092
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
1093
+ while (1) switch (_context.prev = _context.next) {
1094
+ case 0:
1095
+ _context.t0 = name;
1096
+ _context.next = 3;
1097
+ return pdfDoc.embedFont(StandardFonts[name]);
1098
+ case 3:
1099
+ _context.t1 = _context.sent;
1100
+ return _context.abrupt("return", [_context.t0, _context.t1]);
1101
+ case 5:
1102
+ case "end":
1103
+ return _context.stop();
1104
+ }
1105
+ }, _callee);
1106
+ }));
1107
+ return function (_x2) {
1108
+ return _ref3.apply(this, arguments);
1109
+ };
1110
+ }()));
1111
+ case 21:
1112
+ _context2.t1 = _context2.sent;
1113
+ embeddedFonts = _context2.t0.fromEntries.call(_context2.t0, _context2.t1);
1114
+ mappings.forEach(function (mapping) {
1115
+ var page = pages[mapping.page - 1];
1116
+ if (!page) return;
1117
+ var text = sanitizeForPdf(valueFor(mapping) || "");
1118
+ if (!text) return;
1119
+ var _page$getSize = page.getSize(),
1120
+ pageWidth = _page$getSize.width,
1121
+ pageHeight = _page$getSize.height;
1122
+ var font = embeddedFonts[standardFontName(mapping.font, mapping.bold, mapping.italic)];
1123
+ var size = mapping.fontSize;
1124
+ var _hexToRgbComponents = hexToRgbComponents(mapping.color),
1125
+ r = _hexToRgbComponents.r,
1126
+ g = _hexToRgbComponents.g,
1127
+ b = _hexToRgbComponents.b;
1128
+ var color = rgb(r, g, b);
1129
+ var boxLeft = mapping.x * pageWidth;
1130
+ var boxWidth = mapping.width * pageWidth;
1131
+ var textWidth = font.widthOfTextAtSize(text, size);
1132
+ var x = boxLeft;
1133
+ if (mapping.align === "center") x = boxLeft + (boxWidth - textWidth) / 2;else if (mapping.align === "right") x = boxLeft + boxWidth - textWidth;
1134
+ var y = pageHeight - mapping.y * pageHeight - size;
1135
+ page.drawText(text, {
1136
+ x: x,
1137
+ y: y,
1138
+ size: size,
1139
+ font: font,
1140
+ color: color
1141
+ });
1142
+ if (mapping.underline) {
1143
+ var lineY = y - size * 0.1;
1144
+ page.drawLine({
1145
+ start: {
1146
+ x: x,
1147
+ y: lineY
1148
+ },
1149
+ end: {
1150
+ x: x + textWidth,
1151
+ y: lineY
1152
+ },
1153
+ thickness: Math.max(0.5, size * 0.06),
1154
+ color: color
1155
+ });
1156
+ }
1157
+ });
1158
+ _context2.t2 = triggerBlobDownload;
1159
+ _context2.next = 27;
1160
+ return pdfDoc.save();
1161
+ case 27:
1162
+ _context2.t3 = _context2.sent;
1163
+ _context2.t4 = fileName;
1164
+ (0, _context2.t2)(_context2.t3, _context2.t4);
1165
+ case 30:
1166
+ case "end":
1167
+ return _context2.stop();
1168
+ }
1169
+ }, _callee2);
1170
+ }));
1171
+ return function downloadFilledPdf(_x) {
1172
+ return _ref2.apply(this, arguments);
1173
+ };
1174
+ }();
1175
+
1176
+ var usePdfDownload = function usePdfDownload(_ref) {
1177
+ var mappings = _ref.mappings,
1178
+ pdfDocument = _ref.pdfDocument,
1179
+ previewRecord = _ref.previewRecord,
1180
+ resolveValue = _ref.resolveValue,
1181
+ t = _ref.t;
1182
+ var _useState = useState(false),
1183
+ _useState2 = _slicedToArray(_useState, 2),
1184
+ isDownloading = _useState2[0],
1185
+ setIsDownloading = _useState2[1];
1186
+ var downloadPdf = /*#__PURE__*/function () {
1187
+ var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
1188
+ var _pdfDocument$template;
1189
+ var templateUrl;
1190
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
1191
+ while (1) switch (_context.prev = _context.next) {
1192
+ case 0:
1193
+ templateUrl = pdfDocument === null || pdfDocument === void 0 || (_pdfDocument$template = pdfDocument.templateFile) === null || _pdfDocument$template === void 0 ? void 0 : _pdfDocument$template.url;
1194
+ if (!(!templateUrl || !previewRecord)) {
1195
+ _context.next = 3;
1196
+ break;
1197
+ }
1198
+ return _context.abrupt("return");
1199
+ case 3:
1200
+ setIsDownloading(true);
1201
+ _context.prev = 4;
1202
+ _context.next = 7;
1203
+ return downloadFilledPdf({
1204
+ templateUrl: templateUrl,
1205
+ mappings: mappings,
1206
+ valueFor: resolveValue,
1207
+ fileName: buildOutputFilename(pdfDocument, previewRecord)
1208
+ });
1209
+ case 7:
1210
+ _context.next = 13;
1211
+ break;
1212
+ case 9:
1213
+ _context.prev = 9;
1214
+ _context.t0 = _context["catch"](4);
1215
+ logger.error(_context.t0);
1216
+ Toastr.error(t("neetoPdf.pdfDocuments.editor.downloadError"));
1217
+ case 13:
1218
+ _context.prev = 13;
1219
+ setIsDownloading(false);
1220
+ return _context.finish(13);
1221
+ case 16:
1222
+ case "end":
1223
+ return _context.stop();
1224
+ }
1225
+ }, _callee, null, [[4, 9, 13, 16]]);
1226
+ }));
1227
+ return function downloadPdf() {
1228
+ return _ref2.apply(this, arguments);
1229
+ };
1230
+ }();
1231
+ return {
1232
+ downloadPdf: downloadPdf,
1233
+ isDownloading: isDownloading
1234
+ };
1235
+ };
1236
+
1237
+ var usePdfEditorDocument = function usePdfEditorDocument(_ref) {
1238
+ var _pdfDocument$template;
1239
+ var apiBaseUrl = _ref.apiBaseUrl,
1240
+ documentId = _ref.documentId,
1241
+ ownerId = _ref.ownerId,
1242
+ t = _ref.t;
1243
+ var _useFetchPdfDocument = useFetchPdfDocument({
1244
+ apiBaseUrl: apiBaseUrl,
1245
+ ownerId: ownerId,
1246
+ documentId: documentId
1247
+ }),
1248
+ documentResponse = _useFetchPdfDocument.data,
1249
+ isDocumentLoading = _useFetchPdfDocument.isLoading;
1250
+ var pdfDocument = documentResponse === null || documentResponse === void 0 ? void 0 : documentResponse.document;
1251
+ var _useUpdatePdfDocument = useUpdatePdfDocument({
1252
+ apiBaseUrl: apiBaseUrl,
1253
+ ownerId: ownerId,
1254
+ options: {
1255
+ onSuccess: function onSuccess() {
1256
+ return Toastr.success(t("neetoPdf.pdfDocuments.editor.saveSuccess"));
1257
+ },
1258
+ onError: function onError(error) {
1259
+ return Toastr.error(getPdfDocumentApiErrorMessage(error, t("neetoPdf.pdfDocuments.editor.saveError")));
1260
+ }
1261
+ }
1262
+ }),
1263
+ saveMappings = _useUpdatePdfDocument.mutate,
1264
+ isSaving = _useUpdatePdfDocument.isPending;
1265
+ var _useUpdatePdfDocument2 = useUpdatePdfDocument({
1266
+ apiBaseUrl: apiBaseUrl,
1267
+ ownerId: ownerId,
1268
+ options: {
1269
+ onSuccess: function onSuccess() {
1270
+ return Toastr.success(t("neetoPdf.pdfDocuments.rename.success"));
1271
+ },
1272
+ onError: function onError(error) {
1273
+ return Toastr.error(getPdfDocumentApiErrorMessage(error, t("neetoPdf.pdfDocuments.rename.error")));
1274
+ }
1275
+ }
1276
+ }),
1277
+ renameDocument = _useUpdatePdfDocument2.mutate;
1278
+ var saveDocumentMappings = function saveDocumentMappings(_ref2) {
1279
+ var mappings = _ref2.mappings,
1280
+ onSuccess = _ref2.onSuccess;
1281
+ saveMappings({
1282
+ documentId: documentId,
1283
+ payload: {
1284
+ mappings: mappings
1285
+ }
1286
+ }, {
1287
+ onSuccess: onSuccess
1288
+ });
1289
+ };
1290
+ var renamePdfDocument = function renamePdfDocument(name) {
1291
+ var trimmedName = name.trim();
1292
+ renameDocument({
1293
+ documentId: documentId,
1294
+ payload: {
1295
+ name: trimmedName,
1296
+ outputFilename: buildOutputFilenameTemplate(trimmedName)
1297
+ }
1298
+ });
1299
+ };
1300
+ return {
1301
+ documentName: (pdfDocument === null || pdfDocument === void 0 ? void 0 : pdfDocument.name) || "",
1302
+ isDocumentLoading: isDocumentLoading,
1303
+ isSaving: isSaving,
1304
+ pdfDocument: pdfDocument,
1305
+ renamePdfDocument: renamePdfDocument,
1306
+ saveDocumentMappings: saveDocumentMappings,
1307
+ templateUrl: pdfDocument === null || pdfDocument === void 0 || (_pdfDocument$template = pdfDocument.templateFile) === null || _pdfDocument$template === void 0 ? void 0 : _pdfDocument$template.url
1308
+ };
1309
+ };
1310
+
1311
+ function ownKeys$1(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
1312
+ function _objectSpread$1(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$1(Object(t), true).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$1(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
1313
+ var htmlToPlainText = function htmlToPlainText(value) {
1314
+ var element = window.document.createElement("div");
1315
+ element.innerHTML = value || "";
1316
+ return element.textContent || element.innerText || "";
1317
+ };
1318
+ var generateId = function generateId() {
1319
+ var _window$crypto, _window$crypto$random;
1320
+ return ((_window$crypto = window.crypto) === null || _window$crypto === void 0 || (_window$crypto$random = _window$crypto.randomUUID) === null || _window$crypto$random === void 0 ? void 0 : _window$crypto$random.call(_window$crypto)) || "".concat(Date.now(), "-").concat(Math.random());
1321
+ };
1322
+
1323
+ // Turn the form's records into the "Answers" list shown in the left panel.
1324
+ var buildAnswerFields = function buildAnswerFields() {
1325
+ var fields = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
1326
+ return fields.filter(function (field) {
1327
+ return field;
1328
+ }).map(function (field) {
1329
+ return {
1330
+ source: FIELD_SOURCES.ANSWER,
1331
+ key: field.key || field.slug,
1332
+ recordId: field.recordId || field.id || null,
1333
+ slug: field.slug || field.key,
1334
+ label: htmlToPlainText(field.label || ""),
1335
+ kind: field.kind,
1336
+ icon: field.icon,
1337
+ typeLabel: field.typeLabel || field.kind || ""
1338
+ };
1339
+ });
1340
+ };
1341
+ var buildMapping = function buildMapping(_ref) {
1342
+ var _field$recordId;
1343
+ var field = _ref.field,
1344
+ page = _ref.page,
1345
+ scale = _ref.scale;
1346
+ return _objectSpread$1(_objectSpread$1(_objectSpread$1({
1347
+ id: generateId(),
1348
+ source: field.source,
1349
+ fieldSlug: field.key,
1350
+ recordId: (_field$recordId = field.recordId) !== null && _field$recordId !== void 0 ? _field$recordId : null,
1351
+ label: field.label,
1352
+ kind: field.kind,
1353
+ page: page
1354
+ }, DEFAULT_BOX), DEFAULT_STYLE), {}, {
1355
+ fontSize: getDefaultFontSizeForScale(scale)
1356
+ });
1357
+ };
1358
+
1359
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
1360
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), true).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
1361
+ var usePdfMappingsState = function usePdfMappingsState(_ref) {
1362
+ var documentId = _ref.documentId,
1363
+ pdfDocument = _ref.pdfDocument;
1364
+ var _useState = useState([]),
1365
+ _useState2 = _slicedToArray(_useState, 2),
1366
+ mappings = _useState2[0],
1367
+ setMappings = _useState2[1];
1368
+ var _useState3 = useState(null),
1369
+ _useState4 = _slicedToArray(_useState3, 2),
1370
+ selectedId = _useState4[0],
1371
+ setSelectedId = _useState4[1];
1372
+ var _useState5 = useState(function () {
1373
+ return new Map();
1374
+ }),
1375
+ _useState6 = _slicedToArray(_useState5, 2),
1376
+ pageScales = _useState6[0],
1377
+ setPageScales = _useState6[1];
1378
+ var _useState7 = useState(false),
1379
+ _useState8 = _slicedToArray(_useState7, 2),
1380
+ isDirty = _useState8[0],
1381
+ setIsDirty = _useState8[1];
1382
+ var draggedFieldRef = useRef(null);
1383
+ var initializedRef = useRef(null);
1384
+ useEffect(function () {
1385
+ if (!(pdfDocument && initializedRef.current !== documentId)) return;
1386
+ initializedRef.current = documentId;
1387
+ setMappings(pdfDocument.mappings || []);
1388
+ setIsDirty(false);
1389
+ }, [pdfDocument, documentId]);
1390
+ var selectedMapping = findById(selectedId, mappings) || null;
1391
+ var mutateMappings = function mutateMappings(updater) {
1392
+ setMappings(updater);
1393
+ setIsDirty(true);
1394
+ };
1395
+ var handleAddField = function handleAddField(field) {
1396
+ var mapping = buildMapping({
1397
+ field: field,
1398
+ page: 1,
1399
+ scale: pageScales.get(1)
1400
+ });
1401
+ mutateMappings(append(mapping));
1402
+ setSelectedId(mapping.id);
1403
+ };
1404
+ var handleDropField = function handleDropField(_ref2) {
1405
+ var pageNumber = _ref2.pageNumber,
1406
+ scale = _ref2.scale,
1407
+ x = _ref2.x,
1408
+ y = _ref2.y;
1409
+ var field = draggedFieldRef.current;
1410
+ if (!field) return;
1411
+ var mapping = _objectSpread(_objectSpread({}, buildMapping({
1412
+ field: field,
1413
+ page: pageNumber,
1414
+ scale: scale
1415
+ })), {}, {
1416
+ x: clamp(x, 0, 1 - DEFAULT_BOX.width),
1417
+ y: clamp(y, 0, 1 - DEFAULT_BOX.height)
1418
+ });
1419
+ mutateMappings(append(mapping));
1420
+ setSelectedId(mapping.id);
1421
+ };
1422
+ var handleChangeMapping = function handleChangeMapping(id, patch) {
1423
+ return mutateMappings(function (prev) {
1424
+ return prev.map(function (mapping) {
1425
+ return mapping.id === id ? _objectSpread(_objectSpread({}, mapping), patch) : mapping;
1426
+ });
1427
+ });
1428
+ };
1429
+ var handlePageScaleChange = function handlePageScaleChange(pageNumber, scale) {
1430
+ setPageScales(function (prev) {
1431
+ if (prev.get(pageNumber) === scale) return prev;
1432
+ var nextPageScales = new Map(prev);
1433
+ nextPageScales.set(pageNumber, scale);
1434
+ return nextPageScales;
1435
+ });
1436
+ };
1437
+ var handleRemoveMapping = function handleRemoveMapping(id) {
1438
+ mutateMappings(function (prev) {
1439
+ return removeById(id, prev);
1440
+ });
1441
+ setSelectedId(function (current) {
1442
+ return current === id ? null : current;
1443
+ });
1444
+ };
1445
+ var handleDragEndField = function handleDragEndField() {
1446
+ draggedFieldRef.current = null;
1447
+ };
1448
+ var handleDragStartField = function handleDragStartField(field) {
1449
+ draggedFieldRef.current = field;
1450
+ };
1451
+ return {
1452
+ handleAddField: handleAddField,
1453
+ handleChangeMapping: handleChangeMapping,
1454
+ handleDragEndField: handleDragEndField,
1455
+ handleDragStartField: handleDragStartField,
1456
+ handleDropField: handleDropField,
1457
+ handlePageScaleChange: handlePageScaleChange,
1458
+ handleRemoveMapping: handleRemoveMapping,
1459
+ isDirty: isDirty,
1460
+ mappings: mappings,
1461
+ selectedId: selectedId,
1462
+ selectedMapping: selectedMapping,
1463
+ setIsDirty: setIsDirty,
1464
+ setSelectedId: setSelectedId
1465
+ };
1466
+ };
1467
+
1468
+ var usePreviewPagination = function usePreviewPagination(_ref) {
1469
+ var controlledMode = _ref.controlledMode,
1470
+ onModeChange = _ref.onModeChange,
1471
+ onPreviewPageChange = _ref.onPreviewPageChange,
1472
+ previewPage = _ref.previewPage,
1473
+ setSelectedId = _ref.setSelectedId;
1474
+ var _useState = useState(previewPage),
1475
+ _useState2 = _slicedToArray(_useState, 2),
1476
+ localPreviewPage = _useState2[0],
1477
+ setLocalPreviewPage = _useState2[1];
1478
+ var _useState3 = useState(EDITOR_MODES.MAP),
1479
+ _useState4 = _slicedToArray(_useState3, 2),
1480
+ localMode = _useState4[0],
1481
+ setLocalMode = _useState4[1];
1482
+ var mode = controlledMode || localMode;
1483
+ var isPreview = mode === EDITOR_MODES.PREVIEW;
1484
+ var currentPreviewPage = onPreviewPageChange ? previewPage : localPreviewPage;
1485
+ useEffect(function () {
1486
+ if (!isPreview) return;
1487
+ setSelectedId(null);
1488
+ setLocalPreviewPage(1);
1489
+ onPreviewPageChange === null || onPreviewPageChange === void 0 || onPreviewPageChange(1);
1490
+ }, [isPreview, onPreviewPageChange, setSelectedId]);
1491
+ var setPreviewPage = function setPreviewPage(page) {
1492
+ setLocalPreviewPage(page);
1493
+ onPreviewPageChange === null || onPreviewPageChange === void 0 || onPreviewPageChange(page);
1494
+ };
1495
+ var handleModeChange = function handleModeChange(nextMode) {
1496
+ setLocalMode(nextMode);
1497
+ onModeChange === null || onModeChange === void 0 || onModeChange(nextMode);
1498
+ };
1499
+ return {
1500
+ currentPreviewPage: currentPreviewPage,
1501
+ handleModeChange: handleModeChange,
1502
+ isPreview: isPreview,
1503
+ mode: mode,
1504
+ setPreviewPage: setPreviewPage
1505
+ };
1506
+ };
1507
+
1508
+ var PreviewPager = function PreviewPager(_ref) {
1509
+ var page = _ref.page,
1510
+ total = _ref.total,
1511
+ isLoading = _ref.isLoading,
1512
+ onPrev = _ref.onPrev,
1513
+ onNext = _ref.onNext;
1514
+ var _useTranslation = useTranslation(),
1515
+ t = _useTranslation.t;
1516
+ if (!isLoading && total === 0) {
1517
+ return /*#__PURE__*/jsx("div", {
1518
+ className: "border-border bg-background shadow-md rounded-lg border px-3 py-1.5",
1519
+ children: /*#__PURE__*/jsx(Typography, {
1520
+ className: "text-muted-foreground",
1521
+ variant: "body3",
1522
+ children: t("neetoPdf.pdfDocuments.editor.preview.noSubmissions")
1523
+ })
1524
+ });
1525
+ }
1526
+ return /*#__PURE__*/jsxs("div", {
1527
+ className: "border-border bg-background shadow-md rounded-lg flex items-center gap-1 border px-1",
1528
+ children: [/*#__PURE__*/jsx(Button, {
1529
+ disabled: page <= 1 || isLoading,
1530
+ icon: Left,
1531
+ size: "small",
1532
+ variant: "ghost",
1533
+ onClick: onPrev
1534
+ }), /*#__PURE__*/jsx(Typography, {
1535
+ className: "px-1 whitespace-nowrap",
1536
+ variant: "body3",
1537
+ children: t("neetoPdf.pdfDocuments.editor.preview.counter", {
1538
+ page: page,
1539
+ total: total
1540
+ })
1541
+ }), /*#__PURE__*/jsx(Button, {
1542
+ disabled: page >= total || isLoading,
1543
+ icon: Right,
1544
+ size: "small",
1545
+ variant: "ghost",
1546
+ onClick: onNext
1547
+ })]
1548
+ });
1549
+ };
1550
+
1551
+ var _coerceToText = function coerceToText(value) {
1552
+ if (value === null || value === undefined) return "";
1553
+ if (Array.isArray(value)) {
1554
+ return value.map(_coerceToText).filter(Boolean).join(", ");
1555
+ }
1556
+ if (_typeof(value) === "object") {
1557
+ if ("value" in value) return _coerceToText(value.value);
1558
+ if ("label" in value) return _coerceToText(value.label);
1559
+ return "";
1560
+ }
1561
+ return String(value);
1562
+ };
1563
+
1564
+ // Resolve the text shown for a placement in "Preview with data" mode. Returns
1565
+ // "" (rendered blank) when the current submission has no answer for the field.
1566
+ var resolvePreviewValue = function resolvePreviewValue(_ref) {
1567
+ var mapping = _ref.mapping,
1568
+ _ref$responsesBySlug = _ref.responsesBySlug,
1569
+ responsesBySlug = _ref$responsesBySlug === void 0 ? {} : _ref$responsesBySlug,
1570
+ form = _ref.form,
1571
+ submission = _ref.submission;
1572
+ if (mapping.source === FIELD_SOURCES.SYSTEM) {
1573
+ switch (mapping.fieldSlug) {
1574
+ case SYSTEM_FIELD_KEYS.FORM_NAME:
1575
+ return (form === null || form === void 0 ? void 0 : form.title) || (form === null || form === void 0 ? void 0 : form.name) || "";
1576
+ case SYSTEM_FIELD_KEYS.SUBMISSION_ID:
1577
+ return (submission === null || submission === void 0 ? void 0 : submission.id) || "";
1578
+ case SYSTEM_FIELD_KEYS.SUBMISSION_DATE:
1579
+ return submission !== null && submission !== void 0 && submission.createdAt ? dateFormat.dateTime(submission.createdAt) : "";
1580
+ default:
1581
+ return "";
1582
+ }
1583
+ }
1584
+ return _coerceToText(responsesBySlug[mapping.fieldSlug]);
1585
+ };
1586
+
1587
+ // Build a slug -> value lookup from a single submission's responses array.
1588
+ var buildResponsesBySlug = function buildResponsesBySlug() {
1589
+ var responses = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
1590
+ return responses.reduce(function (acc, response) {
1591
+ if ((response === null || response === void 0 ? void 0 : response.slug) !== undefined) acc[response.slug] = response.value;
1592
+ return acc;
1593
+ }, {});
1594
+ };
1595
+
1596
+ var TopBar = function TopBar(_ref) {
1597
+ var name = _ref.name,
1598
+ onRename = _ref.onRename,
1599
+ canManage = _ref.canManage,
1600
+ homeUrl = _ref.homeUrl,
1601
+ isPreview = _ref.isPreview,
1602
+ zoom = _ref.zoom,
1603
+ onZoomIn = _ref.onZoomIn,
1604
+ onZoomOut = _ref.onZoomOut,
1605
+ onDownload = _ref.onDownload,
1606
+ isDownloading = _ref.isDownloading,
1607
+ canDownload = _ref.canDownload,
1608
+ onSave = _ref.onSave,
1609
+ isSaving = _ref.isSaving,
1610
+ isDirty = _ref.isDirty,
1611
+ onBack = _ref.onBack,
1612
+ onModeChange = _ref.onModeChange;
1613
+ var _useTranslation = useTranslation(),
1614
+ t = _useTranslation.t;
1615
+ var headerLinks = [{
1616
+ key: EDITOR_MODES.MAP,
1617
+ label: t("neetoPdf.pdfDocuments.editor.mapFields"),
1618
+ to: "#map",
1619
+ isActive: function isActive() {
1620
+ return !isPreview;
1621
+ },
1622
+ onClick: function onClick(event) {
1623
+ event.preventDefault();
1624
+ onModeChange(EDITOR_MODES.MAP);
1625
+ }
1626
+ }, {
1627
+ key: EDITOR_MODES.PREVIEW,
1628
+ label: t("neetoPdf.pdfDocuments.editor.previewWithData"),
1629
+ to: "#preview",
1630
+ isActive: function isActive() {
1631
+ return isPreview;
1632
+ },
1633
+ onClick: function onClick(event) {
1634
+ event.preventDefault();
1635
+ onModeChange(EDITOR_MODES.PREVIEW);
1636
+ }
1637
+ }];
1638
+ var rightActionBlock = /*#__PURE__*/jsxs("div", {
1639
+ className: "flex w-full items-center justify-end gap-3",
1640
+ children: [/*#__PURE__*/jsxs("div", {
1641
+ className: "flex items-center gap-1",
1642
+ children: [/*#__PURE__*/jsx(Button, {
1643
+ disabled: zoom <= ZOOM.MIN,
1644
+ icon: Minus,
1645
+ size: "small",
1646
+ variant: "ghost",
1647
+ onClick: onZoomOut
1648
+ }), /*#__PURE__*/jsxs(Typography, {
1649
+ className: "w-10 text-center",
1650
+ variant: "body3",
1651
+ children: [Math.round(zoom * 100), "%"]
1652
+ }), /*#__PURE__*/jsx(Button, {
1653
+ disabled: zoom >= ZOOM.MAX,
1654
+ icon: Plus,
1655
+ size: "small",
1656
+ variant: "ghost",
1657
+ onClick: onZoomIn
1658
+ })]
1659
+ }), /*#__PURE__*/jsx(Button, {
1660
+ disabled: !canDownload,
1661
+ icon: Download,
1662
+ label: t("neetoPdf.pdfDocuments.editor.downloadPdf"),
1663
+ loading: isDownloading,
1664
+ variant: "secondary",
1665
+ tooltipProps: {
1666
+ content: canDownload ? t("neetoPdf.pdfDocuments.editor.downloadTooltip") : t("neetoPdf.pdfDocuments.editor.downloadHint")
1667
+ },
1668
+ onClick: onDownload
1669
+ }), /*#__PURE__*/jsx(Button, {
1670
+ disabled: !isDirty,
1671
+ label: t("neetoPdf.common.save"),
1672
+ loading: isSaving,
1673
+ onClick: onSave
1674
+ })]
1675
+ });
1676
+ return /*#__PURE__*/jsx(NavigationHeader, {
1677
+ rightActionBlock: rightActionBlock,
1678
+ leftActionBlock: /*#__PURE__*/jsx(NavigationHeader.LeftActionBlock, {
1679
+ homeUrl: homeUrl || "#",
1680
+ homeButtonProps: {
1681
+ icon: /*#__PURE__*/jsx(LeftArrow, {}),
1682
+ tooltip: {
1683
+ content: t("neetoPdf.pdfDocuments.editor.back"),
1684
+ position: "bottom"
1685
+ },
1686
+ onClick: onBack
1687
+ },
1688
+ renameProps: {
1689
+ value: name,
1690
+ disabled: !canManage,
1691
+ placeholder: t("neetoPdf.pdfDocuments.rename.placeholder"),
1692
+ onRename: onRename
1693
+ }
1694
+ }),
1695
+ navigationLinks: /*#__PURE__*/jsx(NavigationHeader.NavigationLinks, {
1696
+ headerLinks: headerLinks,
1697
+ maxVisibleLinks: 2
1698
+ })
1699
+ });
1700
+ };
1701
+
1702
+ var FullScreenSpinner = function FullScreenSpinner() {
1703
+ return /*#__PURE__*/jsx("div", {
1704
+ className: "bg-background fixed inset-0 z-50 flex items-center justify-center",
1705
+ children: /*#__PURE__*/jsx(Spinner, {})
1706
+ });
1707
+ };
1708
+ var PdfEditorPage = function PdfEditorPage(_ref) {
1709
+ var apiBaseUrl = _ref.apiBaseUrl,
1710
+ ownerId = _ref.ownerId,
1711
+ documentId = _ref.documentId,
1712
+ _ref$canManage = _ref.canManage,
1713
+ canManage = _ref$canManage === void 0 ? true : _ref$canManage,
1714
+ _ref$fields = _ref.fields,
1715
+ fields = _ref$fields === void 0 ? [] : _ref$fields,
1716
+ _ref$ownerRecord = _ref.ownerRecord,
1717
+ ownerRecord = _ref$ownerRecord === void 0 ? {} : _ref$ownerRecord,
1718
+ previewRecord = _ref.previewRecord,
1719
+ _ref$previewTotal = _ref.previewTotal,
1720
+ previewTotal = _ref$previewTotal === void 0 ? 0 : _ref$previewTotal,
1721
+ _ref$previewPage = _ref.previewPage,
1722
+ previewPage = _ref$previewPage === void 0 ? 1 : _ref$previewPage,
1723
+ _ref$isPreviewLoading = _ref.isPreviewLoading,
1724
+ isPreviewLoading = _ref$isPreviewLoading === void 0 ? false : _ref$isPreviewLoading,
1725
+ controlledMode = _ref.mode,
1726
+ homeUrl = _ref.homeUrl,
1727
+ onBack = _ref.onBack,
1728
+ onModeChange = _ref.onModeChange,
1729
+ onPreviewPageChange = _ref.onPreviewPageChange;
1730
+ var _useTranslation = useTranslation(),
1731
+ t = _useTranslation.t;
1732
+ var _useState = useState(ZOOM.DEFAULT),
1733
+ _useState2 = _slicedToArray(_useState, 2),
1734
+ zoom = _useState2[0],
1735
+ setZoom = _useState2[1];
1736
+ var _usePdfEditorDocument = usePdfEditorDocument({
1737
+ apiBaseUrl: apiBaseUrl,
1738
+ documentId: documentId,
1739
+ ownerId: ownerId,
1740
+ t: t
1741
+ }),
1742
+ documentName = _usePdfEditorDocument.documentName,
1743
+ isDocumentLoading = _usePdfEditorDocument.isDocumentLoading,
1744
+ isSaving = _usePdfEditorDocument.isSaving,
1745
+ pdfDocument = _usePdfEditorDocument.pdfDocument,
1746
+ renamePdfDocument = _usePdfEditorDocument.renamePdfDocument,
1747
+ saveDocumentMappings = _usePdfEditorDocument.saveDocumentMappings,
1748
+ templateUrl = _usePdfEditorDocument.templateUrl;
1749
+ var _usePdfMappingsState = usePdfMappingsState({
1750
+ documentId: documentId,
1751
+ pdfDocument: pdfDocument
1752
+ }),
1753
+ handleAddField = _usePdfMappingsState.handleAddField,
1754
+ handleChangeMapping = _usePdfMappingsState.handleChangeMapping,
1755
+ handleDragEndField = _usePdfMappingsState.handleDragEndField,
1756
+ handleDragStartField = _usePdfMappingsState.handleDragStartField,
1757
+ handleDropField = _usePdfMappingsState.handleDropField,
1758
+ handlePageScaleChange = _usePdfMappingsState.handlePageScaleChange,
1759
+ handleRemoveMapping = _usePdfMappingsState.handleRemoveMapping,
1760
+ isDirty = _usePdfMappingsState.isDirty,
1761
+ mappings = _usePdfMappingsState.mappings,
1762
+ selectedId = _usePdfMappingsState.selectedId,
1763
+ selectedMapping = _usePdfMappingsState.selectedMapping,
1764
+ setIsDirty = _usePdfMappingsState.setIsDirty,
1765
+ setSelectedId = _usePdfMappingsState.setSelectedId;
1766
+ var _usePreviewPagination = usePreviewPagination({
1767
+ controlledMode: controlledMode,
1768
+ onModeChange: onModeChange,
1769
+ onPreviewPageChange: onPreviewPageChange,
1770
+ previewPage: previewPage,
1771
+ setSelectedId: setSelectedId
1772
+ }),
1773
+ currentPreviewPage = _usePreviewPagination.currentPreviewPage,
1774
+ handleModeChange = _usePreviewPagination.handleModeChange,
1775
+ isPreview = _usePreviewPagination.isPreview,
1776
+ mode = _usePreviewPagination.mode,
1777
+ setPreviewPage = _usePreviewPagination.setPreviewPage;
1778
+ var answerFields = useMemo(function () {
1779
+ return buildAnswerFields(fields);
1780
+ }, [fields]);
1781
+ var systemFields = useMemo(function () {
1782
+ return SYSTEM_FIELDS.map(function (_ref2) {
1783
+ var key = _ref2.key,
1784
+ labelKey = _ref2.labelKey,
1785
+ icon = _ref2.icon;
1786
+ return {
1787
+ source: FIELD_SOURCES.SYSTEM,
1788
+ key: key,
1789
+ label: t(labelKey),
1790
+ typeLabel: t("neetoPdf.pdfDocuments.editor.system"),
1791
+ kind: key,
1792
+ icon: icon
1793
+ };
1794
+ });
1795
+ }, [t]);
1796
+ var responsesBySlug = useMemo(function () {
1797
+ return buildResponsesBySlug(previewRecord === null || previewRecord === void 0 ? void 0 : previewRecord.responses);
1798
+ }, [previewRecord]);
1799
+ var resolveValue = function resolveValue(mapping) {
1800
+ return resolvePreviewValue({
1801
+ mapping: mapping,
1802
+ responsesBySlug: responsesBySlug,
1803
+ form: ownerRecord,
1804
+ submission: previewRecord
1805
+ });
1806
+ };
1807
+ var _usePdfDownload = usePdfDownload({
1808
+ mappings: mappings,
1809
+ pdfDocument: pdfDocument,
1810
+ previewRecord: previewRecord,
1811
+ resolveValue: resolveValue,
1812
+ t: t
1813
+ }),
1814
+ downloadPdf = _usePdfDownload.downloadPdf,
1815
+ isDownloading = _usePdfDownload.isDownloading;
1816
+ var handleSave = function handleSave() {
1817
+ return saveDocumentMappings({
1818
+ mappings: mappings,
1819
+ onSuccess: function onSuccess() {
1820
+ return setIsDirty(false);
1821
+ }
1822
+ });
1823
+ };
1824
+ if (isDocumentLoading) return /*#__PURE__*/jsx(FullScreenSpinner, {});
1825
+ return /*#__PURE__*/createPortal(/*#__PURE__*/jsxs("div", {
1826
+ className: "bg-background fixed inset-0 z-50 flex flex-col",
1827
+ children: [/*#__PURE__*/jsx(TopBar, {
1828
+ canManage: canManage,
1829
+ documentId: documentId,
1830
+ homeUrl: homeUrl,
1831
+ isDirty: isDirty,
1832
+ isDownloading: isDownloading,
1833
+ isPreview: isPreview,
1834
+ isSaving: isSaving,
1835
+ mode: mode,
1836
+ onBack: onBack,
1837
+ zoom: zoom,
1838
+ canDownload: isPreview && Boolean(previewRecord),
1839
+ name: documentName,
1840
+ onDownload: downloadPdf,
1841
+ onModeChange: handleModeChange,
1842
+ onRename: renamePdfDocument,
1843
+ onSave: handleSave,
1844
+ onZoomIn: function onZoomIn() {
1845
+ return setZoom(function (value) {
1846
+ return clamp(value + ZOOM.STEP, ZOOM.MIN, ZOOM.MAX);
1847
+ });
1848
+ },
1849
+ onZoomOut: function onZoomOut() {
1850
+ return setZoom(function (value) {
1851
+ return clamp(value - ZOOM.STEP, ZOOM.MIN, ZOOM.MAX);
1852
+ });
1853
+ }
1854
+ }), /*#__PURE__*/jsxs("div", {
1855
+ className: "flex min-h-0 grow overflow-hidden",
1856
+ children: [!isPreview && /*#__PURE__*/jsx(FieldsPanel, {
1857
+ answerFields: answerFields,
1858
+ systemFields: systemFields,
1859
+ onDragEndField: handleDragEndField,
1860
+ onDragStartField: handleDragStartField,
1861
+ onPlace: handleAddField
1862
+ }), /*#__PURE__*/jsxs("div", {
1863
+ className: "relative h-full min-w-0 flex-1 overflow-hidden",
1864
+ children: [isPreview && /*#__PURE__*/jsx("div", {
1865
+ className: "absolute top-4 left-1/2 z-10 -translate-x-1/2",
1866
+ children: /*#__PURE__*/jsx(PreviewPager, {
1867
+ isLoading: isPreviewLoading,
1868
+ page: currentPreviewPage,
1869
+ total: previewTotal,
1870
+ onNext: function onNext() {
1871
+ return setPreviewPage(Math.min(currentPreviewPage + 1, previewTotal));
1872
+ },
1873
+ onPrev: function onPrev() {
1874
+ return setPreviewPage(Math.max(currentPreviewPage - 1, 1));
1875
+ }
1876
+ })
1877
+ }), /*#__PURE__*/jsx(Canvas, {
1878
+ mappings: mappings,
1879
+ mode: mode,
1880
+ resolveValue: resolveValue,
1881
+ selectedId: selectedId,
1882
+ templateUrl: templateUrl,
1883
+ zoom: zoom,
1884
+ onChange: handleChangeMapping,
1885
+ onDropField: handleDropField,
1886
+ onPageScaleChange: handlePageScaleChange,
1887
+ onSelect: setSelectedId
1888
+ })]
1889
+ }), !isPreview && /*#__PURE__*/jsx(FieldPanel, {
1890
+ mapping: selectedMapping,
1891
+ onChange: handleChangeMapping,
1892
+ onRemove: handleRemoveMapping
1893
+ })]
1894
+ })]
1895
+ }), window.document.body);
1896
+ };
1897
+
1898
+ export { PdfEditorPage as default };
1899
+ //# sourceMappingURL=PdfEditorPage.js.map