@pdfme/schemas 6.0.6 → 6.1.0-dev.2

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 (38) hide show
  1. package/dist/builtins-CWHhKSVA.js +1389 -0
  2. package/dist/builtins-CWHhKSVA.js.map +1 -0
  3. package/dist/builtins.js +1 -1
  4. package/dist/{dynamicTemplate-D_DHR3-X.js → dynamicTemplate-DmuRoTw4.js} +23 -350
  5. package/dist/dynamicTemplate-DmuRoTw4.js.map +1 -0
  6. package/dist/helper-M_MmV_d5.js +357 -0
  7. package/dist/helper-M_MmV_d5.js.map +1 -0
  8. package/dist/index.d.ts +4 -2
  9. package/dist/index.js +959 -178
  10. package/dist/index.js.map +1 -1
  11. package/dist/list/constants.d.ts +10 -0
  12. package/dist/list/dynamicTemplate.d.ts +2 -0
  13. package/dist/list/helper.d.ts +15 -0
  14. package/dist/list/index.d.ts +4 -0
  15. package/dist/list/pdfRender.d.ts +3 -0
  16. package/dist/list/propPanel.d.ts +3 -0
  17. package/dist/list/types.d.ts +36 -0
  18. package/dist/list/uiRender.d.ts +3 -0
  19. package/dist/lists-B6dmgpkS.js +117 -0
  20. package/dist/lists-B6dmgpkS.js.map +1 -0
  21. package/dist/lists.d.ts +3 -0
  22. package/dist/lists.js +2 -0
  23. package/dist/multiVariableText/helper.d.ts +2 -1
  24. package/dist/tables/dynamicTemplate.d.ts +2 -1
  25. package/dist/tables.d.ts +1 -1
  26. package/dist/tables.js +2 -2
  27. package/dist/text/constants.d.ts +13 -0
  28. package/dist/text/inlineMarkdown.d.ts +4 -0
  29. package/dist/text/richText.d.ts +46 -0
  30. package/dist/text/richTextPdfRender.d.ts +34 -0
  31. package/dist/text/types.d.ts +18 -0
  32. package/dist/text/uiRender.d.ts +1 -1
  33. package/dist/utils.js +2 -2
  34. package/dist/utils.js.map +1 -1
  35. package/package.json +12 -7
  36. package/dist/builtins-CgaZ0UX3.js +0 -613
  37. package/dist/builtins-CgaZ0UX3.js.map +0 -1
  38. package/dist/dynamicTemplate-D_DHR3-X.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,11 +1,13 @@
1
- import { C as DEFAULT_FONT_COLOR, O as VERTICAL_ALIGN_MIDDLE, a as getColumnStylesPropPanelSchema, c as createSingleTable, i as getCellPropPanelSchema, n as getBody, o as getDefaultCellStyles, p as getFontKitFont, r as getBodyWithRange, s as HEX_COLOR_PATTERN, t as getDynamicHeightsForTable, x as DEFAULT_ALIGNMENT } from "./dynamicTemplate-D_DHR3-X.js";
1
+ import { D as PLACEHOLDER_FONT_COLOR, N as VERTICAL_ALIGN_MIDDLE, O as SYNTHETIC_BOLD_CSS_TEXT_SHADOW, a as getFontKitFont, g as DEFAULT_ALIGNMENT, m as CODE_BACKGROUND_COLOR, v as DEFAULT_FONT_COLOR } from "./helper-M_MmV_d5.js";
2
+ import { a as mapVerticalAlignToFlex, c as Formatter, d as isInlineMarkdownTextSchema, f as resolveFontVariant, i as makeElementPlainTextContentEditable, l as getExtraFormatterSchema, m as parseInlineMarkdown, n as textSchema, o as uiRender$4, p as escapeInlineMarkdown, r as buildStyledTextContainer, s as propPanel$3, t as builtInPlugins, u as pdfRender$4 } from "./builtins-CWHhKSVA.js";
3
+ import { a as getCellPropPanelSchema, c as HEX_COLOR_PATTERN, i as getBodyWithRange, l as createSingleTable, n as getDynamicLayoutForTable, o as getColumnStylesPropPanelSchema, r as getBody, s as getDefaultCellStyles, t as getDynamicHeightsForTable } from "./dynamicTemplate-DmuRoTw4.js";
2
4
  import { addAlphaToHex, convertForPdfLayoutProps, createErrorElm, createSvgStr, hex2PrintingColor, isEditable, readFile, rotatePoint } from "./utils.js";
3
- import { a as mapVerticalAlignToFlex, c as Formatter, i as makeElementPlainTextContentEditable, l as getExtraFormatterSchema, n as textSchema, o as uiRender$3, r as buildStyledTextContainer, s as propPanel$2, t as builtInPlugins, u as pdfRender$3 } from "./builtins-CgaZ0UX3.js";
5
+ import { a as normalizeListItems, c as LIST_STYLE_BULLET, i as normalizeListItemEntries, l as LIST_STYLE_ORDERED, n as calculateListLayout, o as serializeListItems, s as DEFAULT_LIST_STYLE, t as getDynamicLayoutForList } from "./lists-B6dmgpkS.js";
4
6
  import "./tables.js";
5
7
  import { DEFAULT_FONT_NAME, ZOOM, b64toUint8Array, getDefaultFont, getFallbackFontName, mm2pt, px2mm } from "@pdfme/common";
6
8
  import { Buffer as Buffer$1 } from "buffer";
7
9
  import { toRadians } from "@pdfme/pdf-lib";
8
- import { Barcode, Calendar, CalendarClock, ChevronDown, Circle, CircleDot, Clock, Image, Minus, QrCode, Route, Square, SquareCheck, Table, Type } from "lucide";
10
+ import { Barcode, Calendar, CalendarClock, ChevronDown, Circle, CircleDot, Clock, Image, List, Minus, QrCode, Route, Square, SquareCheck, Table, Type } from "lucide";
9
11
  import DOMPurify from "dompurify";
10
12
  import bwipjs from "bwip-js";
11
13
  import AirDatepicker from "air-datepicker";
@@ -18,7 +20,7 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
18
20
  var __getOwnPropNames = Object.getOwnPropertyNames;
19
21
  var __getProtoOf = Object.getPrototypeOf;
20
22
  var __hasOwnProp = Object.prototype.hasOwnProperty;
21
- var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
23
+ var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
22
24
  var __copyProps = (to, from, except, desc) => {
23
25
  if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
24
26
  key = keys[i];
@@ -35,7 +37,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
35
37
  }) : target, mod));
36
38
  //#endregion
37
39
  //#region src/multiVariableText/helper.ts
38
- var substituteVariables = (text, variablesIn) => {
40
+ var substituteVariables = (text, variablesIn, valueMapper = (value) => value) => {
39
41
  if (!text) return "";
40
42
  let substitutedText = text;
41
43
  if (variablesIn) {
@@ -48,12 +50,13 @@ var substituteVariables = (text, variablesIn) => {
48
50
  Object.keys(variables).forEach((variableName) => {
49
51
  const variableForRegex = variableName.replace(/[/\-\\^$*+?.()|[\]{}]/g, "\\$&");
50
52
  const regex = new RegExp("\\{" + variableForRegex + "\\}", "g");
51
- substitutedText = substitutedText.replace(regex, variables[variableName]);
53
+ substitutedText = substitutedText.replace(regex, valueMapper(variables[variableName], variableName));
52
54
  });
53
55
  }
54
56
  substitutedText = substitutedText.replace(/{[^{}]+}/g, "");
55
57
  return substitutedText;
56
58
  };
59
+ var substituteVariablesAsInlineMarkdownLiterals = (text, variablesIn) => substituteVariables(text, variablesIn, escapeInlineMarkdown);
57
60
  var validateVariables = (value, schema) => {
58
61
  if (schema.variables.length === 0) return true;
59
62
  let values;
@@ -70,11 +73,11 @@ var validateVariables = (value, schema) => {
70
73
  };
71
74
  //#endregion
72
75
  //#region src/multiVariableText/pdfRender.ts
73
- var pdfRender$2 = async (arg) => {
76
+ var pdfRender$3 = async (arg) => {
74
77
  const { value, schema, ...rest } = arg;
75
78
  if (!validateVariables(value, schema)) return;
76
- await pdfRender$3({
77
- value: substituteVariables(schema.text || "", value),
79
+ await pdfRender$4({
80
+ value: isInlineMarkdownTextSchema(schema) ? substituteVariablesAsInlineMarkdownLiterals(schema.text || "", value) : substituteVariables(schema.text || "", value),
78
81
  schema,
79
82
  ...rest
80
83
  });
@@ -100,13 +103,6 @@ var visitVariables = (content, visitor) => {
100
103
  }
101
104
  }
102
105
  };
103
- var getVariableIndices = (content) => {
104
- const indices = /* @__PURE__ */ new Map();
105
- visitVariables(content, ({ name, startIndex }) => {
106
- indices.set(startIndex, name);
107
- });
108
- return indices;
109
- };
110
106
  var countUniqueVariableNames = (content) => {
111
107
  const variableNames = /* @__PURE__ */ new Set();
112
108
  visitVariables(content, ({ name }) => {
@@ -190,17 +186,19 @@ var mapDynamicVariables = (props) => {
190
186
  rootElement.appendChild(para);
191
187
  }
192
188
  };
193
- var propPanel$1 = {
189
+ var propPanel$2 = {
194
190
  schema: (propPanelProps) => {
195
- if (typeof propPanel$2.schema !== "function") throw new Error("Oops, is text schema no longer a function?");
191
+ if (typeof propPanel$3.schema !== "function") throw new Error("Oops, is text schema no longer a function?");
192
+ const parentSchema = typeof propPanel$3.schema === "function" ? propPanel$3.schema(propPanelProps) : {};
193
+ const i18n = propPanelProps.i18n;
196
194
  return {
197
- ...typeof propPanel$2.schema === "function" ? propPanel$2.schema(propPanelProps) : {},
195
+ ...parentSchema,
198
196
  "-------": {
199
197
  type: "void",
200
198
  widget: "Divider"
201
199
  },
202
200
  dynamicVarContainer: {
203
- title: "Variables Sample Data",
201
+ title: i18n("schemas.mvt.variablesSampleData"),
204
202
  type: "string",
205
203
  widget: "Card",
206
204
  span: 24,
@@ -212,7 +210,7 @@ var propPanel$1 = {
212
210
  span: 24
213
211
  },
214
212
  placeholderDynamicVar: {
215
- title: "Placeholder Dynamic Variable",
213
+ title: i18n("schemas.mvt.placeholderDynamicVariable"),
216
214
  type: "string",
217
215
  format: "textarea",
218
216
  props: {
@@ -229,11 +227,11 @@ var propPanel$1 = {
229
227
  };
230
228
  },
231
229
  widgets: {
232
- ...propPanel$2.widgets,
230
+ ...propPanel$3.widgets,
233
231
  mapDynamicVariables
234
232
  },
235
233
  defaultSchema: {
236
- ...propPanel$2.defaultSchema,
234
+ ...propPanel$3.defaultSchema,
237
235
  readOnly: false,
238
236
  type: "multiVariableText",
239
237
  text: "Add text here using {} for variables ",
@@ -266,7 +264,7 @@ var updateVariablesFromText = (text, variables) => {
266
264
  };
267
265
  //#endregion
268
266
  //#region src/multiVariableText/uiRender.ts
269
- var uiRender$2 = async (arg) => {
267
+ var uiRender$3 = async (arg) => {
270
268
  const { value, schema, rootElement, mode, onChange, ...rest } = arg;
271
269
  let text = schema.text;
272
270
  let numVariables = schema.variables.length;
@@ -274,8 +272,9 @@ var uiRender$2 = async (arg) => {
274
272
  await formUiRender(arg);
275
273
  return;
276
274
  }
277
- await uiRender$3({
278
- value: isEditable(mode, schema) ? text : substituteVariables(text, value),
275
+ const renderValue = isInlineMarkdownTextSchema(schema) ? substituteVariablesAsInlineMarkdownLiterals(text, value) : substituteVariables(text, value);
276
+ await uiRender$4({
277
+ value: isEditable(mode, schema) ? text : renderValue,
279
278
  schema,
280
279
  mode: mode === "form" ? "viewer" : mode,
281
280
  rootElement,
@@ -314,10 +313,27 @@ var formUiRender = async (arg) => {
314
313
  const parsed = JSON.parse(value);
315
314
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) variables = parsed;
316
315
  } catch {}
317
- const variableIndices = getVariableIndices(rawText);
318
316
  const substitutedText = substituteVariables(rawText, variables);
317
+ const inlineMarkdownRuns = isInlineMarkdownTextSchema(schema) ? parseInlineMarkdown(rawText) : void 0;
319
318
  const font = options?.font || getDefaultFont();
320
- const textBlock = buildStyledTextContainer(arg, await getFontKitFont(schema.fontName, font, _cache), substitutedText);
319
+ const textBlock = buildStyledTextContainer(arg, await getFontKitFont(schema.fontName, font, _cache), inlineMarkdownRuns ? getInlineMarkdownFormDisplayText(inlineMarkdownRuns, variables) : substitutedText);
320
+ if (inlineMarkdownRuns) {
321
+ renderInlineMarkdownVariableSpans({
322
+ runs: inlineMarkdownRuns,
323
+ variables,
324
+ textBlock,
325
+ schema,
326
+ font,
327
+ theme,
328
+ onChange,
329
+ stopEditing
330
+ });
331
+ return;
332
+ }
333
+ const variableIndices = /* @__PURE__ */ new Map();
334
+ visitVariables(rawText, ({ name, startIndex }) => {
335
+ variableIndices.set(startIndex, name);
336
+ });
321
337
  let inVarString = false;
322
338
  for (let i = 0; i < rawText.length; i++) {
323
339
  const variableName = variableIndices.get(i);
@@ -349,6 +365,97 @@ var formUiRender = async (arg) => {
349
365
  }
350
366
  }
351
367
  };
368
+ var getInlineMarkdownFormDisplayText = (runs, variables) => runs.map((run) => substituteVariables(run.text, variables)).join("");
369
+ var applyInlineMarkdownStyle = (arg) => {
370
+ const { element, run, schema, font } = arg;
371
+ const resolvedFont = resolveFontVariant(run, schema, font);
372
+ if (resolvedFont.fontName) element.style.fontFamily = `'${resolvedFont.fontName}'`;
373
+ if (resolvedFont.syntheticBold) {
374
+ element.style.fontWeight = "800";
375
+ element.style.textShadow = SYNTHETIC_BOLD_CSS_TEXT_SHADOW;
376
+ }
377
+ if (resolvedFont.syntheticItalic) element.style.fontStyle = "italic";
378
+ if (run.strikethrough) element.style.textDecoration = "line-through";
379
+ if (run.code) {
380
+ element.style.backgroundColor = CODE_BACKGROUND_COLOR;
381
+ element.style.borderRadius = "2px";
382
+ element.style.padding = "0 0.15em";
383
+ if (!schema.fontVariants?.code || !font[schema.fontVariants.code]) element.style.fontFamily = resolvedFont.fontName ? `'${resolvedFont.fontName}', monospace` : "monospace";
384
+ }
385
+ };
386
+ var appendTextSpan = (arg) => {
387
+ const { textBlock, text, run, schema, font } = arg;
388
+ if (!text) return;
389
+ const span = document.createElement("span");
390
+ span.textContent = text;
391
+ applyInlineMarkdownStyle({
392
+ element: span,
393
+ run,
394
+ schema,
395
+ font
396
+ });
397
+ textBlock.appendChild(span);
398
+ };
399
+ var appendVariableSpan = (arg) => {
400
+ const { textBlock, variableName, variables, run, schema, font, theme, onChange, stopEditing } = arg;
401
+ const span = document.createElement("span");
402
+ span.style.outline = `${theme.colorPrimary} dashed 1px`;
403
+ applyInlineMarkdownStyle({
404
+ element: span,
405
+ run,
406
+ schema,
407
+ font
408
+ });
409
+ makeElementPlainTextContentEditable(span);
410
+ span.textContent = variables[variableName] ?? "";
411
+ span.addEventListener("blur", (e) => {
412
+ const newValue = e.target.textContent || "";
413
+ if (newValue !== variables[variableName]) {
414
+ variables[variableName] = newValue;
415
+ if (onChange) onChange({
416
+ key: "content",
417
+ value: JSON.stringify(variables)
418
+ });
419
+ if (stopEditing) stopEditing();
420
+ }
421
+ });
422
+ textBlock.appendChild(span);
423
+ };
424
+ var renderInlineMarkdownVariableSpans = (arg) => {
425
+ const { runs, variables, textBlock, schema, font, theme, onChange, stopEditing } = arg;
426
+ textBlock.innerHTML = "";
427
+ runs.forEach((run) => {
428
+ let lastIndex = 0;
429
+ visitVariables(run.text, ({ name, startIndex, endIndex }) => {
430
+ appendTextSpan({
431
+ textBlock,
432
+ text: run.text.slice(lastIndex, startIndex),
433
+ run,
434
+ schema,
435
+ font
436
+ });
437
+ appendVariableSpan({
438
+ textBlock,
439
+ variableName: name,
440
+ variables,
441
+ run,
442
+ schema,
443
+ font,
444
+ theme,
445
+ onChange,
446
+ stopEditing
447
+ });
448
+ lastIndex = endIndex + 1;
449
+ });
450
+ appendTextSpan({
451
+ textBlock,
452
+ text: run.text.slice(lastIndex),
453
+ run,
454
+ schema,
455
+ font
456
+ });
457
+ });
458
+ };
352
459
  /**
353
460
  * An optimisation to try to minimise jank while typing.
354
461
  * Only check whether variables were modified based on certain key presses.
@@ -365,11 +472,775 @@ var keyPressShouldBeChecked = (event) => {
365
472
  //#endregion
366
473
  //#region src/multiVariableText/index.ts
367
474
  var schema$1 = {
475
+ pdf: pdfRender$3,
476
+ ui: uiRender$3,
477
+ propPanel: propPanel$2,
478
+ icon: createSvgStr(Type),
479
+ uninterruptedEditMode: true
480
+ };
481
+ //#endregion
482
+ //#region src/shapes/rectAndEllipse.ts
483
+ var shape = {
484
+ ui: (arg) => {
485
+ const { schema, rootElement } = arg;
486
+ const div = document.createElement("div");
487
+ div.style.width = "100%";
488
+ div.style.height = "100%";
489
+ div.style.boxSizing = "border-box";
490
+ if (schema.type === "ellipse") div.style.borderRadius = "50%";
491
+ else if (schema.radius && schema.radius > 0) div.style.borderRadius = `${schema.radius}mm`;
492
+ div.style.borderWidth = `${schema.borderWidth ?? 0}mm`;
493
+ div.style.borderStyle = schema.borderWidth && schema.borderColor ? "solid" : "none";
494
+ div.style.borderColor = schema.borderColor ?? "transparent";
495
+ div.style.backgroundColor = schema.color ?? "transparent";
496
+ rootElement.appendChild(div);
497
+ },
498
+ pdf: (arg) => {
499
+ const { schema, page, options } = arg;
500
+ if (!schema.color && !schema.borderColor) return;
501
+ const { colorType } = options;
502
+ const cArg = {
503
+ schema,
504
+ pageHeight: page.getHeight()
505
+ };
506
+ const { position, width, height, rotate, opacity } = convertForPdfLayoutProps(cArg);
507
+ const { position: { x: x4Ellipse, y: y4Ellipse } } = convertForPdfLayoutProps({
508
+ ...cArg,
509
+ applyRotateTranslate: false
510
+ });
511
+ const borderWidth = schema.borderWidth ? mm2pt(schema.borderWidth) : 0;
512
+ const drawOptions = {
513
+ rotate,
514
+ borderWidth,
515
+ borderColor: hex2PrintingColor(schema.borderColor, colorType),
516
+ color: hex2PrintingColor(schema.color, colorType),
517
+ opacity,
518
+ borderOpacity: opacity
519
+ };
520
+ if (schema.type === "ellipse") page.drawEllipse({
521
+ x: x4Ellipse + width / 2,
522
+ y: y4Ellipse + height / 2,
523
+ xScale: width / 2 - borderWidth / 2,
524
+ yScale: height / 2 - borderWidth / 2,
525
+ ...drawOptions
526
+ });
527
+ else if (schema.type === "rectangle") {
528
+ const radius = schema.radius ?? 0;
529
+ page.drawRectangle({
530
+ x: position.x + borderWidth * ((1 - Math.sin(toRadians(rotate))) / 2) + Math.tan(toRadians(rotate)) * Math.PI ** 2,
531
+ y: position.y + borderWidth * ((1 + Math.sin(toRadians(rotate))) / 2) + Math.tan(toRadians(rotate)) * Math.PI ** 2,
532
+ width: width - borderWidth,
533
+ height: height - borderWidth,
534
+ ...radius ? { radius: mm2pt(radius) } : {},
535
+ ...drawOptions
536
+ });
537
+ }
538
+ },
539
+ propPanel: {
540
+ schema: ({ i18n }) => ({
541
+ borderWidth: {
542
+ title: i18n("schemas.borderWidth"),
543
+ type: "number",
544
+ widget: "inputNumber",
545
+ props: {
546
+ min: 0,
547
+ step: 1
548
+ },
549
+ span: 12
550
+ },
551
+ borderColor: {
552
+ title: i18n("schemas.borderColor"),
553
+ type: "string",
554
+ widget: "color",
555
+ props: { disabledAlpha: true },
556
+ rules: [{
557
+ pattern: HEX_COLOR_PATTERN,
558
+ message: i18n("validation.hexColor")
559
+ }],
560
+ span: 12
561
+ },
562
+ color: {
563
+ title: i18n("schemas.color"),
564
+ type: "string",
565
+ widget: "color",
566
+ props: { disabledAlpha: true },
567
+ rules: [{
568
+ pattern: HEX_COLOR_PATTERN,
569
+ message: i18n("validation.hexColor")
570
+ }]
571
+ },
572
+ radius: {
573
+ title: i18n("schemas.radius"),
574
+ type: "number",
575
+ widget: "inputNumber",
576
+ props: {
577
+ min: 0,
578
+ step: 1
579
+ },
580
+ span: 12
581
+ }
582
+ }),
583
+ defaultSchema: {
584
+ name: "",
585
+ type: "rectangle",
586
+ position: {
587
+ x: 0,
588
+ y: 0
589
+ },
590
+ width: 62.5,
591
+ height: 37.5,
592
+ rotate: 0,
593
+ opacity: 1,
594
+ borderWidth: 1,
595
+ borderColor: "#000000",
596
+ color: "",
597
+ readOnly: true,
598
+ radius: 0
599
+ }
600
+ }
601
+ };
602
+ var getPropPanelSchema = (type) => ({
603
+ ...shape.propPanel,
604
+ defaultSchema: {
605
+ ...shape.propPanel.defaultSchema,
606
+ type
607
+ }
608
+ });
609
+ var rectangle = {
610
+ ...shape,
611
+ propPanel: getPropPanelSchema("rectangle"),
612
+ icon: createSvgStr(Square)
613
+ };
614
+ var ellipse = {
615
+ ...shape,
616
+ propPanel: getPropPanelSchema("ellipse"),
617
+ icon: createSvgStr(Circle)
618
+ };
619
+ //#endregion
620
+ //#region src/list/pdfRender.ts
621
+ var rectanglePdfRender$2 = rectangle.pdf;
622
+ var pdfRender$2 = async (arg) => {
623
+ const { schema, value } = arg;
624
+ const items = normalizeListItems(value);
625
+ const range = schema.__itemRange ?? {
626
+ start: 0,
627
+ end: items.length
628
+ };
629
+ const visibleItems = items.slice(range.start, range.end);
630
+ if (visibleItems.length === 0) return;
631
+ const layout = await calculateListLayout({
632
+ schema,
633
+ items: visibleItems,
634
+ markerItems: items,
635
+ startIndex: range.start,
636
+ options: arg.options,
637
+ _cache: arg._cache
638
+ });
639
+ if (schema.backgroundColor) await rectanglePdfRender$2({
640
+ ...arg,
641
+ schema: {
642
+ ...schema,
643
+ type: "rectangle",
644
+ borderWidth: 0,
645
+ borderColor: "",
646
+ color: schema.backgroundColor
647
+ }
648
+ });
649
+ let y = schema.position.y;
650
+ for (const item of layout.items) {
651
+ await pdfRender$4({
652
+ ...arg,
653
+ value: item.marker,
654
+ schema: {
655
+ ...schema,
656
+ type: "text",
657
+ position: {
658
+ x: schema.position.x + item.markerX,
659
+ y
660
+ },
661
+ width: layout.markerWidth,
662
+ height: item.height,
663
+ backgroundColor: "",
664
+ alignment: "right",
665
+ verticalAlignment: "top",
666
+ dynamicFontSize: void 0
667
+ }
668
+ });
669
+ await pdfRender$4({
670
+ ...arg,
671
+ value: item.item,
672
+ schema: {
673
+ ...schema,
674
+ type: "text",
675
+ position: {
676
+ x: schema.position.x + item.bodyX,
677
+ y
678
+ },
679
+ width: item.bodyWidth,
680
+ height: item.height,
681
+ backgroundColor: "",
682
+ verticalAlignment: "top",
683
+ dynamicFontSize: void 0
684
+ }
685
+ });
686
+ y += item.height;
687
+ }
688
+ };
689
+ //#endregion
690
+ //#region src/list/propPanel.ts
691
+ var propPanel$1 = {
692
+ schema: (propPanelProps) => {
693
+ if (typeof propPanel$3.schema !== "function") throw new Error("Oops, is text schema no longer a function?");
694
+ const parentSchema = propPanel$3.schema(propPanelProps);
695
+ const i18n = propPanelProps.i18n;
696
+ const listSchema = { ...parentSchema };
697
+ delete listSchema.useDynamicFontSize;
698
+ delete listSchema.dynamicFontSize;
699
+ return {
700
+ ...listSchema,
701
+ "-------": {
702
+ type: "void",
703
+ widget: "Divider"
704
+ },
705
+ listStyle: {
706
+ title: i18n("schemas.list.listStyle"),
707
+ type: "string",
708
+ widget: "select",
709
+ props: { options: [{
710
+ label: i18n("schemas.list.bullet"),
711
+ value: LIST_STYLE_BULLET
712
+ }, {
713
+ label: i18n("schemas.list.ordered"),
714
+ value: LIST_STYLE_ORDERED
715
+ }] },
716
+ span: 24
717
+ },
718
+ markerWidth: {
719
+ title: i18n("schemas.list.markerWidth"),
720
+ type: "number",
721
+ widget: "inputNumber",
722
+ props: { min: 0 },
723
+ span: 6
724
+ },
725
+ markerGap: {
726
+ title: i18n("schemas.list.markerGap"),
727
+ type: "number",
728
+ widget: "inputNumber",
729
+ props: { min: 0 },
730
+ span: 6
731
+ },
732
+ indentSize: {
733
+ title: i18n("schemas.list.indentSize"),
734
+ type: "number",
735
+ widget: "inputNumber",
736
+ props: { min: 0 },
737
+ span: 6
738
+ },
739
+ itemSpacing: {
740
+ title: i18n("schemas.list.itemSpacing"),
741
+ type: "number",
742
+ widget: "inputNumber",
743
+ props: { min: 0 },
744
+ span: 6
745
+ }
746
+ };
747
+ },
748
+ widgets: propPanel$3.widgets,
749
+ defaultSchema: {
750
+ ...propPanel$3.defaultSchema,
751
+ type: "list",
752
+ content: JSON.stringify(["First item", "Second item"]),
753
+ width: 80,
754
+ height: 20,
755
+ listStyle: DEFAULT_LIST_STYLE,
756
+ markerWidth: 6,
757
+ markerGap: 2,
758
+ indentSize: 6,
759
+ itemSpacing: 1,
760
+ dynamicFontSize: void 0,
761
+ verticalAlignment: "top"
762
+ }
763
+ };
764
+ //#endregion
765
+ //#region src/list/uiRender.ts
766
+ var focusDataKey = "pdfmeListFocusIndex";
767
+ var actionDataKey = "pdfmeListAction";
768
+ var internalFocusDataKey = "pdfmeListInternalFocus";
769
+ var caretMarker = "​";
770
+ var pendingFocusIndexes = /* @__PURE__ */ new Map();
771
+ var getListFocusKey = (schema) => schema.id || schema.name;
772
+ var isComposingKeyboardEvent = (event) => event.isComposing || event.keyCode === 229;
773
+ var getText = (element) => {
774
+ const rawText = element.innerText;
775
+ const hasCaretMarker = rawText.includes(caretMarker);
776
+ let text = rawText.replace(/\u200B/g, "");
777
+ if (!hasCaretMarker && text.endsWith("\n")) text = text.slice(0, -1);
778
+ return text;
779
+ };
780
+ var setStyles = (element, styles) => {
781
+ Object.assign(element.style, styles);
782
+ };
783
+ var focusBody = (body) => {
784
+ body.focus();
785
+ const selection = window.getSelection();
786
+ const range = document.createRange();
787
+ if (selection && range) {
788
+ range.selectNodeContents(body);
789
+ range.collapse(false);
790
+ selection.removeAllRanges();
791
+ selection.addRange(range);
792
+ }
793
+ };
794
+ var getCaretRangeFromPoint = (x, y) => {
795
+ const documentWithCaret = document;
796
+ if (documentWithCaret.caretRangeFromPoint) return documentWithCaret.caretRangeFromPoint(x, y);
797
+ const caretPosition = documentWithCaret.caretPositionFromPoint?.(x, y);
798
+ if (!caretPosition) return null;
799
+ const range = document.createRange();
800
+ range.setStart(caretPosition.offsetNode, caretPosition.offset);
801
+ range.collapse(true);
802
+ return range;
803
+ };
804
+ var focusBodyFromMouseEvent = (body, event) => {
805
+ body.focus();
806
+ const range = getCaretRangeFromPoint(event.clientX, event.clientY);
807
+ if (!range || !body.contains(range.startContainer)) return;
808
+ const selection = window.getSelection();
809
+ if (!selection) return;
810
+ selection.removeAllRanges();
811
+ selection.addRange(range);
812
+ };
813
+ var getBodyEditor = (body) => body.querySelector("[contenteditable], [tabindex]");
814
+ var insertLineBreakAtSelection = (element) => {
815
+ const fallbackText = getText(element);
816
+ const selection = window.getSelection();
817
+ if (!selection?.rangeCount) {
818
+ element.innerText = `${fallbackText}\n${caretMarker}`;
819
+ focusBody(element);
820
+ return true;
821
+ }
822
+ const range = selection.getRangeAt(0);
823
+ if (!element.contains(range.commonAncestorContainer)) {
824
+ element.innerText = `${fallbackText}\n${caretMarker}`;
825
+ focusBody(element);
826
+ return true;
827
+ }
828
+ selection.deleteFromDocument();
829
+ const fragment = document.createDocumentFragment();
830
+ const lineBreak = document.createElement("br");
831
+ const marker = document.createTextNode(caretMarker);
832
+ fragment.append(lineBreak, marker);
833
+ range.insertNode(fragment);
834
+ range.setStart(marker, marker.length);
835
+ range.collapse(true);
836
+ selection.removeAllRanges();
837
+ selection.addRange(range);
838
+ if (!element.innerText.includes(caretMarker)) {
839
+ element.innerText = `${fallbackText}\n${caretMarker}`;
840
+ focusBody(element);
841
+ }
842
+ return true;
843
+ };
844
+ var createActionButton = (arg) => {
845
+ const button = document.createElement("button");
846
+ button.type = "button";
847
+ button.innerText = arg.label;
848
+ button.setAttribute("aria-label", arg.ariaLabel);
849
+ button.disabled = Boolean(arg.disabled);
850
+ setStyles(button, {
851
+ width: "18px",
852
+ height: "18px",
853
+ display: "inline-flex",
854
+ alignItems: "center",
855
+ justifyContent: "center",
856
+ padding: "0",
857
+ border: "1px solid #d9d9d9",
858
+ borderRadius: "3px",
859
+ background: "#ffffff",
860
+ color: "#333333",
861
+ fontSize: "11px",
862
+ lineHeight: "1",
863
+ cursor: arg.disabled ? "not-allowed" : "pointer",
864
+ opacity: arg.disabled ? .45 : 1
865
+ });
866
+ button.addEventListener("pointerdown", (event) => {
867
+ arg.onPressStart?.();
868
+ event.stopPropagation();
869
+ });
870
+ button.addEventListener("mousedown", (event) => {
871
+ arg.onPressStart?.();
872
+ event.preventDefault();
873
+ event.stopPropagation();
874
+ });
875
+ button.addEventListener("click", (event) => {
876
+ event.preventDefault();
877
+ event.stopPropagation();
878
+ if (!arg.disabled) arg.onClick();
879
+ });
880
+ return button;
881
+ };
882
+ var uiRender$2 = async (arg) => {
883
+ const { rootElement, schema, value, mode, onChange, stopEditing, tabIndex, placeholder } = arg;
884
+ const focusKey = getListFocusKey(schema);
885
+ const editable = isEditable(mode, schema);
886
+ const showControls = editable && (mode === "form" || mode === "designer");
887
+ const usePlaceholder = editable && !value && Boolean(placeholder);
888
+ const items = normalizeListItems(usePlaceholder ? placeholder || "" : value);
889
+ const originalItems = normalizeListItemEntries(value);
890
+ const range = schema.__itemRange ?? {
891
+ start: 0,
892
+ end: items.length
893
+ };
894
+ const visibleItems = items.slice(range.start, range.end);
895
+ const renderItems = visibleItems;
896
+ rootElement.innerHTML = "";
897
+ setStyles(rootElement, {
898
+ position: "relative",
899
+ width: "100%",
900
+ height: "100%",
901
+ backgroundColor: schema.backgroundColor || "transparent",
902
+ overflow: "visible"
903
+ });
904
+ const layout = await calculateListLayout({
905
+ schema,
906
+ items: renderItems,
907
+ markerItems: items,
908
+ startIndex: range.start,
909
+ options: arg.options,
910
+ _cache: arg._cache
911
+ });
912
+ const bodyElements = [];
913
+ const getEditedItems = () => layout.items.map((item, index) => ({
914
+ level: item.level,
915
+ text: getText(bodyElements[index])
916
+ }));
917
+ const getNextItems = () => {
918
+ const editedItems = getEditedItems();
919
+ if (usePlaceholder) return editedItems;
920
+ const nextItems = [...originalItems];
921
+ nextItems.splice(range.start, visibleItems.length, ...editedItems);
922
+ return nextItems;
923
+ };
924
+ const commitItems = (nextItems, focusIndex) => {
925
+ if (!onChange) return;
926
+ if (focusIndex !== void 0) {
927
+ rootElement.dataset[focusDataKey] = String(focusIndex);
928
+ pendingFocusIndexes.set(focusKey, focusIndex);
929
+ }
930
+ onChange({
931
+ key: "content",
932
+ value: serializeListItems(nextItems)
933
+ });
934
+ };
935
+ const commitHeight = async (focusIndex) => {
936
+ if (!onChange) return;
937
+ if (focusIndex !== void 0) {
938
+ rootElement.dataset[focusDataKey] = String(focusIndex);
939
+ pendingFocusIndexes.set(focusKey, focusIndex);
940
+ }
941
+ const rawItems = normalizeListItems(serializeListItems(getNextItems()));
942
+ const nextLayout = await calculateListLayout({
943
+ schema,
944
+ items: rawItems.slice(range.start, range.end),
945
+ markerItems: rawItems,
946
+ startIndex: range.start,
947
+ options: arg.options,
948
+ _cache: arg._cache
949
+ });
950
+ if (schema.height !== nextLayout.totalHeight) onChange({
951
+ key: "height",
952
+ value: nextLayout.totalHeight
953
+ });
954
+ };
955
+ const preserveEditingForAction = () => {
956
+ rootElement.dataset[actionDataKey] = "true";
957
+ };
958
+ const updateItems = (rowIndex, mutate) => {
959
+ const nextItems = getNextItems();
960
+ if (nextItems.length === 0) nextItems.push({
961
+ level: 0,
962
+ text: ""
963
+ });
964
+ const focusIndex = mutate(nextItems, Math.min(Math.max(range.start + rowIndex, 0), nextItems.length - 1));
965
+ preserveEditingForAction();
966
+ commitItems(nextItems, focusIndex);
967
+ };
968
+ const preserveEditingForInternalFocus = () => {
969
+ rootElement.dataset[internalFocusDataKey] = "true";
970
+ };
971
+ const preserveEditingForKeyboardCommit = () => {
972
+ preserveEditingForInternalFocus();
973
+ setTimeout(() => {
974
+ if (rootElement.dataset[internalFocusDataKey] === "true") delete rootElement.dataset[internalFocusDataKey];
975
+ });
976
+ };
977
+ const handleInternalFocusPointer = (event) => {
978
+ preserveEditingForInternalFocus();
979
+ event.stopPropagation();
980
+ };
981
+ const handleBodyMouseDown = (body, event) => {
982
+ handleInternalFocusPointer(event);
983
+ focusBodyFromMouseEvent(body, event);
984
+ };
985
+ const appendEmptyListControls = () => {
986
+ const controls = document.createElement("div");
987
+ controls.addEventListener("pointerdown", preserveEditingForAction);
988
+ controls.addEventListener("mousedown", preserveEditingForAction);
989
+ setStyles(controls, {
990
+ position: "absolute",
991
+ top: "0mm",
992
+ right: "-20px",
993
+ display: "flex",
994
+ gap: "2px"
995
+ });
996
+ controls.appendChild(createActionButton({
997
+ label: "+",
998
+ ariaLabel: arg.i18n("schemas.list.addItem"),
999
+ onPressStart: preserveEditingForAction,
1000
+ onClick: () => {
1001
+ const nextItems = [...originalItems];
1002
+ nextItems.splice(range.start, 0, {
1003
+ level: 0,
1004
+ text: ""
1005
+ });
1006
+ commitItems(nextItems, range.start);
1007
+ }
1008
+ }));
1009
+ rootElement.appendChild(controls);
1010
+ };
1011
+ let offsetY = 0;
1012
+ for (let index = 0; index < layout.items.length; index += 1) {
1013
+ const item = layout.items[index];
1014
+ const row = document.createElement("div");
1015
+ setStyles(row, {
1016
+ position: "absolute",
1017
+ top: `${offsetY}mm`,
1018
+ left: "0mm",
1019
+ width: `${schema.width}mm`,
1020
+ height: `${item.height}mm`
1021
+ });
1022
+ const marker = document.createElement("div");
1023
+ setStyles(marker, {
1024
+ position: "absolute",
1025
+ top: "0mm",
1026
+ left: `${item.markerX}mm`,
1027
+ width: `${layout.markerWidth}mm`,
1028
+ height: "100%",
1029
+ backgroundColor: "transparent",
1030
+ cursor: "default"
1031
+ });
1032
+ const body = document.createElement("div");
1033
+ setStyles(body, {
1034
+ position: "absolute",
1035
+ top: "0mm",
1036
+ left: `${item.bodyX}mm`,
1037
+ width: `${item.bodyWidth}mm`,
1038
+ height: `${item.height}mm`,
1039
+ backgroundColor: "transparent",
1040
+ cursor: editable ? "text" : "default"
1041
+ });
1042
+ const schemaForUI = schema;
1043
+ const textSchema = {
1044
+ ...schema,
1045
+ id: `${schemaForUI.id || schema.name}-list-item-${item.itemIndex}`,
1046
+ name: `${schema.name}-list-item-${item.itemIndex}`,
1047
+ type: "text",
1048
+ content: item.item,
1049
+ position: {
1050
+ x: 0,
1051
+ y: 0
1052
+ },
1053
+ width: item.bodyWidth,
1054
+ height: item.height,
1055
+ alignment: schema.alignment ?? "left",
1056
+ fontSize: schema.fontSize ?? 13,
1057
+ lineHeight: schema.lineHeight ?? 1,
1058
+ characterSpacing: schema.characterSpacing ?? 0,
1059
+ fontColor: usePlaceholder ? PLACEHOLDER_FONT_COLOR : schema.fontColor || "#000000",
1060
+ backgroundColor: ""
1061
+ };
1062
+ const markerTextSchema = {
1063
+ ...textSchema,
1064
+ id: `${schemaForUI.id || schema.name}-list-marker-${item.itemIndex}`,
1065
+ name: `${schema.name}-list-marker-${item.itemIndex}`,
1066
+ content: item.marker,
1067
+ width: layout.markerWidth,
1068
+ height: item.height,
1069
+ alignment: "right",
1070
+ fontColor: schema.fontColor || "#000000"
1071
+ };
1072
+ await uiRender$4({
1073
+ ...arg,
1074
+ rootElement: marker,
1075
+ schema: markerTextSchema,
1076
+ value: item.marker,
1077
+ mode: "viewer",
1078
+ placeholder: "",
1079
+ onChange: void 0,
1080
+ stopEditing: void 0
1081
+ });
1082
+ await uiRender$4({
1083
+ ...arg,
1084
+ rootElement: body,
1085
+ schema: textSchema,
1086
+ value: item.item,
1087
+ placeholder: "",
1088
+ onChange: void 0,
1089
+ stopEditing: void 0
1090
+ });
1091
+ if (editable) {
1092
+ const editor = getBodyEditor(body);
1093
+ if (!editor) throw new Error("Unable to find list item text editor");
1094
+ editor.tabIndex = tabIndex || 0;
1095
+ body.addEventListener("pointerdown", handleInternalFocusPointer);
1096
+ body.addEventListener("mousedown", (event) => {
1097
+ handleBodyMouseDown(editor, event);
1098
+ });
1099
+ body.addEventListener("click", (event) => {
1100
+ event.stopPropagation();
1101
+ focusBodyFromMouseEvent(editor, event);
1102
+ });
1103
+ editor.addEventListener("focus", () => {
1104
+ if (usePlaceholder) {
1105
+ editor.innerText = "";
1106
+ editor.style.color = schema.fontColor || "#000000";
1107
+ }
1108
+ });
1109
+ body.addEventListener("blur", (event) => {
1110
+ const isListAction = rootElement.dataset[actionDataKey] === "true";
1111
+ const relatedTarget = event.relatedTarget;
1112
+ const isInternalFocus = rootElement.dataset[internalFocusDataKey] === "true" || relatedTarget instanceof Node && rootElement.contains(relatedTarget);
1113
+ delete rootElement.dataset[internalFocusDataKey];
1114
+ if (isListAction || isInternalFocus) return;
1115
+ if (!onChange) return;
1116
+ commitItems(getNextItems());
1117
+ if (stopEditing) stopEditing();
1118
+ }, true);
1119
+ editor.addEventListener("keydown", (event) => {
1120
+ if (event.key === "Enter") {
1121
+ if (isComposingKeyboardEvent(event)) return;
1122
+ event.preventDefault();
1123
+ if (insertLineBreakAtSelection(editor)) {
1124
+ preserveEditingForKeyboardCommit();
1125
+ if (mode === "form") commitHeight(range.start + index);
1126
+ else commitItems(getNextItems(), range.start + index);
1127
+ }
1128
+ } else if (event.key === "Tab") {
1129
+ event.preventDefault();
1130
+ updateItems(index, (nextItems, itemIndex) => {
1131
+ const itemToUpdate = nextItems[itemIndex];
1132
+ itemToUpdate.level = event.shiftKey ? Math.max(itemToUpdate.level - 1, 0) : Math.min(itemToUpdate.level + 1, 8);
1133
+ return itemIndex;
1134
+ });
1135
+ } else if (event.key === "Backspace" && getText(editor) === "") {
1136
+ event.preventDefault();
1137
+ updateItems(index, (nextItems, itemIndex) => {
1138
+ if (nextItems.length <= 1) {
1139
+ nextItems.splice(0);
1140
+ return;
1141
+ }
1142
+ nextItems.splice(itemIndex, 1);
1143
+ return Math.min(itemIndex, nextItems.length - 1);
1144
+ });
1145
+ }
1146
+ });
1147
+ bodyElements.push(editor);
1148
+ }
1149
+ row.appendChild(marker);
1150
+ row.appendChild(body);
1151
+ if (showControls) {
1152
+ const controls = document.createElement("div");
1153
+ controls.addEventListener("pointerdown", preserveEditingForAction);
1154
+ controls.addEventListener("mousedown", preserveEditingForAction);
1155
+ setStyles(controls, {
1156
+ position: "absolute",
1157
+ top: "0mm",
1158
+ right: "-82px",
1159
+ display: "flex",
1160
+ gap: "2px"
1161
+ });
1162
+ controls.appendChild(createActionButton({
1163
+ label: "+",
1164
+ ariaLabel: arg.i18n("schemas.list.addItem"),
1165
+ onPressStart: preserveEditingForAction,
1166
+ onClick: () => {
1167
+ updateItems(index, (nextItems, itemIndex) => {
1168
+ nextItems.splice(itemIndex + 1, 0, {
1169
+ level: nextItems[itemIndex]?.level ?? 0,
1170
+ text: ""
1171
+ });
1172
+ return itemIndex + 1;
1173
+ });
1174
+ }
1175
+ }));
1176
+ controls.appendChild(createActionButton({
1177
+ label: "-",
1178
+ ariaLabel: arg.i18n("schemas.list.removeItem"),
1179
+ onPressStart: preserveEditingForAction,
1180
+ onClick: () => {
1181
+ updateItems(index, (nextItems, itemIndex) => {
1182
+ if (nextItems.length <= 1) {
1183
+ nextItems.splice(0);
1184
+ return;
1185
+ }
1186
+ nextItems.splice(itemIndex, 1);
1187
+ return Math.min(itemIndex, nextItems.length - 1);
1188
+ });
1189
+ }
1190
+ }));
1191
+ controls.appendChild(createActionButton({
1192
+ label: "<",
1193
+ ariaLabel: arg.i18n("schemas.list.outdentItem"),
1194
+ disabled: item.level === 0,
1195
+ onPressStart: preserveEditingForAction,
1196
+ onClick: () => {
1197
+ updateItems(index, (nextItems, itemIndex) => {
1198
+ nextItems[itemIndex].level = Math.max(nextItems[itemIndex].level - 1, 0);
1199
+ return itemIndex;
1200
+ });
1201
+ }
1202
+ }));
1203
+ controls.appendChild(createActionButton({
1204
+ label: ">",
1205
+ ariaLabel: arg.i18n("schemas.list.indentItem"),
1206
+ disabled: item.level >= 8,
1207
+ onPressStart: preserveEditingForAction,
1208
+ onClick: () => {
1209
+ updateItems(index, (nextItems, itemIndex) => {
1210
+ nextItems[itemIndex].level = Math.min(nextItems[itemIndex].level + 1, 8);
1211
+ return itemIndex;
1212
+ });
1213
+ }
1214
+ }));
1215
+ row.appendChild(controls);
1216
+ }
1217
+ rootElement.appendChild(row);
1218
+ offsetY += item.height;
1219
+ }
1220
+ if (showControls && visibleItems.length === 0) appendEmptyListControls();
1221
+ const pendingFocusIndex = pendingFocusIndexes.get(focusKey);
1222
+ if (pendingFocusIndex !== void 0) pendingFocusIndexes.delete(focusKey);
1223
+ const requestedFocusIndex = Number(rootElement.dataset[focusDataKey] ?? pendingFocusIndex);
1224
+ delete rootElement.dataset[focusDataKey];
1225
+ delete rootElement.dataset[actionDataKey];
1226
+ delete rootElement.dataset[internalFocusDataKey];
1227
+ const relativeFocusIndex = requestedFocusIndex - range.start;
1228
+ if (editable && Number.isFinite(requestedFocusIndex) && bodyElements[relativeFocusIndex]) setTimeout(() => focusBody(bodyElements[relativeFocusIndex]));
1229
+ else if (editable && mode === "designer" && bodyElements[0]) setTimeout(() => {
1230
+ if (!rootElement.contains(document.activeElement)) focusBody(bodyElements[0]);
1231
+ });
1232
+ if (schema.height !== layout.totalHeight && onChange) onChange({
1233
+ key: "height",
1234
+ value: layout.totalHeight
1235
+ });
1236
+ };
1237
+ //#endregion
1238
+ //#region src/list/index.ts
1239
+ var listSchema = {
368
1240
  pdf: pdfRender$2,
369
1241
  ui: uiRender$2,
370
1242
  propPanel: propPanel$1,
371
- icon: createSvgStr(Type),
372
- uninterruptedEditMode: true
1243
+ icon: createSvgStr(List)
373
1244
  };
374
1245
  //#endregion
375
1246
  //#region src/graphics/imagehelper.ts
@@ -457,7 +1328,30 @@ var imageSize = (imgBuffer) => {
457
1328
  };
458
1329
  //#endregion
459
1330
  //#region src/graphics/image.ts
460
- var getCacheKey = (schema, input) => `${schema.type}${input}`;
1331
+ /**
1332
+ * Build a short fingerprint for a potentially-large base64 image string.
1333
+ * Previously `${schema.type}${input}` was used, pinning multi-MB base64
1334
+ * strings in the cache Map forever — every unique image input created a
1335
+ * permanent Map key whose byte length matched the image itself.
1336
+ *
1337
+ * The fingerprint is an FNV-1a 32-bit hash over the full input, combined
1338
+ * with the schema type and input byte length. An earlier revision sampled
1339
+ * three 16-char regions (first + middle + last) instead of hashing, but
1340
+ * the first-16 slice is a constant data-URI prefix for any image of the
1341
+ * same MIME type (`data:image/png;b…` / `data:image/jpeg…`), contributing
1342
+ * no entropy. Hashing every byte removes that weakness at the same O(n)
1343
+ * cost, without retaining any slice of the input as a Map key. Keys stay
1344
+ * well under ~40 chars regardless of input size.
1345
+ */
1346
+ var getCacheKey = (schema, input) => {
1347
+ let hash = 2166136261;
1348
+ for (let i = 0; i < input.length; i++) {
1349
+ hash ^= input.charCodeAt(i);
1350
+ hash = Math.imul(hash, 16777619);
1351
+ }
1352
+ const hex = (hash >>> 0).toString(16).padStart(8, "0");
1353
+ return `${schema.type}:${input.length}:${hex}`;
1354
+ };
461
1355
  var fullSize$1 = {
462
1356
  width: "100%",
463
1357
  height: "100%"
@@ -1406,144 +2300,6 @@ var lineSchema = {
1406
2300
  icon: createSvgStr(Minus)
1407
2301
  };
1408
2302
  //#endregion
1409
- //#region src/shapes/rectAndEllipse.ts
1410
- var shape = {
1411
- ui: (arg) => {
1412
- const { schema, rootElement } = arg;
1413
- const div = document.createElement("div");
1414
- div.style.width = "100%";
1415
- div.style.height = "100%";
1416
- div.style.boxSizing = "border-box";
1417
- if (schema.type === "ellipse") div.style.borderRadius = "50%";
1418
- else if (schema.radius && schema.radius > 0) div.style.borderRadius = `${schema.radius}mm`;
1419
- div.style.borderWidth = `${schema.borderWidth ?? 0}mm`;
1420
- div.style.borderStyle = schema.borderWidth && schema.borderColor ? "solid" : "none";
1421
- div.style.borderColor = schema.borderColor ?? "transparent";
1422
- div.style.backgroundColor = schema.color ?? "transparent";
1423
- rootElement.appendChild(div);
1424
- },
1425
- pdf: (arg) => {
1426
- const { schema, page, options } = arg;
1427
- if (!schema.color && !schema.borderColor) return;
1428
- const { colorType } = options;
1429
- const cArg = {
1430
- schema,
1431
- pageHeight: page.getHeight()
1432
- };
1433
- const { position, width, height, rotate, opacity } = convertForPdfLayoutProps(cArg);
1434
- const { position: { x: x4Ellipse, y: y4Ellipse } } = convertForPdfLayoutProps({
1435
- ...cArg,
1436
- applyRotateTranslate: false
1437
- });
1438
- const borderWidth = schema.borderWidth ? mm2pt(schema.borderWidth) : 0;
1439
- const drawOptions = {
1440
- rotate,
1441
- borderWidth,
1442
- borderColor: hex2PrintingColor(schema.borderColor, colorType),
1443
- color: hex2PrintingColor(schema.color, colorType),
1444
- opacity,
1445
- borderOpacity: opacity
1446
- };
1447
- if (schema.type === "ellipse") page.drawEllipse({
1448
- x: x4Ellipse + width / 2,
1449
- y: y4Ellipse + height / 2,
1450
- xScale: width / 2 - borderWidth / 2,
1451
- yScale: height / 2 - borderWidth / 2,
1452
- ...drawOptions
1453
- });
1454
- else if (schema.type === "rectangle") {
1455
- const radius = schema.radius ?? 0;
1456
- page.drawRectangle({
1457
- x: position.x + borderWidth * ((1 - Math.sin(toRadians(rotate))) / 2) + Math.tan(toRadians(rotate)) * Math.PI ** 2,
1458
- y: position.y + borderWidth * ((1 + Math.sin(toRadians(rotate))) / 2) + Math.tan(toRadians(rotate)) * Math.PI ** 2,
1459
- width: width - borderWidth,
1460
- height: height - borderWidth,
1461
- ...radius ? { radius: mm2pt(radius) } : {},
1462
- ...drawOptions
1463
- });
1464
- }
1465
- },
1466
- propPanel: {
1467
- schema: ({ i18n }) => ({
1468
- borderWidth: {
1469
- title: i18n("schemas.borderWidth"),
1470
- type: "number",
1471
- widget: "inputNumber",
1472
- props: {
1473
- min: 0,
1474
- step: 1
1475
- },
1476
- span: 12
1477
- },
1478
- borderColor: {
1479
- title: i18n("schemas.borderColor"),
1480
- type: "string",
1481
- widget: "color",
1482
- props: { disabledAlpha: true },
1483
- rules: [{
1484
- pattern: HEX_COLOR_PATTERN,
1485
- message: i18n("validation.hexColor")
1486
- }],
1487
- span: 12
1488
- },
1489
- color: {
1490
- title: i18n("schemas.color"),
1491
- type: "string",
1492
- widget: "color",
1493
- props: { disabledAlpha: true },
1494
- rules: [{
1495
- pattern: HEX_COLOR_PATTERN,
1496
- message: i18n("validation.hexColor")
1497
- }]
1498
- },
1499
- radius: {
1500
- title: i18n("schemas.radius"),
1501
- type: "number",
1502
- widget: "inputNumber",
1503
- props: {
1504
- min: 0,
1505
- step: 1
1506
- },
1507
- span: 12
1508
- }
1509
- }),
1510
- defaultSchema: {
1511
- name: "",
1512
- type: "rectangle",
1513
- position: {
1514
- x: 0,
1515
- y: 0
1516
- },
1517
- width: 62.5,
1518
- height: 37.5,
1519
- rotate: 0,
1520
- opacity: 1,
1521
- borderWidth: 1,
1522
- borderColor: "#000000",
1523
- color: "",
1524
- readOnly: true,
1525
- radius: 0
1526
- }
1527
- }
1528
- };
1529
- var getPropPanelSchema = (type) => ({
1530
- ...shape.propPanel,
1531
- defaultSchema: {
1532
- ...shape.propPanel.defaultSchema,
1533
- type
1534
- }
1535
- });
1536
- var rectangle = {
1537
- ...shape,
1538
- propPanel: getPropPanelSchema("rectangle"),
1539
- icon: createSvgStr(Square)
1540
- };
1541
- var ellipse = {
1542
- ...shape,
1543
- propPanel: getPropPanelSchema("ellipse"),
1544
- icon: createSvgStr(Circle)
1545
- };
1546
- //#endregion
1547
2303
  //#region src/tables/cell.ts
1548
2304
  var linePdfRender = lineSchema.pdf;
1549
2305
  var rectanglePdfRender$1 = rectangle.pdf;
@@ -1615,7 +2371,7 @@ var cellSchema = {
1615
2371
  y: position.y
1616
2372
  }, borderWidth.left, height)
1617
2373
  ]);
1618
- await pdfRender$3({
2374
+ await pdfRender$4({
1619
2375
  ...arg,
1620
2376
  schema: {
1621
2377
  ...schema,
@@ -1635,7 +2391,7 @@ var cellSchema = {
1635
2391
  const { borderWidth, width, height, borderColor, backgroundColor } = schema;
1636
2392
  rootElement.style.backgroundColor = backgroundColor;
1637
2393
  const textDiv = createTextDiv(schema);
1638
- await uiRender$3({
2394
+ await uiRender$4({
1639
2395
  ...arg,
1640
2396
  schema: {
1641
2397
  ...schema,
@@ -1770,17 +2526,38 @@ var pdfRender = async (arg) => {
1770
2526
  };
1771
2527
  //#endregion
1772
2528
  //#region src/tables/uiRender.ts
1773
- var buttonSize = 30;
2529
+ var buttonSize = 18;
1774
2530
  function createButton(options) {
1775
2531
  const button = document.createElement("button");
2532
+ button.type = "button";
2533
+ button.innerText = options.text;
2534
+ if (options.ariaLabel) button.setAttribute("aria-label", options.ariaLabel);
1776
2535
  button.style.width = `${options.width}px`;
1777
2536
  button.style.height = `${options.height}px`;
1778
2537
  button.style.position = "absolute";
1779
2538
  button.style.top = options.top;
2539
+ button.style.display = "inline-flex";
2540
+ button.style.alignItems = "center";
2541
+ button.style.justifyContent = "center";
2542
+ button.style.padding = "0";
2543
+ button.style.border = "1px solid #d9d9d9";
2544
+ button.style.borderRadius = "3px";
2545
+ button.style.background = "#ffffff";
2546
+ button.style.color = "#333333";
2547
+ button.style.fontSize = "11px";
2548
+ button.style.lineHeight = "1";
2549
+ button.style.cursor = "pointer";
2550
+ button.style.zIndex = "20";
1780
2551
  if (options.left !== void 0) button.style.left = options.left;
1781
2552
  if (options.right !== void 0) button.style.right = options.right;
1782
- button.innerText = options.text;
1783
- button.onclick = options.onClick;
2553
+ button.addEventListener("mousedown", (event) => {
2554
+ event.preventDefault();
2555
+ });
2556
+ button.addEventListener("click", (event) => {
2557
+ event.preventDefault();
2558
+ event.stopPropagation();
2559
+ options.onClick(event);
2560
+ });
1784
2561
  return button;
1785
2562
  }
1786
2563
  var cellUiRender = cellSchema.ui;
@@ -1950,6 +2727,7 @@ var uiRender = async (arg) => {
1950
2727
  top: `${table.getHeight()}mm`,
1951
2728
  left: `calc(50% - ${buttonSize / 2}px)`,
1952
2729
  text: "+",
2730
+ ariaLabel: "Add row",
1953
2731
  onClick: () => {
1954
2732
  const newRow = Array(schema.head.length).fill("");
1955
2733
  if (onChange) onChange({
@@ -1968,6 +2746,7 @@ var uiRender = async (arg) => {
1968
2746
  top: `${offsetY - px2mm(buttonSize)}mm`,
1969
2747
  right: `-${buttonSize}px`,
1970
2748
  text: "-",
2749
+ ariaLabel: "Remove row",
1971
2750
  onClick: () => {
1972
2751
  const newTableBody = body.filter((_, j) => j !== i + (schema.__bodyRange?.start ?? 0));
1973
2752
  if (onChange) onChange({
@@ -1989,6 +2768,7 @@ var uiRender = async (arg) => {
1989
2768
  top: `${(showHead ? table.getHeadHeight() : 0) - px2mm(buttonSize)}mm`,
1990
2769
  right: `-${buttonSize}px`,
1991
2770
  text: "+",
2771
+ ariaLabel: "Add column",
1992
2772
  onClick: (e) => {
1993
2773
  e.preventDefault();
1994
2774
  const newColumnWidthPercentage = 25;
@@ -2024,6 +2804,7 @@ var uiRender = async (arg) => {
2024
2804
  top: `${-buttonSize}px`,
2025
2805
  left: `${offsetX - px2mm(buttonSize)}mm`,
2026
2806
  text: "-",
2807
+ ariaLabel: "Remove column",
2027
2808
  onClick: () => {
2028
2809
  const totalWidthMinusRemoved = schema.headWidthPercentages.reduce((sum, width, j) => j !== i ? sum + width : sum, 0);
2029
2810
  onChange([
@@ -5190,13 +5971,13 @@ var schema$3 = {
5190
5971
  propPanel: {
5191
5972
  ...textSchema.propPanel,
5192
5973
  widgets: {
5193
- ...propPanel$2.widgets,
5974
+ ...propPanel$3.widgets,
5194
5975
  addOptions
5195
5976
  },
5196
5977
  schema: (propPanelProps) => {
5197
- if (typeof propPanel$2.schema !== "function") throw Error("Oops, is text schema no longer a function?");
5978
+ if (typeof propPanel$3.schema !== "function") throw Error("Oops, is text schema no longer a function?");
5198
5979
  return {
5199
- ...propPanel$2.schema(propPanelProps),
5980
+ ...propPanel$3.schema(propPanelProps),
5200
5981
  "-------": {
5201
5982
  type: "void",
5202
5983
  widget: "Divider"
@@ -5378,6 +6159,6 @@ var schema = {
5378
6159
  icon: getCheckedIcon()
5379
6160
  };
5380
6161
  //#endregion
5381
- export { barcodes, builtInPlugins, schema as checkbox, date_default as date, dateTime_default as dateTime, ellipse, getDynamicHeightsForTable, imageSchema as image, lineSchema as line, schema$1 as multiVariableText, schema$2 as radioGroup, rectangle, schema$3 as select, signature, svgSchema as svg, tableSchema as table, textSchema as text, time_default as time };
6162
+ export { barcodes, builtInPlugins, schema as checkbox, date_default as date, dateTime_default as dateTime, ellipse, getDynamicHeightsForTable, getDynamicLayoutForList, getDynamicLayoutForTable, imageSchema as image, lineSchema as line, listSchema as list, schema$1 as multiVariableText, schema$2 as radioGroup, rectangle, schema$3 as select, signature, svgSchema as svg, tableSchema as table, textSchema as text, time_default as time };
5382
6163
 
5383
6164
  //# sourceMappingURL=index.js.map