@pdfme/schemas 3.1.5 → 3.2.0-dev.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 (146) hide show
  1. package/README.md +303 -0
  2. package/dist/cjs/__tests__/{renderUtils.test.js → utils.test.js} +38 -12
  3. package/dist/cjs/__tests__/utils.test.js.map +1 -0
  4. package/dist/cjs/src/barcodes/constants.js +2 -1
  5. package/dist/cjs/src/barcodes/constants.js.map +1 -1
  6. package/dist/cjs/src/barcodes/helper.js +1 -2
  7. package/dist/cjs/src/barcodes/helper.js.map +1 -1
  8. package/dist/cjs/src/barcodes/index.js +2 -2
  9. package/dist/cjs/src/barcodes/index.js.map +1 -1
  10. package/dist/cjs/src/barcodes/pdfRender.js +3 -3
  11. package/dist/cjs/src/barcodes/pdfRender.js.map +1 -1
  12. package/dist/cjs/src/barcodes/propPanel.js +45 -30
  13. package/dist/cjs/src/barcodes/propPanel.js.map +1 -1
  14. package/dist/cjs/src/barcodes/uiRender.js +11 -37
  15. package/dist/cjs/src/barcodes/uiRender.js.map +1 -1
  16. package/dist/cjs/src/graphics/helper.js +115 -0
  17. package/dist/cjs/src/graphics/helper.js.map +1 -0
  18. package/dist/cjs/src/graphics/image.js +179 -0
  19. package/dist/cjs/src/graphics/image.js.map +1 -0
  20. package/dist/cjs/src/graphics/svg.js +96 -0
  21. package/dist/cjs/src/graphics/svg.js.map +1 -0
  22. package/dist/cjs/src/index.js +42 -9
  23. package/dist/cjs/src/index.js.map +1 -1
  24. package/dist/cjs/src/shapes/line.js +57 -0
  25. package/dist/cjs/src/shapes/line.js.map +1 -0
  26. package/dist/cjs/src/shapes/rectAndEllipse.js +100 -0
  27. package/dist/cjs/src/shapes/rectAndEllipse.js.map +1 -0
  28. package/dist/cjs/src/text/helper.js.map +1 -1
  29. package/dist/cjs/src/text/index.js +16 -2
  30. package/dist/cjs/src/text/index.js.map +1 -1
  31. package/dist/cjs/src/text/pdfRender.js +9 -32
  32. package/dist/cjs/src/text/pdfRender.js.map +1 -1
  33. package/dist/cjs/src/text/propPanel.js +2 -2
  34. package/dist/cjs/src/text/propPanel.js.map +1 -1
  35. package/dist/cjs/src/text/uiRender.js +12 -18
  36. package/dist/cjs/src/text/uiRender.js.map +1 -1
  37. package/dist/cjs/src/utils.js +134 -0
  38. package/dist/cjs/src/utils.js.map +1 -0
  39. package/dist/esm/__tests__/{renderUtils.test.js → utils.test.js} +34 -8
  40. package/dist/esm/__tests__/utils.test.js.map +1 -0
  41. package/dist/esm/src/barcodes/constants.js +1 -0
  42. package/dist/esm/src/barcodes/constants.js.map +1 -1
  43. package/dist/esm/src/barcodes/helper.js +2 -3
  44. package/dist/esm/src/barcodes/helper.js.map +1 -1
  45. package/dist/esm/src/barcodes/index.js +2 -2
  46. package/dist/esm/src/barcodes/index.js.map +1 -1
  47. package/dist/esm/src/barcodes/pdfRender.js +2 -2
  48. package/dist/esm/src/barcodes/pdfRender.js.map +1 -1
  49. package/dist/esm/src/barcodes/propPanel.js +46 -31
  50. package/dist/esm/src/barcodes/propPanel.js.map +1 -1
  51. package/dist/esm/src/barcodes/uiRender.js +11 -37
  52. package/dist/esm/src/barcodes/uiRender.js.map +1 -1
  53. package/dist/esm/src/graphics/helper.js +111 -0
  54. package/dist/esm/src/graphics/helper.js.map +1 -0
  55. package/dist/esm/src/graphics/image.js +176 -0
  56. package/dist/esm/src/graphics/image.js.map +1 -0
  57. package/dist/esm/src/graphics/svg.js +93 -0
  58. package/dist/esm/src/graphics/svg.js.map +1 -0
  59. package/dist/esm/src/index.js +7 -4
  60. package/dist/esm/src/index.js.map +1 -1
  61. package/dist/esm/src/shapes/line.js +55 -0
  62. package/dist/esm/src/shapes/line.js.map +1 -0
  63. package/dist/esm/src/shapes/rectAndEllipse.js +97 -0
  64. package/dist/esm/src/shapes/rectAndEllipse.js.map +1 -0
  65. package/dist/esm/src/text/helper.js.map +1 -1
  66. package/dist/esm/src/text/index.js +15 -2
  67. package/dist/esm/src/text/index.js.map +1 -1
  68. package/dist/esm/src/text/pdfRender.js +6 -29
  69. package/dist/esm/src/text/pdfRender.js.map +1 -1
  70. package/dist/esm/src/text/propPanel.js +2 -2
  71. package/dist/esm/src/text/propPanel.js.map +1 -1
  72. package/dist/esm/src/text/uiRender.js +12 -18
  73. package/dist/esm/src/text/uiRender.js.map +1 -1
  74. package/dist/esm/src/utils.js +124 -0
  75. package/dist/esm/src/utils.js.map +1 -0
  76. package/dist/types/src/barcodes/constants.d.ts +1 -0
  77. package/dist/types/src/barcodes/helper.d.ts +1 -0
  78. package/dist/types/src/barcodes/index.d.ts +2 -2
  79. package/dist/types/src/barcodes/types.d.ts +1 -0
  80. package/dist/types/src/graphics/helper.d.ts +5 -0
  81. package/dist/types/src/graphics/image.d.ts +7 -0
  82. package/dist/types/src/graphics/svg.d.ts +6 -0
  83. package/dist/types/src/index.d.ts +7 -4
  84. package/dist/types/src/shapes/line.d.ts +6 -0
  85. package/dist/types/src/shapes/rectAndEllipse.d.ts +144 -0
  86. package/dist/types/src/text/index.d.ts +3 -2
  87. package/dist/types/src/text/pdfRender.d.ts +1 -1
  88. package/dist/types/src/{renderUtils.d.ts → utils.d.ts} +5 -1
  89. package/package.json +4 -3
  90. package/src/barcodes/constants.ts +2 -0
  91. package/src/barcodes/helper.ts +12 -3
  92. package/src/barcodes/index.ts +2 -2
  93. package/src/barcodes/pdfRender.ts +2 -2
  94. package/src/barcodes/propPanel.ts +50 -30
  95. package/src/barcodes/types.ts +1 -0
  96. package/src/barcodes/uiRender.ts +11 -41
  97. package/src/graphics/helper.ts +147 -0
  98. package/src/graphics/image.ts +207 -0
  99. package/src/graphics/svg.ts +98 -0
  100. package/src/index.ts +21 -4
  101. package/src/shapes/line.ts +67 -0
  102. package/src/shapes/rectAndEllipse.ts +110 -0
  103. package/src/text/helper.ts +0 -1
  104. package/src/text/index.ts +16 -2
  105. package/src/text/pdfRender.ts +6 -42
  106. package/src/text/propPanel.ts +2 -2
  107. package/src/text/uiRender.ts +14 -29
  108. package/src/utils.ts +161 -0
  109. package/dist/cjs/__tests__/renderUtils.test.js.map +0 -1
  110. package/dist/cjs/src/image/index.js +0 -8
  111. package/dist/cjs/src/image/index.js.map +0 -1
  112. package/dist/cjs/src/image/pdfRender.js +0 -20
  113. package/dist/cjs/src/image/pdfRender.js.map +0 -1
  114. package/dist/cjs/src/image/propPanel.js +0 -19
  115. package/dist/cjs/src/image/propPanel.js.map +0 -1
  116. package/dist/cjs/src/image/types.js +0 -3
  117. package/dist/cjs/src/image/types.js.map +0 -1
  118. package/dist/cjs/src/image/uiRender.js +0 -111
  119. package/dist/cjs/src/image/uiRender.js.map +0 -1
  120. package/dist/cjs/src/renderUtils.js +0 -59
  121. package/dist/cjs/src/renderUtils.js.map +0 -1
  122. package/dist/esm/__tests__/renderUtils.test.js.map +0 -1
  123. package/dist/esm/src/image/index.js +0 -6
  124. package/dist/esm/src/image/index.js.map +0 -1
  125. package/dist/esm/src/image/pdfRender.js +0 -16
  126. package/dist/esm/src/image/pdfRender.js.map +0 -1
  127. package/dist/esm/src/image/propPanel.js +0 -16
  128. package/dist/esm/src/image/propPanel.js.map +0 -1
  129. package/dist/esm/src/image/types.js +0 -2
  130. package/dist/esm/src/image/types.js.map +0 -1
  131. package/dist/esm/src/image/uiRender.js +0 -107
  132. package/dist/esm/src/image/uiRender.js.map +0 -1
  133. package/dist/esm/src/renderUtils.js +0 -53
  134. package/dist/esm/src/renderUtils.js.map +0 -1
  135. package/dist/types/src/image/index.d.ts +0 -4
  136. package/dist/types/src/image/pdfRender.d.ts +0 -3
  137. package/dist/types/src/image/propPanel.d.ts +0 -3
  138. package/dist/types/src/image/types.d.ts +0 -3
  139. package/dist/types/src/image/uiRender.d.ts +0 -3
  140. package/src/image/index.ts +0 -8
  141. package/src/image/pdfRender.ts +0 -28
  142. package/src/image/propPanel.ts +0 -19
  143. package/src/image/types.ts +0 -3
  144. package/src/image/uiRender.ts +0 -121
  145. package/src/renderUtils.ts +0 -73
  146. /package/dist/types/__tests__/{renderUtils.test.d.ts → utils.test.d.ts} +0 -0
@@ -0,0 +1,207 @@
1
+ import type { ChangeEvent } from 'react';
2
+ import type { PDFImage } from '@pdfme/pdf-lib';
3
+ import type { Plugin } from '@pdfme/common';
4
+ import type { PDFRenderProps, Schema } from '@pdfme/common';
5
+ import type * as CSS from 'csstype';
6
+ import { Buffer } from 'buffer';
7
+ import { UIRenderProps } from '@pdfme/common';
8
+ import { convertForPdfLayoutProps, addAlphaToHex, isEditable, readFile } from '../utils.js';
9
+ import { DEFAULT_OPACITY } from '../constants.js';
10
+ import { imageSize } from './helper.js';
11
+
12
+ const px2mm = (px: number): number => {
13
+ // http://www.endmemo.com/sconvert/millimeterpixel.php
14
+ const ratio = 0.26458333333333;
15
+ return parseFloat(String(px)) * ratio;
16
+ };
17
+
18
+ const getCacheKey = (schema: Schema, input: string) => `${schema.type}${input}`;
19
+ const fullSize = { width: '100%', height: '100%' };
20
+ const defaultValue =
21
+ 'data:image/png;base64,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';
22
+
23
+ interface ImageSchema extends Schema {}
24
+
25
+ const imageSchema: Plugin<ImageSchema> = {
26
+ pdf: async (arg: PDFRenderProps<ImageSchema>) => {
27
+ const { value, schema, pdfDoc, page, _cache } = arg;
28
+ if (!value || !value.startsWith('data:image/')) return;
29
+
30
+ const inputImageCacheKey = getCacheKey(schema, value);
31
+ let image = _cache.get(inputImageCacheKey) as PDFImage;
32
+ if (!image) {
33
+ const isPng = value.startsWith('data:image/png;');
34
+ image = await (isPng ? pdfDoc.embedPng(value) : pdfDoc.embedJpg(value));
35
+ _cache.set(inputImageCacheKey, image);
36
+ }
37
+
38
+ const _schema = { ...schema, position: { ...schema.position } };
39
+ const dataUriPrefix = ';base64,';
40
+ const idx = value.indexOf(dataUriPrefix);
41
+ const imgBase64 = value.substring(idx + dataUriPrefix.length, value.length);
42
+ const dimension = imageSize(Buffer.from(imgBase64, 'base64'));
43
+
44
+ const imageWidth = px2mm(dimension.width);
45
+ const imageHeight = px2mm(dimension.height);
46
+ const boxWidth = _schema.width;
47
+ const boxHeight = _schema.height;
48
+
49
+ const imageRatio = imageWidth / imageHeight;
50
+ const boxRatio = boxWidth / boxHeight;
51
+
52
+ if (imageRatio > boxRatio) {
53
+ _schema.width = boxWidth;
54
+ _schema.height = boxWidth / imageRatio;
55
+ _schema.position.y += (boxHeight - _schema.height) / 2;
56
+ } else {
57
+ _schema.width = boxHeight * imageRatio;
58
+ _schema.height = boxHeight;
59
+ _schema.position.x += (boxWidth - _schema.width) / 2;
60
+ }
61
+
62
+ const pageHeight = page.getHeight();
63
+ const lProps = convertForPdfLayoutProps({ schema: _schema, pageHeight });
64
+ const { width, height, rotate, position, opacity } = lProps;
65
+ const { x, y } = position;
66
+ page.drawImage(image, { x, y, rotate, width, height, opacity });
67
+ },
68
+ ui: (arg: UIRenderProps<ImageSchema>) => {
69
+ const {
70
+ value,
71
+ rootElement,
72
+ mode,
73
+ onChange,
74
+ stopEditing,
75
+ tabIndex,
76
+ placeholder,
77
+ theme,
78
+ schema,
79
+ } = arg;
80
+ const editable = isEditable(mode, schema);
81
+ const isDefault = value === defaultValue;
82
+
83
+ const container = document.createElement('div');
84
+ const backgroundStyle = placeholder ? `url(${placeholder})` : 'none';
85
+ const containerStyle: CSS.Properties = {
86
+ ...fullSize,
87
+ backgroundImage: value ? 'none' : backgroundStyle,
88
+ backgroundSize: `contain`,
89
+ backgroundRepeat: 'no-repeat',
90
+ backgroundPosition: 'center',
91
+ };
92
+ Object.assign(container.style, containerStyle);
93
+ container.addEventListener('click', (e) => {
94
+ if (editable) {
95
+ e.stopPropagation();
96
+ }
97
+ });
98
+ rootElement.appendChild(container);
99
+
100
+ // image tag
101
+ if (value) {
102
+ const img = document.createElement('img');
103
+ const imgStyle: CSS.Properties = {
104
+ height: '100%',
105
+ width: '100%',
106
+ borderRadius: 0,
107
+ objectFit: 'contain',
108
+ };
109
+ Object.assign(img.style, imgStyle);
110
+ img.src = value;
111
+ container.appendChild(img);
112
+ }
113
+
114
+ // remove button
115
+ if (value && !isDefault && editable) {
116
+ const button = document.createElement('button');
117
+ button.textContent = 'x';
118
+ const buttonStyle: CSS.Properties = {
119
+ position: 'absolute',
120
+ top: 0,
121
+ left: 0,
122
+ zIndex: 1,
123
+ display: 'flex',
124
+ justifyContent: 'center',
125
+ alignItems: 'center',
126
+ color: '#333',
127
+ background: '#f2f2f2',
128
+ borderRadius: '2px',
129
+ border: '1px solid #767676',
130
+ cursor: 'pointer',
131
+ height: '24px',
132
+ width: '24px',
133
+ };
134
+ Object.assign(button.style, buttonStyle);
135
+ button.addEventListener('click', () => {
136
+ onChange && onChange('');
137
+ });
138
+ container.appendChild(button);
139
+ }
140
+
141
+ // file input
142
+ if ((!value || isDefault) && editable) {
143
+ const label = document.createElement('label');
144
+ const labelStyle: CSS.Properties = {
145
+ ...fullSize,
146
+ display: editable ? 'flex' : 'none',
147
+ position: 'absolute',
148
+ top: 0,
149
+ backgroundColor: editable || value ? addAlphaToHex(theme.colorPrimaryBg, 30) : 'none',
150
+ cursor: 'pointer',
151
+ };
152
+ Object.assign(label.style, labelStyle);
153
+ container.appendChild(label);
154
+ const input = document.createElement('input');
155
+ const inputStyle: CSS.Properties = {
156
+ ...fullSize,
157
+ position: 'absolute',
158
+ top: '50%',
159
+ left: '50%',
160
+ width: '180px',
161
+ height: '30px',
162
+ marginLeft: '-90px',
163
+ marginTop: '-15px',
164
+ };
165
+ Object.assign(input.style, inputStyle);
166
+ input.tabIndex = tabIndex || 0;
167
+ input.type = 'file';
168
+ input.accept = 'image/jpeg, image/png';
169
+ input.addEventListener('change', (event: Event) => {
170
+ const changeEvent = event as unknown as ChangeEvent<HTMLInputElement>;
171
+ readFile(changeEvent.target.files).then((result) => onChange && onChange(result as string));
172
+ });
173
+ input.addEventListener('blur', () => stopEditing && stopEditing());
174
+ label.appendChild(input);
175
+ }
176
+ },
177
+ propPanel: {
178
+ schema: {},
179
+ defaultValue,
180
+ defaultSchema: {
181
+ type: 'image',
182
+ position: { x: 0, y: 0 },
183
+ width: 40,
184
+ height: 40,
185
+ // If the value of "rotate" is set to undefined or not set at all, rotation will be disabled in the UI.
186
+ // Check this document: https://pdfme.com//docs/custom-schemas#learning-how-to-create-from-pdfmeschemas-code
187
+ rotate: 0,
188
+ opacity: DEFAULT_OPACITY,
189
+ },
190
+ },
191
+ };
192
+
193
+ export default imageSchema;
194
+
195
+ export const readOnlyImage: Plugin<ImageSchema> = {
196
+ pdf: imageSchema.pdf,
197
+ ui: imageSchema.ui,
198
+ propPanel: {
199
+ ...imageSchema.propPanel,
200
+ defaultSchema: {
201
+ ...imageSchema.propPanel.defaultSchema,
202
+ type: 'readOnlyImage',
203
+ readOnly: true,
204
+ readOnlyValue: defaultValue,
205
+ },
206
+ },
207
+ };
@@ -0,0 +1,98 @@
1
+ import { Plugin, Schema } from '@pdfme/common';
2
+ import { XMLValidator } from 'fast-xml-parser';
3
+ import { convertForPdfLayoutProps, isEditable, addAlphaToHex, createErrorElm } from '../utils.js';
4
+
5
+ const isValidSVG = (svgString: string) => XMLValidator.validate(svgString) === true;
6
+
7
+ const defaultValue = `<svg viewBox="0 0 488 600" version="1.1" xmlns="http://www.w3.org/2000/svg">
8
+ <g transform="matrix(1,0,0,1,-56,0)" fill="#000000" stroke="none">
9
+ <path d="M228.667,0L56,172.667L56.267,345.334L56.667,518L59.733,527.334C65.867,545.467 72.933,557.067 86,570.134C96.133,580.4 100,583.2 110.667,588.4C134.533,600.134 120,599.334 300,599.334C480,599.334 465.467,600.134 489.334,588.4C500,583.2 503.867,580.4 514,570.134C527.334,556.8 534.534,544.8 540.267,526.667L543.334,516.667L543.334,83.333L540.267,73.333C534.534,55.2 527.334,43.2 514,29.867C503.867,19.6 500,16.8 489.334,11.6C465.734,0 475.467,0.8 344.667,0.267L228.667,0ZM466.4,41.6C483.334,48.933 496.267,61.867 502.934,78.4L506,86L506,514L502.934,521.734C496,538.934 480.267,553.867 463.334,559.334C455.6,561.867 450.8,562 300,562C149.2,562 144.4,561.867 136.667,559.334C119.733,553.867 104,538.934 97.067,521.734L94,514L93.6,351.067L93.333,188.133L149.067,187.733L204.667,187.333L213.6,182.933C224.8,177.467 235.867,165.867 240.267,155.067C243.333,147.467 243.333,146.4 243.733,92.267L244.133,37.2L458,38L466.4,41.6ZM195.067,304C175.6,306.8 164,320.667 165.6,339.467C166,343.6 167.6,348.667 169.733,352.4C174.4,360.267 185.2,365.734 201.867,368.534C208.4,369.734 215.067,371.467 216.8,372.667C224,377.334 221.467,389.067 212.533,392C205.6,394.4 193.733,392.934 185.6,388.8C173.333,382.534 164,385.334 164,395.2C164,400.934 170.133,406.667 180.267,410.134C190.933,413.867 217.067,413.734 225.467,409.867C238.933,403.6 246.667,390 244.8,375.6C242.667,359.734 232.8,351.334 212.267,347.867C193.6,344.8 189.333,342.4 189.333,334.533C189.333,324.267 201.867,320.933 218.267,326.667C228.667,330.267 232.533,330.133 235.867,325.867C242.133,318 237.6,310.667 224.267,306.8C213.333,303.6 204.267,302.8 195.067,304ZM386,304.133C377.6,305.333 374,306.8 367.334,311.6C355.734,320.133 351.2,336.4 352.4,365.334C353.2,385.334 356,394.4 364.134,402.534C372.267,410.667 381.734,413.734 396.667,413.067C406.8,412.667 409.734,412 415.734,408.667C429.2,401.334 434.534,390.934 435.6,370.667C436.4,353.734 436,353.067 420.934,352.267C401.867,351.334 396,353.467 396,361.867C396,367.867 399.467,370.667 407.067,370.667C413.2,370.667 413.334,370.667 413.334,374.934C413.334,394 386.267,400.534 378.534,383.467C374.934,375.334 374.934,341.867 378.534,333.733C382,326.4 387.467,323.467 396.8,324.267C403.067,324.8 404.667,325.6 410.534,331.067C414.267,334.533 418.4,337.333 419.867,337.333C427.334,337.333 433.334,330.267 431.334,323.733C427.2,310.133 406.4,301.2 386,304.133ZM258.4,308C255.067,311.467 254.533,312.8 255.2,316.4C257.067,326.667 285.333,405.867 288.133,408.8C289.733,410.534 293.067,412.267 295.333,412.8C303.867,414.4 310.667,407.867 314.4,394.667C315.067,392.134 321.2,374.134 327.867,354.8C334.8,334.533 340,317.467 340,314.533C340,303.733 325.067,299.867 319.867,309.467C318.533,312.133 309.467,340.933 302.667,364C301.067,369.467 299.333,374.4 298.8,375.067C298.267,375.6 292.933,360.8 286.933,342C275.333,306 274.133,304 266.267,304C263.867,304 261.067,305.467 258.4,308Z" style="fill-rule:nonzero;"/>
10
+ </g>
11
+ </svg>`;
12
+
13
+ interface SVGSchema extends Schema {}
14
+
15
+ const svgSchema: Plugin<SVGSchema> = {
16
+ ui: (arg) => {
17
+ const { rootElement, value, mode, onChange, theme, schema } = arg;
18
+ const container = document.createElement(isEditable(mode, schema) ? 'textarea' : 'div');
19
+ container.style.width = '100%';
20
+ container.style.height = '100%';
21
+ container.style.boxSizing = 'border-box';
22
+ if (isEditable(mode, schema)) {
23
+ const textarea = container as HTMLTextAreaElement;
24
+ textarea.value = value;
25
+ textarea.style.position = 'absolute';
26
+ textarea.style.backgroundColor = addAlphaToHex(theme.colorPrimaryBg, 30);
27
+
28
+ if (isValidSVG(value)) {
29
+ const svgElement = new DOMParser().parseFromString(value, 'text/xml').childNodes[0];
30
+ if (svgElement instanceof SVGElement) {
31
+ svgElement.setAttribute('width', '100%');
32
+ svgElement.setAttribute('height', '100%');
33
+ svgElement.style.position = 'absolute';
34
+ }
35
+ rootElement.appendChild(svgElement);
36
+ } else if (value) {
37
+ const errorElm = createErrorElm();
38
+ errorElm.style.position = 'absolute';
39
+ rootElement.appendChild(errorElm);
40
+ }
41
+
42
+ textarea.addEventListener('change', (e: Event) => {
43
+ const newValue = (e.target as HTMLTextAreaElement).value;
44
+ onChange && onChange(newValue);
45
+ });
46
+ rootElement.appendChild(container);
47
+ textarea.setSelectionRange(value.length, value.length);
48
+ textarea.focus();
49
+ } else {
50
+ if (!value) return;
51
+ if (!isValidSVG(value)) {
52
+ rootElement.appendChild(createErrorElm());
53
+ return;
54
+ }
55
+ container.innerHTML = value;
56
+ const svgElement = container.childNodes[0];
57
+ if (svgElement instanceof SVGElement) {
58
+ svgElement.setAttribute('width', '100%');
59
+ svgElement.setAttribute('height', '100%');
60
+ rootElement.appendChild(container);
61
+ }
62
+ }
63
+ },
64
+ pdf: async (arg) => {
65
+ const { page, schema, value } = arg;
66
+ if (!value || !isValidSVG(value)) return;
67
+ const pageHeight = page.getHeight();
68
+ const { width, height, position } = convertForPdfLayoutProps({ schema, pageHeight });
69
+ const { x, y } = position;
70
+ await page.drawSvg(value, { x, y: y + height, width, height });
71
+ },
72
+ propPanel: {
73
+ schema: {},
74
+ defaultValue,
75
+ defaultSchema: {
76
+ type: 'svg',
77
+ position: { x: 0, y: 0 },
78
+ width: 40,
79
+ height: 40,
80
+ },
81
+ },
82
+ };
83
+
84
+ export default svgSchema;
85
+
86
+ export const readOnlySvg: Plugin<SVGSchema> = {
87
+ pdf: svgSchema.pdf,
88
+ ui: svgSchema.ui,
89
+ propPanel: {
90
+ ...svgSchema.propPanel,
91
+ defaultSchema: {
92
+ ...svgSchema.propPanel.defaultSchema,
93
+ type: 'readOnlySvg',
94
+ readOnly: true,
95
+ readOnlyValue: defaultValue,
96
+ },
97
+ },
98
+ };
package/src/index.ts CHANGED
@@ -1,8 +1,25 @@
1
- import text from './text/index.js';
2
- import image from './image/index.js';
1
+ import text, { readOnlyText } from './text/index.js';
2
+ import image, { readOnlyImage } from './graphics/image.js';
3
+ import svg, { readOnlySvg } from './graphics/svg.js';
3
4
  import barcodes from './barcodes/index.js';
4
- import { convertForPdfLayoutProps, rotatePoint } from './renderUtils.js';
5
+ import line from './shapes/line.js';
6
+ import { rectangle, ellipse } from './shapes/rectAndEllipse.js';
7
+ import { convertForPdfLayoutProps, rotatePoint } from './utils.js';
5
8
 
6
9
  const builtInPlugins = { Text: text };
7
10
 
8
- export { text, image, barcodes, builtInPlugins, convertForPdfLayoutProps, rotatePoint };
11
+ export {
12
+ text,
13
+ readOnlyText,
14
+ image,
15
+ readOnlyImage,
16
+ svg,
17
+ readOnlySvg,
18
+ barcodes,
19
+ line,
20
+ rectangle,
21
+ ellipse,
22
+ builtInPlugins,
23
+ convertForPdfLayoutProps,
24
+ rotatePoint,
25
+ };
@@ -0,0 +1,67 @@
1
+ import type { Schema, Plugin, PDFRenderProps, UIRenderProps } from '@pdfme/common';
2
+ import { rotatePoint, convertForPdfLayoutProps, hex2RgbColor } from '../utils.js';
3
+ import { HEX_COLOR_PATTERN } from '../constants.js';
4
+
5
+ const DEFAULT_LINE_COLOR = '#000000';
6
+
7
+ interface LineSchema extends Schema {
8
+ color: string;
9
+ }
10
+
11
+ const lineSchema: Plugin<LineSchema> = {
12
+ pdf: (arg: PDFRenderProps<LineSchema>) => {
13
+ const { page, schema } = arg;
14
+ const pageHeight = page.getHeight();
15
+ const {
16
+ width,
17
+ height,
18
+ rotate,
19
+ position: { x, y },
20
+ opacity,
21
+ } = convertForPdfLayoutProps({ schema, pageHeight, applyRotateTranslate: false });
22
+ const pivot = { x: x + width / 2, y: y + height / 2 };
23
+ page.drawLine({
24
+ start: rotatePoint({ x, y: y + height / 2 }, pivot, rotate.angle),
25
+ end: rotatePoint({ x: x + width, y: y + height / 2 }, pivot, rotate.angle),
26
+ thickness: height,
27
+ color: hex2RgbColor(schema.color ?? DEFAULT_LINE_COLOR),
28
+ opacity: opacity,
29
+ });
30
+ },
31
+ ui: (arg: UIRenderProps<LineSchema>) => {
32
+ const { schema, rootElement } = arg;
33
+ const div = document.createElement('div');
34
+ div.style.backgroundColor = schema.color ?? DEFAULT_LINE_COLOR;
35
+ div.style.width = '100%';
36
+ div.style.height = '100%';
37
+ rootElement.appendChild(div);
38
+ },
39
+ propPanel: {
40
+ schema: ({ i18n }) => ({
41
+ color: {
42
+ title: i18n('schemas.color'),
43
+ type: 'string',
44
+ widget: 'color',
45
+ required: true,
46
+ rules: [
47
+ {
48
+ pattern: HEX_COLOR_PATTERN,
49
+ message: i18n('hexColorPrompt'),
50
+ },
51
+ ],
52
+ },
53
+ }),
54
+ defaultValue: '',
55
+ defaultSchema: {
56
+ type: 'line',
57
+ position: { x: 0, y: 0 },
58
+ width: 50,
59
+ height: 1,
60
+ rotate: 0,
61
+ opacity: 1,
62
+ readOnly: true,
63
+ color: DEFAULT_LINE_COLOR,
64
+ },
65
+ },
66
+ };
67
+ export default lineSchema;
@@ -0,0 +1,110 @@
1
+ import { Plugin, Schema, mm2pt } from '@pdfme/common';
2
+ import { HEX_COLOR_PATTERN } from '../constants.js';
3
+ import { hex2RgbColor, convertForPdfLayoutProps } from '../utils.js';
4
+
5
+ interface Shape extends Schema {
6
+ type: 'ellipse' | 'rectangle';
7
+ borderWidth: number;
8
+ borderColor: string;
9
+ color: string;
10
+ }
11
+
12
+ const shape: Plugin<Shape> = {
13
+ ui: (arg) => {
14
+ const { schema, rootElement } = arg;
15
+ const div = document.createElement('div');
16
+ div.style.width = '100%';
17
+ div.style.height = '100%';
18
+ div.style.boxSizing = 'border-box';
19
+ if (schema.type === 'ellipse') {
20
+ div.style.borderRadius = '50%';
21
+ }
22
+ div.style.borderWidth = `${schema.borderWidth ?? 0}mm`;
23
+ div.style.borderStyle = schema.borderWidth && schema.borderColor ? 'solid' : 'none';
24
+ div.style.borderColor = schema.borderColor ?? 'transparent';
25
+ div.style.backgroundColor = schema.color ?? 'transparent';
26
+
27
+ rootElement.appendChild(div);
28
+ },
29
+ pdf: (arg) => {
30
+ const { schema, page } = arg;
31
+ const pageHeight = page.getHeight();
32
+ const cArg = { schema, pageHeight };
33
+ const { position, width, height, rotate, opacity } = convertForPdfLayoutProps(cArg);
34
+ const {
35
+ position: { x: x4Ellipse, y: y4Ellipse },
36
+ } = convertForPdfLayoutProps({ ...cArg, applyRotateTranslate: false });
37
+ const borderWidth = schema.borderWidth ? mm2pt(schema.borderWidth) : 0;
38
+
39
+ const drawOptions = {
40
+ rotate,
41
+ borderWidth,
42
+ borderColor: hex2RgbColor(schema.borderColor),
43
+ color: hex2RgbColor(schema.color),
44
+ opacity,
45
+ borderOpacity: opacity,
46
+ };
47
+ if (schema.type === 'ellipse') {
48
+ page.drawEllipse({
49
+ x: x4Ellipse + width / 2,
50
+ y: y4Ellipse + height / 2,
51
+ xScale: width / 2 - borderWidth / 2,
52
+ yScale: height / 2 - borderWidth / 2,
53
+ ...drawOptions,
54
+ });
55
+ } else if (schema.type === 'rectangle') {
56
+ page.drawRectangle({
57
+ x: position.x + borderWidth / 2,
58
+ y: position.y + borderWidth / 2,
59
+ width: width - borderWidth,
60
+ height: height - borderWidth,
61
+ ...drawOptions,
62
+ });
63
+ }
64
+ },
65
+ propPanel: {
66
+ schema: ({ i18n }) => ({
67
+ borderWidth: {
68
+ title: i18n('schemas.borderWidth'),
69
+ type: 'number',
70
+ widget: 'inputNumber',
71
+ min: 0,
72
+ step: 1,
73
+ },
74
+ borderColor: {
75
+ title: i18n('schemas.borderColor'),
76
+ type: 'string',
77
+ widget: 'color',
78
+ rules: [{ pattern: HEX_COLOR_PATTERN, message: i18n('hexColorPrompt') }],
79
+ },
80
+ color: {
81
+ title: i18n('schemas.color'),
82
+ type: 'string',
83
+ widget: 'color',
84
+ rules: [{ pattern: HEX_COLOR_PATTERN, message: i18n('hexColorPrompt') }],
85
+ },
86
+ }),
87
+ defaultValue: '',
88
+ defaultSchema: {
89
+ type: 'rectangle',
90
+ position: { x: 0, y: 0 },
91
+ width: 62.5,
92
+ height: 37.5,
93
+ rotate: 0,
94
+ opacity: 1,
95
+ borderWidth: 5,
96
+ borderColor: '#000000',
97
+ color: '#ffffff',
98
+ readOnly: true,
99
+ },
100
+ },
101
+ };
102
+
103
+ const getPropPanelSchema = (type: 'rectangle' | 'ellipse') => ({
104
+ ...shape.propPanel,
105
+ defaultSchema: { ...shape.propPanel.defaultSchema, type },
106
+ });
107
+
108
+ export const rectangle = { ...shape, propPanel: getPropPanelSchema('rectangle') };
109
+
110
+ export const ellipse = { ...shape, propPanel: getPropPanelSchema('ellipse') };
@@ -5,7 +5,6 @@ import {
5
5
  mm2pt,
6
6
  pt2mm,
7
7
  pt2px,
8
- Schema,
9
8
  Font,
10
9
  getFallbackFontName,
11
10
  getDefaultFont,
package/src/text/index.ts CHANGED
@@ -4,6 +4,20 @@ import { propPanel } from './propPanel.js';
4
4
  import { uiRender } from './uiRender.js';
5
5
  import type { TextSchema } from './types';
6
6
 
7
- const schema: Plugin<TextSchema> = { pdf: pdfRender, ui: uiRender, propPanel };
7
+ const textSchema: Plugin<TextSchema> = { pdf: pdfRender, ui: uiRender, propPanel };
8
8
 
9
- export default schema;
9
+ export default textSchema;
10
+
11
+ export const readOnlyText: Plugin<TextSchema> = {
12
+ pdf: textSchema.pdf,
13
+ ui: textSchema.ui,
14
+ propPanel: {
15
+ ...textSchema.propPanel,
16
+ defaultSchema: {
17
+ ...textSchema.propPanel.defaultSchema,
18
+ type: 'readOnlyText',
19
+ readOnly: true,
20
+ readOnlyValue: textSchema.propPanel.defaultValue,
21
+ },
22
+ },
23
+ };
@@ -1,13 +1,6 @@
1
- import { PDFFont, PDFDocument, rgb } from '@pdfme/pdf-lib';
2
- import {
3
- PDFRenderProps,
4
- Font,
5
- getDefaultFont,
6
- getFallbackFontName,
7
- mm2pt,
8
- isHexValid,
9
- } from '@pdfme/common';
1
+ import { PDFFont, PDFDocument } from '@pdfme/pdf-lib';
10
2
  import type { TextSchema, FontWidthCalcValues } from './types';
3
+ import { PDFRenderProps, Font, getDefaultFont, getFallbackFontName, mm2pt } from '@pdfme/common';
11
4
  import {
12
5
  VERTICAL_ALIGN_TOP,
13
6
  VERTICAL_ALIGN_MIDDLE,
@@ -27,37 +20,7 @@ import {
27
20
  getSplittedLines,
28
21
  widthOfTextAtSize,
29
22
  } from './helper.js';
30
- import { convertForPdfLayoutProps, rotatePoint } from '../renderUtils.js';
31
-
32
- const hex2rgb = (hex: string) => {
33
- if (hex.slice(0, 1) === '#') hex = hex.slice(1);
34
- if (hex.length === 3)
35
- hex =
36
- hex.slice(0, 1) +
37
- hex.slice(0, 1) +
38
- hex.slice(1, 2) +
39
- hex.slice(1, 2) +
40
- hex.slice(2, 3) +
41
- hex.slice(2, 3);
42
-
43
- return [hex.slice(0, 2), hex.slice(2, 4), hex.slice(4, 6)].map((str) => parseInt(str, 16));
44
- };
45
-
46
- const hex2RgbColor = (hexString: string | undefined) => {
47
- if (hexString) {
48
- const isValid = isHexValid(hexString);
49
-
50
- if (!isValid) {
51
- throw new Error(`Invalid hex color value ${hexString}`);
52
- }
53
-
54
- const [r, g, b] = hex2rgb(hexString);
55
-
56
- return rgb(r / 255, g / 255, b / 255);
57
- }
58
-
59
- return undefined;
60
- };
23
+ import { convertForPdfLayoutProps, rotatePoint, hex2RgbColor } from '../utils.js';
61
24
 
62
25
  const embedAndGetFontObj = async (arg: {
63
26
  pdfDoc: PDFDocument;
@@ -118,6 +81,7 @@ const getFontProp = async ({
118
81
 
119
82
  export const pdfRender = async (arg: PDFRenderProps<TextSchema>) => {
120
83
  const { value, pdfDoc, pdfLib, page, options, schema, _cache } = arg;
84
+ if (!value) return;
121
85
 
122
86
  const { font = getDefaultFont() } = options;
123
87
 
@@ -132,7 +96,7 @@ export const pdfRender = async (arg: PDFRenderProps<TextSchema>) => {
132
96
  const fontName = (
133
97
  schema.fontName ? schema.fontName : getFallbackFontName(font)
134
98
  ) as keyof typeof pdfFontObj;
135
- const pdfFontValue = pdfFontObj[fontName];
99
+ const pdfFontValue = pdfFontObj && pdfFontObj[fontName];
136
100
 
137
101
  const pageHeight = page.getHeight();
138
102
  const {
@@ -162,7 +126,7 @@ export const pdfRender = async (arg: PDFRenderProps<TextSchema>) => {
162
126
  };
163
127
 
164
128
  let lines: string[] = [];
165
- value.split(/\r|\n|\r\n/g).forEach((line: string) => {
129
+ value.split(/\r\n|\r|\n/g).forEach((line: string) => {
166
130
  lines = lines.concat(getSplittedLines(line, fontWidthCalcValues));
167
131
  });
168
132
 
@@ -153,7 +153,7 @@ export const propPanel: PropPanel<TextSchema> = {
153
153
  rules: [
154
154
  {
155
155
  pattern: HEX_COLOR_PATTERN,
156
- message: 'Please enter a valid hex color code.',
156
+ message: i18n('hexColorPrompt'),
157
157
  },
158
158
  ],
159
159
  },
@@ -164,7 +164,7 @@ export const propPanel: PropPanel<TextSchema> = {
164
164
  rules: [
165
165
  {
166
166
  pattern: HEX_COLOR_PATTERN,
167
- message: 'Please enter a valid hex color code.',
167
+ message: i18n('hexColorPrompt'),
168
168
  },
169
169
  ],
170
170
  },