@pdfme/schemas 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/.eslintrc.js +31 -0
  2. package/dist/cjs/__tests__/barcode.test.js +341 -0
  3. package/dist/cjs/__tests__/barcode.test.js.map +1 -0
  4. package/dist/cjs/__tests__/text.test.js +318 -0
  5. package/dist/cjs/__tests__/text.test.js.map +1 -0
  6. package/dist/cjs/src/barcodes/constants.js +19 -0
  7. package/dist/cjs/src/barcodes/constants.js.map +1 -0
  8. package/dist/cjs/src/barcodes/helper.js +147 -0
  9. package/dist/cjs/src/barcodes/helper.js.map +1 -0
  10. package/dist/cjs/src/barcodes/index.js +11 -0
  11. package/dist/cjs/src/barcodes/index.js.map +1 -0
  12. package/dist/cjs/src/barcodes/pdfRender.js +37 -0
  13. package/dist/cjs/src/barcodes/pdfRender.js.map +1 -0
  14. package/dist/cjs/src/barcodes/propPanel.js +69 -0
  15. package/dist/cjs/src/barcodes/propPanel.js.map +1 -0
  16. package/dist/cjs/src/barcodes/types.js +3 -0
  17. package/dist/cjs/src/barcodes/types.js.map +1 -0
  18. package/dist/cjs/src/barcodes/uiRender.js +92 -0
  19. package/dist/cjs/src/barcodes/uiRender.js.map +1 -0
  20. package/dist/cjs/src/image/constants.js +3 -0
  21. package/dist/cjs/src/image/constants.js.map +1 -0
  22. package/dist/cjs/src/image/helper.js +3 -0
  23. package/dist/cjs/src/image/helper.js.map +1 -0
  24. package/dist/cjs/src/image/index.js +8 -0
  25. package/dist/cjs/src/image/index.js.map +1 -0
  26. package/dist/cjs/src/image/pdfRender.js +34 -0
  27. package/dist/cjs/src/image/pdfRender.js.map +1 -0
  28. package/dist/cjs/src/image/propPanel.js +9 -0
  29. package/dist/cjs/src/image/propPanel.js.map +1 -0
  30. package/dist/cjs/src/image/types.js +3 -0
  31. package/dist/cjs/src/image/types.js.map +1 -0
  32. package/dist/cjs/src/image/uiRender.js +108 -0
  33. package/dist/cjs/src/image/uiRender.js.map +1 -0
  34. package/dist/cjs/src/index.js +13 -0
  35. package/dist/cjs/src/index.js.map +1 -0
  36. package/dist/cjs/src/renderUtils.js +65 -0
  37. package/dist/cjs/src/renderUtils.js.map +1 -0
  38. package/dist/cjs/src/text/constants.js +22 -0
  39. package/dist/cjs/src/text/constants.js.map +1 -0
  40. package/dist/cjs/src/text/helper.js +270 -0
  41. package/dist/cjs/src/text/helper.js.map +1 -0
  42. package/dist/cjs/src/text/index.js +8 -0
  43. package/dist/cjs/src/text/index.js.map +1 -0
  44. package/dist/cjs/src/text/pdfRender.js +111 -0
  45. package/dist/cjs/src/text/pdfRender.js.map +1 -0
  46. package/dist/cjs/src/text/propPanel.js +122 -0
  47. package/dist/cjs/src/text/propPanel.js.map +1 -0
  48. package/dist/cjs/src/text/types.js +3 -0
  49. package/dist/cjs/src/text/types.js.map +1 -0
  50. package/dist/cjs/src/text/uiRender.js +118 -0
  51. package/dist/cjs/src/text/uiRender.js.map +1 -0
  52. package/dist/esm/__tests__/barcode.test.js +336 -0
  53. package/dist/esm/__tests__/barcode.test.js.map +1 -0
  54. package/dist/esm/__tests__/text.test.js +293 -0
  55. package/dist/esm/__tests__/text.test.js.map +1 -0
  56. package/dist/esm/src/barcodes/constants.js +16 -0
  57. package/dist/esm/src/barcodes/constants.js.map +1 -0
  58. package/dist/esm/src/barcodes/helper.js +137 -0
  59. package/dist/esm/src/barcodes/helper.js.map +1 -0
  60. package/dist/esm/src/barcodes/index.js +9 -0
  61. package/dist/esm/src/barcodes/index.js.map +1 -0
  62. package/dist/esm/src/barcodes/pdfRender.js +33 -0
  63. package/dist/esm/src/barcodes/pdfRender.js.map +1 -0
  64. package/dist/esm/src/barcodes/propPanel.js +65 -0
  65. package/dist/esm/src/barcodes/propPanel.js.map +1 -0
  66. package/dist/esm/src/barcodes/types.js +2 -0
  67. package/dist/esm/src/barcodes/types.js.map +1 -0
  68. package/dist/esm/src/barcodes/uiRender.js +88 -0
  69. package/dist/esm/src/barcodes/uiRender.js.map +1 -0
  70. package/dist/esm/src/image/constants.js +2 -0
  71. package/dist/esm/src/image/constants.js.map +1 -0
  72. package/dist/esm/src/image/helper.js +2 -0
  73. package/dist/esm/src/image/helper.js.map +1 -0
  74. package/dist/esm/src/image/index.js +6 -0
  75. package/dist/esm/src/image/index.js.map +1 -0
  76. package/dist/esm/src/image/pdfRender.js +30 -0
  77. package/dist/esm/src/image/pdfRender.js.map +1 -0
  78. package/dist/esm/src/image/propPanel.js +6 -0
  79. package/dist/esm/src/image/propPanel.js.map +1 -0
  80. package/dist/esm/src/image/types.js +2 -0
  81. package/dist/esm/src/image/types.js.map +1 -0
  82. package/dist/esm/src/image/uiRender.js +104 -0
  83. package/dist/esm/src/image/uiRender.js.map +1 -0
  84. package/dist/esm/src/index.js +7 -0
  85. package/dist/esm/src/index.js.map +1 -0
  86. package/dist/esm/src/renderUtils.js +56 -0
  87. package/dist/esm/src/renderUtils.js.map +1 -0
  88. package/dist/esm/src/text/constants.js +19 -0
  89. package/dist/esm/src/text/constants.js.map +1 -0
  90. package/dist/esm/src/text/helper.js +237 -0
  91. package/dist/esm/src/text/helper.js.map +1 -0
  92. package/dist/esm/src/text/index.js +6 -0
  93. package/dist/esm/src/text/index.js.map +1 -0
  94. package/dist/esm/src/text/pdfRender.js +107 -0
  95. package/dist/esm/src/text/pdfRender.js.map +1 -0
  96. package/dist/esm/src/text/propPanel.js +119 -0
  97. package/dist/esm/src/text/propPanel.js.map +1 -0
  98. package/dist/esm/src/text/types.js +2 -0
  99. package/dist/esm/src/text/types.js.map +1 -0
  100. package/dist/esm/src/text/uiRender.js +114 -0
  101. package/dist/esm/src/text/uiRender.js.map +1 -0
  102. package/dist/types/__tests__/barcode.test.d.ts +1 -0
  103. package/dist/types/__tests__/text.test.d.ts +1 -0
  104. package/dist/types/src/barcodes/constants.d.ts +3 -0
  105. package/dist/types/src/barcodes/helper.d.ts +20 -0
  106. package/dist/types/src/barcodes/index.d.ts +4 -0
  107. package/dist/types/src/barcodes/pdfRender.d.ts +3 -0
  108. package/dist/types/src/barcodes/propPanel.d.ts +3 -0
  109. package/dist/types/src/barcodes/types.d.ts +9 -0
  110. package/dist/types/src/barcodes/uiRender.d.ts +3 -0
  111. package/dist/types/src/image/constants.d.ts +1 -0
  112. package/dist/types/src/image/helper.d.ts +1 -0
  113. package/dist/types/src/image/index.d.ts +4 -0
  114. package/dist/types/src/image/pdfRender.d.ts +3 -0
  115. package/dist/types/src/image/propPanel.d.ts +3 -0
  116. package/dist/types/src/image/types.d.ts +3 -0
  117. package/dist/types/src/image/uiRender.d.ts +3 -0
  118. package/dist/types/src/index.d.ts +3 -0
  119. package/dist/types/src/renderUtils.d.ts +16 -0
  120. package/dist/types/src/text/constants.d.ts +19 -0
  121. package/dist/types/src/text/helper.d.ts +29 -0
  122. package/dist/types/src/text/index.d.ts +4 -0
  123. package/dist/types/src/text/pdfRender.d.ts +3 -0
  124. package/dist/types/src/text/propPanel.d.ts +3 -0
  125. package/dist/types/src/text/types.d.ts +26 -0
  126. package/dist/types/src/text/uiRender.d.ts +3 -0
  127. package/package.json +86 -0
  128. package/src/barcodes/constants.ts +17 -0
  129. package/src/barcodes/helper.ts +161 -0
  130. package/src/barcodes/index.ts +16 -0
  131. package/src/barcodes/pdfRender.ts +29 -0
  132. package/src/barcodes/propPanel.ts +133 -0
  133. package/src/barcodes/types.ts +11 -0
  134. package/src/barcodes/uiRender.ts +116 -0
  135. package/src/image/constants.ts +1 -0
  136. package/src/image/helper.ts +1 -0
  137. package/src/image/index.ts +8 -0
  138. package/src/image/pdfRender.ts +24 -0
  139. package/src/image/propPanel.ts +8 -0
  140. package/src/image/types.ts +3 -0
  141. package/src/image/uiRender.ts +118 -0
  142. package/src/index.ts +7 -0
  143. package/src/renderUtils.ts +74 -0
  144. package/src/text/constants.ts +22 -0
  145. package/src/text/helper.ts +317 -0
  146. package/src/text/index.ts +9 -0
  147. package/src/text/pdfRender.ts +155 -0
  148. package/src/text/propPanel.ts +148 -0
  149. package/src/text/types.ts +29 -0
  150. package/src/text/uiRender.ts +153 -0
  151. package/tsconfig.cjs.json +10 -0
  152. package/tsconfig.esm.json +10 -0
  153. package/tsconfig.json +6 -0
@@ -0,0 +1,155 @@
1
+ import { PDFFont, PDFDocument } from '@pdfme/pdf-lib';
2
+ import { PDFRenderProps, Font, getDefaultFont, getFallbackFontName } from '@pdfme/common';
3
+ import type { TextSchema, FontWidthCalcValues } from './types';
4
+ import {
5
+ VERTICAL_ALIGN_TOP,
6
+ VERTICAL_ALIGN_MIDDLE,
7
+ VERTICAL_ALIGN_BOTTOM,
8
+ DEFAULT_FONT_SIZE,
9
+ DEFAULT_ALIGNMENT,
10
+ DEFAULT_VERTICAL_ALIGNMENT,
11
+ DEFAULT_LINE_HEIGHT,
12
+ DEFAULT_CHARACTER_SPACING,
13
+ DEFAULT_FONT_COLOR,
14
+ } from './constants';
15
+ import {
16
+ calculateDynamicFontSize,
17
+ heightOfFontAtSize,
18
+ getFontDescentInPt,
19
+ getFontKitFont,
20
+ getSplittedLines,
21
+ widthOfTextAtSize,
22
+ } from './helper';
23
+ import {
24
+ hex2RgbColor,
25
+ calcX,
26
+ calcY,
27
+ renderBackgroundColor,
28
+ convertSchemaDimensionsToPt,
29
+ } from '../renderUtils';
30
+
31
+ const embedAndGetFontObjCache = new WeakMap();
32
+ const embedAndGetFontObj = async (arg: { pdfDoc: PDFDocument; font: Font }) => {
33
+ const { pdfDoc, font } = arg;
34
+ if (embedAndGetFontObjCache.has(pdfDoc)) {
35
+ return embedAndGetFontObjCache.get(pdfDoc);
36
+ }
37
+
38
+ const fontValues = await Promise.all(
39
+ Object.values(font).map(async (v) => {
40
+ let fontData = v.data;
41
+ if (typeof fontData === 'string' && fontData.startsWith('http')) {
42
+ fontData = await fetch(fontData).then((res) => res.arrayBuffer());
43
+ }
44
+ return pdfDoc.embedFont(fontData, {
45
+ subset: typeof v.subset === 'undefined' ? true : v.subset,
46
+ });
47
+ })
48
+ );
49
+
50
+ const fontObj = Object.keys(font).reduce(
51
+ (acc, cur, i) => Object.assign(acc, { [cur]: fontValues[i] }),
52
+ {} as { [key: string]: PDFFont }
53
+ );
54
+
55
+ embedAndGetFontObjCache.set(pdfDoc, fontObj);
56
+ return fontObj;
57
+ };
58
+
59
+ const getFontProp = async ({
60
+ value,
61
+ font,
62
+ schema,
63
+ }: {
64
+ value: string;
65
+ font: Font;
66
+ schema: TextSchema;
67
+ }) => {
68
+ const fontSize = schema.dynamicFontSize
69
+ ? await calculateDynamicFontSize({ textSchema: schema, font, value })
70
+ : schema.fontSize ?? DEFAULT_FONT_SIZE;
71
+ const color = hex2RgbColor(schema.fontColor || DEFAULT_FONT_COLOR);
72
+
73
+ return {
74
+ alignment: schema.alignment ?? DEFAULT_ALIGNMENT,
75
+ verticalAlignment: schema.verticalAlignment ?? DEFAULT_VERTICAL_ALIGNMENT,
76
+ lineHeight: schema.lineHeight ?? DEFAULT_LINE_HEIGHT,
77
+ characterSpacing: schema.characterSpacing ?? DEFAULT_CHARACTER_SPACING,
78
+ fontSize,
79
+ color,
80
+ };
81
+ };
82
+
83
+ export const pdfRender = async (arg: PDFRenderProps<TextSchema>) => {
84
+ const { value, pdfDoc, pdfLib, page, options, schema } = arg;
85
+
86
+ const { font = getDefaultFont() } = options;
87
+
88
+ const [pdfFontObj, fontKitFont, fontProp] = await Promise.all([
89
+ embedAndGetFontObj({ pdfDoc, font }),
90
+ getFontKitFont(schema, font),
91
+ getFontProp({ value, font, schema }),
92
+ ]);
93
+
94
+ const { fontSize, color, alignment, verticalAlignment, lineHeight, characterSpacing } = fontProp;
95
+
96
+ const fontName = (
97
+ schema.fontName ? schema.fontName : getFallbackFontName(font)
98
+ ) as keyof typeof pdfFontObj;
99
+ const pdfFontValue = pdfFontObj[fontName];
100
+
101
+ const pageHeight = page.getHeight();
102
+ renderBackgroundColor({ schema, page, pageHeight });
103
+
104
+ const { width, height, rotate } = convertSchemaDimensionsToPt(schema);
105
+
106
+ page.pushOperators(pdfLib.setCharacterSpacing(characterSpacing ?? DEFAULT_CHARACTER_SPACING));
107
+
108
+ const firstLineTextHeight = heightOfFontAtSize(fontKitFont, fontSize);
109
+ const descent = getFontDescentInPt(fontKitFont, fontSize);
110
+ const halfLineHeightAdjustment = lineHeight === 0 ? 0 : ((lineHeight - 1) * fontSize) / 2;
111
+
112
+ const fontWidthCalcValues: FontWidthCalcValues = {
113
+ font: fontKitFont,
114
+ fontSize,
115
+ characterSpacing,
116
+ boxWidthInPt: width,
117
+ };
118
+
119
+ let lines: string[] = [];
120
+ value.split(/\r|\n|\r\n/g).forEach((line) => {
121
+ lines = lines.concat(getSplittedLines(line, fontWidthCalcValues));
122
+ });
123
+
124
+ // Text lines are rendered from the bottom upwards, we need to adjust the position down
125
+ let yOffset = 0;
126
+ if (verticalAlignment === VERTICAL_ALIGN_TOP) {
127
+ yOffset = firstLineTextHeight + halfLineHeightAdjustment;
128
+ } else {
129
+ const otherLinesHeight = lineHeight * fontSize * (lines.length - 1);
130
+
131
+ if (verticalAlignment === VERTICAL_ALIGN_BOTTOM) {
132
+ yOffset = height - otherLinesHeight + descent - halfLineHeightAdjustment;
133
+ } else if (verticalAlignment === VERTICAL_ALIGN_MIDDLE) {
134
+ yOffset =
135
+ (height - otherLinesHeight - firstLineTextHeight + descent) / 2 + firstLineTextHeight;
136
+ }
137
+ }
138
+
139
+ lines.forEach((line, rowIndex) => {
140
+ const textWidth = widthOfTextAtSize(line, fontKitFont, fontSize, characterSpacing);
141
+ const rowYOffset = lineHeight * fontSize * rowIndex;
142
+
143
+ page.drawText(line, {
144
+ x: calcX(schema.position.x, alignment, width, textWidth),
145
+ y: calcY(schema.position.y, pageHeight, yOffset) - rowYOffset,
146
+ rotate,
147
+ size: fontSize,
148
+ color,
149
+ lineHeight: lineHeight * fontSize,
150
+ maxWidth: width,
151
+ font: pdfFontValue,
152
+ wordBreaks: [''],
153
+ });
154
+ });
155
+ };
@@ -0,0 +1,148 @@
1
+ import {
2
+ DEFAULT_FONT_NAME,
3
+ PropPanel,
4
+ PropPanelWidgetProps,
5
+ PropPanelSchema,
6
+ getFallbackFontName,
7
+ } from '@pdfme/common';
8
+ import type { TextSchema } from './types';
9
+ import {
10
+ DEFAULT_FONT_SIZE,
11
+ DEFAULT_ALIGNMENT,
12
+ DEFAULT_VERTICAL_ALIGNMENT,
13
+ DEFAULT_CHARACTER_SPACING,
14
+ DEFAULT_LINE_HEIGHT,
15
+ VERTICAL_ALIGN_TOP,
16
+ VERTICAL_ALIGN_MIDDLE,
17
+ VERTICAL_ALIGN_BOTTOM,
18
+ DEFAULT_FONT_COLOR,
19
+ DYNAMIC_FIT_VERTICAL,
20
+ DYNAMIC_FIT_HORIZONTAL,
21
+ DEFAULT_DYNAMIC_FIT,
22
+ DEFAULT_DYNAMIC_MIN_FONT_SIZE,
23
+ DEFAULT_DYNAMIC_MAX_FONT_SIZE,
24
+ ALIGN_RIGHT,
25
+ ALIGN_CENTER,
26
+ } from './constants';
27
+
28
+ const UseDynamicFontSize = (props: PropPanelWidgetProps) => {
29
+ const { rootElement, changeSchemas, activeSchema } = props;
30
+
31
+ const checkbox = document.createElement('input');
32
+ checkbox.type = 'checkbox';
33
+ checkbox.checked = Boolean((activeSchema as any)?.dynamicFontSize);
34
+ checkbox.onchange = (e: any) => {
35
+ const val = e.target.checked
36
+ ? {
37
+ min: DEFAULT_DYNAMIC_MIN_FONT_SIZE,
38
+ max: DEFAULT_DYNAMIC_MAX_FONT_SIZE,
39
+ fit: DEFAULT_DYNAMIC_FIT,
40
+ }
41
+ : undefined;
42
+ changeSchemas([{ key: 'dynamicFontSize', value: val, schemaId: activeSchema.id }]);
43
+ };
44
+ const label = document.createElement('label');
45
+ label.innerText = 'Dynamic Font Size';
46
+ label.style.cssText = 'display: flex; width: 100%;';
47
+ label.appendChild(checkbox);
48
+ rootElement.appendChild(label);
49
+ };
50
+
51
+ export const propPanel: PropPanel<TextSchema> = {
52
+ propPanelSchema: ({ options, activeSchema }) => {
53
+ const font = options.font || { [DEFAULT_FONT_NAME]: { data: '', fallback: true } };
54
+ const fontNames = Object.keys(font);
55
+ const fallbackFontName = getFallbackFontName(font);
56
+
57
+ const enableDynamicFont = Boolean((activeSchema as any)?.dynamicFontSize);
58
+
59
+ const textSchema: Record<string, PropPanelSchema> = {
60
+ fontName: {
61
+ title: 'Font Name',
62
+ type: 'string',
63
+ widget: 'select',
64
+ default: fallbackFontName,
65
+ props: { options: fontNames.map((name) => ({ label: name, value: name })) },
66
+ span: 8,
67
+ },
68
+ alignment: {
69
+ title: 'Text Align',
70
+ type: 'string',
71
+ widget: 'select',
72
+ props: {
73
+ options: [
74
+ { label: 'Left', value: DEFAULT_ALIGNMENT },
75
+ { label: 'Center', value: ALIGN_CENTER },
76
+ { label: 'Right', value: ALIGN_RIGHT },
77
+ ],
78
+ },
79
+ span: 8,
80
+ },
81
+ verticalAlignment: {
82
+ title: 'Vertical Align',
83
+ type: 'string',
84
+ widget: 'select',
85
+ props: {
86
+ options: [
87
+ { label: 'Top', value: VERTICAL_ALIGN_TOP },
88
+ { label: 'Middle', value: VERTICAL_ALIGN_MIDDLE },
89
+ { label: 'Bottom', value: VERTICAL_ALIGN_BOTTOM },
90
+ ],
91
+ },
92
+ span: 8,
93
+ },
94
+ fontSize: {
95
+ title: 'Font Size',
96
+ type: 'number',
97
+ widget: 'inputNumber',
98
+ span: 8,
99
+ disabled: enableDynamicFont,
100
+ },
101
+ lineHeight: { title: 'Line Height', type: 'number', widget: 'inputNumber', span: 8 },
102
+ characterSpacing: { title: 'Char Spc', type: 'number', widget: 'inputNumber', span: 8 },
103
+ useDynamicFontSize: { type: 'boolean', widget: 'UseDynamicFontSize', bind: false },
104
+ dynamicFontSize: {
105
+ type: 'object',
106
+ widget: 'card',
107
+ column: 3,
108
+ properties: {
109
+ min: { title: 'Min', type: 'number', widget: 'inputNumber', hidden: !enableDynamicFont },
110
+ max: { title: 'Max', type: 'number', widget: 'inputNumber', hidden: !enableDynamicFont },
111
+ fit: {
112
+ title: 'Fit',
113
+ type: 'string',
114
+ widget: 'select',
115
+ hidden: !enableDynamicFont,
116
+ props: {
117
+ options: [
118
+ { label: 'Horizontal', value: DYNAMIC_FIT_HORIZONTAL },
119
+ { label: 'Vertical', value: DYNAMIC_FIT_VERTICAL },
120
+ ],
121
+ },
122
+ },
123
+ },
124
+ },
125
+ fontColor: { title: 'Font Color', type: 'string', widget: 'color' },
126
+ backgroundColor: { title: 'Background', type: 'string', widget: 'color' },
127
+ };
128
+
129
+ return textSchema;
130
+ },
131
+ widgets: { UseDynamicFontSize },
132
+ defaultValue: 'Type Something...',
133
+ defaultSchema: {
134
+ type: 'text',
135
+ position: { x: 0, y: 0 },
136
+ width: 45,
137
+ height: 10,
138
+ alignment: DEFAULT_ALIGNMENT,
139
+ verticalAlignment: DEFAULT_VERTICAL_ALIGNMENT,
140
+ fontSize: DEFAULT_FONT_SIZE,
141
+ lineHeight: DEFAULT_LINE_HEIGHT,
142
+ characterSpacing: DEFAULT_CHARACTER_SPACING,
143
+ dynamicFontSize: undefined,
144
+ fontColor: DEFAULT_FONT_COLOR,
145
+ fontName: undefined,
146
+ backgroundColor: '',
147
+ },
148
+ };
@@ -0,0 +1,29 @@
1
+ import type { Schema } from '@pdfme/common';
2
+ import type { Font as FontKitFont } from 'fontkit';
3
+
4
+ export type ALIGNMENT = 'left' | 'center' | 'right';
5
+ export type VERTICAL_ALIGNMENT = 'top' | 'middle' | 'bottom';
6
+ export type DYNAMIC_FONT_SIZE_FIT = 'horizontal' | 'vertical';
7
+
8
+ export type FontWidthCalcValues = {
9
+ font: FontKitFont;
10
+ fontSize: number;
11
+ characterSpacing: number;
12
+ boxWidthInPt: number;
13
+ };
14
+ export interface TextSchema extends Schema {
15
+ fontName?: string;
16
+ alignment: ALIGNMENT;
17
+ verticalAlignment: VERTICAL_ALIGNMENT;
18
+ fontSize: number;
19
+ lineHeight: number;
20
+ characterSpacing: number;
21
+ dynamicFontSize?: {
22
+ min: number;
23
+ max: number;
24
+ fit: DYNAMIC_FONT_SIZE_FIT;
25
+ };
26
+
27
+ fontColor: string;
28
+ backgroundColor: string;
29
+ }
@@ -0,0 +1,153 @@
1
+ import type * as CSS from 'csstype';
2
+ import { UIRenderProps, Schema, getDefaultFont } from '@pdfme/common';
3
+ import type { TextSchema } from './types';
4
+ import {
5
+ DEFAULT_FONT_SIZE,
6
+ DEFAULT_ALIGNMENT,
7
+ VERTICAL_ALIGN_TOP,
8
+ VERTICAL_ALIGN_MIDDLE,
9
+ VERTICAL_ALIGN_BOTTOM,
10
+ DEFAULT_VERTICAL_ALIGNMENT,
11
+ DEFAULT_LINE_HEIGHT,
12
+ DEFAULT_CHARACTER_SPACING,
13
+ DEFAULT_FONT_COLOR,
14
+ } from './constants';
15
+ import {
16
+ calculateDynamicFontSize,
17
+ getFontKitFont,
18
+ getBrowserVerticalFontAdjustments,
19
+ } from './helper';
20
+
21
+ const mapVerticalAlignToFlex = (verticalAlignmentValue: string | undefined) => {
22
+ switch (verticalAlignmentValue) {
23
+ case VERTICAL_ALIGN_TOP:
24
+ return 'flex-start';
25
+ case VERTICAL_ALIGN_MIDDLE:
26
+ return 'center';
27
+ case VERTICAL_ALIGN_BOTTOM:
28
+ return 'flex-end';
29
+ }
30
+ return 'flex-start';
31
+ };
32
+
33
+ export const uiRender = async (arg: UIRenderProps<TextSchema>) => {
34
+ const {
35
+ value,
36
+ schema,
37
+ rootElement,
38
+ mode,
39
+ onChange,
40
+ stopEditing,
41
+ tabIndex,
42
+ placeholder,
43
+ options,
44
+ } = arg;
45
+ const font = options?.font || getDefaultFont();
46
+
47
+ let dynamicFontSize: undefined | number = undefined;
48
+ if (schema.dynamicFontSize && value) {
49
+ dynamicFontSize = await calculateDynamicFontSize({
50
+ textSchema: schema,
51
+ font,
52
+ value,
53
+ startingFontSize: dynamicFontSize,
54
+ });
55
+ }
56
+
57
+ const fontKitFont = await getFontKitFont(schema, font);
58
+ // Depending on vertical alignment, we need to move the top or bottom of the font to keep
59
+ // it within it's defined box and align it with the generated pdf.
60
+ const { topAdj, bottomAdj } = getBrowserVerticalFontAdjustments(
61
+ fontKitFont,
62
+ dynamicFontSize ?? schema.fontSize ?? DEFAULT_FONT_SIZE,
63
+ schema.lineHeight ?? DEFAULT_LINE_HEIGHT,
64
+ schema.verticalAlignment ?? DEFAULT_VERTICAL_ALIGNMENT
65
+ );
66
+
67
+ const topAdjustment = topAdj;
68
+ const bottomAdjustment = bottomAdj;
69
+
70
+ const container = document.createElement('div');
71
+ function getBackgroundColor(mode: 'form' | 'viewer', value: string, schema: Schema) {
72
+ if (mode === 'form' && value && schema.backgroundColor) {
73
+ return schema.backgroundColor as string;
74
+ } else if (mode === 'viewer') {
75
+ return (schema.backgroundColor as string) ?? 'transparent';
76
+ } else {
77
+ return 'rgb(242 244 255 / 75%)';
78
+ }
79
+ }
80
+
81
+ const containerStyle: CSS.Properties = {
82
+ padding: 0,
83
+ resize: 'none',
84
+ backgroundColor: getBackgroundColor(mode, value, schema),
85
+ border: 'none',
86
+ display: 'flex',
87
+ flexDirection: 'column',
88
+ justifyContent: mapVerticalAlignToFlex(schema.verticalAlignment),
89
+ width: '100%',
90
+ height: '100%',
91
+ };
92
+ Object.assign(container.style, containerStyle);
93
+ rootElement.innerHTML = '';
94
+ rootElement.appendChild(container);
95
+
96
+ const fontStyles: CSS.Properties = {
97
+ fontFamily: schema.fontName ? `'${schema.fontName}'` : 'inherit',
98
+ color: schema.fontColor ? schema.fontColor : DEFAULT_FONT_COLOR,
99
+ fontSize: `${dynamicFontSize ?? schema.fontSize ?? DEFAULT_FONT_SIZE}pt`,
100
+ letterSpacing: `${schema.characterSpacing ?? DEFAULT_CHARACTER_SPACING}pt`,
101
+ lineHeight: `${schema.lineHeight ?? DEFAULT_LINE_HEIGHT}em`,
102
+ textAlign: schema.alignment ?? DEFAULT_ALIGNMENT,
103
+ whiteSpace: 'pre-wrap',
104
+ wordBreak: 'break-word',
105
+ };
106
+
107
+ if (mode === 'form') {
108
+ const textarea = document.createElement('textarea');
109
+ const textareaStyle: CSS.Properties = {
110
+ padding: 0,
111
+ resize: 'none',
112
+ border: 'none',
113
+ outline: 'none',
114
+ paddingTop: topAdjustment + 'px',
115
+ backgroundColor: 'transparent',
116
+ width: '100%',
117
+ height: '100%',
118
+ };
119
+ Object.assign(textarea.style, textareaStyle, fontStyles);
120
+ textarea.rows = 1;
121
+ textarea.placeholder = placeholder || '';
122
+ textarea.tabIndex = tabIndex || 0;
123
+
124
+ textarea.addEventListener(
125
+ 'change',
126
+ (e: Event) => onChange && onChange((e.target as HTMLTextAreaElement).value)
127
+ );
128
+ textarea.addEventListener('blur', () => stopEditing && stopEditing());
129
+ textarea.value = value;
130
+ container.appendChild(textarea);
131
+ textarea.setSelectionRange(value.length, value.length);
132
+ textarea.focus();
133
+ } else {
134
+ const div = document.createElement('div');
135
+ const divStyle: CSS.Properties = {
136
+ ...fontStyles,
137
+ marginBottom: bottomAdjustment + 'px',
138
+ paddingTop: topAdjustment + 'px',
139
+ };
140
+ Object.assign(div.style, divStyle);
141
+ div.innerHTML = value
142
+ .split('')
143
+ .map(
144
+ (l: string, i: number) =>
145
+ `<span style="letter-spacing:${
146
+ String(value).length === i + 1 ? 0 : 'inherit'
147
+ };">${l}</span>`
148
+ )
149
+ .join('');
150
+
151
+ container.appendChild(div);
152
+ }
153
+ };
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "../../tsconfig.base",
3
+ "compilerOptions": {
4
+ "module": "commonjs",
5
+ "outDir": "./dist/cjs",
6
+ "declaration": true,
7
+ "declarationDir": "dist/types",
8
+ "skipLibCheck": true,
9
+ }
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "../../tsconfig.base",
3
+ "compilerOptions": {
4
+ "module": "ESNext",
5
+ "outDir": "./dist/esm",
6
+ "declaration": true,
7
+ "declarationDir": "dist/types",
8
+ "skipLibCheck": true,
9
+ }
10
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "extends": "./tsconfig.esm",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ }
6
+ }