@pdfme/ui 6.2.1-dev.18 → 6.2.1-dev.26

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.
package/dist/index.js CHANGED
@@ -56820,7 +56820,7 @@ var dictionaries = {
56820
56820
  bulkUpdateFieldName: "Bulk update field names",
56821
56821
  addPageAfter: "Add Page After",
56822
56822
  removePage: "Remove Current Page",
56823
- removePageConfirm: "Are you sure you want to delete this page? This action cannot be undone.",
56823
+ removePageConfirm: "Are you sure you want to delete this page?",
56824
56824
  zoomIn: "Zoom in",
56825
56825
  zoomOut: "Zoom out",
56826
56826
  fitWidth: "Fit width",
@@ -56940,7 +56940,7 @@ var dictionaries = {
56940
56940
  bulkUpdateFieldName: "批量更新字段名称",
56941
56941
  addPageAfter: "在之后添加页面",
56942
56942
  removePage: "删除当前页面",
56943
- removePageConfirm: "您确定要删除此页面吗?此操作无法撤销。",
56943
+ removePageConfirm: "您确定要删除此页面吗?",
56944
56944
  zoomIn: "放大",
56945
56945
  zoomOut: "缩小",
56946
56946
  fitWidth: "适合宽度",
@@ -57060,7 +57060,7 @@ var dictionaries = {
57060
57060
  bulkUpdateFieldName: "批量更新字段名稱",
57061
57061
  addPageAfter: "在之後添加頁面",
57062
57062
  removePage: "刪除當前頁面",
57063
- removePageConfirm: "您確定要刪除此頁面嗎?此操作無法撤銷。",
57063
+ removePageConfirm: "您確定要刪除此頁面嗎?",
57064
57064
  zoomIn: "放大",
57065
57065
  zoomOut: "縮小",
57066
57066
  fitWidth: "適合寬度",
@@ -57180,7 +57180,7 @@ var dictionaries = {
57180
57180
  bulkUpdateFieldName: "項目名を一括変更",
57181
57181
  addPageAfter: "次にページを追加",
57182
57182
  removePage: "現在のページを削除",
57183
- removePageConfirm: "ページを削除してもよろしいですか?この操作は元に戻せません。",
57183
+ removePageConfirm: "ページを削除してもよろしいですか?",
57184
57184
  zoomIn: "拡大",
57185
57185
  zoomOut: "縮小",
57186
57186
  fitWidth: "横幅に合わせる",
@@ -57300,7 +57300,7 @@ var dictionaries = {
57300
57300
  bulkUpdateFieldName: "필드 이름 일괄 업데이트",
57301
57301
  addPageAfter: "다음에 페이지 추가",
57302
57302
  removePage: "현재 페이지 제거",
57303
- removePageConfirm: "이 페이지를 삭제하시겠습니까? 이 작업은 취소할 수 없습니다.",
57303
+ removePageConfirm: "이 페이지를 삭제하시겠습니까?",
57304
57304
  zoomIn: "확대",
57305
57305
  zoomOut: "축소",
57306
57306
  fitWidth: "너비에 맞춤",
@@ -57420,7 +57420,7 @@ var dictionaries = {
57420
57420
  bulkUpdateFieldName: "تغيير الأسماء",
57421
57421
  addPageAfter: "إضافة صفحة بعد",
57422
57422
  removePage: "احذف الصفحة الحالية",
57423
- removePageConfirm: "هل أنت متأكد من رغبتك في حذف هذه الصفحة؟ لا يمكن التراجع عن هذا الإجراء.",
57423
+ removePageConfirm: "هل أنت متأكد من رغبتك في حذف هذه الصفحة؟",
57424
57424
  zoomIn: "تكبير",
57425
57425
  zoomOut: "تصغير",
57426
57426
  fitWidth: "ملاءمة العرض",
@@ -57540,7 +57540,7 @@ var dictionaries = {
57540
57540
  bulkUpdateFieldName: "แก้ไขชื่อฟิลด์เป็นชุด",
57541
57541
  addPageAfter: "เพิ่มหน้าถัดไป",
57542
57542
  removePage: "ลบหน้าปัจจุบัน",
57543
- removePageConfirm: "คุณแน่ใจหรือไม่ว่าต้องการลบหน้านี้? การกระทำนี้ไม่สามารถย้อนกลับได้",
57543
+ removePageConfirm: "คุณแน่ใจหรือไม่ว่าต้องการลบหน้านี้?",
57544
57544
  zoomIn: "ซูมเข้า",
57545
57545
  zoomOut: "ซูมออก",
57546
57546
  fitWidth: "พอดีกับความกว้าง",
@@ -57660,7 +57660,7 @@ var dictionaries = {
57660
57660
  bulkUpdateFieldName: "Alan adlarını toplu güncelle",
57661
57661
  addPageAfter: "Sonrasına Sayfa Ekle",
57662
57662
  removePage: "Mevcut Sayfayı Kaldır",
57663
- removePageConfirm: "Bu sayfayı silmek istediğinizden emin misiniz? Bu işlem geri alınamaz.",
57663
+ removePageConfirm: "Bu sayfayı silmek istediğinizden emin misiniz?",
57664
57664
  zoomIn: "Yakınlaştır",
57665
57665
  zoomOut: "Uzaklaştır",
57666
57666
  fitWidth: "Genişliğe sığdır",
@@ -57780,7 +57780,7 @@ var dictionaries = {
57780
57780
  bulkUpdateFieldName: "Modifica nomi campi in blocco",
57781
57781
  addPageAfter: "Aggiungi pagina dopo",
57782
57782
  removePage: "Rimuovi la Pagina Corrente",
57783
- removePageConfirm: "Sei sicuro di voler eliminare questa pagina? Questa azione non può essere annullata.",
57783
+ removePageConfirm: "Sei sicuro di voler eliminare questa pagina?",
57784
57784
  zoomIn: "Ingrandisci",
57785
57785
  zoomOut: "Riduci",
57786
57786
  fitWidth: "Adatta larghezza",
@@ -57900,7 +57900,7 @@ var dictionaries = {
57900
57900
  bulkUpdateFieldName: "Masowo aktualizuj klucze pól",
57901
57901
  addPageAfter: "Dodaj stronę po",
57902
57902
  removePage: "Usuń Bieżącą Stronę",
57903
- removePageConfirm: "Czy na pewno chcesz usunąć tę stronę? Tej operacji nie można cofnąć.",
57903
+ removePageConfirm: "Czy na pewno chcesz usunąć tę stronę?",
57904
57904
  zoomIn: "Powiększ",
57905
57905
  zoomOut: "Pomniejsz",
57906
57906
  fitWidth: "Dopasuj szerokość",
@@ -58020,7 +58020,7 @@ var dictionaries = {
58020
58020
  bulkUpdateFieldName: "Mehrfachaktualisierung der Feldnamen",
58021
58021
  addPageAfter: "Seite danach hinzufügen",
58022
58022
  removePage: "Aktuelle Seite entfernen",
58023
- removePageConfirm: "Sind Sie sicher, dass Sie diese Seite löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden.",
58023
+ removePageConfirm: "Sind Sie sicher, dass Sie diese Seite löschen möchten?",
58024
58024
  zoomIn: "Vergrößern",
58025
58025
  zoomOut: "Verkleinern",
58026
58026
  fitWidth: "Breite anpassen",
@@ -58140,7 +58140,7 @@ var dictionaries = {
58140
58140
  bulkUpdateFieldName: "Actualizar en bloque el nombre de los campos",
58141
58141
  addPageAfter: "Insertar página",
58142
58142
  removePage: "Eliminar página actual",
58143
- removePageConfirm: "¿Estás seguro de que quieres eliminar esta página? Esta acción no se puede deshacer.",
58143
+ removePageConfirm: "¿Estás seguro de que quieres eliminar esta página?",
58144
58144
  zoomIn: "Acercar",
58145
58145
  zoomOut: "Alejar",
58146
58146
  fitWidth: "Ajustar ancho",
@@ -58260,7 +58260,7 @@ var dictionaries = {
58260
58260
  bulkUpdateFieldName: "Modifier les noms de champs en masse",
58261
58261
  addPageAfter: "Ajouter une page après",
58262
58262
  removePage: "Supprimer la page actuelle",
58263
- removePageConfirm: "Êtes-vous sûr de vouloir supprimer cette page ? Cette action est irréversible.",
58263
+ removePageConfirm: "Êtes-vous sûr de vouloir supprimer cette page ?",
58264
58264
  zoomIn: "Zoom avant",
58265
58265
  zoomOut: "Zoom arrière",
58266
58266
  fitWidth: "Ajuster la largeur",
@@ -87842,6 +87842,13 @@ var round$2 = (number, precision) => {
87842
87842
  return shift(Math.round(shift(number, precision, false)), precision, true);
87843
87843
  };
87844
87844
  var flatten = (arr) => [].concat(...arr);
87845
+ /**
87846
+ * Single source of truth for whether a schema type supports rotation in the
87847
+ * Designer (rotate handle on the canvas and rotate input in the detail view).
87848
+ * A plugin opts out by omitting `rotate` from its propPanel.defaultSchema or
87849
+ * setting it to `undefined` (e.g. `{ ...text.propPanel.defaultSchema, rotate: undefined }`).
87850
+ */
87851
+ var isRotatableSchema = (defaultSchema) => typeof defaultSchema?.rotate !== "undefined";
87845
87852
  var up = "up";
87846
87853
  var shiftUp = "shift+up";
87847
87854
  var down = "down";
@@ -87993,9 +88000,7 @@ var template2SchemasList = async (_template) => {
87993
88000
  const pdfArrayBuffer = b64toUint8Array(await getB64BasePdf(basePdf));
87994
88001
  pageSizes = await pdf2size(pdfArrayBuffer);
87995
88002
  }
87996
- const ssl = schemasForUI.length;
87997
- const psl = pageSizes.length;
87998
- return (ssl < psl ? schemasForUI.concat(Array.from({ length: psl - ssl }, () => cloneDeep$1([]))) : schemasForUI.slice(0, pageSizes.length)).map((schema, i) => {
88003
+ return alignSchemasListToPageCount(schemasForUI, pageSizes.length).map((schema, i) => {
87999
88004
  Object.values(schema).forEach((value) => {
88000
88005
  const { width, height } = pageSizes[i];
88001
88006
  const xEdge = value.position.x + value.width;
@@ -88006,6 +88011,26 @@ var template2SchemasList = async (_template) => {
88006
88011
  return schema;
88007
88012
  });
88008
88013
  };
88014
+ /**
88015
+ * Pad or truncate schema pages so the list length matches `pageCount`.
88016
+ * Empty pages are distinct arrays. This is the same alignment `template2SchemasList`
88017
+ * uses when a base PDF's page count and the schema pages differ.
88018
+ */
88019
+ var alignSchemasListToPageCount = (schemasList, pageCount) => {
88020
+ if (schemasList.length === pageCount) return schemasList;
88021
+ if (schemasList.length < pageCount) return schemasList.concat(Array.from({ length: pageCount - schemasList.length }, () => []));
88022
+ return schemasList.slice(0, Math.max(pageCount, 0));
88023
+ };
88024
+ /**
88025
+ * Fit a history snapshot to the pages of the current base PDF.
88026
+ * Blank PDFs follow the snapshot length. A non-blank PDF keeps `pageSizes.length`,
88027
+ * using the same pad/truncate as `template2SchemasList`. A zero page count means
88028
+ * sizes are not loaded yet, so the snapshot is left unchanged.
88029
+ */
88030
+ var normalizeSchemasListForBasePdf = (schemasList, basePdf, pageCount) => {
88031
+ if (isBlankPdf(basePdf) || pageCount <= 0) return schemasList;
88032
+ return alignSchemasListToPageCount(schemasList, pageCount);
88033
+ };
88009
88034
  var schemasList2template = (schemasList, basePdf) => ({
88010
88035
  schemas: cloneDeep$1(schemasList).map((page) => page.map((schema) => {
88011
88036
  delete schema.id;
@@ -133193,7 +133218,7 @@ var useMountStatus = () => {
133193
133218
  }, []);
133194
133219
  return isMounted;
133195
133220
  };
133196
- var useInitEvents = ({ pageCursor, pageSizes, activeElements, template, schemasList, changeSchemas, commitSchemas, removeSchemas, onSaveTemplate, past, future, setSchemasList, onEdit, onEditEnd }) => {
133221
+ var useInitEvents = ({ pageCursor, pageSizes, activeElements, template, schemasList, changeSchemas, commitSchemas, removeSchemas, onSaveTemplate, undo, redo, onEdit, onEditEnd }) => {
133197
133222
  const copiedSchemas = (0, import_react$9.useRef)(null);
133198
133223
  const initEvents = (0, import_react$9.useCallback)(() => {
133199
133224
  const getElementsByIds = (ids) => ids.map((id) => document.getElementById(id)).filter((element) => element instanceof HTMLElement);
@@ -133201,15 +133226,6 @@ var useInitEvents = ({ pageCursor, pageSizes, activeElements, template, schemasL
133201
133226
  const ids = activeElements.map((ae) => ae.id);
133202
133227
  return schemasList[pageCursor].filter((s) => ids.includes(s.id));
133203
133228
  };
133204
- const timeTravel = (mode) => {
133205
- const isUndo = mode === "undo";
133206
- const stack = isUndo ? past : future;
133207
- if (stack.current.length <= 0) return;
133208
- (isUndo ? future : past).current.push(cloneDeep$1(schemasList[pageCursor]));
133209
- const s = cloneDeep$1(schemasList);
133210
- s[pageCursor] = stack.current.pop();
133211
- setSchemasList(s);
133212
- };
133213
133229
  initShortCuts({
133214
133230
  move: (command, isShift) => {
133215
133231
  const pageSize = pageSizes[pageCursor];
@@ -133254,8 +133270,8 @@ var useInitEvents = ({ pageCursor, pageSizes, activeElements, template, schemasL
133254
133270
  });
133255
133271
  copiedSchemas.current = pasteSchemas;
133256
133272
  },
133257
- redo: () => timeTravel("redo"),
133258
- undo: () => timeTravel("undo"),
133273
+ redo: () => redo(),
133274
+ undo: () => undo(),
133259
133275
  save: () => onSaveTemplate && onSaveTemplate(schemasList2template(schemasList, template.basePdf)),
133260
133276
  remove: () => removeSchemas(getActiveSchemas().map((s) => s.id)),
133261
133277
  esc: onEditEnd,
@@ -133271,9 +133287,8 @@ var useInitEvents = ({ pageCursor, pageSizes, activeElements, template, schemasL
133271
133287
  schemasList,
133272
133288
  onSaveTemplate,
133273
133289
  removeSchemas,
133274
- past,
133275
- future,
133276
- setSchemasList,
133290
+ undo,
133291
+ redo,
133277
133292
  copiedSchemas,
133278
133293
  onEdit,
133279
133294
  onEditEnd
@@ -215796,7 +215811,7 @@ var TEXT_OVERFLOW_EXPAND_SCHEMA_TYPES = /* @__PURE__ */ new Set(["text", "multiV
215796
215811
  var getElementIds = (elements) => elements.map(({ id }) => id);
215797
215812
  var DetailView = (props) => {
215798
215813
  const { token } = theme.useToken();
215799
- const { schemasList, changeSchemas, deselectSchema, activeSchema, pageSize, basePdf } = props;
215814
+ const { schemasList, changeSchemas, syncSchemas, deselectSchema, activeSchema, pageSize, basePdf } = props;
215800
215815
  const formInstance = useForm();
215801
215816
  const form = (0, import_react$9.useRef)(formInstance).current;
215802
215817
  const i18n = (0, import_react$9.useContext)(I18nContext);
@@ -215870,7 +215885,7 @@ var DetailView = (props) => {
215870
215885
  (0, import_react$9.useEffect)(() => {
215871
215886
  if (isBlankPdf(basePdf) || !TEXT_OVERFLOW_EXPAND_SCHEMA_TYPES.has(activeSchema.type)) return;
215872
215887
  if (activeSchema.overflow !== "expand") return;
215873
- changeSchemas([{
215888
+ syncSchemas([{
215874
215889
  key: "overflow",
215875
215890
  value: TEXT_OVERFLOW_VISIBLE,
215876
215891
  schemaId: activeSchema.id
@@ -215878,7 +215893,7 @@ var DetailView = (props) => {
215878
215893
  }, [
215879
215894
  activeSchema,
215880
215895
  basePdf,
215881
- changeSchemas
215896
+ syncSchemas
215882
215897
  ]);
215883
215898
  (0, import_react$9.useEffect)(() => {
215884
215899
  uniqueSchemaName.current = (value) => {
@@ -216090,7 +216105,7 @@ var DetailView = (props) => {
216090
216105
  title: typedI18n("rotate"),
216091
216106
  type: "number",
216092
216107
  widget: "inputNumber",
216093
- disabled: typeof defaultSchema.rotate === "undefined",
216108
+ disabled: !isRotatableSchema(defaultSchema),
216094
216109
  max: 360,
216095
216110
  props: { min: 0 },
216096
216111
  span: 6
@@ -236559,7 +236574,7 @@ var DeleteButton = ({ activeElements: aes, controlScale }) => {
236559
236574
  });
236560
236575
  };
236561
236576
  var Canvas = (props, ref) => {
236562
- const { basePdf, pageCursor, scale, renderScale, backgrounds, pageSizes, size, activeElements, schemasList, hoveringSchemaId, onEdit, changeSchemas, removeSchemas, onChangeHoveringSchemaId, paperRefs, sidebarOpen } = props;
236577
+ const { basePdf, pageCursor, scale, renderScale, backgrounds, pageSizes, size, activeElements, schemasList, hoveringSchemaId, onEdit, changeSchemas, syncSchemas, removeSchemas, onChangeHoveringSchemaId, paperRefs, sidebarOpen } = props;
236563
236578
  const { token } = theme.useToken();
236564
236579
  const pluginsRegistry = (0, import_react$9.useContext)(PluginsRegistry);
236565
236580
  const verticalGuides = (0, import_react$9.useRef)([]);
@@ -236772,8 +236787,7 @@ var Canvas = (props, ref) => {
236772
236787
  if (plugin.propPanel.defaultSchema) defaultSchemas.push(plugin.propPanel.defaultSchema);
236773
236788
  });
236774
236789
  return uniqueSchemaTypes.every((type) => {
236775
- const matchingSchema = defaultSchemas.find((ds) => ds && "type" in ds && ds.type === type);
236776
- return matchingSchema && "rotate" in matchingSchema;
236790
+ return isRotatableSchema(defaultSchemas.find((ds) => ds && "type" in ds && ds.type === type));
236777
236791
  });
236778
236792
  }, [
236779
236793
  activeElements,
@@ -236900,11 +236914,19 @@ var Canvas = (props, ref) => {
236900
236914
  onChangeHoveringSchemaId,
236901
236915
  mode,
236902
236916
  onChange: (schemasList[pageCursor] || []).some((s) => s.id === schema.id) ? (arg) => {
236903
- changeSchemas((Array.isArray(arg) ? arg : [arg]).map(({ key, value }) => ({
236917
+ const changes = (Array.isArray(arg) ? arg : [arg]).map(({ key, value }) => ({
236904
236918
  key,
236905
236919
  value,
236906
236920
  schemaId: schema.id
236907
- })));
236921
+ }));
236922
+ if (changes.length > 0 && changes.every((change) => change.key === "height")) {
236923
+ syncSchemas(changes.map((change) => ({
236924
+ ...change,
236925
+ value: typeof change.value === "number" && Number.isFinite(change.value) ? round$2(change.value, 2) : change.value
236926
+ })));
236927
+ return;
236928
+ }
236929
+ changeSchemas(changes);
236908
236930
  } : void 0,
236909
236931
  stopEditing: () => setEditing(false),
236910
236932
  outline: `1px ${hoveringSchemaId === schema.id ? "solid" : "dashed"} ${schema.readOnly && hoveringSchemaId !== schema.id ? "transparent" : token.colorPrimary}`,
@@ -237328,6 +237350,22 @@ var CtlBar = (props) => {
237328
237350
  };
237329
237351
  //#endregion
237330
237352
  //#region src/components/Designer/index.tsx
237353
+ var MAX_HISTORY_LENGTH = 100;
237354
+ /** Release scroll suppression if a pending page scroll never finishes. */
237355
+ var SCROLL_SUPPRESS_FALLBACK_MS = 1e3;
237356
+ var pushHistory = (stack, entry) => {
237357
+ stack.push({
237358
+ schemasList: cloneDeep$1(entry.schemasList),
237359
+ pageCursor: entry.pageCursor,
237360
+ appliedCursor: entry.appliedCursor
237361
+ });
237362
+ if (stack.length > MAX_HISTORY_LENGTH) stack.splice(0, stack.length - MAX_HISTORY_LENGTH);
237363
+ };
237364
+ var clampPageCursor = (pageCursor, pageCount) => {
237365
+ if (pageCount <= 0) return 0;
237366
+ return Math.min(Math.max(Number.isFinite(pageCursor) ? Math.trunc(pageCursor) : 0, 0), pageCount - 1);
237367
+ };
237368
+ var schemasEqual = (left, right) => JSON.stringify(left) === JSON.stringify(right);
237331
237369
  /**
237332
237370
  * When the canvas scales there is a displacement of the starting position of the dragged schema.
237333
237371
  * It moves left or right from the top-left corner of the drag icon depending on the scale.
@@ -237342,6 +237380,12 @@ var MIN_CANVAS_WIDTH = 100;
237342
237380
  var TemplateEditor = ({ template, size, onSaveTemplate, onChangeTemplate, onPageCursorChange, onChangeSelection, onRegisterSchemaSelectionHandler, onUpdateTemplatePageApplied, updateTemplatePage }) => {
237343
237381
  const past = (0, import_react$9.useRef)([]);
237344
237382
  const future = (0, import_react$9.useRef)([]);
237383
+ const schemasListRef = (0, import_react$9.useRef)([[]]);
237384
+ const pageCursorRef = (0, import_react$9.useRef)(0);
237385
+ const pendingSelectionIdsRef = (0, import_react$9.useRef)(null);
237386
+ const suppressScrollPageCursorRef = (0, import_react$9.useRef)(false);
237387
+ const scrollSuppressTokenRef = (0, import_react$9.useRef)(0);
237388
+ const scrollSuppressTimerRef = (0, import_react$9.useRef)(null);
237345
237389
  const canvasRef = (0, import_react$9.useRef)(null);
237346
237390
  const paperRefs = (0, import_react$9.useRef)([]);
237347
237391
  const i18n = (0, import_react$9.useContext)(I18nContext);
@@ -237351,8 +237395,12 @@ var TemplateEditor = ({ template, size, onSaveTemplate, onChangeTemplate, onPage
237351
237395
  const canvasWidth = size.width - 45;
237352
237396
  const [hoveringSchemaId, setHoveringSchemaId] = (0, import_react$9.useState)(null);
237353
237397
  const [activeElements, setActiveElements] = (0, import_react$9.useState)([]);
237398
+ const activeElementsRef = (0, import_react$9.useRef)(activeElements);
237399
+ activeElementsRef.current = activeElements;
237354
237400
  const [schemasList, setSchemasList] = (0, import_react$9.useState)([[]]);
237355
237401
  const [pageCursor, setPageCursor] = (0, import_react$9.useState)(0);
237402
+ schemasListRef.current = schemasList;
237403
+ pageCursorRef.current = pageCursor;
237356
237404
  const [pendingScrollPage, setPendingScrollPage] = (0, import_react$9.useState)(null);
237357
237405
  const [sidebarOpen, setSidebarOpen] = (0, import_react$9.useState)(options.sidebarOpen ?? canvasWidth - 400 >= MIN_CANVAS_WIDTH);
237358
237406
  const [canvasHeight, setCanvasHeight] = (0, import_react$9.useState)(0);
@@ -237440,6 +237488,22 @@ var TemplateEditor = ({ template, size, onSaveTemplate, onChangeTemplate, onPage
237440
237488
  setActiveElements([]);
237441
237489
  setHoveringSchemaId(null);
237442
237490
  };
237491
+ const onEditRef = (0, import_react$9.useRef)(onEdit);
237492
+ const onEditEndRef = (0, import_react$9.useRef)(onEditEnd);
237493
+ onEditRef.current = onEdit;
237494
+ onEditEndRef.current = onEditEnd;
237495
+ (0, import_react$9.useLayoutEffect)(() => {
237496
+ const ids = pendingSelectionIdsRef.current;
237497
+ if (!ids) return;
237498
+ if (pageSizes.length !== schemasList.length || backgrounds.length !== schemasList.length) return;
237499
+ pendingSelectionIdsRef.current = null;
237500
+ const elements = ids.map((id) => document.getElementById(id)).filter((element) => element instanceof HTMLElement);
237501
+ onEditRef.current(elements);
237502
+ }, [
237503
+ backgrounds,
237504
+ pageSizes,
237505
+ schemasList
237506
+ ]);
237443
237507
  (0, import_react$9.useEffect)(() => {
237444
237508
  if (previousOptionsZoomLevelRef.current === options.zoomLevel) return;
237445
237509
  previousOptionsZoomLevelRef.current = options.zoomLevel;
@@ -237448,6 +237512,31 @@ var TemplateEditor = ({ template, size, onSaveTemplate, onChangeTemplate, onPage
237448
237512
  (0, import_react$9.useEffect)(() => {
237449
237513
  if (typeof options.sidebarOpen === "boolean") setSidebarOpen(options.sidebarOpen);
237450
237514
  }, [options.sidebarOpen]);
237515
+ const armScrollSuppression = (fallbackMs) => {
237516
+ const token = ++scrollSuppressTokenRef.current;
237517
+ suppressScrollPageCursorRef.current = true;
237518
+ if (scrollSuppressTimerRef.current !== null) {
237519
+ window.clearTimeout(scrollSuppressTimerRef.current);
237520
+ scrollSuppressTimerRef.current = null;
237521
+ }
237522
+ if (fallbackMs !== void 0) {
237523
+ scrollSuppressTimerRef.current = window.setTimeout(() => {
237524
+ scrollSuppressTimerRef.current = null;
237525
+ if (scrollSuppressTokenRef.current !== token) return;
237526
+ suppressScrollPageCursorRef.current = false;
237527
+ }, fallbackMs);
237528
+ return;
237529
+ }
237530
+ requestAnimationFrame(() => {
237531
+ if (scrollSuppressTokenRef.current !== token) return;
237532
+ suppressScrollPageCursorRef.current = false;
237533
+ });
237534
+ };
237535
+ (0, import_react$9.useEffect)(() => {
237536
+ return () => {
237537
+ if (scrollSuppressTimerRef.current !== null) window.clearTimeout(scrollSuppressTimerRef.current);
237538
+ };
237539
+ }, []);
237451
237540
  useScrollPageCursor({
237452
237541
  ref: canvasRef,
237453
237542
  paperRefs,
@@ -237455,6 +237544,7 @@ var TemplateEditor = ({ template, size, onSaveTemplate, onChangeTemplate, onPage
237455
237544
  scale: displayScale,
237456
237545
  pageCursor,
237457
237546
  onChangePageCursor: (p) => {
237547
+ if (suppressScrollPageCursorRef.current) return;
237458
237548
  setPageCursor(p);
237459
237549
  onPageCursorChange(p, schemasList.length);
237460
237550
  onEditEnd();
@@ -237469,6 +237559,7 @@ var TemplateEditor = ({ template, size, onSaveTemplate, onChangeTemplate, onPage
237469
237559
  if (!pageSizes.every((pageSize) => pageSize.width === width && pageSize.height === height)) return;
237470
237560
  } else if (pageSizes === queuedPageSizes) return;
237471
237561
  setPendingScrollPage(null);
237562
+ armScrollSuppression();
237472
237563
  canvasRef.current.scrollTop = getPagesScrollTopByIndex(pageSizes, pendingPage, displayScale);
237473
237564
  if (requestedPage !== void 0) onUpdateTemplatePageApplied?.(requestedPage);
237474
237565
  }, [
@@ -237491,44 +237582,122 @@ var TemplateEditor = ({ template, size, onSaveTemplate, onChangeTemplate, onPage
237491
237582
  return () => observer.disconnect();
237492
237583
  }
237493
237584
  }, [displayScale]);
237585
+ const applyDocument = (0, import_react$9.useCallback)((nextSchemasList, nextPageCursor, options) => {
237586
+ const basePdf = template.basePdf;
237587
+ const next = normalizeSchemasListForBasePdf(nextSchemasList, basePdf, pageSizes.length);
237588
+ const clampedCursor = clampPageCursor(nextPageCursor, next.length);
237589
+ const pageCountChanged = next.length !== schemasListRef.current.length;
237590
+ const cursorChanged = clampedCursor !== pageCursorRef.current;
237591
+ if (options.preserveSelection) {
237592
+ const landingPage = next[clampedCursor] ?? [];
237593
+ const previousIds = activeElementsRef.current.map((element) => element.id);
237594
+ const survivingIds = previousIds.filter((id) => landingPage.some((schema) => schema.id === id));
237595
+ if (survivingIds.length !== previousIds.length) onEditEndRef.current();
237596
+ pendingSelectionIdsRef.current = survivingIds.length > 0 ? survivingIds : null;
237597
+ }
237598
+ schemasListRef.current = next;
237599
+ pageCursorRef.current = clampedCursor;
237600
+ setSchemasList(next);
237601
+ setPageCursor(clampedCursor);
237602
+ const newTemplate = schemasList2template(next, basePdf);
237603
+ onChangeTemplate(newTemplate);
237604
+ if (options.notifyPageCursor === "always") onPageCursorChange(clampedCursor, next.length);
237605
+ if (pageCountChanged) refresh(newTemplate);
237606
+ if (cursorChanged) {
237607
+ if (pageCountChanged) {
237608
+ armScrollSuppression(SCROLL_SUPPRESS_FALLBACK_MS);
237609
+ setPendingScrollPage({
237610
+ page: clampedCursor,
237611
+ queuedPageSizes: pageSizes
237612
+ });
237613
+ } else if (canvasRef.current) {
237614
+ armScrollSuppression();
237615
+ canvasRef.current.scrollTop = getPagesScrollTopByIndex(pageSizes, clampedCursor, displayScale);
237616
+ }
237617
+ }
237618
+ }, [
237619
+ displayScale,
237620
+ onChangeTemplate,
237621
+ onPageCursorChange,
237622
+ pageSizes,
237623
+ refresh,
237624
+ template.basePdf
237625
+ ]);
237494
237626
  const commitSchemas = (0, import_react$9.useCallback)((newSchemas) => {
237627
+ const currentSchemas = schemasListRef.current;
237628
+ const currentPage = pageCursorRef.current;
237629
+ if (schemasEqual(currentSchemas[currentPage], newSchemas)) return;
237495
237630
  future.current = [];
237496
- past.current.push(cloneDeep$1(schemasList[pageCursor]));
237497
- const _schemasList = cloneDeep$1(schemasList);
237498
- _schemasList[pageCursor] = newSchemas;
237499
- setSchemasList(_schemasList);
237500
- onChangeTemplate(schemasList2template(_schemasList, template.basePdf));
237631
+ pushHistory(past.current, {
237632
+ schemasList: currentSchemas,
237633
+ pageCursor: currentPage,
237634
+ appliedCursor: currentPage
237635
+ });
237636
+ const next = cloneDeep$1(currentSchemas);
237637
+ next[currentPage] = newSchemas;
237638
+ applyDocument(next, currentPage, { notifyPageCursor: "never" });
237639
+ }, [applyDocument]);
237640
+ const syncSchemas = (0, import_react$9.useCallback)((objs) => {
237641
+ const currentPage = pageCursorRef.current;
237642
+ const pageSize = pageSizes[currentPage];
237643
+ if (!pageSize || objs.length === 0) return;
237644
+ changeSchemas({
237645
+ objs,
237646
+ schemas: schemasListRef.current[currentPage] ?? [],
237647
+ basePdf: template.basePdf,
237648
+ pluginsRegistry,
237649
+ pageSize,
237650
+ commitSchemas: (newSchemas) => {
237651
+ const currentSchemas = schemasListRef.current;
237652
+ if (schemasEqual(currentSchemas[currentPage], newSchemas)) return;
237653
+ const next = cloneDeep$1(currentSchemas);
237654
+ next[currentPage] = newSchemas;
237655
+ applyDocument(next, currentPage, { notifyPageCursor: "never" });
237656
+ }
237657
+ });
237501
237658
  }, [
237502
- template,
237503
- schemasList,
237504
- pageCursor,
237505
- onChangeTemplate
237659
+ applyDocument,
237660
+ pageSizes,
237661
+ pluginsRegistry,
237662
+ template.basePdf
237506
237663
  ]);
237507
237664
  const removeSchemas = (0, import_react$9.useCallback)((ids) => {
237508
- commitSchemas(schemasList[pageCursor].filter((schema) => !ids.includes(schema.id)));
237509
- onEditEnd();
237510
- }, [
237511
- schemasList,
237512
- pageCursor,
237513
- commitSchemas
237514
- ]);
237665
+ const currentPage = pageCursorRef.current;
237666
+ const pageSchemas = schemasListRef.current[currentPage] ?? [];
237667
+ commitSchemas(pageSchemas.filter((schema) => !ids.includes(schema.id)));
237668
+ onEditEndRef.current();
237669
+ }, [commitSchemas]);
237515
237670
  const changeSchemas$1 = (0, import_react$9.useCallback)((objs) => {
237671
+ const currentPage = pageCursorRef.current;
237516
237672
  changeSchemas({
237517
237673
  objs,
237518
- schemas: schemasList[pageCursor],
237674
+ schemas: schemasListRef.current[currentPage] ?? [],
237519
237675
  basePdf: template.basePdf,
237520
237676
  pluginsRegistry,
237521
- pageSize: pageSizes[pageCursor],
237677
+ pageSize: pageSizes[currentPage],
237522
237678
  commitSchemas
237523
237679
  });
237524
237680
  }, [
237525
237681
  commitSchemas,
237526
- pageCursor,
237527
- schemasList,
237528
- pluginsRegistry,
237529
237682
  pageSizes,
237683
+ pluginsRegistry,
237530
237684
  template.basePdf
237531
237685
  ]);
237686
+ const timeTravel = (0, import_react$9.useCallback)((mode) => {
237687
+ const source = mode === "undo" ? past : future;
237688
+ const destination = mode === "undo" ? future : past;
237689
+ const target = source.current.pop();
237690
+ if (!target) return;
237691
+ pushHistory(destination.current, {
237692
+ schemasList: schemasListRef.current,
237693
+ pageCursor: target.appliedCursor,
237694
+ appliedCursor: target.pageCursor
237695
+ });
237696
+ applyDocument(target.schemasList, target.pageCursor, {
237697
+ notifyPageCursor: "always",
237698
+ preserveSelection: true
237699
+ });
237700
+ }, [applyDocument]);
237532
237701
  useInitEvents({
237533
237702
  pageCursor,
237534
237703
  pageSizes,
@@ -237539,18 +237708,20 @@ var TemplateEditor = ({ template, size, onSaveTemplate, onChangeTemplate, onPage
237539
237708
  commitSchemas,
237540
237709
  removeSchemas,
237541
237710
  onSaveTemplate,
237542
- past,
237543
- future,
237544
- setSchemasList,
237711
+ undo: (0, import_react$9.useCallback)(() => timeTravel("undo"), [timeTravel]),
237712
+ redo: (0, import_react$9.useCallback)(() => timeTravel("redo"), [timeTravel]),
237545
237713
  onEdit,
237546
237714
  onEditEnd
237547
237715
  });
237548
237716
  const updateTemplate = (0, import_react$9.useCallback)(async (newTemplate, targetPage) => {
237549
237717
  const sl = await template2SchemasList(newTemplate);
237718
+ schemasListRef.current = sl;
237550
237719
  setSchemasList(sl);
237551
- onEditEnd();
237720
+ pendingSelectionIdsRef.current = null;
237721
+ onEditEndRef.current();
237552
237722
  if (targetPage !== void 0) {
237553
237723
  const clampedPage = Math.min(Math.max(Number.isFinite(targetPage) ? Math.trunc(targetPage) : 0, 0), sl.length - 1);
237724
+ pageCursorRef.current = clampedPage;
237554
237725
  setPageCursor(clampedPage);
237555
237726
  onPageCursorChange(clampedPage, sl.length);
237556
237727
  setPendingScrollPage({
@@ -237559,9 +237730,11 @@ var TemplateEditor = ({ template, size, onSaveTemplate, onChangeTemplate, onPage
237559
237730
  requestedPage: targetPage
237560
237731
  });
237561
237732
  } else {
237562
- const clampedPage = Math.min(pageCursor, sl.length - 1);
237733
+ const clampedPage = Math.min(pageCursorRef.current, sl.length - 1);
237734
+ const cursorChanged = clampedPage !== pageCursorRef.current;
237735
+ pageCursorRef.current = clampedPage;
237563
237736
  setPageCursor(clampedPage);
237564
- if (clampedPage !== pageCursor) {
237737
+ if (cursorChanged) {
237565
237738
  onPageCursorChange(clampedPage, sl.length);
237566
237739
  setPendingScrollPage({
237567
237740
  page: clampedPage,
@@ -237569,11 +237742,7 @@ var TemplateEditor = ({ template, size, onSaveTemplate, onChangeTemplate, onPage
237569
237742
  });
237570
237743
  }
237571
237744
  }
237572
- }, [
237573
- pageCursor,
237574
- pageSizes,
237575
- onPageCursorChange
237576
- ]);
237745
+ }, [pageSizes, onPageCursorChange]);
237577
237746
  const addSchema = (defaultSchema) => {
237578
237747
  const [paddingTop, paddingRight, paddingBottom, paddingLeft] = isBlankPdf(template.basePdf) ? template.basePdf.padding : [
237579
237748
  0,
@@ -237616,27 +237785,37 @@ var TemplateEditor = ({ template, size, onSaveTemplate, onChangeTemplate, onPage
237616
237785
  const onChangeHoveringSchemaId = (id) => {
237617
237786
  setHoveringSchemaId(id);
237618
237787
  };
237619
- const updatePage = async (sl, newPageCursor) => {
237620
- setPageCursor(newPageCursor);
237621
- const newTemplate = schemasList2template(sl, template.basePdf);
237622
- onChangeTemplate(newTemplate);
237623
- await updateTemplate(newTemplate, newPageCursor);
237624
- refresh(newTemplate);
237625
- setTimeout(() => {
237626
- if (canvasRef.current) canvasRef.current.scrollTop = getPagesScrollTopByIndex(pageSizes, newPageCursor, displayScale);
237627
- }, 0);
237628
- };
237629
237788
  const handleRemovePage = () => {
237630
- if (pageCursor === 0) return;
237789
+ const currentPage = pageCursorRef.current;
237790
+ if (currentPage === 0) return;
237631
237791
  if (!window.confirm(i18n("removePageConfirm"))) return;
237632
- const _schemasList = cloneDeep$1(schemasList);
237633
- _schemasList.splice(pageCursor, 1);
237634
- updatePage(_schemasList, pageCursor - 1);
237792
+ future.current = [];
237793
+ const currentSchemas = schemasListRef.current;
237794
+ pushHistory(past.current, {
237795
+ schemasList: currentSchemas,
237796
+ pageCursor: currentPage,
237797
+ appliedCursor: currentPage - 1
237798
+ });
237799
+ const next = cloneDeep$1(currentSchemas);
237800
+ next.splice(currentPage, 1);
237801
+ onEditEndRef.current();
237802
+ pendingSelectionIdsRef.current = null;
237803
+ applyDocument(next, currentPage - 1, { notifyPageCursor: "always" });
237635
237804
  };
237636
237805
  const handleAddPageAfter = () => {
237637
- const _schemasList = cloneDeep$1(schemasList);
237638
- _schemasList.splice(pageCursor + 1, 0, []);
237639
- updatePage(_schemasList, pageCursor + 1);
237806
+ future.current = [];
237807
+ const currentSchemas = schemasListRef.current;
237808
+ const currentPage = pageCursorRef.current;
237809
+ pushHistory(past.current, {
237810
+ schemasList: currentSchemas,
237811
+ pageCursor: currentPage,
237812
+ appliedCursor: currentPage + 1
237813
+ });
237814
+ const next = cloneDeep$1(currentSchemas);
237815
+ next.splice(currentPage + 1, 0, []);
237816
+ onEditEndRef.current();
237817
+ pendingSelectionIdsRef.current = null;
237818
+ applyDocument(next, currentPage + 1, { notifyPageCursor: "always" });
237640
237819
  };
237641
237820
  if (prevTemplate !== template) {
237642
237821
  setPrevTemplate(template);
@@ -237714,6 +237893,7 @@ var TemplateEditor = ({ template, size, onSaveTemplate, onChangeTemplate, onPage
237714
237893
  schemasList,
237715
237894
  schemas: schemasList[pageCursor] ?? [],
237716
237895
  changeSchemas: changeSchemas$1,
237896
+ syncSchemas,
237717
237897
  onSortEnd,
237718
237898
  onEdit: (id) => {
237719
237899
  const editingElem = document.getElementById(id);
@@ -237740,6 +237920,7 @@ var TemplateEditor = ({ template, size, onSaveTemplate, onChangeTemplate, onPage
237740
237920
  activeElements,
237741
237921
  schemasList,
237742
237922
  changeSchemas: changeSchemas$1,
237923
+ syncSchemas,
237743
237924
  removeSchemas,
237744
237925
  sidebarOpen,
237745
237926
  onEdit