@pdfme/ui 2.2.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 (72) hide show
  1. package/dist/index.js +1 -1
  2. package/dist/index.js.LICENSE.txt +1 -1
  3. package/dist/index.js.map +1 -1
  4. package/dist/types/builtInRenderer.d.ts +3 -0
  5. package/dist/types/class.d.ts +9 -1
  6. package/dist/types/components/CtlBar/Pager.d.ts +3 -2
  7. package/dist/types/components/CtlBar/Zoom.d.ts +3 -2
  8. package/dist/types/components/CtlBar/index.d.ts +3 -2
  9. package/dist/types/components/Designer/Main/Guides.d.ts +2 -2
  10. package/dist/types/components/Designer/Main/Mask.d.ts +2 -1
  11. package/dist/types/components/Designer/Main/Moveable.d.ts +1 -1
  12. package/dist/types/components/Designer/Main/Selecto.d.ts +2 -1
  13. package/dist/types/components/Designer/Sidebar/DetailView/BarCodePropEditor.d.ts +7 -0
  14. package/dist/types/components/Designer/Sidebar/DetailView/ExampleInputEditor.d.ts +2 -1
  15. package/dist/types/components/Designer/Sidebar/DetailView/FormComponents/ColorInputSet.d.ts +9 -0
  16. package/dist/types/components/Designer/Sidebar/DetailView/PositionAndSizeEditor.d.ts +2 -1
  17. package/dist/types/components/Designer/Sidebar/DetailView/TextPropEditor.d.ts +2 -1
  18. package/dist/types/components/Designer/Sidebar/DetailView/TypeAndKeyEditor.d.ts +2 -1
  19. package/dist/types/components/Designer/Sidebar/DetailView/index.d.ts +3 -2
  20. package/dist/types/components/Designer/Sidebar/ListView/SelectableSortableContainer.d.ts +2 -1
  21. package/dist/types/components/Designer/Sidebar/ListView/SelectableSortableItem.d.ts +1 -1
  22. package/dist/types/components/Designer/Sidebar/ListView/index.d.ts +2 -1
  23. package/dist/types/components/Designer/Sidebar/index.d.ts +4 -2
  24. package/dist/types/components/Designer/index.d.ts +9 -2
  25. package/dist/types/components/Divider.d.ts +2 -1
  26. package/dist/types/components/Error.d.ts +2 -1
  27. package/dist/types/components/Paper.d.ts +2 -2
  28. package/dist/types/components/Preview.d.ts +2 -1
  29. package/dist/types/components/Renderer.d.ts +4 -0
  30. package/dist/types/components/Root.d.ts +1 -1
  31. package/dist/types/components/Spinner.d.ts +2 -1
  32. package/dist/types/components/UnitPager.d.ts +3 -2
  33. package/dist/types/contexts.d.ts +3 -1
  34. package/dist/types/helper.d.ts +4 -0
  35. package/dist/types/hooks.d.ts +2 -2
  36. package/dist/types/i18n.d.ts +4 -1
  37. package/dist/types/renders/barcodes.d.ts +2 -0
  38. package/dist/types/renders/image.d.ts +2 -0
  39. package/dist/types/renders/text.d.ts +2 -0
  40. package/dist/types/types.d.ts +25 -0
  41. package/package.json +2 -1
  42. package/src/Designer.tsx +21 -17
  43. package/src/Form.tsx +18 -14
  44. package/src/Viewer.tsx +6 -2
  45. package/src/builtInRenderer.ts +14 -0
  46. package/src/class.ts +22 -2
  47. package/src/components/Designer/Main/index.tsx +4 -15
  48. package/src/components/Designer/Sidebar/DetailView/BarCodePropEditor.tsx +81 -0
  49. package/src/components/Designer/Sidebar/DetailView/ExampleInputEditor.tsx +1 -2
  50. package/src/components/Designer/Sidebar/DetailView/FormComponents/ColorInputSet.tsx +50 -0
  51. package/src/components/Designer/Sidebar/DetailView/PositionAndSizeEditor.tsx +1 -3
  52. package/src/components/Designer/Sidebar/DetailView/TextPropEditor.tsx +183 -217
  53. package/src/components/Designer/Sidebar/DetailView/index.tsx +16 -8
  54. package/src/components/Designer/Sidebar/index.tsx +3 -2
  55. package/src/components/Designer/index.tsx +1 -0
  56. package/src/components/Preview.tsx +6 -6
  57. package/src/components/Renderer.tsx +80 -0
  58. package/src/contexts.ts +5 -0
  59. package/src/helper.ts +8 -0
  60. package/src/i18n.ts +44 -1
  61. package/src/renders/barcodes.ts +117 -0
  62. package/src/renders/image.ts +101 -0
  63. package/src/renders/text.ts +138 -0
  64. package/src/types.ts +28 -0
  65. package/dist/types/components/Schemas/BarcodeSchema.d.ts +0 -15
  66. package/dist/types/components/Schemas/ImageSchema.d.ts +0 -15
  67. package/dist/types/components/Schemas/SchemaUI.d.ts +0 -15
  68. package/dist/types/components/Schemas/TextSchema.d.ts +0 -28
  69. package/src/components/Schemas/BarcodeSchema.tsx +0 -124
  70. package/src/components/Schemas/ImageSchema.tsx +0 -87
  71. package/src/components/Schemas/SchemaUI.tsx +0 -62
  72. package/src/components/Schemas/TextSchema.tsx +0 -175
@@ -15,8 +15,9 @@ import {
15
15
  DEFAULT_DYNAMIC_FIT,
16
16
  } from '@pdfme/common';
17
17
  import { FontContext } from '../../../../contexts';
18
+ import Divider from '../../../Divider';
18
19
  import { SidebarProps } from '..';
19
- import { XMarkIcon } from '@heroicons/react/24/outline';
20
+ import ColorInputSet from './FormComponents/ColorInputSet';
20
21
 
21
22
  const inputStyle = {
22
23
  width: '90%',
@@ -60,46 +61,6 @@ const NumberInputSet = (props: {
60
61
  );
61
62
  };
62
63
 
63
- const ColorInputSet = (props: {
64
- label: string;
65
- value: string;
66
- onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
67
- onClear: () => void;
68
- }) => {
69
- const { label, value, onChange, onClear } = props;
70
- const formattedLabel = label.replace(/\s/g, '');
71
-
72
- return (
73
- <div style={{ width: '45%' }}>
74
- <label htmlFor={`input-${formattedLabel}`}>{label}</label>
75
- <div style={{ display: 'flex' }}>
76
- <input
77
- id={`input-${formattedLabel}`}
78
- name={`input-${formattedLabel}`}
79
- onChange={onChange}
80
- value={value || '#ffffff'}
81
- type="color"
82
- style={inputStyle}
83
- />
84
- <button
85
- onClick={onClear}
86
- style={{
87
- display: 'flex',
88
- alignItems: 'center',
89
- justifyContent: 'center',
90
- background: 'none',
91
- borderRadius: 2,
92
- border: '1px solid #767676',
93
- cursor: 'pointer',
94
- }}
95
- >
96
- <XMarkIcon width={10} height={10} />
97
- </button>
98
- </div>
99
- </div>
100
- );
101
- };
102
-
103
64
  const SelectSet = (props: {
104
65
  label: string;
105
66
  value: string;
@@ -137,9 +98,11 @@ const CheckboxSet = (props: {
137
98
  checked: boolean | undefined;
138
99
  }) => {
139
100
  const { width, label, onChange, checked } = props;
101
+ const fieldId = 'input-' + label.replace(/\s/g, '');
140
102
 
141
103
  return (
142
104
  <label
105
+ htmlFor={fieldId}
143
106
  style={{
144
107
  display: 'flex',
145
108
  alignItems: 'center',
@@ -147,7 +110,7 @@ const CheckboxSet = (props: {
147
110
  width: `${width}`,
148
111
  }}
149
112
  >
150
- <input type="checkbox" checked={checked} onChange={onChange} />
113
+ <input id={fieldId} type="checkbox" checked={checked} onChange={onChange} />
151
114
  {label}
152
115
  </label>
153
116
  );
@@ -166,191 +129,194 @@ const TextPropEditor = (
166
129
  if (activeSchema.type !== 'text') return <></>;
167
130
 
168
131
  return (
169
- <section style={{ fontSize: '0.7rem' }}>
170
- <div
171
- style={{
172
- display: 'flex',
173
- alignItems: 'center',
174
- justifyContent: 'space-between',
175
- marginBottom: '0.25rem',
176
- }}
177
- >
178
- <SelectSet
179
- label={'FontName'}
180
- value={activeSchema.fontName ?? fallbackFontName}
181
- options={Object.keys(font)}
182
- onChange={(e) => {
183
- 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',
184
140
  }}
185
- />
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
+ />
186
150
 
187
- <SelectSet
188
- label={'Horizontal Align'}
189
- value={activeSchema.alignment ?? 'left'}
190
- options={alignments}
191
- onChange={(e) =>
192
- changeSchemas([{ key: 'alignment', value: e.target.value, schemaId: activeSchema.id }])
193
- }
194
- />
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
+ />
195
159
 
196
- <SelectSet
197
- label={'Vertical Align'}
198
- value={activeSchema.verticalAlignment ?? DEFAULT_VERTICAL_ALIGNMENT}
199
- options={verticalAlignments}
200
- onChange={(e) => {
201
- changeSchemas([{ key: 'verticalAlignment', value: e.target.value, schemaId: activeSchema.id }]);
202
- }}
203
- />
204
- </div>
205
- <div
206
- style={{
207
- display: 'flex',
208
- alignItems: 'center',
209
- justifyContent: 'space-between',
210
- marginBottom: '0.25rem',
211
- }}
212
- >
213
- <NumberInputSet
214
- width="30%"
215
- label={'FontSize(pt)'}
216
- value={activeSchema.dynamicFontSize ? NaN : (activeSchema.fontSize ?? DEFAULT_FONT_SIZE)}
217
- style={activeSchema.dynamicFontSize ? { background: '#ccc', cursor: 'not-allowed' } : {}}
218
- disabled={!!activeSchema.dynamicFontSize}
219
- onChange={(e) => {
220
- changeSchemas([{ key: 'fontSize', value: Number(e.target.value), schemaId: activeSchema.id }])
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',
221
175
  }}
222
- />
223
- <NumberInputSet
224
- width="30%"
225
- label={'LineHeight(em)'}
226
- step={0.1}
227
- value={activeSchema.lineHeight ?? DEFAULT_LINE_HEIGHT}
228
- onChange={(e) =>
229
- changeSchemas([
230
- { key: 'lineHeight', value: Number(e.target.value), schemaId: activeSchema.id },
231
- ])
232
- }
233
- />
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
+ />
234
198
 
235
- <NumberInputSet
236
- width="40%"
237
- label={'CharacterSpacing(pt)'}
238
- step={0.1}
239
- value={activeSchema.characterSpacing ?? DEFAULT_CHARACTER_SPACING}
240
- onChange={async (e) => {
241
- const currentCharacterSpacing = Number(e.target.value);
242
- changeSchemas([
243
- { key: 'characterSpacing', value: currentCharacterSpacing, schemaId: activeSchema.id, },
244
- ]);
245
- }}
246
- />
247
- </div>
248
- <div
249
- style={{
250
- display: 'flex',
251
- alignItems: 'center',
252
- justifyContent: 'space-between',
253
- flexWrap: 'wrap',
254
- marginBottom: '0.25rem',
255
- }}
256
- >
257
- <CheckboxSet
258
- width="100%"
259
- label="Use dynamic font size"
260
- checked={Boolean(activeSchema.dynamicFontSize)}
261
- onChange={(e) => {
262
- changeSchemas([
263
- {
264
- key: 'dynamicFontSize', value: e.target.checked ? {
265
- min: activeSchema.fontSize || DEFAULT_FONT_SIZE,
266
- max: activeSchema.fontSize || DEFAULT_FONT_SIZE,
267
- } : undefined, schemaId: activeSchema.id,
268
- },
269
- ]);
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',
270
219
  }}
271
- />
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
+ />
272
236
 
273
- {activeSchema.dynamicFontSize && (
274
- <>
275
- <NumberInputSet
276
- width="30%"
277
- label={'FontSize Min(pt)'}
278
- value={activeSchema.dynamicFontSize.min ?? Number(activeSchema.fontSize)}
279
- minNumber={0}
280
- style={
281
- activeSchema.dynamicFontSize &&
282
- activeSchema.dynamicFontSize.max < activeSchema.dynamicFontSize.min
283
- ? { background: 'rgb(200 0 0 / 30%)' }
284
- : {}
285
- }
286
- onChange={(e) => {
287
- changeSchemas([{ key: 'dynamicFontSize.min', value: Number(e.target.value), schemaId: activeSchema.id }])
288
- }}
289
- />
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
+ />
290
254
 
291
- <NumberInputSet
292
- width="30%"
293
- label={'FontSize Max(pt)'}
294
- value={activeSchema.dynamicFontSize.max ?? Number(activeSchema.fontSize)}
295
- minNumber={0}
296
- style={
297
- activeSchema.dynamicFontSize &&
298
- activeSchema.dynamicFontSize.max < activeSchema.dynamicFontSize.min
299
- ? { background: 'rgb(200 0 0 / 30%)' }
300
- : {}
301
- }
302
- onChange={(e) => {
303
- changeSchemas([{ key: 'dynamicFontSize.max', value: Number(e.target.value), schemaId: activeSchema.id }])
304
- }}
305
- />
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
+ />
306
270
 
307
- <SelectSet
308
- width="40%"
309
- label={'Fit'}
310
- value={activeSchema.dynamicFontSize.fit ?? DEFAULT_DYNAMIC_FIT}
311
- options={dynamicFits}
312
- onChange={(e) => {
313
- changeSchemas([{ key: 'dynamicFontSize.fit', value: e.target.value, schemaId: activeSchema.id }])
314
- }}
315
- />
316
- </>
317
- )}
318
- </div>
319
- <div
320
- style={{
321
- marginBottom: '0.25rem',
322
- display: 'flex',
323
- alignItems: 'center',
324
- justifyContent: 'space-between',
325
- }}
326
- >
327
- <ColorInputSet
328
- label={'FontColor'}
329
- value={activeSchema.fontColor ?? '#000000'}
330
- onChange={(e) =>
331
- changeSchemas([{ key: 'fontColor', value: e.target.value, schemaId: activeSchema.id }])
332
- }
333
- onClear={() =>
334
- changeSchemas([
335
- { key: 'fontColor', value: DEFAULT_FONT_COLOR, schemaId: activeSchema.id },
336
- ])
337
- }
338
- />
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
+ />
339
303
 
340
- <ColorInputSet
341
- label={'Background'}
342
- value={activeSchema.backgroundColor ?? '#ffffff'}
343
- onChange={(e) =>
344
- changeSchemas([
345
- { key: 'backgroundColor', value: e.target.value, schemaId: activeSchema.id },
346
- ])
347
- }
348
- onClear={() =>
349
- changeSchemas([{ key: 'backgroundColor', value: '', schemaId: activeSchema.id }])
350
- }
351
- />
352
- </div>
353
- </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
+ </>
354
320
  );
355
321
  };
356
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({});