@pdfme/ui 2.1.0 → 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 (73) hide show
  1. package/README.md +7 -3
  2. package/dist/index.js +1 -1
  3. package/dist/index.js.LICENSE.txt +1 -1
  4. package/dist/index.js.map +1 -1
  5. package/dist/types/builtInRenderer.d.ts +3 -0
  6. package/dist/types/class.d.ts +10 -1
  7. package/dist/types/components/CtlBar/Pager.d.ts +3 -2
  8. package/dist/types/components/CtlBar/Zoom.d.ts +3 -2
  9. package/dist/types/components/CtlBar/index.d.ts +3 -2
  10. package/dist/types/components/Designer/Main/Guides.d.ts +2 -2
  11. package/dist/types/components/Designer/Main/Mask.d.ts +2 -1
  12. package/dist/types/components/Designer/Main/Moveable.d.ts +1 -1
  13. package/dist/types/components/Designer/Main/Selecto.d.ts +2 -1
  14. package/dist/types/components/Designer/Sidebar/DetailView/BarCodePropEditor.d.ts +7 -0
  15. package/dist/types/components/Designer/Sidebar/DetailView/ExampleInputEditor.d.ts +2 -1
  16. package/dist/types/components/Designer/Sidebar/DetailView/FormComponents/ColorInputSet.d.ts +9 -0
  17. package/dist/types/components/Designer/Sidebar/DetailView/PositionAndSizeEditor.d.ts +2 -1
  18. package/dist/types/components/Designer/Sidebar/DetailView/TextPropEditor.d.ts +2 -1
  19. package/dist/types/components/Designer/Sidebar/DetailView/TypeAndKeyEditor.d.ts +2 -1
  20. package/dist/types/components/Designer/Sidebar/DetailView/index.d.ts +3 -2
  21. package/dist/types/components/Designer/Sidebar/ListView/SelectableSortableContainer.d.ts +2 -1
  22. package/dist/types/components/Designer/Sidebar/ListView/SelectableSortableItem.d.ts +1 -1
  23. package/dist/types/components/Designer/Sidebar/ListView/index.d.ts +2 -1
  24. package/dist/types/components/Designer/Sidebar/index.d.ts +4 -2
  25. package/dist/types/components/Designer/index.d.ts +11 -2
  26. package/dist/types/components/Divider.d.ts +2 -1
  27. package/dist/types/components/Error.d.ts +2 -1
  28. package/dist/types/components/Paper.d.ts +2 -2
  29. package/dist/types/components/Preview.d.ts +2 -1
  30. package/dist/types/components/Renderer.d.ts +4 -0
  31. package/dist/types/components/Root.d.ts +1 -1
  32. package/dist/types/components/Spinner.d.ts +2 -1
  33. package/dist/types/components/UnitPager.d.ts +3 -2
  34. package/dist/types/contexts.d.ts +3 -1
  35. package/dist/types/helper.d.ts +5 -0
  36. package/dist/types/hooks.d.ts +2 -2
  37. package/dist/types/i18n.d.ts +4 -1
  38. package/dist/types/renders/barcodes.d.ts +2 -0
  39. package/dist/types/renders/image.d.ts +2 -0
  40. package/dist/types/renders/text.d.ts +2 -0
  41. package/dist/types/types.d.ts +25 -0
  42. package/package.json +2 -1
  43. package/src/Designer.tsx +21 -17
  44. package/src/Form.tsx +18 -14
  45. package/src/Viewer.tsx +6 -2
  46. package/src/builtInRenderer.ts +14 -0
  47. package/src/class.ts +22 -2
  48. package/src/components/Designer/Main/index.tsx +4 -15
  49. package/src/components/Designer/Sidebar/DetailView/BarCodePropEditor.tsx +81 -0
  50. package/src/components/Designer/Sidebar/DetailView/ExampleInputEditor.tsx +1 -2
  51. package/src/components/Designer/Sidebar/DetailView/FormComponents/ColorInputSet.tsx +50 -0
  52. package/src/components/Designer/Sidebar/DetailView/PositionAndSizeEditor.tsx +1 -3
  53. package/src/components/Designer/Sidebar/DetailView/TextPropEditor.tsx +189 -209
  54. package/src/components/Designer/Sidebar/DetailView/index.tsx +16 -8
  55. package/src/components/Designer/Sidebar/index.tsx +3 -2
  56. package/src/components/Designer/index.tsx +1 -0
  57. package/src/components/Preview.tsx +6 -6
  58. package/src/components/Renderer.tsx +80 -0
  59. package/src/contexts.ts +5 -0
  60. package/src/helper.ts +8 -0
  61. package/src/i18n.ts +44 -1
  62. package/src/renders/barcodes.ts +117 -0
  63. package/src/renders/image.ts +101 -0
  64. package/src/renders/text.ts +138 -0
  65. package/src/types.ts +28 -0
  66. package/dist/types/components/Schemas/BarcodeSchema.d.ts +0 -15
  67. package/dist/types/components/Schemas/ImageSchema.d.ts +0 -15
  68. package/dist/types/components/Schemas/SchemaUI.d.ts +0 -15
  69. package/dist/types/components/Schemas/TextSchema.d.ts +0 -27
  70. package/src/components/Schemas/BarcodeSchema.tsx +0 -124
  71. package/src/components/Schemas/ImageSchema.tsx +0 -87
  72. package/src/components/Schemas/SchemaUI.tsx +0 -62
  73. package/src/components/Schemas/TextSchema.tsx +0 -117
@@ -6,13 +6,18 @@ import {
6
6
  DEFAULT_LINE_HEIGHT,
7
7
  DEFAULT_CHARACTER_SPACING,
8
8
  DEFAULT_FONT_COLOR,
9
+ VERTICAL_ALIGN_TOP,
10
+ VERTICAL_ALIGN_MIDDLE,
11
+ VERTICAL_ALIGN_BOTTOM,
12
+ DEFAULT_VERTICAL_ALIGNMENT,
9
13
  DYNAMIC_FIT_VERTICAL,
10
14
  DYNAMIC_FIT_HORIZONTAL,
11
15
  DEFAULT_DYNAMIC_FIT,
12
16
  } from '@pdfme/common';
13
17
  import { FontContext } from '../../../../contexts';
18
+ import Divider from '../../../Divider';
14
19
  import { SidebarProps } from '..';
15
- import { XMarkIcon } from '@heroicons/react/24/outline';
20
+ import ColorInputSet from './FormComponents/ColorInputSet';
16
21
 
17
22
  const inputStyle = {
18
23
  width: '90%',
@@ -56,46 +61,6 @@ const NumberInputSet = (props: {
56
61
  );
57
62
  };
58
63
 
59
- const ColorInputSet = (props: {
60
- label: string;
61
- value: string;
62
- onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
63
- onClear: () => void;
64
- }) => {
65
- const { label, value, onChange, onClear } = props;
66
- const formattedLabel = label.replace(/\s/g, '');
67
-
68
- return (
69
- <div style={{ width: '45%' }}>
70
- <label htmlFor={`input-${formattedLabel}`}>{label}</label>
71
- <div style={{ display: 'flex' }}>
72
- <input
73
- id={`input-${formattedLabel}`}
74
- name={`input-${formattedLabel}`}
75
- onChange={onChange}
76
- value={value || '#ffffff'}
77
- type="color"
78
- style={inputStyle}
79
- />
80
- <button
81
- onClick={onClear}
82
- style={{
83
- display: 'flex',
84
- alignItems: 'center',
85
- justifyContent: 'center',
86
- background: 'none',
87
- borderRadius: 2,
88
- border: '1px solid #767676',
89
- cursor: 'pointer',
90
- }}
91
- >
92
- <XMarkIcon width={10} height={10} />
93
- </button>
94
- </div>
95
- </div>
96
- );
97
- };
98
-
99
64
  const SelectSet = (props: {
100
65
  label: string;
101
66
  value: string;
@@ -133,9 +98,11 @@ const CheckboxSet = (props: {
133
98
  checked: boolean | undefined;
134
99
  }) => {
135
100
  const { width, label, onChange, checked } = props;
101
+ const fieldId = 'input-' + label.replace(/\s/g, '');
136
102
 
137
103
  return (
138
104
  <label
105
+ htmlFor={fieldId}
139
106
  style={{
140
107
  display: 'flex',
141
108
  alignItems: 'center',
@@ -143,7 +110,7 @@ const CheckboxSet = (props: {
143
110
  width: `${width}`,
144
111
  }}
145
112
  >
146
- <input type="checkbox" checked={checked} onChange={onChange} />
113
+ <input id={fieldId} type="checkbox" checked={checked} onChange={onChange} />
147
114
  {label}
148
115
  </label>
149
116
  );
@@ -154,6 +121,7 @@ const TextPropEditor = (
154
121
  ) => {
155
122
  const { changeSchemas, activeSchema } = props;
156
123
  const alignments = ['left', 'center', 'right'];
124
+ const verticalAlignments = [VERTICAL_ALIGN_TOP, VERTICAL_ALIGN_MIDDLE, VERTICAL_ALIGN_BOTTOM];
157
125
  const dynamicFits = [DYNAMIC_FIT_HORIZONTAL, DYNAMIC_FIT_VERTICAL];
158
126
  const font = useContext(FontContext);
159
127
  const fallbackFontName = getFallbackFontName(font);
@@ -161,182 +129,194 @@ const TextPropEditor = (
161
129
  if (activeSchema.type !== 'text') return <></>;
162
130
 
163
131
  return (
164
- <section style={{ fontSize: '0.7rem' }}>
165
- <div
166
- style={{
167
- display: 'flex',
168
- alignItems: 'center',
169
- justifyContent: 'space-between',
170
- marginBottom: '0.25rem',
171
- }}
172
- >
173
- <SelectSet
174
- label={'FontName'}
175
- value={activeSchema.fontName ?? fallbackFontName}
176
- options={Object.keys(font)}
177
- onChange={(e) => {
178
- changeSchemas([{ key: 'fontName', value: e.target.value, schemaId: activeSchema.id }]);
132
+ <>
133
+ <section style={{ fontSize: '0.7rem' }}>
134
+ <div
135
+ style={{
136
+ display: 'flex',
137
+ alignItems: 'center',
138
+ justifyContent: 'space-between',
139
+ marginBottom: '0.25rem',
179
140
  }}
180
- />
141
+ >
142
+ <SelectSet
143
+ label={'FontName'}
144
+ value={activeSchema.fontName ?? fallbackFontName}
145
+ options={Object.keys(font)}
146
+ onChange={(e) => {
147
+ changeSchemas([{ key: 'fontName', value: e.target.value, schemaId: activeSchema.id }]);
148
+ }}
149
+ />
181
150
 
182
- <SelectSet
183
- label={'Alignment'}
184
- value={activeSchema.alignment ?? 'left'}
185
- options={alignments}
186
- onChange={(e) =>
187
- changeSchemas([{ key: 'alignment', value: e.target.value, schemaId: activeSchema.id }])
188
- }
189
- />
190
- </div>
191
- <div
192
- style={{
193
- display: 'flex',
194
- alignItems: 'center',
195
- justifyContent: 'space-between',
196
- marginBottom: '0.25rem',
197
- }}
198
- >
199
- <NumberInputSet
200
- width="30%"
201
- label={'FontSize(pt)'}
202
- value={activeSchema.dynamicFontSize ? NaN : (activeSchema.fontSize ?? DEFAULT_FONT_SIZE)}
203
- style={activeSchema.dynamicFontSize ? { background: '#ccc', cursor: 'not-allowed' } : {}}
204
- disabled={!!activeSchema.dynamicFontSize}
205
- onChange={(e) => {
206
- changeSchemas([{ key: 'fontSize', value: Number(e.target.value), schemaId: activeSchema.id }])
207
- }}
208
- />
209
- <NumberInputSet
210
- width="30%"
211
- label={'LineHeight(em)'}
212
- step={0.1}
213
- value={activeSchema.lineHeight ?? DEFAULT_LINE_HEIGHT}
214
- onChange={(e) =>
215
- changeSchemas([
216
- { key: 'lineHeight', value: Number(e.target.value), schemaId: activeSchema.id },
217
- ])
218
- }
219
- />
151
+ <SelectSet
152
+ label={'Horizontal Align'}
153
+ value={activeSchema.alignment ?? 'left'}
154
+ options={alignments}
155
+ onChange={(e) =>
156
+ changeSchemas([{ key: 'alignment', value: e.target.value, schemaId: activeSchema.id }])
157
+ }
158
+ />
220
159
 
221
- <NumberInputSet
222
- width="40%"
223
- label={'CharacterSpacing(pt)'}
224
- step={0.1}
225
- value={activeSchema.characterSpacing ?? DEFAULT_CHARACTER_SPACING}
226
- onChange={async (e) => {
227
- const currentCharacterSpacing = Number(e.target.value);
228
- changeSchemas([
229
- { key: 'characterSpacing', value: currentCharacterSpacing, schemaId: activeSchema.id, },
230
- ]);
160
+ <SelectSet
161
+ label={'Vertical Align'}
162
+ value={activeSchema.verticalAlignment ?? DEFAULT_VERTICAL_ALIGNMENT}
163
+ options={verticalAlignments}
164
+ onChange={(e) => {
165
+ changeSchemas([{ key: 'verticalAlignment', value: e.target.value, schemaId: activeSchema.id }]);
166
+ }}
167
+ />
168
+ </div>
169
+ <div
170
+ style={{
171
+ display: 'flex',
172
+ alignItems: 'center',
173
+ justifyContent: 'space-between',
174
+ marginBottom: '0.25rem',
231
175
  }}
232
- />
233
- </div>
234
- <div
235
- style={{
236
- display: 'flex',
237
- alignItems: 'center',
238
- justifyContent: 'space-between',
239
- flexWrap: 'wrap',
240
- marginBottom: '0.25rem',
241
- }}
242
- >
243
- <CheckboxSet
244
- width="100%"
245
- label="Use dynamic font size"
246
- checked={Boolean(activeSchema.dynamicFontSize)}
247
- onChange={(e) => {
248
- changeSchemas([
249
- {
250
- key: 'dynamicFontSize', value: e.target.checked ? {
251
- min: activeSchema.fontSize || DEFAULT_FONT_SIZE,
252
- max: activeSchema.fontSize || DEFAULT_FONT_SIZE,
253
- } : undefined, schemaId: activeSchema.id,
254
- },
255
- ]);
176
+ >
177
+ <NumberInputSet
178
+ width="30%"
179
+ label={'FontSize(pt)'}
180
+ value={activeSchema.dynamicFontSize ? NaN : (activeSchema.fontSize ?? DEFAULT_FONT_SIZE)}
181
+ style={activeSchema.dynamicFontSize ? { background: '#ccc', cursor: 'not-allowed' } : {}}
182
+ disabled={!!activeSchema.dynamicFontSize}
183
+ onChange={(e) => {
184
+ changeSchemas([{ key: 'fontSize', value: Number(e.target.value), schemaId: activeSchema.id }])
185
+ }}
186
+ />
187
+ <NumberInputSet
188
+ width="30%"
189
+ label={'LineHeight(em)'}
190
+ step={0.1}
191
+ value={activeSchema.lineHeight ?? DEFAULT_LINE_HEIGHT}
192
+ onChange={(e) =>
193
+ changeSchemas([
194
+ { key: 'lineHeight', value: Number(e.target.value), schemaId: activeSchema.id },
195
+ ])
196
+ }
197
+ />
198
+
199
+ <NumberInputSet
200
+ width="40%"
201
+ label={'CharacterSpacing(pt)'}
202
+ step={0.1}
203
+ value={activeSchema.characterSpacing ?? DEFAULT_CHARACTER_SPACING}
204
+ onChange={async (e) => {
205
+ const currentCharacterSpacing = Number(e.target.value);
206
+ changeSchemas([
207
+ { key: 'characterSpacing', value: currentCharacterSpacing, schemaId: activeSchema.id, },
208
+ ]);
209
+ }}
210
+ />
211
+ </div>
212
+ <div
213
+ style={{
214
+ display: 'flex',
215
+ alignItems: 'center',
216
+ justifyContent: 'space-between',
217
+ flexWrap: 'wrap',
218
+ marginBottom: '0.25rem',
256
219
  }}
257
- />
220
+ >
221
+ <CheckboxSet
222
+ width="100%"
223
+ label="Use dynamic font size"
224
+ checked={Boolean(activeSchema.dynamicFontSize)}
225
+ onChange={(e) => {
226
+ changeSchemas([
227
+ {
228
+ key: 'dynamicFontSize', value: e.target.checked ? {
229
+ min: activeSchema.fontSize || DEFAULT_FONT_SIZE,
230
+ max: activeSchema.fontSize || DEFAULT_FONT_SIZE,
231
+ } : undefined, schemaId: activeSchema.id,
232
+ },
233
+ ]);
234
+ }}
235
+ />
258
236
 
259
- {activeSchema.dynamicFontSize && (
260
- <>
261
- <NumberInputSet
262
- width="30%"
263
- label={'FontSize Min(pt)'}
264
- value={activeSchema.dynamicFontSize.min ?? Number(activeSchema.fontSize)}
265
- minNumber={0}
266
- style={
267
- activeSchema.dynamicFontSize &&
268
- activeSchema.dynamicFontSize.max < activeSchema.dynamicFontSize.min
269
- ? { background: 'rgb(200 0 0 / 30%)' }
270
- : {}
271
- }
272
- onChange={(e) => {
273
- changeSchemas([{ key: 'dynamicFontSize.min', value: Number(e.target.value), schemaId: activeSchema.id }])
274
- }}
275
- />
237
+ {activeSchema.dynamicFontSize && (
238
+ <>
239
+ <NumberInputSet
240
+ width="30%"
241
+ label={'FontSize Min(pt)'}
242
+ value={activeSchema.dynamicFontSize.min ?? Number(activeSchema.fontSize)}
243
+ minNumber={0}
244
+ style={
245
+ activeSchema.dynamicFontSize &&
246
+ activeSchema.dynamicFontSize.max < activeSchema.dynamicFontSize.min
247
+ ? { background: 'rgb(200 0 0 / 30%)' }
248
+ : {}
249
+ }
250
+ onChange={(e) => {
251
+ changeSchemas([{ key: 'dynamicFontSize.min', value: Number(e.target.value), schemaId: activeSchema.id }])
252
+ }}
253
+ />
276
254
 
277
- <NumberInputSet
278
- width="30%"
279
- label={'FontSize Max(pt)'}
280
- value={activeSchema.dynamicFontSize.max ?? Number(activeSchema.fontSize)}
281
- minNumber={0}
282
- style={
283
- activeSchema.dynamicFontSize &&
284
- activeSchema.dynamicFontSize.max < activeSchema.dynamicFontSize.min
285
- ? { background: 'rgb(200 0 0 / 30%)' }
286
- : {}
287
- }
288
- onChange={(e) => {
289
- changeSchemas([{ key: 'dynamicFontSize.max', value: Number(e.target.value), schemaId: activeSchema.id }])
290
- }}
291
- />
255
+ <NumberInputSet
256
+ width="30%"
257
+ label={'FontSize Max(pt)'}
258
+ value={activeSchema.dynamicFontSize.max ?? Number(activeSchema.fontSize)}
259
+ minNumber={0}
260
+ style={
261
+ activeSchema.dynamicFontSize &&
262
+ activeSchema.dynamicFontSize.max < activeSchema.dynamicFontSize.min
263
+ ? { background: 'rgb(200 0 0 / 30%)' }
264
+ : {}
265
+ }
266
+ onChange={(e) => {
267
+ changeSchemas([{ key: 'dynamicFontSize.max', value: Number(e.target.value), schemaId: activeSchema.id }])
268
+ }}
269
+ />
292
270
 
293
- <SelectSet
294
- width="40%"
295
- label={'Fit'}
296
- value={activeSchema.dynamicFontSize.fit ?? DEFAULT_DYNAMIC_FIT}
297
- options={dynamicFits}
298
- onChange={(e) => {
299
- changeSchemas([{ key: 'dynamicFontSize.fit', value: e.target.value, schemaId: activeSchema.id }])
300
- }}
301
- />
302
- </>
303
- )}
304
- </div>
305
- <div
306
- style={{
307
- marginBottom: '0.25rem',
308
- display: 'flex',
309
- alignItems: 'center',
310
- justifyContent: 'space-between',
311
- }}
312
- >
313
- <ColorInputSet
314
- label={'FontColor'}
315
- value={activeSchema.fontColor ?? '#000000'}
316
- onChange={(e) =>
317
- changeSchemas([{ key: 'fontColor', value: e.target.value, schemaId: activeSchema.id }])
318
- }
319
- onClear={() =>
320
- changeSchemas([
321
- { key: 'fontColor', value: DEFAULT_FONT_COLOR, schemaId: activeSchema.id },
322
- ])
323
- }
324
- />
271
+ <SelectSet
272
+ width="40%"
273
+ label={'Fit'}
274
+ value={activeSchema.dynamicFontSize.fit ?? DEFAULT_DYNAMIC_FIT}
275
+ options={dynamicFits}
276
+ onChange={(e) => {
277
+ changeSchemas([{ key: 'dynamicFontSize.fit', value: e.target.value, schemaId: activeSchema.id }])
278
+ }}
279
+ />
280
+ </>
281
+ )}
282
+ </div>
283
+ <div
284
+ style={{
285
+ marginBottom: '0.25rem',
286
+ display: 'flex',
287
+ alignItems: 'center',
288
+ justifyContent: 'space-between',
289
+ }}
290
+ >
291
+ <ColorInputSet
292
+ label={'FontColor'}
293
+ value={activeSchema.fontColor ?? '#000000'}
294
+ onChange={(e) =>
295
+ changeSchemas([{ key: 'fontColor', value: e.target.value, schemaId: activeSchema.id }])
296
+ }
297
+ onClear={() =>
298
+ changeSchemas([
299
+ { key: 'fontColor', value: DEFAULT_FONT_COLOR, schemaId: activeSchema.id },
300
+ ])
301
+ }
302
+ />
325
303
 
326
- <ColorInputSet
327
- label={'Background'}
328
- value={activeSchema.backgroundColor ?? '#ffffff'}
329
- onChange={(e) =>
330
- changeSchemas([
331
- { key: 'backgroundColor', value: e.target.value, schemaId: activeSchema.id },
332
- ])
333
- }
334
- onClear={() =>
335
- changeSchemas([{ key: 'backgroundColor', value: '', schemaId: activeSchema.id }])
336
- }
337
- />
338
- </div>
339
- </section>
304
+ <ColorInputSet
305
+ label={'Background'}
306
+ value={activeSchema.backgroundColor ?? '#ffffff'}
307
+ onChange={(e) =>
308
+ changeSchemas([
309
+ { key: 'backgroundColor', value: e.target.value, schemaId: activeSchema.id },
310
+ ])
311
+ }
312
+ onClear={() =>
313
+ changeSchemas([{ key: 'backgroundColor', value: '', schemaId: activeSchema.id }])
314
+ }
315
+ />
316
+ </div>
317
+ </section>
318
+ <Divider />
319
+ </>
340
320
  );
341
321
  };
342
322
 
@@ -1,5 +1,6 @@
1
1
  import React, { useContext } from 'react';
2
- import { SchemaForUI } from '@pdfme/common';
2
+ import { SchemaForUI, isBarcodeSchema, isTextSchema } from '@pdfme/common';
3
+ import { Bars3Icon } from '@heroicons/react/20/solid';
3
4
  import { I18nContext } from '../../../../contexts';
4
5
  import Divider from '../../../Divider';
5
6
  import { SidebarProps } from '../index';
@@ -7,18 +8,25 @@ import TextPropEditor from './TextPropEditor';
7
8
  import ExampleInputEditor from './ExampleInputEditor';
8
9
  import PositionAndSizeEditor from './PositionAndSizeEditor';
9
10
  import TypeAndKeyEditor from './TypeAndKeyEditor';
11
+ import BarcodePropEditor from './BarCodePropEditor';
10
12
 
11
13
  const DetailView = (
12
- props: Pick<SidebarProps, 'schemas' | 'pageSize' | 'changeSchemas' | 'activeElements'> & {
14
+ props: Pick<SidebarProps, 'schemas' | 'pageSize' | 'changeSchemas' | 'activeElements' | 'deselectSchema'> & {
13
15
  activeSchema: SchemaForUI;
14
16
  }
15
17
  ) => {
16
- const { activeSchema } = props;
18
+ const { activeSchema, deselectSchema } = props;
17
19
  const i18n = useContext(I18nContext);
18
20
 
19
21
  return (
20
22
  <div>
21
23
  <div style={{ height: 40, display: 'flex', alignItems: 'center' }}>
24
+ <span
25
+ style={{ position: 'absolute', width: 20, padding: '5px', cursor: 'pointer' }}
26
+ onClick={deselectSchema}
27
+ >
28
+ <Bars3Icon />
29
+ </span>
22
30
  <span style={{ textAlign: 'center', width: '100%', fontWeight: 'bold' }}>
23
31
  {i18n('editField')}
24
32
  </span>
@@ -29,11 +37,11 @@ const DetailView = (
29
37
  <Divider />
30
38
  <PositionAndSizeEditor {...props} />
31
39
  <Divider />
32
- {activeSchema.type === 'text' && (
33
- <>
34
- <TextPropEditor {...props} />
35
- <Divider />
36
- </>
40
+ {isBarcodeSchema(activeSchema) && (
41
+ <BarcodePropEditor {...props} />
42
+ )}
43
+ {isTextSchema(activeSchema) && (
44
+ <TextPropEditor {...props} />
37
45
  )}
38
46
  <ExampleInputEditor {...props} />
39
47
  </div>
@@ -27,14 +27,15 @@ export type SidebarProps = {
27
27
  }[]
28
28
  ) => void;
29
29
  addSchema: () => void;
30
+ deselectSchema: () => void;
30
31
  };
31
32
 
32
33
  const Sidebar = (props: SidebarProps) => {
33
34
  const { height, size, activeElements, schemas, addSchema } = props;
34
35
 
35
36
  const i18n = useContext(I18nContext);
36
- const fonts = useContext(FontContext);
37
- const fallbackFont = getFallbackFontName(fonts);
37
+ const font = useContext(FontContext);
38
+ const fallbackFont = getFallbackFontName(font);
38
39
  const [open, setOpen] = useState(true);
39
40
 
40
41
  const getActiveSchemas = () => {
@@ -262,6 +262,7 @@ const TemplateEditor = ({
262
262
  }}
263
263
  onEditEnd={onEditEnd}
264
264
  addSchema={addSchema}
265
+ deselectSchema={onEditEnd}
265
266
  />
266
267
  <Main
267
268
  ref={mainRef}
@@ -6,7 +6,7 @@ import Root from './Root';
6
6
  import Error from './Error';
7
7
  import CtlBar from './CtlBar/index';
8
8
  import Paper from './Paper';
9
- import SchemaUI from './Schemas/SchemaUI';
9
+ import Renderer from './Renderer';
10
10
  import { useUIPreProcessor, useScrollPageCursor } from '../hooks';
11
11
  import { templateSchemas2SchemasList, getPagesScrollTopByIndex } from '../helper';
12
12
 
@@ -47,7 +47,8 @@ const Preview = ({ template, inputs, size, onChangeInput }: PreviewReactProps) =
47
47
  const handleChangeInput = ({ key, value }: { key: string; value: string }) =>
48
48
  onChangeInput && onChangeInput({ index: unitCursor, key, value });
49
49
 
50
- const editable = Boolean(onChangeInput);
50
+ const isForm = Boolean(onChangeInput);
51
+
51
52
  const input = inputs[unitCursor];
52
53
 
53
54
  if (error) {
@@ -96,15 +97,14 @@ const Preview = ({ template, inputs, size, onChangeInput }: PreviewReactProps) =
96
97
  const { key } = schema;
97
98
  const data = (input && input[key]) || '';
98
99
  return (
99
- <SchemaUI
100
+ <Renderer
100
101
  key={schema.id}
101
102
  schema={Object.assign(schema, { data })}
102
- editable={editable}
103
+ mode={isForm ? 'form' : 'viewer'}
103
104
  placeholder={template.sampledata?.[0]?.[key] ?? ''}
104
105
  tabIndex={index + 100}
105
- onStopEditing={() => { }}
106
106
  onChange={(value) => handleChangeInput({ key, value })}
107
- outline={editable ? '1px dashed #4af' : 'transparent'}
107
+ outline={isForm ? '1px dashed #4af' : 'transparent'}
108
108
  />
109
109
  );
110
110
  }}
@@ -0,0 +1,80 @@
1
+ import React, { useEffect, useContext, ReactNode, useRef } from 'react';
2
+ import { ZOOM, SELECTABLE_CLASSNAME } from '../constants';
3
+ import { RendererRegistry, OptionsContext } from '../contexts';
4
+ import { RendererProps } from "../types"
5
+
6
+ const Wrapper = ({
7
+ children,
8
+ outline,
9
+ onChangeHoveringSchemaId,
10
+ schema,
11
+ }: RendererProps & { children: ReactNode }) => (
12
+ <div
13
+ title={schema.key}
14
+ onMouseEnter={() => onChangeHoveringSchemaId && onChangeHoveringSchemaId(schema.id)}
15
+ onMouseLeave={() => onChangeHoveringSchemaId && onChangeHoveringSchemaId(null)}
16
+ className={SELECTABLE_CLASSNAME}
17
+ id={schema.id}
18
+ style={{
19
+ position: 'absolute',
20
+ cursor: 'pointer',
21
+ height: schema.height * ZOOM,
22
+ width: schema.width * ZOOM,
23
+ top: schema.position.y * ZOOM,
24
+ left: schema.position.x * ZOOM,
25
+ outline,
26
+ }}
27
+ >
28
+ {children}
29
+ </div>
30
+ );
31
+
32
+ const Renderer = (props: RendererProps) => {
33
+ const rendererRegistry = useContext(RendererRegistry);
34
+ const options = useContext(OptionsContext);
35
+
36
+ const { schema, mode, onChange, stopEditing, tabIndex, placeholder } = props;
37
+
38
+ const ref = useRef<HTMLDivElement>(null);
39
+
40
+
41
+ useEffect(() => {
42
+ if (ref.current && schema.type) {
43
+ const schemaType = schema.type as string;
44
+ const renderer = rendererRegistry[schemaType];
45
+ if (!renderer) {
46
+ console.error(`Renderer for type ${schema.type} not found`);
47
+ return;
48
+ }
49
+
50
+ ref.current.innerHTML = '';
51
+
52
+ const isForm = mode === 'form';
53
+
54
+ renderer.render({
55
+ value: schema.data,
56
+ schema,
57
+ rootElement: ref.current,
58
+ mode,
59
+ onChange: isForm ? onChange : undefined,
60
+ stopEditing: isForm ? stopEditing : undefined,
61
+ tabIndex,
62
+ placeholder,
63
+ options,
64
+ });
65
+ }
66
+ return () => {
67
+ if (ref.current) {
68
+ ref.current.innerHTML = '';
69
+ }
70
+ };
71
+ }, [JSON.stringify(schema), mode, options]);
72
+
73
+
74
+ return (
75
+ <Wrapper {...props}>
76
+ <div style={{ height: '100%', width: '100%' }} ref={ref} />
77
+ </Wrapper>
78
+ );
79
+ };
80
+ export default Renderer
package/src/contexts.ts CHANGED
@@ -1,8 +1,13 @@
1
1
  import { createContext } from 'react';
2
2
  import { curriedI18n } from './i18n';
3
3
  import { DEFAULT_LANG } from './constants';
4
+ import builtInRenderer from './builtInRenderer';
4
5
  import { getDefaultFont } from '@pdfme/common';
5
6
 
6
7
  export const I18nContext = createContext(curriedI18n(DEFAULT_LANG));
7
8
 
8
9
  export const FontContext = createContext(getDefaultFont());
10
+
11
+ export const RendererRegistry = createContext(builtInRenderer);
12
+
13
+ export const OptionsContext = createContext({});