@unicef-polymer/etools-form-builder 4.0.1 → 4.0.3

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 (40) hide show
  1. package/LICENSE +674 -674
  2. package/README.md +1 -1
  3. package/dist/form-attachments-popup/form-attachments-popup.js +135 -135
  4. package/dist/form-fields/abstract-field-base.class.js +100 -100
  5. package/dist/form-fields/field-renderer-component.d.ts +4 -3
  6. package/dist/form-fields/field-renderer-component.js +209 -195
  7. package/dist/form-fields/repeatable-fields/repeatable-attachment-field.js +111 -111
  8. package/dist/form-fields/repeatable-fields/repeatable-base-field.js +22 -22
  9. package/dist/form-fields/repeatable-fields/repeatable-choice-field.d.ts +1 -0
  10. package/dist/form-fields/repeatable-fields/repeatable-choice-field.js +66 -63
  11. package/dist/form-fields/repeatable-fields/repeatable-number-field.js +19 -19
  12. package/dist/form-fields/repeatable-fields/repeatable-scale-field.js +57 -57
  13. package/dist/form-fields/repeatable-fields/repeatable-text-field.js +19 -19
  14. package/dist/form-fields/single-fields/attachment-field.js +13 -13
  15. package/dist/form-fields/single-fields/boolean-field.js +16 -16
  16. package/dist/form-fields/single-fields/choice-field.d.ts +2 -0
  17. package/dist/form-fields/single-fields/choice-field.js +68 -65
  18. package/dist/form-fields/single-fields/number-field.js +20 -20
  19. package/dist/form-fields/single-fields/scale-field.d.ts +1 -0
  20. package/dist/form-fields/single-fields/scale-field.js +58 -58
  21. package/dist/form-fields/single-fields/text-field.js +30 -30
  22. package/dist/form-groups/form-abstract-group.js +129 -129
  23. package/dist/form-groups/form-card.js +30 -30
  24. package/dist/form-groups/form-collapsed-card.js +34 -34
  25. package/dist/lib/additional-components/confirmation-dialog.js +20 -20
  26. package/dist/lib/additional-components/etools-fb-card.js +144 -144
  27. package/dist/lib/styles/attachments.styles.js +61 -61
  28. package/dist/lib/styles/card-styles.js +147 -147
  29. package/dist/lib/styles/dialog.styles.js +83 -83
  30. package/dist/lib/styles/elevation-styles.js +46 -46
  31. package/dist/lib/styles/flex-layout-classes.js +316 -316
  32. package/dist/lib/styles/form-builder-card.styles.js +53 -53
  33. package/dist/lib/styles/page-layout-styles.js +198 -198
  34. package/dist/lib/styles/shared-styles.js +61 -61
  35. package/dist/lib/types/form-builder.types.d.ts +1 -0
  36. package/dist/rich-editor/rich-action.js +34 -34
  37. package/dist/rich-editor/rich-text.js +64 -64
  38. package/dist/rich-editor/rich-toolbar.js +125 -125
  39. package/dist/rich-editor/rich-viewer.js +21 -21
  40. package/package.json +53 -53
@@ -24,55 +24,55 @@ let RepeatableAttachmentField = class RepeatableAttachmentField extends Repeatab
24
24
  render() {
25
25
  var _a;
26
26
  const values = this.getValues();
27
- return html `
28
- <div class="finding-container">
29
- <div class="question layout start"><slot>${this.questionTemplate()}</slot></div>
30
- <div class="question-control layout vertical center-justified start">
27
+ return html `
28
+ <div class="finding-container">
29
+ <div class="question layout start"><slot>${this.questionTemplate()}</slot></div>
30
+ <div class="question-control layout vertical center-justified start">
31
31
  ${values.map((value, index) => value
32
- ? html `
33
- <div class="layout horizontal file-container">
34
- <!-- File name component -->
35
- <div class="filename-container file-selector__filename">
36
- <etools-icon class="file-icon" name="attachment"></etools-icon>
37
- <span class="filename" title="${value.filename}">${value.filename}</span>
38
- </div>
39
-
40
- <!-- Download Button -->
41
- <etools-button
42
- class="neutral download-button file-selector__download"
43
- variant="text"
44
- ?hidden="${!value.url}"
45
- @click="${() => this.downloadFile(value)}"
46
- >
47
- <etools-icon name="cloud-download" class="dw-icon" slot="prefix"></etools-icon>
48
- ${getTranslation(this.language, 'DOWNLOAD')}
49
- </etools-button>
50
-
51
- <!-- Delete Button -->
52
- <etools-button
53
- variant="danger"
54
- class="file-selector__delete"
55
- ?hidden="${this.isReadonly}"
56
- @click="${() => this.removeControl(index)}"
57
- >
58
- ${getTranslation(this.language, 'DELETE')}
59
- </etools-button>
60
- </div>
32
+ ? html `
33
+ <div class="layout horizontal file-container">
34
+ <!-- File name component -->
35
+ <div class="filename-container file-selector__filename">
36
+ <etools-icon class="file-icon" name="attachment"></etools-icon>
37
+ <span class="filename" title="${value.filename}">${value.filename}</span>
38
+ </div>
39
+
40
+ <!-- Download Button -->
41
+ <etools-button
42
+ class="neutral download-button file-selector__download"
43
+ variant="text"
44
+ ?hidden="${!value.url}"
45
+ @click="${() => this.downloadFile(value)}"
46
+ >
47
+ <etools-icon name="cloud-download" class="dw-icon" slot="prefix"></etools-icon>
48
+ ${getTranslation(this.language, 'DOWNLOAD')}
49
+ </etools-button>
50
+
51
+ <!-- Delete Button -->
52
+ <etools-button
53
+ variant="danger"
54
+ class="file-selector__delete"
55
+ ?hidden="${this.isReadonly}"
56
+ @click="${() => this.removeControl(index)}"
57
+ >
58
+ ${getTranslation(this.language, 'DELETE')}
59
+ </etools-button>
60
+ </div>
61
61
  `
62
- : '')}
63
- <!-- Upload button -->
64
- <etools-upload-multi
65
- class="with-padding"
66
- activate-offline
67
- ?hidden="${this.isReadonly}"
68
- @upload-finished="${({ detail }) => this.attachmentsUploaded(detail)}"
69
- .endpointInfo="${{ endpoint: this.uploadUrl, extraInfo: { composedPath: this.computedPath } }}"
70
- .jwtLocalStorageKey="${this.jwtLocalStorageKey}"
71
- >
72
- </etools-upload-multi>
73
- <div ?hidden="${!this.isReadonly || ((_a = this.value) === null || _a === void 0 ? void 0 : _a.length)}">—</div>
74
- </div>
75
- </div>
62
+ : '')}
63
+ <!-- Upload button -->
64
+ <etools-upload-multi
65
+ class="with-padding"
66
+ activate-offline
67
+ ?hidden="${this.isReadonly}"
68
+ @upload-finished="${({ detail }) => this.attachmentsUploaded(detail)}"
69
+ .endpointInfo="${{ endpoint: this.uploadUrl, extraInfo: { composedPath: this.computedPath } }}"
70
+ .jwtLocalStorageKey="${this.jwtLocalStorageKey}"
71
+ >
72
+ </etools-upload-multi>
73
+ <div ?hidden="${!this.isReadonly || ((_a = this.value) === null || _a === void 0 ? void 0 : _a.length)}">—</div>
74
+ </div>
75
+ </div>
76
76
  `;
77
77
  }
78
78
  controlTemplate() {
@@ -135,70 +135,70 @@ let RepeatableAttachmentField = class RepeatableAttachmentField extends Repeatab
135
135
  ...RepeatableBaseField.styles,
136
136
  SharedStyles,
137
137
  AttachmentsStyles,
138
- css `
139
- .file-selector__type-dropdown {
140
- flex-basis: 25%;
141
- padding-left: 8px;
142
- padding-right: 8px;
143
- }
144
-
145
- .file-selector__filename {
146
- flex-basis: 35%;
147
- }
148
-
149
- .file-selector__download {
150
- flex-basis: 10%;
151
- }
152
-
153
- .file-selector__delete {
154
- flex-basis: 10%;
155
- }
156
-
157
- .file-selector-container.with-type-dropdown {
158
- flex-wrap: nowrap;
159
- }
160
-
161
- .popup-container {
162
- padding: 12px 12px 0;
163
- }
164
-
165
- .file-container {
166
- padding: 8px 0;
167
- }
168
-
169
- @media (max-width: 380px) {
170
- .file-selector-container.with-type-dropdown {
171
- justify-content: center;
172
- }
173
-
174
- .file-selector-container.with-type-dropdown etools-dropdown.type-dropdown {
175
- flex-basis: 90%;
176
- }
177
-
178
- .file-selector__filename {
179
- flex-basis: 90%;
180
- }
181
-
182
- .file-selector__download {
183
- flex-basis: 5%;
184
- }
185
-
186
- .file-selector__delete {
187
- flex-basis: 5%;
188
- }
189
- }
190
-
191
- @media (max-width: 600px) {
192
- etools-dropdown {
193
- padding: 0;
194
- }
195
-
196
- .file-selector-container.with-type-dropdown {
197
- border-bottom: 1px solid lightgrey;
198
- flex-wrap: wrap;
199
- padding-bottom: 10px;
200
- }
201
- }
138
+ css `
139
+ .file-selector__type-dropdown {
140
+ flex-basis: 25%;
141
+ padding-left: 8px;
142
+ padding-right: 8px;
143
+ }
144
+
145
+ .file-selector__filename {
146
+ flex-basis: 35%;
147
+ }
148
+
149
+ .file-selector__download {
150
+ flex-basis: 10%;
151
+ }
152
+
153
+ .file-selector__delete {
154
+ flex-basis: 10%;
155
+ }
156
+
157
+ .file-selector-container.with-type-dropdown {
158
+ flex-wrap: nowrap;
159
+ }
160
+
161
+ .popup-container {
162
+ padding: 12px 12px 0;
163
+ }
164
+
165
+ .file-container {
166
+ padding: 8px 0;
167
+ }
168
+
169
+ @media (max-width: 380px) {
170
+ .file-selector-container.with-type-dropdown {
171
+ justify-content: center;
172
+ }
173
+
174
+ .file-selector-container.with-type-dropdown etools-dropdown.type-dropdown {
175
+ flex-basis: 90%;
176
+ }
177
+
178
+ .file-selector__filename {
179
+ flex-basis: 90%;
180
+ }
181
+
182
+ .file-selector__download {
183
+ flex-basis: 5%;
184
+ }
185
+
186
+ .file-selector__delete {
187
+ flex-basis: 5%;
188
+ }
189
+ }
190
+
191
+ @media (max-width: 600px) {
192
+ etools-dropdown {
193
+ padding: 0;
194
+ }
195
+
196
+ .file-selector-container.with-type-dropdown {
197
+ border-bottom: 1px solid lightgrey;
198
+ flex-wrap: wrap;
199
+ padding-bottom: 10px;
200
+ }
201
+ }
202
202
  `
203
203
  ];
204
204
  }
@@ -19,23 +19,23 @@ export class RepeatableBaseField extends AbstractFieldBaseClass {
19
19
  }
20
20
  render() {
21
21
  const values = this.getValues();
22
- return html `
23
- <div class="finding-container">
24
- <div class="question layout start"><slot>${this.questionTemplate()}</slot></div>
25
- <div class="question-control layout vertical center-justified start">
26
- ${values.map((value, index) => html `<div class="layout horizontal center full-width">
27
- ${this.controlTemplate(value, index)}
28
- <etools-icon-button
29
- name="close"
30
- ?hidden="${this.isReadonly || values.length < 2}"
31
- @click="${() => this.removeControl(index)}"
32
- ></etools-icon-button>
33
- </div>`)}
34
- <etools-button variant="primary" class="add-button" ?hidden="${this.isReadonly}" @click="${this.addNewField}">
35
- ${getTranslation(this.language, 'ADD')}
36
- </etools-button>
37
- </div>
38
- </div>
22
+ return html `
23
+ <div class="finding-container">
24
+ <div class="question layout start"><slot>${this.questionTemplate()}</slot></div>
25
+ <div class="question-control layout vertical center-justified start">
26
+ ${values.map((value, index) => html `<div class="layout horizontal center full-width">
27
+ ${this.controlTemplate(value, index)}
28
+ <etools-icon-button
29
+ name="close"
30
+ ?hidden="${this.isReadonly || values.length < 2}"
31
+ @click="${() => this.removeControl(index)}"
32
+ ></etools-icon-button>
33
+ </div>`)}
34
+ <etools-button variant="primary" class="add-button" ?hidden="${this.isReadonly}" @click="${this.addNewField}">
35
+ ${getTranslation(this.language, 'ADD')}
36
+ </etools-button>
37
+ </div>
38
+ </div>
39
39
  `;
40
40
  }
41
41
  questionTemplate() {
@@ -104,11 +104,11 @@ export class RepeatableBaseField extends AbstractFieldBaseClass {
104
104
  // language=CSS
105
105
  return [
106
106
  ...AbstractFieldBaseClass.styles,
107
- css `
108
- :host(:not([is-readonly])) .question-control,
109
- :host(:not([is-readonly])) .question {
110
- padding-bottom: 10px;
111
- }
107
+ css `
108
+ :host(:not([is-readonly])) .question-control,
109
+ :host(:not([is-readonly])) .question {
110
+ padding-bottom: 10px;
111
+ }
112
112
  `
113
113
  ];
114
114
  }
@@ -10,6 +10,7 @@ export declare class RepeatableChoiceField extends RepeatableBaseField<(string |
10
10
  protected onToggle(itemValue: string | number, checked: boolean, index: number): void;
11
11
  protected getLabel(option: FieldOption | string | number): unknown;
12
12
  protected getValue(option: FieldOption | string | number): unknown;
13
+ protected getDisabled(option: FieldOption | string | number): unknown;
13
14
  protected customValidation(): string | null;
14
15
  static get styles(): CSSResultArray;
15
16
  }
@@ -14,36 +14,36 @@ let RepeatableChoiceField = class RepeatableChoiceField extends RepeatableBaseFi
14
14
  this.values = [];
15
15
  }
16
16
  controlTemplate(value, index) {
17
- return html `
18
- <div class="container">
19
- <div class="checkbox-group">
17
+ return html `
18
+ <div class="container">
19
+ <div class="checkbox-group">
20
20
  ${repeat(this.options, (option) => {
21
21
  const val = this.getValue(option);
22
22
  const checked = Array.isArray(value) && value.includes(val);
23
- return html `
24
- <etools-checkbox
25
- class="checkbox"
26
- value="${val}"
27
- ?checked="${checked}"
28
- ?disabled="${this.isReadonly}"
29
- @sl-change="${(e) => this.onToggle(val, e.target.checked, index)}"
30
- >
31
- ${this.getLabel(option)}
32
- </etools-checkbox>
23
+ return html `
24
+ <etools-checkbox
25
+ class="checkbox"
26
+ value="${val}"
27
+ ?checked="${checked}"
28
+ ?disabled="${this.isReadonly || this.getDisabled(option)}"
29
+ @sl-change="${(e) => this.onToggle(val, e.target.checked, index)}"
30
+ >
31
+ ${this.getLabel(option)}
32
+ </etools-checkbox>
33
33
  `;
34
- })}
35
- </div>
36
-
37
- <etools-button
38
- class="neutral clear-button"
39
- variant="text"
40
- ?hidden="${this.isReadonly}"
41
- @click="${() => this.valueChanged([], index)}"
42
- >
43
- <etools-icon name="clear" slot="prefix"></etools-icon>
44
- ${getTranslation(this.language, 'CLEAR')}
45
- </etools-button>
46
- </div>
34
+ })}
35
+ </div>
36
+
37
+ <etools-button
38
+ class="neutral clear-button"
39
+ variant="text"
40
+ ?hidden="${this.isReadonly}"
41
+ @click="${() => this.valueChanged([], index)}"
42
+ >
43
+ <etools-icon name="clear" slot="prefix"></etools-icon>
44
+ ${getTranslation(this.language, 'CLEAR')}
45
+ </etools-button>
46
+ </div>
47
47
  `;
48
48
  }
49
49
  onToggle(itemValue, checked, index) {
@@ -64,49 +64,52 @@ let RepeatableChoiceField = class RepeatableChoiceField extends RepeatableBaseFi
64
64
  getValue(option) {
65
65
  return typeof option === 'object' ? option.value : option;
66
66
  }
67
+ getDisabled(option) {
68
+ return typeof option === 'object' ? option.disabled : false;
69
+ }
67
70
  customValidation() {
68
71
  return null;
69
72
  }
70
73
  static get styles() {
71
74
  return [
72
75
  ...AbstractFieldBaseClass.styles,
73
- css `
74
- .container {
75
- position: relative;
76
- min-height: 48px;
77
- display: flex;
78
- align-items: center;
79
- flex-direction: row;
80
- }
81
-
82
- .checkbox-group {
83
- display: flex;
84
- flex-direction: row;
85
- flex-wrap: wrap;
86
- gap: 0.5rem;
87
- }
88
-
89
- :host([is-readonly]) .checkbox-group {
90
- pointer-events: none;
91
- opacity: 0.55;
92
- }
93
-
94
- @media (max-width: 1080px) {
95
- .container {
96
- flex-direction: column;
97
- align-items: flex-start;
98
- }
99
- .checkbox-group {
100
- flex-direction: column;
101
- }
102
- .checkbox {
103
- padding-left: 3px;
104
- }
105
- .clear-button {
106
- margin: 0;
107
- padding-left: 0;
108
- }
109
- }
76
+ css `
77
+ .container {
78
+ position: relative;
79
+ min-height: 48px;
80
+ display: flex;
81
+ align-items: center;
82
+ flex-direction: row;
83
+ }
84
+
85
+ .checkbox-group {
86
+ display: flex;
87
+ flex-direction: row;
88
+ flex-wrap: wrap;
89
+ gap: 0.5rem;
90
+ }
91
+
92
+ :host([is-readonly]) .checkbox-group {
93
+ pointer-events: none;
94
+ opacity: 0.55;
95
+ }
96
+
97
+ @media (max-width: 1080px) {
98
+ .container {
99
+ flex-direction: column;
100
+ align-items: flex-start;
101
+ }
102
+ .checkbox-group {
103
+ flex-direction: column;
104
+ }
105
+ .checkbox {
106
+ padding-left: 3px;
107
+ }
108
+ .clear-button {
109
+ margin: 0;
110
+ padding-left: 0;
111
+ }
112
+ }
110
113
  `
111
114
  ];
112
115
  }
@@ -11,19 +11,19 @@ let RepeatableNumberField = class RepeatableNumberField extends RepeatableBaseFi
11
11
  this.isInteger = false;
12
12
  }
13
13
  controlTemplate(value, index) {
14
- return html `
15
- <etools-input
16
- class="no-padding-left"
17
- no-label-float
18
- placeholder="${this.isReadonly ? '—' : this.placeholder}"
19
- .value="${value}"
20
- @value-changed="${({ detail }) => this.valueChanged(detail.value, index)}"
21
- placeholder="&#8212;"
22
- ?invalid="${this.errorMessage[index]}"
23
- error-message="${this.errorMessage[index]}"
24
- ?readonly="${this.isReadonly}"
25
- >
26
- </etools-input>
14
+ return html `
15
+ <etools-input
16
+ class="no-padding-left"
17
+ no-label-float
18
+ placeholder="${this.isReadonly ? '—' : this.placeholder}"
19
+ .value="${value}"
20
+ @value-changed="${({ detail }) => this.valueChanged(detail.value, index)}"
21
+ placeholder="&#8212;"
22
+ ?invalid="${this.errorMessage[index]}"
23
+ error-message="${this.errorMessage[index]}"
24
+ ?readonly="${this.isReadonly}"
25
+ >
26
+ </etools-input>
27
27
  `;
28
28
  }
29
29
  valueChanged(newValue, index) {
@@ -45,12 +45,12 @@ let RepeatableNumberField = class RepeatableNumberField extends RepeatableBaseFi
45
45
  // language=CSS
46
46
  return [
47
47
  ...AbstractFieldBaseClass.styles,
48
- css `
49
- @media (max-width: 380px) {
50
- .no-padding-left {
51
- padding-left: 0;
52
- }
53
- }
48
+ css `
49
+ @media (max-width: 380px) {
50
+ .no-padding-left {
51
+ padding-left: 0;
52
+ }
53
+ }
54
54
  `
55
55
  ];
56
56
  }
@@ -14,27 +14,27 @@ let RepeatableScaleField = class RepeatableScaleField extends RepeatableBaseFiel
14
14
  this.options = [];
15
15
  }
16
16
  controlTemplate(value, index) {
17
- return html `
18
- <div class="container">
19
- <etools-radio-group
20
- class="radio-group"
21
- .value="${value}"
22
- @sl-change="${(e) => this.onSelect(e.target.value, index)}"
23
- >
24
- ${repeat(this.options, (option) => html `
25
- <sl-radio class="radio-button" value="${this.getValue(option)}"> ${this.getLabel(option)} </sl-radio>
26
- `)}
27
- </etools-radio-group>
28
- <etools-button
29
- class="neutral clear-button"
30
- variant="text"
31
- ?hidden="${this.isReadonly}"
32
- @click="${() => this.valueChanged(null, index)}"
33
- >
34
- <etools-icon name="clear" slot="prefix"></etools-icon>
35
- ${getTranslation(this.language, 'CLEAR')}
36
- </etools-button>
37
- </div>
17
+ return html `
18
+ <div class="container">
19
+ <etools-radio-group
20
+ class="radio-group"
21
+ .value="${value}"
22
+ @sl-change="${(e) => this.onSelect(e.target.value, index)}"
23
+ >
24
+ ${repeat(this.options, (option) => html `
25
+ <sl-radio class="radio-button" value="${this.getValue(option)}"> ${this.getLabel(option)} </sl-radio>
26
+ `)}
27
+ </etools-radio-group>
28
+ <etools-button
29
+ class="neutral clear-button"
30
+ variant="text"
31
+ ?hidden="${this.isReadonly}"
32
+ @click="${() => this.valueChanged(null, index)}"
33
+ >
34
+ <etools-icon name="clear" slot="prefix"></etools-icon>
35
+ ${getTranslation(this.language, 'CLEAR')}
36
+ </etools-button>
37
+ </div>
38
38
  `;
39
39
  }
40
40
  onSelect(itemValue, index) {
@@ -53,42 +53,42 @@ let RepeatableScaleField = class RepeatableScaleField extends RepeatableBaseFiel
53
53
  // language=CSS
54
54
  return [
55
55
  ...AbstractFieldBaseClass.styles,
56
- css `
57
- .container {
58
- position: relative;
59
- min-height: 48px;
60
- display: flex;
61
- align-items: center;
62
- flex-direction: row;
63
- }
64
-
65
- .radio-group {
66
- display: flex;
67
- flex-direction: row;
68
- flex-wrap: wrap;
69
- }
70
-
71
- :host([is-readonly]) etools-radio-group {
72
- pointer-events: none;
73
- opacity: 0.55;
74
- }
75
-
76
- @media (max-width: 1080px) {
77
- .container {
78
- flex-direction: column;
79
- align-items: flex-start;
80
- }
81
- .radio-group {
82
- flex-direction: column;
83
- }
84
- .radio-button {
85
- padding-left: 3px;
86
- }
87
- .clear-button {
88
- margin: 0;
89
- padding-left: 0;
90
- }
91
- }
56
+ css `
57
+ .container {
58
+ position: relative;
59
+ min-height: 48px;
60
+ display: flex;
61
+ align-items: center;
62
+ flex-direction: row;
63
+ }
64
+
65
+ .radio-group {
66
+ display: flex;
67
+ flex-direction: row;
68
+ flex-wrap: wrap;
69
+ }
70
+
71
+ :host([is-readonly]) etools-radio-group {
72
+ pointer-events: none;
73
+ opacity: 0.55;
74
+ }
75
+
76
+ @media (max-width: 1080px) {
77
+ .container {
78
+ flex-direction: column;
79
+ align-items: flex-start;
80
+ }
81
+ .radio-group {
82
+ flex-direction: column;
83
+ }
84
+ .radio-button {
85
+ padding-left: 3px;
86
+ }
87
+ .clear-button {
88
+ margin: 0;
89
+ padding-left: 0;
90
+ }
91
+ }
92
92
  `
93
93
  ];
94
94
  }