@servicetitan/dte-pdf-editor 1.2.0 → 1.3.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/components/field-config-panel.d.ts.map +1 -1
- package/dist/components/field-config-panel.js +4 -2
- package/dist/components/field-config-panel.js.map +1 -1
- package/dist/components/fillable-field-type-list.d.ts.map +1 -1
- package/dist/components/fillable-field-type-list.js +4 -1
- package/dist/components/fillable-field-type-list.js.map +1 -1
- package/dist/components/pdf-editor.d.ts.map +1 -1
- package/dist/components/pdf-editor.js +9 -3
- package/dist/components/pdf-editor.js.map +1 -1
- package/dist/components/pdf-field-overlay.d.ts +10 -0
- package/dist/components/pdf-field-overlay.d.ts.map +1 -1
- package/dist/components/pdf-field-overlay.js +46 -18
- package/dist/components/pdf-field-overlay.js.map +1 -1
- package/dist/components/pdf-view-fields.d.ts +17 -0
- package/dist/components/pdf-view-fields.d.ts.map +1 -0
- package/dist/components/pdf-view-fields.js +53 -0
- package/dist/components/pdf-view-fields.js.map +1 -0
- package/dist/components/pdf-view.d.ts +19 -0
- package/dist/components/pdf-view.d.ts.map +1 -0
- package/dist/components/pdf-view.js +32 -0
- package/dist/components/pdf-view.js.map +1 -0
- package/dist/components/resize-handle.d.ts +7 -0
- package/dist/components/resize-handle.d.ts.map +1 -0
- package/dist/components/resize-handle.js +5 -0
- package/dist/components/resize-handle.js.map +1 -0
- package/dist/constants/field.constants.d.ts +7 -3
- package/dist/constants/field.constants.d.ts.map +1 -1
- package/dist/constants/field.constants.js +10 -3
- package/dist/constants/field.constants.js.map +1 -1
- package/dist/hooks/useFieldResize.d.ts +1 -1
- package/dist/hooks/useFieldResize.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/interface/pdf-editor.d.ts +1 -1
- package/dist/interface/pdf-editor.d.ts.map +1 -1
- package/dist/utils/generate-fillable-path.d.ts +2 -0
- package/dist/utils/generate-fillable-path.d.ts.map +1 -0
- package/dist/utils/generate-fillable-path.js +4 -0
- package/dist/utils/generate-fillable-path.js.map +1 -0
- package/dist/utils/get-field-background-color.d.ts +2 -0
- package/dist/utils/get-field-background-color.d.ts.map +1 -0
- package/dist/utils/get-field-background-color.js +4 -0
- package/dist/utils/get-field-background-color.js.map +1 -0
- package/dist/utils/get-field-placeholder-text.d.ts +3 -0
- package/dist/utils/get-field-placeholder-text.d.ts.map +1 -0
- package/dist/utils/get-field-placeholder-text.js +7 -0
- package/dist/utils/get-field-placeholder-text.js.map +1 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +5 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/parse-fillable-path.d.ts +2 -0
- package/dist/utils/parse-fillable-path.d.ts.map +1 -0
- package/dist/utils/parse-fillable-path.js +9 -0
- package/dist/utils/parse-fillable-path.js.map +1 -0
- package/dist/utils/resolve-pdf-data-values.d.ts +2 -0
- package/dist/utils/resolve-pdf-data-values.d.ts.map +1 -0
- package/dist/utils/resolve-pdf-data-values.js +27 -0
- package/dist/utils/resolve-pdf-data-values.js.map +1 -0
- package/package.json +1 -1
- package/src/components/field-config-panel.tsx +13 -1
- package/src/components/fillable-field-type-list.tsx +6 -1
- package/src/components/pdf-editor.tsx +8 -1
- package/src/components/pdf-field-overlay.tsx +147 -48
- package/src/components/pdf-view-fields.tsx +138 -0
- package/src/components/pdf-view.tsx +99 -0
- package/src/components/resize-handle.tsx +8 -0
- package/src/constants/field.constants.ts +16 -3
- package/src/hooks/useFieldResize.ts +1 -1
- package/src/index.ts +1 -0
- package/src/interface/pdf-editor.ts +1 -1
- package/src/styles/pdf-field-overlay.css +34 -9
- package/src/utils/generate-fillable-path.ts +3 -0
- package/src/utils/get-field-background-color.ts +6 -0
- package/src/utils/get-field-placeholder-text.ts +8 -0
- package/src/utils/index.ts +5 -0
- package/src/utils/parse-fillable-path.ts +8 -0
- package/src/utils/resolve-pdf-data-values.ts +34 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { Flex } from '@servicetitan/anvil2';
|
|
2
|
+
import { FC, ReactNode, useRef, useState } from 'react';
|
|
3
|
+
import { BASE_PAGE_WIDTH } from '../constants';
|
|
4
|
+
import { FieldTypeEnum, PdfField } from '../interface/pdf-editor';
|
|
5
|
+
import { getFieldBackgroundColor, getPagePosition, mapColorsToRecipients } from '../utils';
|
|
6
|
+
import { PdfDocumentRenderer } from './pdf-document-renderer';
|
|
7
|
+
import { RecipientInfo } from './pdf-editor';
|
|
8
|
+
import { FillableFieldView, ViewDataModel, ViewEsign } from './pdf-view-fields';
|
|
9
|
+
|
|
10
|
+
interface PdfViewProps {
|
|
11
|
+
fields: PdfField[];
|
|
12
|
+
data?: Record<string, any>;
|
|
13
|
+
pdfUrl: string;
|
|
14
|
+
loading?: boolean;
|
|
15
|
+
fillingBy?: string[];
|
|
16
|
+
loadingPlaceholder?: ReactNode;
|
|
17
|
+
errorPlaceholder?: ReactNode;
|
|
18
|
+
recipients?: RecipientInfo[];
|
|
19
|
+
onDataChange?(changedData: { [path: string]: string | boolean }): void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const PdfView: FC<PdfViewProps> = ({
|
|
23
|
+
data,
|
|
24
|
+
errorPlaceholder,
|
|
25
|
+
fields,
|
|
26
|
+
fillingBy,
|
|
27
|
+
loading = false,
|
|
28
|
+
loadingPlaceholder,
|
|
29
|
+
onDataChange,
|
|
30
|
+
pdfUrl,
|
|
31
|
+
recipients,
|
|
32
|
+
}) => {
|
|
33
|
+
const [isPdfLoaded, setIsPdfLoaded] = useState<boolean>(false);
|
|
34
|
+
const pdfWrapperRef = useRef<HTMLDivElement>(null);
|
|
35
|
+
|
|
36
|
+
const onDocumentLoadSuccess = (_: number) => {
|
|
37
|
+
setIsPdfLoaded(true);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const recipientsColors = mapColorsToRecipients(recipients);
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<Flex flex={1} className="dte-pdf-view-container" style={{ maxWidth: BASE_PAGE_WIDTH }}>
|
|
44
|
+
<div ref={pdfWrapperRef} className="dte-pdf-wrapper">
|
|
45
|
+
<PdfDocumentRenderer
|
|
46
|
+
pdfUrl={pdfUrl}
|
|
47
|
+
loading={loading}
|
|
48
|
+
pageWidth={BASE_PAGE_WIDTH}
|
|
49
|
+
errorPlaceholder={errorPlaceholder}
|
|
50
|
+
loadingPlaceholder={loadingPlaceholder}
|
|
51
|
+
onDocumentLoadSuccess={onDocumentLoadSuccess}
|
|
52
|
+
/>
|
|
53
|
+
{isPdfLoaded && fields && fields.length > 0 && (
|
|
54
|
+
<div className="dte-pdf-field-overlay --view-mode">
|
|
55
|
+
{fields.map(field => {
|
|
56
|
+
const pagePos = getPagePosition(field.page, pdfWrapperRef);
|
|
57
|
+
const bgColor = getFieldBackgroundColor(
|
|
58
|
+
field.recipient,
|
|
59
|
+
recipientsColors,
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<div
|
|
64
|
+
key={field.id}
|
|
65
|
+
style={{
|
|
66
|
+
display: 'flex',
|
|
67
|
+
alignItems: 'center',
|
|
68
|
+
position: 'absolute',
|
|
69
|
+
padding: '4px',
|
|
70
|
+
background: bgColor,
|
|
71
|
+
left: `${pagePos.left + field.x}px`,
|
|
72
|
+
top: `${pagePos.top + field.y}px`,
|
|
73
|
+
width: `${field.width}px`,
|
|
74
|
+
height: `${field.height}px`,
|
|
75
|
+
}}
|
|
76
|
+
>
|
|
77
|
+
{field.type === FieldTypeEnum.dataModel && (
|
|
78
|
+
<ViewDataModel field={field} data={data} />
|
|
79
|
+
)}
|
|
80
|
+
{field.type === FieldTypeEnum.eSign && (
|
|
81
|
+
<ViewEsign field={field} data={data} />
|
|
82
|
+
)}
|
|
83
|
+
{field.type === FieldTypeEnum.fillable && (
|
|
84
|
+
<FillableFieldView
|
|
85
|
+
data={data}
|
|
86
|
+
field={field}
|
|
87
|
+
fillingBy={fillingBy}
|
|
88
|
+
onDataChange={onDataChange}
|
|
89
|
+
/>
|
|
90
|
+
)}
|
|
91
|
+
</div>
|
|
92
|
+
);
|
|
93
|
+
})}
|
|
94
|
+
</div>
|
|
95
|
+
)}
|
|
96
|
+
</div>
|
|
97
|
+
</Flex>
|
|
98
|
+
);
|
|
99
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { FC, MouseEvent } from 'react';
|
|
2
|
+
|
|
3
|
+
interface ResizeHandleProps {
|
|
4
|
+
handleResizeStart(e: MouseEvent<HTMLDivElement>): void;
|
|
5
|
+
}
|
|
6
|
+
export const ResizeHandle: FC<ResizeHandleProps> = ({ handleResizeStart }) => {
|
|
7
|
+
return <div className="dte-pdf-field-resize-handle" onMouseDown={handleResizeStart} />;
|
|
8
|
+
};
|
|
@@ -1,14 +1,26 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
ESignFieldType,
|
|
3
|
+
FieldTypeEnum,
|
|
4
|
+
FieldTypeOption,
|
|
5
|
+
FillableFieldType,
|
|
6
|
+
} from '../interface/pdf-editor';
|
|
2
7
|
|
|
3
8
|
export const FIELD_CONSTANTS = {
|
|
4
9
|
defaultWidth: 200,
|
|
5
|
-
defaultHeight:
|
|
6
|
-
minWidth:
|
|
10
|
+
defaultHeight: 25,
|
|
11
|
+
minWidth: 20,
|
|
7
12
|
minHeight: 20,
|
|
8
13
|
dropOffsetX: 75,
|
|
9
14
|
dropOffsetY: 15,
|
|
10
15
|
} as const;
|
|
11
16
|
|
|
17
|
+
export const FILLABLE_FIELD_DEFAULT_SIZES = {
|
|
18
|
+
text: { width: 200, height: 25 },
|
|
19
|
+
date: { width: 200, height: 25 },
|
|
20
|
+
radio: { width: 20, height: 20 },
|
|
21
|
+
checkbox: { width: 20, height: 20 },
|
|
22
|
+
} as Record<FillableFieldType | ESignFieldType, { width: number; height: number }>;
|
|
23
|
+
|
|
12
24
|
export const E_SIGN_FIELD_TYPE_OPTIONS: { name: string; id: ESignFieldType }[] = [
|
|
13
25
|
{ name: 'Signature', id: ESignFieldType.signature },
|
|
14
26
|
{ name: 'Initials', id: ESignFieldType.initials },
|
|
@@ -20,6 +32,7 @@ export const FILLABLE_FIELD_TYPES: FieldTypeOption[] = [
|
|
|
20
32
|
{ label: 'Text Field', type: FieldTypeEnum.fillable, subType: 'text' },
|
|
21
33
|
{ label: 'Date Field', type: FieldTypeEnum.fillable, subType: 'date' },
|
|
22
34
|
{ label: 'Checkbox', type: FieldTypeEnum.fillable, subType: 'checkbox' },
|
|
35
|
+
{ label: 'Radio', type: FieldTypeEnum.fillable, subType: 'radio' },
|
|
23
36
|
];
|
|
24
37
|
|
|
25
38
|
export const E_SIGN_FIELD_TYPES: FieldTypeOption[] = [
|
package/src/index.ts
CHANGED
|
@@ -7,15 +7,18 @@
|
|
|
7
7
|
pointer-events: none;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
.dte-pdf-field-overlay.--view-mode {
|
|
11
|
+
pointer-events: auto;
|
|
12
|
+
}
|
|
13
|
+
|
|
10
14
|
.dte-pdf-field {
|
|
11
15
|
position: absolute;
|
|
12
16
|
border: 1px dashed #999;
|
|
13
17
|
display: flex;
|
|
14
18
|
align-items: center;
|
|
15
|
-
justify-content: center;
|
|
16
19
|
font-size: var(--typescale-1, 14px);
|
|
17
20
|
padding: var(--spacing-half, 4px);
|
|
18
|
-
box-sizing:
|
|
21
|
+
box-sizing: content-box;
|
|
19
22
|
pointer-events: auto;
|
|
20
23
|
}
|
|
21
24
|
|
|
@@ -32,23 +35,45 @@
|
|
|
32
35
|
opacity: 0.5;
|
|
33
36
|
}
|
|
34
37
|
|
|
35
|
-
.dte-pdf-field-path {
|
|
36
|
-
margin-top: 2px;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
38
|
.dte-pdf-field-resize-handle {
|
|
40
39
|
position: absolute;
|
|
41
40
|
bottom: 0;
|
|
42
41
|
right: 0;
|
|
43
42
|
width: 12px;
|
|
44
43
|
height: 12px;
|
|
45
|
-
|
|
46
|
-
border: 1px solid var(--border-color-active);
|
|
44
|
+
border: 2px dashed var(--border-color-active);
|
|
47
45
|
cursor: nwse-resize;
|
|
48
46
|
z-index: 10;
|
|
49
47
|
box-sizing: border-box;
|
|
50
48
|
}
|
|
51
49
|
|
|
52
50
|
.dte-pdf-field-resize-handle:hover {
|
|
53
|
-
|
|
51
|
+
border-color: var(--border-color-active);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.dte-pdf-field-view {
|
|
55
|
+
border: none;
|
|
56
|
+
cursor: default;
|
|
57
|
+
overflow: hidden;
|
|
58
|
+
white-space: nowrap;
|
|
59
|
+
pointer-events: none;
|
|
60
|
+
justify-content: left;
|
|
61
|
+
text-overflow: ellipsis;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.dte-pdf-field-value {
|
|
65
|
+
font-weight: normal;
|
|
66
|
+
color: #333;
|
|
67
|
+
white-space: normal;
|
|
68
|
+
overflow: hidden;
|
|
69
|
+
text-overflow: ellipsis;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.dte-pdf-field-fillable {
|
|
73
|
+
width: 100%;
|
|
74
|
+
height: 100%;
|
|
75
|
+
background: inherit;
|
|
76
|
+
border: none;
|
|
77
|
+
pointer-events: none;
|
|
78
|
+
margin: var(--spacing-0, 0);
|
|
54
79
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { PdfField } from '../interface/pdf-editor';
|
|
2
|
+
|
|
3
|
+
export const getFieldPlaceholderText = (field: PdfField, prefix?: string): string => {
|
|
4
|
+
const requiredIndicator = field.required ? '*' : '';
|
|
5
|
+
const label = field.label || '';
|
|
6
|
+
const parts = [prefix, label, requiredIndicator].filter(Boolean);
|
|
7
|
+
return parts.join(' ');
|
|
8
|
+
};
|
package/src/utils/index.ts
CHANGED
|
@@ -10,3 +10,8 @@ export * from './is-drag-over-canvas.utils';
|
|
|
10
10
|
export * from './map-colors-to-recipients';
|
|
11
11
|
export * from './pdfjs-init';
|
|
12
12
|
export * from './generate-e-sign-path';
|
|
13
|
+
export * from './resolve-pdf-data-values';
|
|
14
|
+
export * from './generate-fillable-path';
|
|
15
|
+
export * from './get-field-background-color';
|
|
16
|
+
export * from './get-field-placeholder-text';
|
|
17
|
+
export * from './parse-fillable-path';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export const resolvePdfDataValues = (
|
|
2
|
+
data: Record<string, any> | undefined,
|
|
3
|
+
path: string | undefined,
|
|
4
|
+
): string => {
|
|
5
|
+
if (!data || !path) {
|
|
6
|
+
return '';
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const keys = path.split('.');
|
|
10
|
+
let value: any = data;
|
|
11
|
+
|
|
12
|
+
for (const key of keys) {
|
|
13
|
+
if (value === null || value === undefined || typeof value !== 'object') {
|
|
14
|
+
return '';
|
|
15
|
+
}
|
|
16
|
+
value = value[key];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (value === null || value === undefined) {
|
|
20
|
+
return '';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (typeof value === 'object') {
|
|
24
|
+
if ('Amount' in value && 'Currency' in value) {
|
|
25
|
+
return `${value.Currency} ${value.Amount}`;
|
|
26
|
+
}
|
|
27
|
+
if ('Value' in value) {
|
|
28
|
+
return String(value.Value);
|
|
29
|
+
}
|
|
30
|
+
return JSON.stringify(value);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return String(value);
|
|
34
|
+
};
|