saasufy-components 9.6.1 → 10.0.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.
- package/README.md +7 -3
- package/collection-adder-form.js +29 -13
- package/collection-adder.js +29 -11
- package/collection-deleter.js +2 -2
- package/confirm-modal.js +21 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -458,6 +458,7 @@ This component is a simplified version of the `collection-adder-form` component
|
|
|
458
458
|
- `autocorrect`: Can be set to `off` to disable auto-correction of input on mobile devices.
|
|
459
459
|
- `show-field-errors`: If this attribute exists on the element, then granular error messages will be shown above each corresponding input element instead of a single form-level error message.
|
|
460
460
|
- `trim-spaces`: If this attribute exists on the element, then leading and trailing spaces will be trimmed from each input element's value before submitting the form.
|
|
461
|
+
- `reset-status-on-submit`: If this attribute exists, then the current message and any field errors will be cleared as soon as the form is submitted, instead of when the outcome of the submit is known. By default, the previous status is kept on screen until the insert either succeeds or fails and is then replaced within a single frame; this avoids the form flickering (shrinking and then growing again) when the same error occurs on consecutive submits.
|
|
461
462
|
- `consumers`: This allows you to connect this `collection-adder` to other elements on your page. It should be used in conjunction with the `provider-template` attribute. The `consumers` attribute takes a list of selectors with optional attributes to target in the format `element-selector:attribute-name`. For example `.my-input:value` will find all elements with a `my-input` class and update their `value` attributes with the output of the `collection-adder` component on submit. You can specify multiple selectors separated by commas such as `.my-input,my-div`; in this case, because attribute names are not specified, values will be injected into the `value` attribute (for input elements) or into the `innerHTML` property (for other kinds of elements). The default attribute/property depends on the element type.
|
|
462
463
|
- `success-consumers`: Same as the `consumers` attribute but the target elements are only updated if insertion was a success.
|
|
463
464
|
- `error-consumers`: Same as the `consumers` attribute but the target elements are only updated if insertion was a failure.
|
|
@@ -499,6 +500,7 @@ This component is similar to the `collection-adder` component except that it req
|
|
|
499
500
|
- `show-field-errors`: If this attribute exists on the element, then granular error messages will be shown above each corresponding input element instead of a single form-level error message.
|
|
500
501
|
- `trim-spaces`: If this attribute exists on the element, then leading and trailing spaces will be trimmed from each input element's value before submitting the form.
|
|
501
502
|
- `auto-reset-hidden-inputs`: If this attribute exists, then `hidden` input elements which are inside the `collection-adder-form` will be cleared along with other input fields. By default, `hidden` input elements are not cleared when the form is reset.
|
|
503
|
+
- `reset-status-on-submit`: If this attribute exists, then the current message and any field errors will be cleared as soon as the form is submitted, instead of when the outcome of the submit is known. By default, the previous status is kept on screen until the insert either succeeds or fails and is then replaced within a single frame; this avoids the form flickering (shrinking and then growing again) when the same error occurs on consecutive submits.
|
|
502
504
|
- `disable-submit-on-enter-key`: If this attribute exists, then the form will not submit when the enter key is pressed.
|
|
503
505
|
- `greedy-refresh`: If this attribute exists, the component will refresh itself whenever an attribute is set, even if that attribute's value did not change.
|
|
504
506
|
- `consumers`: This allows you to connect this `collection-adder-form` to other elements on your page. It should be used in conjunction with the `provider-template` attribute. The `consumers` attribute takes a list of selectors with optional attributes to target in the format `element-selector:attribute-name`. For example `.my-input:value` will find all elements with a `my-input` class and update their `value` attributes with the output of the `collection-adder-form` component on submit. You can specify multiple selectors separated by commas such as `.my-input,my-div`; in this case, because attribute names are not specified, values will be injected into the `value` attribute (for input elements) or into the `innerHTML` property (for other kinds of elements). The default attribute/property depends on the element type.
|
|
@@ -541,6 +543,7 @@ OR (with confirmation step)
|
|
|
541
543
|
- `model-id` (required): Specifies the ID of the resource to delete from the parent collection when this component is activated. This can be achieved by invoking either the `deleteItem()` or `confirmDeleteItem()` function from inside an event handler. The example above shows how to achieve deletion via the `onclick` event. You can either invoke `deleteItem()` to delete the resource immediately or you can invoke `confirmDeleteItem()` to require additional confirmation prior to deletion.
|
|
542
544
|
- `onclick` (required): The logic to execute to delete the item. Should be either `deleteItem()` or `confirmDeleteItem()`.
|
|
543
545
|
- `confirm-message`: The confirmation message to show the user when this component's `confirmDeleteItem()` function is invoked.
|
|
546
|
+
- `confirm-heading`: The heading to show in the confirmation modal's title bar when this component's `confirmDeleteItem()` function is invoked.
|
|
544
547
|
- `model-field`: If specified, this attribute can be used to delete a single field of a model instance, instead of the whole instance.
|
|
545
548
|
|
|
546
549
|
If `confirmDeleteItem()` is used, then the parent `collection-viewer` must have a `confirm-modal` element slotted into it as shown here:
|
|
@@ -563,7 +566,7 @@ If `confirmDeleteItem()` is used, then the parent `collection-viewer` must have
|
|
|
563
566
|
<div slot="viewport" class="chat-viewport"></div>
|
|
564
567
|
|
|
565
568
|
<!-- The confirm-modal element must be specified here with slot="modal" to prompt the user for confirmation -->
|
|
566
|
-
<confirm-modal slot="modal"
|
|
569
|
+
<confirm-modal slot="modal" heading="Delete confirmation" message="" confirm-button-label="Delete"></confirm-modal>
|
|
567
570
|
</collection-viewer>
|
|
568
571
|
```
|
|
569
572
|
|
|
@@ -1173,16 +1176,17 @@ A modal component to prompt the user for confirmation before performing sensitiv
|
|
|
1173
1176
|
<div slot="viewport"></div>
|
|
1174
1177
|
|
|
1175
1178
|
<!-- The confirm-modal element must be specified here with slot="modal" to prompt the user for confirmation -->
|
|
1176
|
-
<confirm-modal slot="modal"
|
|
1179
|
+
<confirm-modal slot="modal" heading="Delete confirmation" message="" confirm-button-label="Delete"></confirm-modal>
|
|
1177
1180
|
</collection-viewer>
|
|
1178
1181
|
```
|
|
1179
1182
|
|
|
1180
1183
|
**Attributes**
|
|
1181
1184
|
|
|
1182
|
-
- `
|
|
1185
|
+
- `heading`: The text to show in the modal's title bar.
|
|
1183
1186
|
- `message`: The text to show as the modal's main content.
|
|
1184
1187
|
- `confirm-button-label`: The text to use as the confirm button label.
|
|
1185
1188
|
- `cancel-button-label`: The text to use as the cancel button label.
|
|
1189
|
+
- `auto-focus`: Which button to focus when the modal is shown; either `confirm` (or its alias `delete`) or `cancel`. If not specified, no button will be focused.
|
|
1186
1190
|
|
|
1187
1191
|
### overlay-modal
|
|
1188
1192
|
|
package/collection-adder-form.js
CHANGED
|
@@ -50,22 +50,15 @@ class CollectionAdderForm extends SocketConsumer {
|
|
|
50
50
|
throw new Error('Collection adder form is not ready to be submitted');
|
|
51
51
|
}
|
|
52
52
|
let successMessage = this.getAttribute('success-message');
|
|
53
|
-
let messageContainer
|
|
53
|
+
let messageContainer;
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
// By default, the previous status is only cleared once the outcome of the
|
|
56
|
+
// submit is known so that the status is replaced within a single frame; this
|
|
57
|
+
// avoids the form flickering when the same error occurs twice in a row.
|
|
58
|
+
if (this.hasAttribute('reset-status-on-submit')) {
|
|
59
|
+
this.clearStatus();
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
// Clear any existing field errors
|
|
62
|
-
let existingFieldErrors = this.querySelectorAll('.collection-adder-field-error-container');
|
|
63
|
-
existingFieldErrors.forEach(el => el.remove());
|
|
64
|
-
|
|
65
|
-
// Clear error classes from all inputs
|
|
66
|
-
let allInputs = this.querySelectorAll('input, textarea, select');
|
|
67
|
-
allInputs.forEach(input => input.classList.remove('error'));
|
|
68
|
-
|
|
69
62
|
let trimSpaces = this.hasAttribute('trim-spaces');
|
|
70
63
|
|
|
71
64
|
let inputElements = this.getAllInputElements();
|
|
@@ -133,6 +126,9 @@ class CollectionAdderForm extends SocketConsumer {
|
|
|
133
126
|
};
|
|
134
127
|
|
|
135
128
|
let resourceId = await this.collection.create(newModelData);
|
|
129
|
+
|
|
130
|
+
this.clearStatus();
|
|
131
|
+
|
|
136
132
|
let insertedModelData = {
|
|
137
133
|
...newModelData,
|
|
138
134
|
id: resourceId
|
|
@@ -162,6 +158,8 @@ class CollectionAdderForm extends SocketConsumer {
|
|
|
162
158
|
}
|
|
163
159
|
}
|
|
164
160
|
} catch (error) {
|
|
161
|
+
this.clearStatus();
|
|
162
|
+
|
|
165
163
|
messageContainer = this.shadowRoot.querySelector('slot[name="message"]').assignedElements()[0];
|
|
166
164
|
if (messageContainer) {
|
|
167
165
|
messageContainer.classList.add('error');
|
|
@@ -229,6 +227,24 @@ class CollectionAdderForm extends SocketConsumer {
|
|
|
229
227
|
updateConsumerElements.call(this, oppositeOutcomeConsumers, '', null, selfName);
|
|
230
228
|
}
|
|
231
229
|
|
|
230
|
+
clearStatus() {
|
|
231
|
+
let messageContainer = this.shadowRoot.querySelector('slot[name="message"]').assignedElements()[0];
|
|
232
|
+
|
|
233
|
+
if (messageContainer) {
|
|
234
|
+
messageContainer.classList.remove('success');
|
|
235
|
+
messageContainer.classList.remove('error');
|
|
236
|
+
messageContainer.textContent = '';
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Clear any existing field errors
|
|
240
|
+
let existingFieldErrors = this.querySelectorAll('.collection-adder-field-error-container');
|
|
241
|
+
existingFieldErrors.forEach(el => el.remove());
|
|
242
|
+
|
|
243
|
+
// Clear error classes from all inputs
|
|
244
|
+
let allInputs = this.querySelectorAll('input, textarea, select');
|
|
245
|
+
allInputs.forEach(input => input.classList.remove('error'));
|
|
246
|
+
}
|
|
247
|
+
|
|
232
248
|
getAllInputElements() {
|
|
233
249
|
return this.shadowRoot.querySelector('.input-slot')
|
|
234
250
|
.assignedElements()
|
package/collection-adder.js
CHANGED
|
@@ -55,17 +55,12 @@ class CollectionAdder extends SocketConsumer {
|
|
|
55
55
|
let successMessage = this.getAttribute('success-message');
|
|
56
56
|
let messageContainer = this.querySelector('.collection-adder-message-container');
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
existingFieldErrors.forEach(el => el.textContent = '');
|
|
65
|
-
|
|
66
|
-
// Clear error classes from all inputs
|
|
67
|
-
let allInputs = this.querySelectorAll('.collection-adder-input, .collection-adder-radio');
|
|
68
|
-
allInputs.forEach(input => input.classList.remove('error'));
|
|
58
|
+
// By default, the previous status is only cleared once the outcome of the
|
|
59
|
+
// submit is known so that the status is replaced within a single frame; this
|
|
60
|
+
// avoids the form flickering when the same error occurs twice in a row.
|
|
61
|
+
if (this.hasAttribute('reset-status-on-submit')) {
|
|
62
|
+
this.clearStatus();
|
|
63
|
+
}
|
|
69
64
|
|
|
70
65
|
let radioInputs = [ ...this.querySelectorAll('.collection-adder-radio') ];
|
|
71
66
|
let radioData = {};
|
|
@@ -131,6 +126,9 @@ class CollectionAdder extends SocketConsumer {
|
|
|
131
126
|
)
|
|
132
127
|
};
|
|
133
128
|
let resourceId = await this.collection.create(newModelData);
|
|
129
|
+
|
|
130
|
+
this.clearStatus();
|
|
131
|
+
|
|
134
132
|
let insertedModelData = {
|
|
135
133
|
...newModelData,
|
|
136
134
|
id: resourceId
|
|
@@ -156,6 +154,8 @@ class CollectionAdder extends SocketConsumer {
|
|
|
156
154
|
messageContainer.textContent = '';
|
|
157
155
|
}
|
|
158
156
|
} catch (error) {
|
|
157
|
+
this.clearStatus();
|
|
158
|
+
|
|
159
159
|
messageContainer.classList.add('error');
|
|
160
160
|
messageContainer.classList.remove('success');
|
|
161
161
|
|
|
@@ -213,6 +213,24 @@ class CollectionAdder extends SocketConsumer {
|
|
|
213
213
|
updateConsumerElements.call(this, oppositeOutcomeConsumers, '', null, selfName);
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
+
clearStatus() {
|
|
217
|
+
let messageContainer = this.querySelector('.collection-adder-message-container');
|
|
218
|
+
|
|
219
|
+
if (messageContainer) {
|
|
220
|
+
messageContainer.classList.remove('success');
|
|
221
|
+
messageContainer.classList.remove('error');
|
|
222
|
+
messageContainer.textContent = '';
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Clear any existing field errors
|
|
226
|
+
let existingFieldErrors = this.querySelectorAll('.collection-adder-field-error-container');
|
|
227
|
+
existingFieldErrors.forEach(el => el.textContent = '');
|
|
228
|
+
|
|
229
|
+
// Clear error classes from all inputs
|
|
230
|
+
let allInputs = this.querySelectorAll('.collection-adder-input, .collection-adder-radio');
|
|
231
|
+
allInputs.forEach(input => input.classList.remove('error'));
|
|
232
|
+
}
|
|
233
|
+
|
|
216
234
|
reset() {
|
|
217
235
|
let form = this.querySelector('.collection-adder-form');
|
|
218
236
|
if (form) {
|
package/collection-deleter.js
CHANGED
|
@@ -27,14 +27,14 @@ class CollectionDeleter extends HTMLElement {
|
|
|
27
27
|
|
|
28
28
|
showConfirmModal(deleteField) {
|
|
29
29
|
let message = this.getAttribute('confirm-message');
|
|
30
|
-
let
|
|
30
|
+
let heading = this.getAttribute('confirm-heading');
|
|
31
31
|
let confirmButtonLabel = this.getAttribute('confirm-button-label');
|
|
32
32
|
let cancelButtonLabel = this.getAttribute('cancel-button-label');
|
|
33
33
|
this.dispatchEvent(
|
|
34
34
|
new CustomEvent('showModal', {
|
|
35
35
|
detail: {
|
|
36
36
|
message,
|
|
37
|
-
|
|
37
|
+
heading,
|
|
38
38
|
confirmButtonLabel,
|
|
39
39
|
cancelButtonLabel,
|
|
40
40
|
callback: () => {
|
package/confirm-modal.js
CHANGED
|
@@ -3,7 +3,7 @@ import './overlay-modal.js';
|
|
|
3
3
|
class ConfirmModal extends HTMLElement {
|
|
4
4
|
constructor() {
|
|
5
5
|
super();
|
|
6
|
-
this.
|
|
6
|
+
this.isHidden = true;
|
|
7
7
|
this.isReady = false;
|
|
8
8
|
}
|
|
9
9
|
|
|
@@ -13,7 +13,7 @@ class ConfirmModal extends HTMLElement {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
static get observedAttributes() {
|
|
16
|
-
return [ 'message', '
|
|
16
|
+
return [ 'message', 'heading', 'confirm-button-label', 'cancel-button-label' ];
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
@@ -27,12 +27,12 @@ class ConfirmModal extends HTMLElement {
|
|
|
27
27
|
overlayModal.removeAttribute('style');
|
|
28
28
|
}
|
|
29
29
|
this.confirmCallback = confirmCallback;
|
|
30
|
-
this.
|
|
30
|
+
this.isHidden = false;
|
|
31
31
|
if (typeof options === 'string') {
|
|
32
32
|
this.setAttribute('message', options);
|
|
33
33
|
} else {
|
|
34
|
-
if (options.
|
|
35
|
-
this.setAttribute('
|
|
34
|
+
if (options.heading != null) {
|
|
35
|
+
this.setAttribute('heading', options.heading);
|
|
36
36
|
}
|
|
37
37
|
if (options.confirmButtonLabel != null) {
|
|
38
38
|
this.setAttribute('confirm-button-label', options.confirmButtonLabel);
|
|
@@ -44,17 +44,30 @@ class ConfirmModal extends HTMLElement {
|
|
|
44
44
|
this.setAttribute('message', options.message);
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
|
+
this.applyAutoFocus();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
applyAutoFocus() {
|
|
51
|
+
let autoFocus = this.getAttribute('auto-focus');
|
|
52
|
+
let selector;
|
|
53
|
+
if (autoFocus === 'confirm' || autoFocus === 'delete') {
|
|
54
|
+
selector = '.modal-confirm-button';
|
|
55
|
+
} else if (autoFocus === 'cancel') {
|
|
56
|
+
selector = '.modal-cancel-button';
|
|
57
|
+
}
|
|
58
|
+
if (!selector) return;
|
|
59
|
+
this.querySelector(selector)?.focus({ preventScroll: true });
|
|
47
60
|
}
|
|
48
61
|
|
|
49
62
|
render() {
|
|
50
63
|
let message = this.getAttribute('message') || '';
|
|
51
|
-
let
|
|
64
|
+
let heading = this.getAttribute('heading') || '';
|
|
52
65
|
let confirmButtonLabel = this.getAttribute('confirm-button-label') || 'Confirm';
|
|
53
66
|
let cancelButtonLabel = this.getAttribute('cancel-button-label') || 'Cancel';
|
|
54
67
|
|
|
55
68
|
this.innerHTML = `
|
|
56
|
-
<overlay-modal${this.
|
|
57
|
-
<div slot="title">${
|
|
69
|
+
<overlay-modal${this.isHidden ? ' style="display: none;"' : ''}>
|
|
70
|
+
<div slot="title">${heading}</div>
|
|
58
71
|
<div class="confirm-modal-content" slot="content">
|
|
59
72
|
<div>${message}</div>
|
|
60
73
|
<div class="confirm-modal-buttons-container">
|