@pdfme/schemas 4.1.0 → 4.1.1-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 (72) hide show
  1. package/dist/cjs/src/constants.js +1 -1
  2. package/dist/cjs/src/constants.js.map +1 -1
  3. package/dist/cjs/src/graphics/image.js +3 -1
  4. package/dist/cjs/src/graphics/image.js.map +1 -1
  5. package/dist/cjs/src/index.js +11 -9
  6. package/dist/cjs/src/index.js.map +1 -1
  7. package/dist/cjs/src/multiVariableText/helper.js +19 -0
  8. package/dist/cjs/src/multiVariableText/helper.js.map +1 -0
  9. package/dist/cjs/src/multiVariableText/index.js +8 -0
  10. package/dist/cjs/src/multiVariableText/index.js.map +1 -0
  11. package/dist/cjs/src/multiVariableText/pdfRender.js +16 -0
  12. package/dist/cjs/src/multiVariableText/pdfRender.js.map +1 -0
  13. package/dist/cjs/src/multiVariableText/propPanel.js +128 -0
  14. package/dist/cjs/src/multiVariableText/propPanel.js.map +1 -0
  15. package/dist/cjs/src/multiVariableText/types.js +3 -0
  16. package/dist/cjs/src/multiVariableText/types.js.map +1 -0
  17. package/dist/cjs/src/multiVariableText/uiRender.js +133 -0
  18. package/dist/cjs/src/multiVariableText/uiRender.js.map +1 -0
  19. package/dist/cjs/src/tables/tableHelper.js +2 -2
  20. package/dist/cjs/src/tables/tableHelper.js.map +1 -1
  21. package/dist/cjs/src/text/extraFormatter.js +1 -1
  22. package/dist/cjs/src/text/propPanel.js +1 -1
  23. package/dist/cjs/src/text/uiRender.js +122 -103
  24. package/dist/cjs/src/text/uiRender.js.map +1 -1
  25. package/dist/esm/src/constants.js +1 -1
  26. package/dist/esm/src/constants.js.map +1 -1
  27. package/dist/esm/src/graphics/image.js +3 -1
  28. package/dist/esm/src/graphics/image.js.map +1 -1
  29. package/dist/esm/src/index.js +2 -1
  30. package/dist/esm/src/index.js.map +1 -1
  31. package/dist/esm/src/multiVariableText/helper.js +15 -0
  32. package/dist/esm/src/multiVariableText/helper.js.map +1 -0
  33. package/dist/esm/src/multiVariableText/index.js +6 -0
  34. package/dist/esm/src/multiVariableText/index.js.map +1 -0
  35. package/dist/esm/src/multiVariableText/pdfRender.js +12 -0
  36. package/dist/esm/src/multiVariableText/pdfRender.js.map +1 -0
  37. package/dist/esm/src/multiVariableText/propPanel.js +125 -0
  38. package/dist/esm/src/multiVariableText/propPanel.js.map +1 -0
  39. package/dist/esm/src/multiVariableText/types.js +2 -0
  40. package/dist/esm/src/multiVariableText/types.js.map +1 -0
  41. package/dist/esm/src/multiVariableText/uiRender.js +129 -0
  42. package/dist/esm/src/multiVariableText/uiRender.js.map +1 -0
  43. package/dist/esm/src/tables/tableHelper.js +2 -2
  44. package/dist/esm/src/tables/tableHelper.js.map +1 -1
  45. package/dist/esm/src/text/extraFormatter.js +1 -1
  46. package/dist/esm/src/text/propPanel.js +1 -1
  47. package/dist/esm/src/text/uiRender.js +118 -101
  48. package/dist/esm/src/text/uiRender.js.map +1 -1
  49. package/dist/types/src/constants.d.ts +1 -1
  50. package/dist/types/src/index.d.ts +2 -1
  51. package/dist/types/src/multiVariableText/helper.d.ts +1 -0
  52. package/dist/types/src/multiVariableText/index.d.ts +4 -0
  53. package/dist/types/src/multiVariableText/pdfRender.d.ts +3 -0
  54. package/dist/types/src/multiVariableText/propPanel.d.ts +3 -0
  55. package/dist/types/src/multiVariableText/types.d.ts +5 -0
  56. package/dist/types/src/multiVariableText/uiRender.d.ts +3 -0
  57. package/dist/types/src/shapes/rectAndEllipse.d.ts +2 -0
  58. package/dist/types/src/text/uiRender.d.ts +6 -0
  59. package/package.json +1 -1
  60. package/src/constants.ts +1 -1
  61. package/src/graphics/image.ts +2 -1
  62. package/src/index.ts +2 -0
  63. package/src/multiVariableText/helper.ts +18 -0
  64. package/src/multiVariableText/index.ts +8 -0
  65. package/src/multiVariableText/pdfRender.ts +16 -0
  66. package/src/multiVariableText/propPanel.ts +139 -0
  67. package/src/multiVariableText/types.ts +6 -0
  68. package/src/multiVariableText/uiRender.ts +161 -0
  69. package/src/tables/tableHelper.ts +2 -2
  70. package/src/text/extraFormatter.ts +1 -1
  71. package/src/text/propPanel.ts +1 -1
  72. package/src/text/uiRender.ts +150 -118
@@ -1,5 +1,5 @@
1
1
  import type * as CSS from 'csstype';
2
- import { UIRenderProps, Schema, getDefaultFont } from '@pdfme/common';
2
+ import { UIRenderProps, getDefaultFont } from '@pdfme/common';
3
3
  import type { TextSchema } from './types';
4
4
  import {
5
5
  DEFAULT_FONT_SIZE,
@@ -21,28 +21,10 @@ import {
21
21
  } from './helper.js';
22
22
  import { isEditable } from '../utils.js';
23
23
 
24
- const mapVerticalAlignToFlex = (verticalAlignmentValue: string | undefined) => {
25
- switch (verticalAlignmentValue) {
26
- case VERTICAL_ALIGN_TOP:
27
- return 'flex-start';
28
- case VERTICAL_ALIGN_MIDDLE:
29
- return 'center';
30
- case VERTICAL_ALIGN_BOTTOM:
31
- return 'flex-end';
32
- }
33
- return 'flex-start';
34
- };
35
-
36
- const getBackgroundColor = (value: string, schema: Schema) => {
37
- if (!value || !schema.backgroundColor) return 'transparent';
38
- return schema.backgroundColor as string;
39
- };
40
-
41
24
  export const uiRender = async (arg: UIRenderProps<TextSchema>) => {
42
25
  const {
43
26
  value,
44
27
  schema,
45
- rootElement,
46
28
  mode,
47
29
  onChange,
48
30
  stopEditing,
@@ -51,28 +33,120 @@ export const uiRender = async (arg: UIRenderProps<TextSchema>) => {
51
33
  options,
52
34
  _cache,
53
35
  } = arg;
36
+ const usePlaceholder = isEditable(mode, schema) && placeholder && !value;
37
+
38
+ const textBlock = await buildStyledTextContainer(arg, usePlaceholder ? placeholder : value);
39
+
40
+ if (!isEditable(mode, schema)) {
41
+ // Read-only mode
42
+ textBlock.innerHTML = value
43
+ .split('')
44
+ .map(
45
+ (l: string, i: number) =>
46
+ `<span style="letter-spacing:${
47
+ String(value).length === i + 1 ? 0 : 'inherit'
48
+ };">${l}</span>`
49
+ )
50
+ .join('');
51
+ return;
52
+ }
53
+
54
+ makeElementPlainTextContentEditable(textBlock);
55
+ textBlock.tabIndex = tabIndex || 0;
56
+ textBlock.innerText = value;
57
+ textBlock.addEventListener('blur', (e: Event) => {
58
+ onChange && onChange({ key: 'content', value: (e.target as HTMLDivElement).innerText });
59
+ stopEditing && stopEditing();
60
+ });
61
+
62
+ if (schema.dynamicFontSize) {
63
+ let dynamicFontSize: undefined | number = undefined;
64
+ const font = options?.font || getDefaultFont();
65
+ const fontKitFont = await getFontKitFont(schema.fontName, font, _cache);
66
+
67
+ textBlock.addEventListener('keyup', () => {
68
+ setTimeout(() => {
69
+ void (async () => {
70
+ if (!textBlock.textContent) return;
71
+ dynamicFontSize = await calculateDynamicFontSize({
72
+ textSchema: schema,
73
+ font,
74
+ value: textBlock.textContent,
75
+ startingFontSize: dynamicFontSize,
76
+ _cache,
77
+ });
78
+ textBlock.style.fontSize = `${dynamicFontSize}pt`;
79
+
80
+ const { topAdj: newTopAdj, bottomAdj: newBottomAdj } =
81
+ getBrowserVerticalFontAdjustments(
82
+ fontKitFont,
83
+ dynamicFontSize ?? schema.fontSize ?? DEFAULT_FONT_SIZE,
84
+ schema.lineHeight ?? DEFAULT_LINE_HEIGHT,
85
+ schema.verticalAlignment ?? DEFAULT_VERTICAL_ALIGNMENT
86
+ );
87
+ textBlock.style.paddingTop = `${newTopAdj}px`;
88
+ textBlock.style.marginBottom = `${newBottomAdj}px`;
89
+ })();
90
+ }, 0);
91
+ });
92
+ }
93
+
94
+ if (usePlaceholder) {
95
+ textBlock.style.color = PLACEHOLDER_FONT_COLOR;
96
+ textBlock.addEventListener('focus', () => {
97
+ if (textBlock.innerText === placeholder) {
98
+ textBlock.innerText = '';
99
+ textBlock.style.color = schema.fontColor ?? DEFAULT_FONT_COLOR;
100
+ }
101
+ });
102
+ }
103
+
104
+ if (mode === 'designer') {
105
+ setTimeout(() => {
106
+ textBlock.focus();
107
+ // Set the focus to the end of the editable element when you focus, as we would for a textarea
108
+ const selection = window.getSelection();
109
+ const range = document.createRange();
110
+ if (selection && range) {
111
+ range.selectNodeContents(textBlock);
112
+ range.collapse(false); // Collapse range to the end
113
+ selection?.removeAllRanges();
114
+ selection?.addRange(range);
115
+ }
116
+ });
117
+ }
118
+ };
119
+
120
+ export const buildStyledTextContainer = async (arg: UIRenderProps<TextSchema>, value: string) => {
121
+ const {
122
+ schema,
123
+ rootElement,
124
+ mode,
125
+ options,
126
+ _cache,
127
+ } = arg;
54
128
  const font = options?.font || getDefaultFont();
55
129
 
56
130
  let dynamicFontSize: undefined | number = undefined;
57
- const getCdfArg = (v: string) => ({
58
- textSchema: schema,
59
- font,
60
- value: v,
61
- startingFontSize: dynamicFontSize,
62
- _cache,
63
- });
131
+
64
132
  if (schema.dynamicFontSize && value) {
65
- dynamicFontSize = await calculateDynamicFontSize(getCdfArg(value));
133
+ dynamicFontSize = await calculateDynamicFontSize({
134
+ textSchema: schema,
135
+ font,
136
+ value,
137
+ startingFontSize: dynamicFontSize,
138
+ _cache,
139
+ });
66
140
  }
67
141
 
68
142
  const fontKitFont = await getFontKitFont(schema.fontName, font, _cache);
69
143
  // Depending on vertical alignment, we need to move the top or bottom of the font to keep
70
144
  // it within it's defined box and align it with the generated pdf.
71
145
  const { topAdj, bottomAdj } = getBrowserVerticalFontAdjustments(
72
- fontKitFont,
73
- dynamicFontSize ?? schema.fontSize ?? DEFAULT_FONT_SIZE,
74
- schema.lineHeight ?? DEFAULT_LINE_HEIGHT,
75
- schema.verticalAlignment ?? DEFAULT_VERTICAL_ALIGNMENT
146
+ fontKitFont,
147
+ dynamicFontSize ?? schema.fontSize ?? DEFAULT_FONT_SIZE,
148
+ schema.lineHeight ?? DEFAULT_LINE_HEIGHT,
149
+ schema.verticalAlignment ?? DEFAULT_VERTICAL_ALIGNMENT
76
150
  );
77
151
 
78
152
  const topAdjustment = topAdj.toString();
@@ -120,100 +194,58 @@ export const uiRender = async (arg: UIRenderProps<TextSchema>) => {
120
194
  backgroundColor: 'transparent',
121
195
  textDecoration: textDecorations.join(' '),
122
196
  };
197
+
123
198
  const textBlock = document.createElement('div');
199
+ textBlock.id = 'text-' + schema.id;
124
200
  Object.assign(textBlock.style, textBlockStyle);
125
201
 
126
- if (isEditable(mode, schema)) {
127
- if (!isFirefox()) {
128
- textBlock.contentEditable = 'plaintext-only';
129
- } else {
130
- textBlock.contentEditable = 'true';
131
- textBlock.addEventListener('keydown', (e: KeyboardEvent) => {
132
- if (e.key === 'Enter' && !e.shiftKey) {
133
- e.preventDefault();
134
- document.execCommand('insertLineBreak', false, undefined);
135
- }
136
- });
137
-
138
- textBlock.addEventListener('paste', (e: ClipboardEvent) => {
139
- e.preventDefault();
140
- const paste = e.clipboardData?.getData('text');
141
- const selection = window.getSelection();
142
- if (!selection?.rangeCount) return;
143
- selection.deleteFromDocument();
144
- selection.getRangeAt(0).insertNode(document.createTextNode(paste || ''));
145
- selection.collapseToEnd();
146
- });
147
- }
148
- textBlock.tabIndex = tabIndex || 0;
149
- textBlock.innerText = value;
150
- textBlock.addEventListener('blur', (e: Event) => {
151
- onChange && onChange({ key: 'content', value: (e.target as HTMLDivElement).innerText });
152
- stopEditing && stopEditing();
153
- });
202
+ container.appendChild(textBlock);
154
203
 
155
- if (schema.dynamicFontSize) {
156
- textBlock.addEventListener('keyup', () => {
157
- setTimeout(() => {
158
- void (async () => {
159
- if (!textBlock.textContent) return;
160
- dynamicFontSize = await calculateDynamicFontSize(getCdfArg(textBlock.textContent));
161
- textBlock.style.fontSize = `${dynamicFontSize}pt`;
162
-
163
- const { topAdj: newTopAdj, bottomAdj: newBottomAdj } =
164
- getBrowserVerticalFontAdjustments(
165
- fontKitFont,
166
- dynamicFontSize ?? schema.fontSize ?? DEFAULT_FONT_SIZE,
167
- schema.lineHeight ?? DEFAULT_LINE_HEIGHT,
168
- schema.verticalAlignment ?? DEFAULT_VERTICAL_ALIGNMENT
169
- );
170
- textBlock.style.paddingTop = `${newTopAdj}px`;
171
- textBlock.style.marginBottom = `${newBottomAdj}px`;
172
- })();
173
- }, 0);
174
- });
175
- }
204
+ return textBlock;
205
+ };
176
206
 
177
- if (placeholder && !value) {
178
- textBlock.innerText = placeholder;
179
- textBlock.style.color = PLACEHOLDER_FONT_COLOR;
180
- if (schema.dynamicFontSize) {
181
- const fontSize = await calculateDynamicFontSize(getCdfArg(placeholder));
182
- textBlock.style.fontSize = `${fontSize}pt`;
183
- }
184
- textBlock.addEventListener('focus', () => {
185
- if (textBlock.innerText === placeholder) {
186
- textBlock.innerText = '';
187
- textBlock.style.color = schema.fontColor ?? DEFAULT_FONT_COLOR;
188
- }
189
- });
207
+ /**
208
+ * Firefox doesn't support 'plaintext-only' contentEditable mode, which we want to avoid mark-up.
209
+ * This function adds a workaround for Firefox to make the contentEditable element behave like 'plaintext-only'.
210
+ */
211
+ export const makeElementPlainTextContentEditable = (element: HTMLElement) => {
212
+ if (!isFirefox()) {
213
+ element.contentEditable = 'plaintext-only';
214
+ return;
215
+ }
216
+
217
+ element.contentEditable = 'true';
218
+ element.addEventListener('keydown', (e: KeyboardEvent) => {
219
+ if (e.key === 'Enter' && !e.shiftKey) {
220
+ e.preventDefault();
221
+ document.execCommand('insertLineBreak', false, undefined);
190
222
  }
223
+ });
191
224
 
192
- container.appendChild(textBlock);
225
+ element.addEventListener('paste', (e: ClipboardEvent) => {
226
+ e.preventDefault();
227
+ const paste = e.clipboardData?.getData('text');
228
+ const selection = window.getSelection();
229
+ if (!selection?.rangeCount) return;
230
+ selection.deleteFromDocument();
231
+ selection.getRangeAt(0).insertNode(document.createTextNode(paste || ''));
232
+ selection.collapseToEnd();
233
+ });
234
+ }
193
235
 
194
- if (mode === 'designer') {
195
- setTimeout(() => {
196
- textBlock.focus();
197
- // Set the focus to the end of the editable element when you focus, as we would for a textarea
198
- const selection = window.getSelection();
199
- const range = document.createRange();
200
- range.selectNodeContents(textBlock);
201
- range.collapse(false); // Collapse range to the end
202
- selection?.removeAllRanges();
203
- selection?.addRange(range);
204
- });
205
- }
206
- } else {
207
- textBlock.innerHTML = value
208
- .split('')
209
- .map(
210
- (l: string, i: number) =>
211
- `<span style="letter-spacing:${
212
- String(value).length === i + 1 ? 0 : 'inherit'
213
- };">${l}</span>`
214
- )
215
- .join('');
216
-
217
- container.appendChild(textBlock);
236
+ const mapVerticalAlignToFlex = (verticalAlignmentValue: string | undefined) => {
237
+ switch (verticalAlignmentValue) {
238
+ case VERTICAL_ALIGN_TOP:
239
+ return 'flex-start';
240
+ case VERTICAL_ALIGN_MIDDLE:
241
+ return 'center';
242
+ case VERTICAL_ALIGN_BOTTOM:
243
+ return 'flex-end';
218
244
  }
245
+ return 'flex-start';
246
+ };
247
+
248
+ const getBackgroundColor = (value: string, schema: TextSchema) => {
249
+ if (!value || !schema.backgroundColor) return 'transparent';
250
+ return schema.backgroundColor as string;
219
251
  };