@pdfme/ui 2.0.2 → 2.1.0
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.
- package/dist/index.js +1 -1
- package/dist/index.js.LICENSE.txt +1 -1
- package/dist/index.js.map +1 -1
- package/dist/types/class.d.ts +1 -0
- package/dist/types/components/Designer/index.d.ts +2 -0
- package/dist/types/components/Paper.d.ts +1 -1
- package/dist/types/components/Schemas/SchemaUI.d.ts +1 -0
- package/dist/types/components/Schemas/TextSchema.d.ts +1 -0
- package/dist/types/helper.d.ts +1 -0
- package/package.json +2 -2
- package/src/components/Designer/Main/index.tsx +14 -27
- package/src/components/Designer/Sidebar/DetailView/TextPropEditor.tsx +46 -24
- package/src/components/Paper.tsx +2 -2
- package/src/components/Preview.tsx +2 -1
- package/src/components/Schemas/BarcodeSchema.tsx +2 -1
- package/src/components/Schemas/ImageSchema.tsx +2 -1
- package/src/components/Schemas/SchemaUI.tsx +1 -0
- package/src/components/Schemas/TextSchema.tsx +35 -4
- package/src/helper.ts +1 -1
package/dist/types/class.d.ts
CHANGED
@@ -20,6 +20,7 @@ declare const TemplateEditor: ({ template, size, onSaveTemplate, onChangeTemplat
|
|
20
20
|
dynamicFontSize?: {
|
21
21
|
max: number;
|
22
22
|
min: number;
|
23
|
+
fit?: string | undefined;
|
23
24
|
} | undefined;
|
24
25
|
} | {
|
25
26
|
type: "image";
|
@@ -68,6 +69,7 @@ declare const TemplateEditor: ({ template, size, onSaveTemplate, onChangeTemplat
|
|
68
69
|
dynamicFontSize?: {
|
69
70
|
max: number;
|
70
71
|
min: number;
|
72
|
+
fit?: string | undefined;
|
71
73
|
} | undefined;
|
72
74
|
} | {
|
73
75
|
type: "image";
|
package/dist/types/helper.d.ts
CHANGED
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@pdfme/ui",
|
3
|
-
"version": "2.0
|
3
|
+
"version": "2.1.0",
|
4
4
|
"sideEffects": false,
|
5
5
|
"author": "hand-dot",
|
6
6
|
"license": "MIT",
|
@@ -64,7 +64,7 @@
|
|
64
64
|
"webpack-cli": "^5.0.1"
|
65
65
|
},
|
66
66
|
"peerDependencies": {
|
67
|
-
"@pdfme/common": "^2.
|
67
|
+
"@pdfme/common": "^2.1.0"
|
68
68
|
},
|
69
69
|
"jest": {
|
70
70
|
"setupFiles": [
|
@@ -39,6 +39,7 @@ const DeleteButton = ({ activeElements: aes }: { activeElements: HTMLElement[] }
|
|
39
39
|
zIndex: 1,
|
40
40
|
top,
|
41
41
|
left,
|
42
|
+
padding: 2,
|
42
43
|
height: 24,
|
43
44
|
width: 24,
|
44
45
|
cursor: 'pointer',
|
@@ -52,7 +53,7 @@ const DeleteButton = ({ activeElements: aes }: { activeElements: HTMLElement[] }
|
|
52
53
|
justifyContent: 'center',
|
53
54
|
}}
|
54
55
|
>
|
55
|
-
<XMarkIcon width={
|
56
|
+
<XMarkIcon style={{ pointerEvents: 'none' }} width={24} height={24} />
|
56
57
|
</button>
|
57
58
|
);
|
58
59
|
};
|
@@ -195,14 +196,6 @@ const Main = (props: Props, ref: Ref<HTMLDivElement>) => {
|
|
195
196
|
changeSchemas(flatten(arg));
|
196
197
|
};
|
197
198
|
|
198
|
-
const currentlyEditingThisTextSchema = (target: EventTarget | null) => {
|
199
|
-
if (!target) return false;
|
200
|
-
if (target instanceof HTMLTextAreaElement) {
|
201
|
-
return activeElements.map((ae) => ae.id).includes(target.parentElement?.id || '');
|
202
|
-
}
|
203
|
-
return false;
|
204
|
-
};
|
205
|
-
|
206
199
|
const onResize = ({ target, width, height, direction }: OnResize) => {
|
207
200
|
if (!target) return;
|
208
201
|
const s = target.style;
|
@@ -239,20 +232,7 @@ const Main = (props: Props, ref: Ref<HTMLDivElement>) => {
|
|
239
232
|
};
|
240
233
|
|
241
234
|
return (
|
242
|
-
<div
|
243
|
-
ref={ref}
|
244
|
-
onClick={(e) => {
|
245
|
-
e.stopPropagation();
|
246
|
-
if (!currentlyEditingThisTextSchema(e.target)) {
|
247
|
-
setEditing(false);
|
248
|
-
}
|
249
|
-
// For MacOS CMD+SHIFT+3/4 screenshots where the keydown event is never received, check mouse too
|
250
|
-
if (!e.shiftKey) {
|
251
|
-
setIsPressShiftKey(false);
|
252
|
-
}
|
253
|
-
}}
|
254
|
-
style={{ overflow: 'overlay' }}
|
255
|
-
>
|
235
|
+
<div ref={ref} style={{ overflow: 'overlay' }}>
|
256
236
|
<Selecto
|
257
237
|
container={paperRefs.current[pageCursor]}
|
258
238
|
continueSelect={isPressShiftKey}
|
@@ -266,8 +246,7 @@ const Main = (props: Props, ref: Ref<HTMLDivElement>) => {
|
|
266
246
|
if (paperRefs.current[pageCursor] === inputEvent.target) {
|
267
247
|
onEdit([]);
|
268
248
|
}
|
269
|
-
|
270
|
-
if (inputEvent.target.id === DELETE_BTN_ID) {
|
249
|
+
if (inputEvent.target?.id === DELETE_BTN_ID) {
|
271
250
|
removeSchemas(activeElements.map((ae) => ae.id));
|
272
251
|
}
|
273
252
|
}}
|
@@ -280,8 +259,15 @@ const Main = (props: Props, ref: Ref<HTMLDivElement>) => {
|
|
280
259
|
if (!isClick && removed.length > 0) {
|
281
260
|
newActiveElements = activeElements.filter((ae) => !removed.includes(ae));
|
282
261
|
}
|
283
|
-
|
284
262
|
onEdit(newActiveElements);
|
263
|
+
|
264
|
+
if (newActiveElements != activeElements) {
|
265
|
+
setEditing(false);
|
266
|
+
}
|
267
|
+
// For MacOS CMD+SHIFT+3/4 screenshots where the keydown event is never received, check mouse too
|
268
|
+
if (!inputEvent.shiftKey) {
|
269
|
+
setIsPressShiftKey(false);
|
270
|
+
}
|
285
271
|
}}
|
286
272
|
/>
|
287
273
|
<Paper
|
@@ -338,9 +324,10 @@ const Main = (props: Props, ref: Ref<HTMLDivElement>) => {
|
|
338
324
|
schema={schema}
|
339
325
|
onChangeHoveringSchemaId={onChangeHoveringSchemaId}
|
340
326
|
editable={editing && activeElements.map((ae) => ae.id).includes(schema.id)}
|
341
|
-
onChange={
|
327
|
+
onChange={(value) => {
|
342
328
|
changeSchemas([{ key: 'data', value, schemaId: schema.id }]);
|
343
329
|
}}
|
330
|
+
onStopEditing={() => setEditing(false)}
|
344
331
|
outline={hoveringSchemaId === schema.id ? '1px solid #18a0fb' : '1px dashed #4af'}
|
345
332
|
ref={inputRef}
|
346
333
|
/>
|
@@ -6,6 +6,9 @@ import {
|
|
6
6
|
DEFAULT_LINE_HEIGHT,
|
7
7
|
DEFAULT_CHARACTER_SPACING,
|
8
8
|
DEFAULT_FONT_COLOR,
|
9
|
+
DYNAMIC_FIT_VERTICAL,
|
10
|
+
DYNAMIC_FIT_HORIZONTAL,
|
11
|
+
DEFAULT_DYNAMIC_FIT,
|
9
12
|
} from '@pdfme/common';
|
10
13
|
import { FontContext } from '../../../../contexts';
|
11
14
|
import { SidebarProps } from '..';
|
@@ -24,11 +27,14 @@ const NumberInputSet = (props: {
|
|
24
27
|
width: string;
|
25
28
|
label: string;
|
26
29
|
value: number;
|
30
|
+
step?: number;
|
27
31
|
minNumber?: number;
|
28
32
|
maxNumber?: number;
|
33
|
+
disabled?: boolean;
|
34
|
+
style?: object;
|
29
35
|
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
30
36
|
}) => {
|
31
|
-
const { label, value, width, minNumber, maxNumber, onChange } = props;
|
37
|
+
const { label, step, value, width, minNumber, maxNumber, disabled, style, onChange } = props;
|
32
38
|
const formattedLabel = label.replace(/\s/g, '');
|
33
39
|
|
34
40
|
return (
|
@@ -37,10 +43,12 @@ const NumberInputSet = (props: {
|
|
37
43
|
<input
|
38
44
|
id={`input-${formattedLabel}`}
|
39
45
|
name={`input-${formattedLabel}`}
|
40
|
-
style={inputStyle}
|
46
|
+
style={{ ...inputStyle, ...style }}
|
41
47
|
onChange={onChange}
|
42
|
-
value={value}
|
48
|
+
value={isNaN(value) ? '' : value}
|
43
49
|
type="number"
|
50
|
+
step={step ?? 1}
|
51
|
+
disabled={disabled}
|
44
52
|
{...(minNumber && { min: minNumber })}
|
45
53
|
{...(maxNumber && { max: maxNumber })}
|
46
54
|
/>
|
@@ -92,13 +100,14 @@ const SelectSet = (props: {
|
|
92
100
|
label: string;
|
93
101
|
value: string;
|
94
102
|
options: string[];
|
103
|
+
width?: string;
|
95
104
|
onChange: (e: React.ChangeEvent<HTMLSelectElement>) => void;
|
96
105
|
}) => {
|
97
|
-
const { label, value, options, onChange } = props;
|
106
|
+
const { label, value, options, width, onChange } = props;
|
98
107
|
const formattedLabel = label.replace(/\s/g, '');
|
99
108
|
|
100
109
|
return (
|
101
|
-
<div style={{ width: '45%' }}>
|
110
|
+
<div style={{ width: width ?? '45%' }}>
|
102
111
|
<label htmlFor={`select-${formattedLabel}`}>{label}:</label>
|
103
112
|
<select
|
104
113
|
id={`select-${formattedLabel}`}
|
@@ -145,6 +154,7 @@ const TextPropEditor = (
|
|
145
154
|
) => {
|
146
155
|
const { changeSchemas, activeSchema } = props;
|
147
156
|
const alignments = ['left', 'center', 'right'];
|
157
|
+
const dynamicFits = [DYNAMIC_FIT_HORIZONTAL, DYNAMIC_FIT_VERTICAL];
|
148
158
|
const font = useContext(FontContext);
|
149
159
|
const fallbackFontName = getFallbackFontName(font);
|
150
160
|
|
@@ -189,26 +199,17 @@ const TextPropEditor = (
|
|
189
199
|
<NumberInputSet
|
190
200
|
width="30%"
|
191
201
|
label={'FontSize(pt)'}
|
192
|
-
value={activeSchema.fontSize ?? DEFAULT_FONT_SIZE}
|
202
|
+
value={activeSchema.dynamicFontSize ? NaN : (activeSchema.fontSize ?? DEFAULT_FONT_SIZE)}
|
203
|
+
style={activeSchema.dynamicFontSize ? { background: '#ccc', cursor: 'not-allowed' } : {}}
|
204
|
+
disabled={!!activeSchema.dynamicFontSize}
|
193
205
|
onChange={(e) => {
|
194
|
-
|
195
|
-
const dynamincFontSizeMinAdjust = activeSchema.dynamicFontSize && activeSchema.dynamicFontSize.min > currentFontSize;
|
196
|
-
|
197
|
-
changeSchemas([
|
198
|
-
{ key: 'fontSize', value: currentFontSize, schemaId: activeSchema.id },
|
199
|
-
...(dynamincFontSizeMinAdjust
|
200
|
-
? [{
|
201
|
-
key: 'dynamicFontSize.min',
|
202
|
-
value: currentFontSize,
|
203
|
-
schemaId: activeSchema.id,
|
204
|
-
}]
|
205
|
-
: []),
|
206
|
-
]);
|
206
|
+
changeSchemas([{ key: 'fontSize', value: Number(e.target.value), schemaId: activeSchema.id }])
|
207
207
|
}}
|
208
208
|
/>
|
209
209
|
<NumberInputSet
|
210
210
|
width="30%"
|
211
211
|
label={'LineHeight(em)'}
|
212
|
+
step={0.1}
|
212
213
|
value={activeSchema.lineHeight ?? DEFAULT_LINE_HEIGHT}
|
213
214
|
onChange={(e) =>
|
214
215
|
changeSchemas([
|
@@ -220,6 +221,7 @@ const TextPropEditor = (
|
|
220
221
|
<NumberInputSet
|
221
222
|
width="40%"
|
222
223
|
label={'CharacterSpacing(pt)'}
|
224
|
+
step={0.1}
|
223
225
|
value={activeSchema.characterSpacing ?? DEFAULT_CHARACTER_SPACING}
|
224
226
|
onChange={async (e) => {
|
225
227
|
const currentCharacterSpacing = Number(e.target.value);
|
@@ -257,26 +259,46 @@ const TextPropEditor = (
|
|
257
259
|
{activeSchema.dynamicFontSize && (
|
258
260
|
<>
|
259
261
|
<NumberInputSet
|
260
|
-
width="
|
262
|
+
width="30%"
|
261
263
|
label={'FontSize Min(pt)'}
|
262
264
|
value={activeSchema.dynamicFontSize.min ?? Number(activeSchema.fontSize)}
|
263
265
|
minNumber={0}
|
264
|
-
|
266
|
+
style={
|
267
|
+
activeSchema.dynamicFontSize &&
|
268
|
+
activeSchema.dynamicFontSize.max < activeSchema.dynamicFontSize.min
|
269
|
+
? { background: 'rgb(200 0 0 / 30%)' }
|
270
|
+
: {}
|
271
|
+
}
|
265
272
|
onChange={(e) => {
|
266
273
|
changeSchemas([{ key: 'dynamicFontSize.min', value: Number(e.target.value), schemaId: activeSchema.id }])
|
267
|
-
|
268
274
|
}}
|
269
275
|
/>
|
270
276
|
|
271
277
|
<NumberInputSet
|
272
|
-
width="
|
278
|
+
width="30%"
|
273
279
|
label={'FontSize Max(pt)'}
|
274
280
|
value={activeSchema.dynamicFontSize.max ?? Number(activeSchema.fontSize)}
|
275
|
-
minNumber={
|
281
|
+
minNumber={0}
|
282
|
+
style={
|
283
|
+
activeSchema.dynamicFontSize &&
|
284
|
+
activeSchema.dynamicFontSize.max < activeSchema.dynamicFontSize.min
|
285
|
+
? { background: 'rgb(200 0 0 / 30%)' }
|
286
|
+
: {}
|
287
|
+
}
|
276
288
|
onChange={(e) => {
|
277
289
|
changeSchemas([{ key: 'dynamicFontSize.max', value: Number(e.target.value), schemaId: activeSchema.id }])
|
278
290
|
}}
|
279
291
|
/>
|
292
|
+
|
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
|
+
/>
|
280
302
|
</>
|
281
303
|
)}
|
282
304
|
</div>
|
package/src/components/Paper.tsx
CHANGED
@@ -3,7 +3,7 @@ import { SchemaForUI, Size, getFallbackFontName } from '@pdfme/common';
|
|
3
3
|
import { FontContext } from '../contexts';
|
4
4
|
import { ZOOM, RULER_HEIGHT } from '../constants';
|
5
5
|
|
6
|
-
const Paper = (
|
6
|
+
const Paper = (props: {
|
7
7
|
paperRefs: MutableRefObject<HTMLDivElement[]>;
|
8
8
|
scale: number;
|
9
9
|
size: Size;
|
@@ -14,7 +14,7 @@ const Paper = (porps: {
|
|
14
14
|
renderSchema: (arg: { index: number; schema: SchemaForUI }) => ReactNode;
|
15
15
|
}) => {
|
16
16
|
const { paperRefs, scale, size, schemasList, pageSizes, backgrounds, renderPaper, renderSchema } =
|
17
|
-
|
17
|
+
props;
|
18
18
|
const font = useContext(FontContext);
|
19
19
|
|
20
20
|
if (pageSizes.length !== backgrounds.length || pageSizes.length !== schemasList.length) {
|
@@ -100,8 +100,9 @@ const Preview = ({ template, inputs, size, onChangeInput }: PreviewReactProps) =
|
|
100
100
|
key={schema.id}
|
101
101
|
schema={Object.assign(schema, { data })}
|
102
102
|
editable={editable}
|
103
|
-
placeholder={template.sampledata
|
103
|
+
placeholder={template.sampledata?.[0]?.[key] ?? ''}
|
104
104
|
tabIndex={index + 100}
|
105
|
+
onStopEditing={() => { }}
|
105
106
|
onChange={(value) => handleChangeInput({ key, value })}
|
106
107
|
outline={editable ? '1px dashed #4af' : 'transparent'}
|
107
108
|
/>
|
@@ -69,7 +69,7 @@ const BarcodePreview = (props: { schema: BarcodeSchema; value: string }) => {
|
|
69
69
|
type Props = SchemaUIProps & { schema: BarcodeSchema };
|
70
70
|
|
71
71
|
const BarcodeSchemaUI = (
|
72
|
-
{ schema, editable, placeholder, tabIndex, onChange }: Props,
|
72
|
+
{ schema, editable, placeholder, tabIndex, onChange, onStopEditing }: Props,
|
73
73
|
ref: Ref<HTMLInputElement>
|
74
74
|
) => {
|
75
75
|
const value = schema.data;
|
@@ -109,6 +109,7 @@ const BarcodeSchemaUI = (
|
|
109
109
|
style={style}
|
110
110
|
value={value}
|
111
111
|
onChange={(e) => onChange(e.target.value)}
|
112
|
+
onBlur={onStopEditing}
|
112
113
|
/>
|
113
114
|
) : (
|
114
115
|
<div style={style}>
|
@@ -8,7 +8,7 @@ import { XMarkIcon } from '@heroicons/react/24/outline';
|
|
8
8
|
type Props = SchemaUIProps & { schema: ImageSchema };
|
9
9
|
|
10
10
|
const ImageSchemaUI = (props: Props, ref: Ref<HTMLInputElement>) => {
|
11
|
-
const { editable, placeholder, tabIndex, schema, onChange } = props;
|
11
|
+
const { editable, placeholder, tabIndex, schema, onChange, onStopEditing } = props;
|
12
12
|
const [fileName, setFileName] = useState<string>('');
|
13
13
|
const hasData = Boolean(schema.data);
|
14
14
|
|
@@ -75,6 +75,7 @@ const ImageSchemaUI = (props: Props, ref: Ref<HTMLInputElement>) => {
|
|
75
75
|
onChange={(event: ChangeEvent<HTMLInputElement>) =>
|
76
76
|
readFiles(event.target.files, 'dataURL').then((result) => onChange(result as string))
|
77
77
|
}
|
78
|
+
onBlur={onStopEditing}
|
78
79
|
type="file"
|
79
80
|
accept="image/jpeg, image/png"
|
80
81
|
/>
|
@@ -17,7 +17,7 @@ import { FontContext } from '../../contexts';
|
|
17
17
|
type Props = SchemaUIProps & { schema: TextSchema };
|
18
18
|
|
19
19
|
const TextSchemaUI = (
|
20
|
-
{ schema, editable, placeholder, tabIndex, onChange }: Props,
|
20
|
+
{ schema, editable, placeholder, tabIndex, onChange, onStopEditing }: Props,
|
21
21
|
ref: Ref<HTMLTextAreaElement>
|
22
22
|
) => {
|
23
23
|
const font = useContext(FontContext);
|
@@ -27,15 +27,45 @@ const TextSchemaUI = (
|
|
27
27
|
|
28
28
|
useEffect(() => {
|
29
29
|
if (schema.dynamicFontSize && schema.data) {
|
30
|
-
calculateDynamicFontSize({
|
30
|
+
calculateDynamicFontSize({
|
31
|
+
textSchema: schema,
|
32
|
+
font,
|
33
|
+
input: schema.data,
|
34
|
+
startingFontSize: dynamicFontSize,
|
35
|
+
}).then(setDynamicFontSize);
|
31
36
|
} else {
|
32
37
|
setDynamicFontSize(undefined);
|
33
38
|
}
|
39
|
+
}, [
|
40
|
+
schema.data,
|
41
|
+
schema.width,
|
42
|
+
schema.height,
|
43
|
+
schema.dynamicFontSize?.min,
|
44
|
+
schema.dynamicFontSize?.max,
|
45
|
+
schema.dynamicFontSize?.fit,
|
46
|
+
schema.characterSpacing,
|
47
|
+
schema.lineHeight,
|
48
|
+
font
|
49
|
+
]);
|
50
|
+
|
51
|
+
useEffect(() => {
|
34
52
|
getFontKitFont(schema, font).then(fontKitFont => {
|
35
53
|
const fav = getFontAlignmentValue(fontKitFont, dynamicFontSize ?? schema.fontSize ?? DEFAULT_FONT_SIZE);
|
36
54
|
setFontAlignmentValue(fav);
|
37
55
|
});
|
38
|
-
}, [
|
56
|
+
}, [
|
57
|
+
schema.width,
|
58
|
+
schema.height,
|
59
|
+
schema.fontName,
|
60
|
+
schema.fontSize,
|
61
|
+
schema.dynamicFontSize?.max,
|
62
|
+
schema.dynamicFontSize?.min,
|
63
|
+
schema.dynamicFontSize?.fit,
|
64
|
+
schema.characterSpacing,
|
65
|
+
schema.lineHeight,
|
66
|
+
font,
|
67
|
+
dynamicFontSize
|
68
|
+
]);
|
39
69
|
|
40
70
|
|
41
71
|
const style: React.CSSProperties = {
|
@@ -53,7 +83,7 @@ const TextSchemaUI = (
|
|
53
83
|
letterSpacing: `${schema.characterSpacing ?? DEFAULT_CHARACTER_SPACING}pt`,
|
54
84
|
lineHeight: `${schema.lineHeight ?? DEFAULT_LINE_HEIGHT}em`,
|
55
85
|
textAlign: schema.alignment ?? DEFAULT_ALIGNMENT,
|
56
|
-
whiteSpace: 'pre-
|
86
|
+
whiteSpace: 'pre-wrap',
|
57
87
|
wordBreak: 'break-word',
|
58
88
|
backgroundColor:
|
59
89
|
schema.data && schema.backgroundColor ? schema.backgroundColor : 'rgb(242 244 255 / 75%)',
|
@@ -67,6 +97,7 @@ const TextSchemaUI = (
|
|
67
97
|
tabIndex={tabIndex}
|
68
98
|
style={style}
|
69
99
|
onChange={(e) => onChange(e.target.value)}
|
100
|
+
onBlur={onStopEditing}
|
70
101
|
value={schema.data}
|
71
102
|
></textarea>
|
72
103
|
) : (
|
package/src/helper.ts
CHANGED
@@ -314,7 +314,7 @@ const sortSchemasList = (template: Template, pageNum: number): SchemaForUI[][] =
|
|
314
314
|
})
|
315
315
|
.map((e) => {
|
316
316
|
const [key, value] = e;
|
317
|
-
const data = template.sampledata
|
317
|
+
const data = template.sampledata?.[0]?.[key] ?? '';
|
318
318
|
|
319
319
|
return Object.assign(value, {
|
320
320
|
key,
|