@docuseal/angular 1.0.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/.eslintrc.json +41 -0
- package/LICENSE +20 -0
- package/README.md +76 -0
- package/angular.json +30 -0
- package/ng-package.json +7 -0
- package/package.json +51 -0
- package/src/builder.component.ts +225 -0
- package/src/form.component.ts +240 -0
- package/src/public-api.ts +2 -0
- package/tsconfig.json +33 -0
package/.eslintrc.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"root": true,
|
|
3
|
+
"ignorePatterns": ["projects/**/*"],
|
|
4
|
+
"overrides": [
|
|
5
|
+
{
|
|
6
|
+
"files": ["*.ts"],
|
|
7
|
+
"extends": [
|
|
8
|
+
"eslint:recommended",
|
|
9
|
+
"plugin:@typescript-eslint/recommended",
|
|
10
|
+
"plugin:@angular-eslint/recommended",
|
|
11
|
+
"plugin:@angular-eslint/template/process-inline-templates"
|
|
12
|
+
],
|
|
13
|
+
"rules": {
|
|
14
|
+
"@angular-eslint/directive-selector": [
|
|
15
|
+
"error",
|
|
16
|
+
{
|
|
17
|
+
"type": "attribute",
|
|
18
|
+
"prefix": "docuseal",
|
|
19
|
+
"style": "camelCase"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"@angular-eslint/component-selector": [
|
|
23
|
+
"error",
|
|
24
|
+
{
|
|
25
|
+
"type": "element",
|
|
26
|
+
"prefix": "docuseal",
|
|
27
|
+
"style": "kebab-case"
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"files": ["*.html"],
|
|
34
|
+
"extends": [
|
|
35
|
+
"plugin:@angular-eslint/template/recommended",
|
|
36
|
+
"plugin:@angular-eslint/template/accessibility"
|
|
37
|
+
],
|
|
38
|
+
"rules": {}
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
}
|
package/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2023 Oleksandr Turchyn
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# DocuSeal Angular Components
|
|
2
|
+
|
|
3
|
+
This package provides a convenient way to embed [DocuSeal](https://www.docuseal.co) into Angular apps. Sign documents and create document forms directly in your apps.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @docuseal/angular
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Documentation
|
|
14
|
+
|
|
15
|
+
For detailed documentation, please click [here](https://www.docuseal.co/docs/embedded).
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
### Signing Form
|
|
20
|
+
|
|
21
|
+
Copy public DocuSeal form URL from [https://docuseal.co](https://docuseal.co) and use it in the `src` component prop:
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { Component, } from '@angular/core';
|
|
25
|
+
import { DocusealFormComponent } from '@docuseal/angular';
|
|
26
|
+
|
|
27
|
+
@Component({
|
|
28
|
+
selector: 'app-root',
|
|
29
|
+
standalone: true,
|
|
30
|
+
imports: [DocusealFormComponent],
|
|
31
|
+
template: `
|
|
32
|
+
<div class="app">
|
|
33
|
+
<docuseal-form
|
|
34
|
+
src="https://docuseal.co/d/LEVGR9rhZYf86M"
|
|
35
|
+
email="signer@example.com">
|
|
36
|
+
</docuseal-form>
|
|
37
|
+
</div>
|
|
38
|
+
`
|
|
39
|
+
})
|
|
40
|
+
export class AppComponent {}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Form Builder
|
|
44
|
+
```typescript
|
|
45
|
+
import { Component, OnInit } from '@angular/core';
|
|
46
|
+
import { HttpClient } from '@angular/common/http';
|
|
47
|
+
import { DocusealBuilderComponent } from '@docuseal/angular';
|
|
48
|
+
|
|
49
|
+
@Component({
|
|
50
|
+
selector: 'app-root',
|
|
51
|
+
standalone: true,
|
|
52
|
+
imports: [DocusealBuilderComponent],
|
|
53
|
+
template: `
|
|
54
|
+
<div class="app">
|
|
55
|
+
<ng-container *ngIf="token">
|
|
56
|
+
<docuseal-builder [token]="token"></docuseal-builder>
|
|
57
|
+
</ng-container>
|
|
58
|
+
</div>
|
|
59
|
+
`
|
|
60
|
+
})
|
|
61
|
+
export class AppComponent implements OnInit {
|
|
62
|
+
token: string = ''
|
|
63
|
+
|
|
64
|
+
constructor(private http: HttpClient) {}
|
|
65
|
+
|
|
66
|
+
ngOnInit() {
|
|
67
|
+
this.http.post('/api/docuseal/builder_token', {}).subscribe((data: any) => {
|
|
68
|
+
this.token = data.token;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
# License
|
|
75
|
+
|
|
76
|
+
MIT
|
package/angular.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"projects": {
|
|
5
|
+
"@docuseal/angular": {
|
|
6
|
+
"root": "src",
|
|
7
|
+
"projectType": "library",
|
|
8
|
+
"prefix": "docuseal",
|
|
9
|
+
"architect": {
|
|
10
|
+
"build": {
|
|
11
|
+
"builder": "@angular-devkit/build-angular:ng-packagr",
|
|
12
|
+
"options": {
|
|
13
|
+
"tsConfig": "tsconfig.json",
|
|
14
|
+
"project": "ng-package.json"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"lint": {
|
|
18
|
+
"builder": "@angular-eslint/builder:lint",
|
|
19
|
+
"options": {
|
|
20
|
+
"lintFilePatterns": ["src/**/*.ts", "src/**/*.html"]
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"cli": {
|
|
27
|
+
"analytics": false,
|
|
28
|
+
"schematicCollections": ["@angular-eslint/schematics"]
|
|
29
|
+
}
|
|
30
|
+
}
|
package/ng-package.json
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@docuseal/angular",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "DocuSeal Angular components to integrate documents signing process into apps. ✍️",
|
|
5
|
+
"esm2022": "dist/esm2022/docuseal-angular.mjs",
|
|
6
|
+
"esm": "dist/esm2022/docuseal-angular.mjs",
|
|
7
|
+
"default": "dist/fesm2022/docuseal-angular.mjs",
|
|
8
|
+
"module": "dist/fesm2022/docuseal-angular.mjs",
|
|
9
|
+
"types": "dist/index.d.ts",
|
|
10
|
+
"author": "Oleksandr Turchyn <alex@docuseal.co>",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"homepage": "https://www.docuseal.co/docs/embedded",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/docusealco/docuseal-angular/issues"
|
|
15
|
+
},
|
|
16
|
+
"repository": "https://github.com/docusealco/docuseal-angular",
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@angular-devkit/build-angular": "^17.3.0",
|
|
19
|
+
"@angular-eslint/builder": "17.3.0",
|
|
20
|
+
"@angular-eslint/eslint-plugin": "17.3.0",
|
|
21
|
+
"@angular-eslint/eslint-plugin-template": "17.3.0",
|
|
22
|
+
"@angular-eslint/schematics": "17.3.0",
|
|
23
|
+
"@angular-eslint/template-parser": "17.3.0",
|
|
24
|
+
"@angular/core": "^17.3.0",
|
|
25
|
+
"@angular/cli": "^17.3.0",
|
|
26
|
+
"@angular/compiler": "^17.3.0",
|
|
27
|
+
"@angular/compiler-cli": "^17.3.0",
|
|
28
|
+
"@angular/platform-browser": "^17.3.0",
|
|
29
|
+
"@angular/platform-browser-dynamic": "^17.3.0",
|
|
30
|
+
"@types/jasmine": "~5.1.0",
|
|
31
|
+
"@typescript-eslint/eslint-plugin": "7.2.0",
|
|
32
|
+
"@typescript-eslint/parser": "7.2.0",
|
|
33
|
+
"eslint": "^8.57.0",
|
|
34
|
+
"jasmine-core": "~5.1.0",
|
|
35
|
+
"ng-packagr": "^17.3.0",
|
|
36
|
+
"prettier": "^3.2.5",
|
|
37
|
+
"typescript": "~5.4.2"
|
|
38
|
+
},
|
|
39
|
+
"keywords": [
|
|
40
|
+
"angular",
|
|
41
|
+
"angular-component",
|
|
42
|
+
"esignature",
|
|
43
|
+
"documents"
|
|
44
|
+
],
|
|
45
|
+
"scripts": {
|
|
46
|
+
"ng": "ng",
|
|
47
|
+
"build": "ng build",
|
|
48
|
+
"lint": "ng lint",
|
|
49
|
+
"format": "prettier --ignore-path .gitignore --write \"**/*.+(js|ts|d.ts|json)\""
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { Component, Input, ElementRef, HostListener, SimpleChanges } from "@angular/core"
|
|
2
|
+
|
|
3
|
+
interface DocusealField {
|
|
4
|
+
name: string,
|
|
5
|
+
type?: string,
|
|
6
|
+
role?: string,
|
|
7
|
+
default_value?: string,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface AfterViewInit {
|
|
11
|
+
ngAfterViewInit(): void
|
|
12
|
+
}
|
|
13
|
+
interface OnChanges {
|
|
14
|
+
ngOnChanges(changes: SimpleChanges): void
|
|
15
|
+
}
|
|
16
|
+
@Component({
|
|
17
|
+
selector: "docuseal-builder",
|
|
18
|
+
standalone: true,
|
|
19
|
+
template: "",
|
|
20
|
+
styles: []
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
export class DocusealBuilderComponent implements AfterViewInit, OnChanges {
|
|
24
|
+
@Input() token: string = ""
|
|
25
|
+
@Input() host: string = "cdn.docuseal.co"
|
|
26
|
+
@Input() language: string = "en"
|
|
27
|
+
@Input() preview: boolean = false
|
|
28
|
+
@Input() autosave: boolean = true
|
|
29
|
+
@Input() withRecipientsButton: boolean = true
|
|
30
|
+
@Input() withDocumentsList: boolean = true
|
|
31
|
+
@Input() withFieldsList: boolean = true
|
|
32
|
+
@Input() withSendButton: boolean = true
|
|
33
|
+
@Input() withTitle: boolean = true
|
|
34
|
+
@Input() onlyDefinedFields: boolean = false
|
|
35
|
+
@Input() withSignYourselfButton: boolean = true
|
|
36
|
+
@Input() withUploadButton: boolean = true
|
|
37
|
+
@Input() roles: string[] = []
|
|
38
|
+
@Input() fields: DocusealField[] = []
|
|
39
|
+
@Input() i18n: object = {}
|
|
40
|
+
@Input() fieldTypes: string[] = []
|
|
41
|
+
@Input() drawFieldType: string = "text"
|
|
42
|
+
@Input() customButton: { title: string, url: string } = { title: "", url: "" }
|
|
43
|
+
@Input() backgroundColor: string = ""
|
|
44
|
+
@Input() onLoad: (detail: any) => void = () => {}
|
|
45
|
+
@Input() onUpload: (detail: any) => void = () => {}
|
|
46
|
+
@Input() onSend: (detail: any) => void = () => {}
|
|
47
|
+
@Input() onSave: (detail: any) => void = () => {}
|
|
48
|
+
@Input() sendButtonText: string = ""
|
|
49
|
+
@Input() saveButtonText: string = ""
|
|
50
|
+
@Input() customCss: string = ""
|
|
51
|
+
|
|
52
|
+
constructor(private el: ElementRef) {}
|
|
53
|
+
|
|
54
|
+
get attributes (): { [key: string]: any } {
|
|
55
|
+
return {
|
|
56
|
+
src: {
|
|
57
|
+
name: "data-token",
|
|
58
|
+
value: () => this.token
|
|
59
|
+
},
|
|
60
|
+
preview: {
|
|
61
|
+
name: "data-preview",
|
|
62
|
+
value: () => this.preview
|
|
63
|
+
},
|
|
64
|
+
language: {
|
|
65
|
+
name: "data-language",
|
|
66
|
+
value: () => this.language
|
|
67
|
+
},
|
|
68
|
+
autosave: {
|
|
69
|
+
name: "data-autosave",
|
|
70
|
+
value: () => this.autosave
|
|
71
|
+
},
|
|
72
|
+
sendButtonText: {
|
|
73
|
+
name: "data-send-button-text",
|
|
74
|
+
value: () => this.sendButtonText
|
|
75
|
+
},
|
|
76
|
+
saveButtonText: {
|
|
77
|
+
name: "data-save-button-text",
|
|
78
|
+
value: () => this.saveButtonText
|
|
79
|
+
},
|
|
80
|
+
roles: {
|
|
81
|
+
name: "data-roles",
|
|
82
|
+
value: () => this.roles.join(',')
|
|
83
|
+
},
|
|
84
|
+
fieldTypes: {
|
|
85
|
+
name: "data-field-types",
|
|
86
|
+
value: () => this.fieldTypes.join(',')
|
|
87
|
+
},
|
|
88
|
+
drawFieldType: {
|
|
89
|
+
name: "data-draw-field-type",
|
|
90
|
+
value: () => this.drawFieldType
|
|
91
|
+
},
|
|
92
|
+
fields: {
|
|
93
|
+
name: "data-fields",
|
|
94
|
+
value: () => JSON.stringify(this.fields)
|
|
95
|
+
},
|
|
96
|
+
i18n: {
|
|
97
|
+
name: "data-i18n",
|
|
98
|
+
value: () => JSON.stringify(this.i18n)
|
|
99
|
+
},
|
|
100
|
+
customButton: [
|
|
101
|
+
{
|
|
102
|
+
name: "data-custom-button-title",
|
|
103
|
+
value: () => this.customButton.title
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: "data-custom-button-url",
|
|
107
|
+
value: () => this.customButton.url
|
|
108
|
+
}
|
|
109
|
+
],
|
|
110
|
+
withRecipientsButton: {
|
|
111
|
+
name: "data-with-recipients-button",
|
|
112
|
+
value: () => this.withRecipientsButton
|
|
113
|
+
},
|
|
114
|
+
withSendButton: {
|
|
115
|
+
name: "data-with-send-button",
|
|
116
|
+
value: () => this.withSendButton
|
|
117
|
+
},
|
|
118
|
+
withDocumentsList: {
|
|
119
|
+
name: "data-with-documents-list",
|
|
120
|
+
value: () => this.withDocumentsList
|
|
121
|
+
},
|
|
122
|
+
withFieldsList: {
|
|
123
|
+
name: "data-with-fields-list",
|
|
124
|
+
value: () => this.withFieldsList
|
|
125
|
+
},
|
|
126
|
+
withTitle: {
|
|
127
|
+
name: "data-with-title",
|
|
128
|
+
value: () => this.withTitle
|
|
129
|
+
},
|
|
130
|
+
onlyDefinedFields: {
|
|
131
|
+
name: "data-only-defined-fields",
|
|
132
|
+
value: () => this.onlyDefinedFields
|
|
133
|
+
},
|
|
134
|
+
withUploadButton: {
|
|
135
|
+
name: "data-with-upload-button",
|
|
136
|
+
value: () => this.withUploadButton
|
|
137
|
+
},
|
|
138
|
+
withSignYourselfButton: {
|
|
139
|
+
name: "data-with-sign-yourself-button",
|
|
140
|
+
value: () => this.withSignYourselfButton
|
|
141
|
+
},
|
|
142
|
+
backgroundColor: {
|
|
143
|
+
name: "data-background-color",
|
|
144
|
+
value: () => this.backgroundColor
|
|
145
|
+
},
|
|
146
|
+
customCss: {
|
|
147
|
+
name: "data-custom-css",
|
|
148
|
+
value: () => this.customCss
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
ngAfterViewInit(): void {
|
|
154
|
+
const builder = this.el.nativeElement;
|
|
155
|
+
|
|
156
|
+
Object.entries(this.attributes).forEach(([_, attribute]) => {
|
|
157
|
+
if (Array.isArray(attribute)) {
|
|
158
|
+
attribute.forEach((attr) => {
|
|
159
|
+
builder.setAttribute(attr.name, attr.value())
|
|
160
|
+
})
|
|
161
|
+
} else if (attribute) {
|
|
162
|
+
builder.setAttribute(attribute.name, attribute.value())
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
this.loadScript()
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
ngOnChanges(changes: SimpleChanges): void {
|
|
170
|
+
const builder = this.el.nativeElement;
|
|
171
|
+
const attributes = this.attributes
|
|
172
|
+
|
|
173
|
+
Object.entries(changes).forEach(([key, change]) => {
|
|
174
|
+
const attribute = attributes[key]
|
|
175
|
+
|
|
176
|
+
if (Array.isArray(attribute)) {
|
|
177
|
+
attribute.forEach((attr) => {
|
|
178
|
+
builder.setAttribute(attr.name, attr.value())
|
|
179
|
+
})
|
|
180
|
+
} else if (attribute) {
|
|
181
|
+
builder.setAttribute(attribute.name, change.currentValue)
|
|
182
|
+
}
|
|
183
|
+
})
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
@HostListener('send', ['$event'])
|
|
187
|
+
onSendEvent(event: CustomEvent): void {
|
|
188
|
+
if (this.onSend) {
|
|
189
|
+
this.onSend(event.detail)
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
@HostListener('load', ['$event'])
|
|
194
|
+
onLoadEvent(event: CustomEvent): void {
|
|
195
|
+
if (this.onLoad) {
|
|
196
|
+
this.onLoad(event.detail)
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
@HostListener('upload', ['$event'])
|
|
201
|
+
onUploadEvent(event: CustomEvent): void {
|
|
202
|
+
if (this.onUpload) {
|
|
203
|
+
this.onUpload(event.detail)
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
@HostListener('save', ['$event'])
|
|
208
|
+
onSaveEvent(event: CustomEvent): void {
|
|
209
|
+
if (this.onSave) {
|
|
210
|
+
this.onSave(event.detail)
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
loadScript(): void {
|
|
215
|
+
const scriptId = 'docuseal-builder-script'
|
|
216
|
+
const scriptSrc = `https://${this.host}/js/builder.js`
|
|
217
|
+
const script = document.createElement("script")
|
|
218
|
+
|
|
219
|
+
script.id = scriptId
|
|
220
|
+
script.async = true
|
|
221
|
+
script.src = scriptSrc
|
|
222
|
+
|
|
223
|
+
document.head.appendChild(script)
|
|
224
|
+
}
|
|
225
|
+
}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { Component, Input, ElementRef, HostListener, SimpleChanges } from "@angular/core"
|
|
2
|
+
|
|
3
|
+
interface DocusealField {
|
|
4
|
+
name: string,
|
|
5
|
+
title?: string,
|
|
6
|
+
type?: string,
|
|
7
|
+
position?: number,
|
|
8
|
+
required?: boolean,
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface AfterViewInit {
|
|
12
|
+
ngAfterViewInit(): void
|
|
13
|
+
}
|
|
14
|
+
interface OnChanges {
|
|
15
|
+
ngOnChanges(changes: SimpleChanges): void
|
|
16
|
+
}
|
|
17
|
+
@Component({
|
|
18
|
+
selector: "docuseal-form",
|
|
19
|
+
standalone: true,
|
|
20
|
+
template: "",
|
|
21
|
+
styles: []
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
export class DocusealFormComponent implements AfterViewInit, OnChanges {
|
|
25
|
+
@Input() src: string = ""
|
|
26
|
+
@Input() host: string = "cdn.docuseal.co"
|
|
27
|
+
@Input() role: string = ""
|
|
28
|
+
@Input() submitter: string = "" // Backward compatibility
|
|
29
|
+
@Input() expand: boolean = true
|
|
30
|
+
@Input() preview: boolean = false
|
|
31
|
+
@Input() email: string = ""
|
|
32
|
+
@Input() applicationKey: string = ""
|
|
33
|
+
@Input() externalId: string = ""
|
|
34
|
+
@Input() backgroundColor: string = ""
|
|
35
|
+
@Input() logo: string = ""
|
|
36
|
+
@Input() language: string = ""
|
|
37
|
+
@Input() completedRedirectUrl: string = ""
|
|
38
|
+
@Input() completedButton: { title: string, url: string } = { title: "", url: "" }
|
|
39
|
+
@Input() goToLast: boolean = true
|
|
40
|
+
@Input() skipFields: boolean = false
|
|
41
|
+
@Input() withTitle: boolean = true
|
|
42
|
+
@Input() withFieldNames: boolean = true
|
|
43
|
+
@Input() withDownloadButton: boolean = true
|
|
44
|
+
@Input() withSendCopyButton: boolean = true
|
|
45
|
+
@Input() allowToResubmit: boolean = true
|
|
46
|
+
@Input() allowTypedSignature: boolean = true
|
|
47
|
+
@Input() sendCopyEmail: boolean = false
|
|
48
|
+
@Input() values: object = {}
|
|
49
|
+
@Input() metadata: object = {}
|
|
50
|
+
@Input() i18n: object = {}
|
|
51
|
+
@Input() fields: DocusealField[] = []
|
|
52
|
+
@Input() readonlyFields: string[] = []
|
|
53
|
+
@Input() onComplete: (detail: any) => void = () => {}
|
|
54
|
+
@Input() onInit: (detail: any) => void = () => {}
|
|
55
|
+
@Input() onLoad: (detail: any) => void = () => {}
|
|
56
|
+
@Input() customCss: string = ""
|
|
57
|
+
|
|
58
|
+
constructor(private el: ElementRef) {}
|
|
59
|
+
|
|
60
|
+
get attributes (): { [key: string]: any } {
|
|
61
|
+
return {
|
|
62
|
+
src: {
|
|
63
|
+
name: "data-src",
|
|
64
|
+
value: () => this.src
|
|
65
|
+
},
|
|
66
|
+
email: {
|
|
67
|
+
name: "data-email",
|
|
68
|
+
value: () => this.email
|
|
69
|
+
},
|
|
70
|
+
role: {
|
|
71
|
+
name: "data-role",
|
|
72
|
+
value: () => this.role || this.submitter
|
|
73
|
+
},
|
|
74
|
+
externalId: {
|
|
75
|
+
name: "data-external-id",
|
|
76
|
+
value: () => this.externalId || this.applicationKey
|
|
77
|
+
},
|
|
78
|
+
expand: {
|
|
79
|
+
name: "data-expand",
|
|
80
|
+
value: () => this.expand
|
|
81
|
+
},
|
|
82
|
+
preview: {
|
|
83
|
+
name: "data-preview",
|
|
84
|
+
value: () => this.preview
|
|
85
|
+
},
|
|
86
|
+
goToLast: {
|
|
87
|
+
name: "data-go-to-last",
|
|
88
|
+
value: () => this.goToLast
|
|
89
|
+
},
|
|
90
|
+
skipFields: {
|
|
91
|
+
name: "data-skip-fields",
|
|
92
|
+
value: () => this.skipFields
|
|
93
|
+
},
|
|
94
|
+
sendCopyEmail: {
|
|
95
|
+
name: "data-send-copy-email",
|
|
96
|
+
value: () => this.sendCopyEmail
|
|
97
|
+
},
|
|
98
|
+
withTitle: {
|
|
99
|
+
name: "data-with-title",
|
|
100
|
+
value: () => this.withTitle
|
|
101
|
+
},
|
|
102
|
+
logo: {
|
|
103
|
+
name: "data-logo",
|
|
104
|
+
value: () => this.logo
|
|
105
|
+
},
|
|
106
|
+
language: {
|
|
107
|
+
name: "data-language",
|
|
108
|
+
value: () => this.language
|
|
109
|
+
},
|
|
110
|
+
withFieldNames: {
|
|
111
|
+
name: "data-with-field-names",
|
|
112
|
+
value: () => this.withFieldNames
|
|
113
|
+
},
|
|
114
|
+
withDownloadButton: {
|
|
115
|
+
name: "data-with-download-button",
|
|
116
|
+
value: () => this.withDownloadButton
|
|
117
|
+
},
|
|
118
|
+
allowToResubmit: {
|
|
119
|
+
name: "data-allow-to-resubmit",
|
|
120
|
+
value: () => this.allowToResubmit
|
|
121
|
+
},
|
|
122
|
+
allowTypedSignature: {
|
|
123
|
+
name: "data-allow-typed-signature",
|
|
124
|
+
value: () => this.allowTypedSignature
|
|
125
|
+
},
|
|
126
|
+
completedRedirectUrl: {
|
|
127
|
+
name: "data-completed-redirect-url",
|
|
128
|
+
value: () => this.completedRedirectUrl
|
|
129
|
+
},
|
|
130
|
+
withSendCopyButton: {
|
|
131
|
+
name: "data-with-send-copy-button",
|
|
132
|
+
value: () => this.withSendCopyButton
|
|
133
|
+
},
|
|
134
|
+
values: {
|
|
135
|
+
name: "data-values",
|
|
136
|
+
value: () => JSON.stringify(this.values)
|
|
137
|
+
},
|
|
138
|
+
metadata: {
|
|
139
|
+
name: "data-metadata",
|
|
140
|
+
value: () => JSON.stringify(this.metadata)
|
|
141
|
+
},
|
|
142
|
+
fields: {
|
|
143
|
+
name: "data-fields",
|
|
144
|
+
value: () => JSON.stringify(this.fields)
|
|
145
|
+
},
|
|
146
|
+
i18n: {
|
|
147
|
+
name: "data-i18n",
|
|
148
|
+
value: () => JSON.stringify(this.i18n)
|
|
149
|
+
},
|
|
150
|
+
readonlyFields: {
|
|
151
|
+
name: "data-readonly-fields",
|
|
152
|
+
value: () => this.readonlyFields.join(',')
|
|
153
|
+
},
|
|
154
|
+
completedButton: [
|
|
155
|
+
{
|
|
156
|
+
name: "data-completed-button-title",
|
|
157
|
+
value: () => this.completedButton.title
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
name: "data-completed-button-url",
|
|
161
|
+
value: () => this.completedButton.url
|
|
162
|
+
}
|
|
163
|
+
],
|
|
164
|
+
backgroundColor: {
|
|
165
|
+
name: "data-background-color",
|
|
166
|
+
value: () => this.backgroundColor
|
|
167
|
+
},
|
|
168
|
+
customCss: {
|
|
169
|
+
name: "data-custom-css",
|
|
170
|
+
value: () => this.customCss
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
ngAfterViewInit(): void {
|
|
176
|
+
const form = this.el.nativeElement;
|
|
177
|
+
|
|
178
|
+
Object.entries(this.attributes).forEach(([_, attribute]) => {
|
|
179
|
+
if (Array.isArray(attribute)) {
|
|
180
|
+
attribute.forEach((attr) => {
|
|
181
|
+
form.setAttribute(attr.name, attr.value())
|
|
182
|
+
})
|
|
183
|
+
} else {
|
|
184
|
+
form.setAttribute(attribute.name, attribute.value())
|
|
185
|
+
}
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
this.loadScript()
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
ngOnChanges(changes: SimpleChanges): void {
|
|
192
|
+
const form = this.el.nativeElement;
|
|
193
|
+
const attributes = this.attributes
|
|
194
|
+
|
|
195
|
+
Object.entries(changes).forEach(([key, change]) => {
|
|
196
|
+
const attribute = attributes[key]
|
|
197
|
+
|
|
198
|
+
if (Array.isArray(attribute)) {
|
|
199
|
+
attribute.forEach((attr) => {
|
|
200
|
+
form.setAttribute(attr.name, attr.value())
|
|
201
|
+
})
|
|
202
|
+
} else if (attribute) {
|
|
203
|
+
form.setAttribute(attribute.name, change.currentValue)
|
|
204
|
+
}
|
|
205
|
+
})
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
@HostListener('completed', ['$event'])
|
|
209
|
+
onCompleteEvent(event: CustomEvent): void {
|
|
210
|
+
if (this.onComplete) {
|
|
211
|
+
this.onComplete(event.detail)
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
@HostListener('init', ['$event'])
|
|
216
|
+
onInitEvent(event: CustomEvent): void {
|
|
217
|
+
if (this.onInit) {
|
|
218
|
+
this.onInit(event.detail)
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
@HostListener('load', ['$event'])
|
|
223
|
+
onLoadEvent(event: CustomEvent): void {
|
|
224
|
+
if (this.onLoad) {
|
|
225
|
+
this.onLoad(event.detail)
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
loadScript(): void {
|
|
230
|
+
const scriptId = "docuseal-form-script"
|
|
231
|
+
const scriptSrc = `https://${this.host}/js/form.js`
|
|
232
|
+
const script = document.createElement("script")
|
|
233
|
+
|
|
234
|
+
script.id = scriptId
|
|
235
|
+
script.async = true
|
|
236
|
+
script.src = scriptSrc
|
|
237
|
+
|
|
238
|
+
document.head.appendChild(script)
|
|
239
|
+
}
|
|
240
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"allowJs": true, // Allow JavaScript files to be compiled
|
|
4
|
+
"allowSyntheticDefaultImports": true, // Allow default imports from modules with no default export
|
|
5
|
+
"baseUrl": "src", // Base directory to resolve non-absolute module names
|
|
6
|
+
"declaration": true, // Generate corresponding .d.ts file
|
|
7
|
+
"esModuleInterop": true, // Disables namespace imports (import * as fs from "fs") and enables CJS/AMD/UMD style imports (import fs from "fs")
|
|
8
|
+
"forceConsistentCasingInFileNames": true, // Disallow inconsistently-cased references to the same file.
|
|
9
|
+
"incremental": true, // Enable incremental compilation by reading/writing information from prior compilations to a file on disk
|
|
10
|
+
"isolatedModules": true, // Unconditionally emit imports for unresolved files
|
|
11
|
+
"lib": ["ES2022", "dom"], // List of library files to be included in the compilation
|
|
12
|
+
"module": "ES2022", // Specify module code generation
|
|
13
|
+
"moduleResolution": "node", // Resolve modules using Node.js style
|
|
14
|
+
"noEmit": false, // Do not emit output (meaning do not compile code, only perform type checking)
|
|
15
|
+
"noFallthroughCasesInSwitch": true, // Report errors for fallthrough cases in switch statement
|
|
16
|
+
"noUnusedLocals": true, // Report errors on unused locals
|
|
17
|
+
"noUnusedParameters": true, // Report errors on unused parameters
|
|
18
|
+
"resolveJsonModule": true, // Include modules imported with .json extension
|
|
19
|
+
"outDir": "./dist",
|
|
20
|
+
"skipLibCheck": true, // Skip type checking of all declaration files
|
|
21
|
+
"sourceMap": true, // Generate corrresponding .map file
|
|
22
|
+
"strict": true, // Enable all strict type checking options
|
|
23
|
+
"target": "ES2022" // Specify ECMAScript target version,
|
|
24
|
+
},
|
|
25
|
+
"angularCompilerOptions": {
|
|
26
|
+
"enableI18nLegacyMessageIdFormat": false, // Use the new message ID format
|
|
27
|
+
"strictInjectionParameters": true, // Ensure that the parameters for the DI token match the constructor
|
|
28
|
+
"strictInputAccessModifiers": true, // Ensure that the accessors of the directive inputs match the declared type
|
|
29
|
+
"strictTemplates": true // Ensure that the templates are type-safe
|
|
30
|
+
},
|
|
31
|
+
"include": ["src/**/*.ts"],
|
|
32
|
+
"exclude": ["node_modules"]
|
|
33
|
+
}
|