saasufy-components 2.7.0 → 2.9.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/README.md +6 -1
- package/collection-adder.js +23 -5
- package/conditional-group.js +10 -1
- package/if-group.js +58 -0
- package/input-provider.js +11 -1
- package/model-input.js +11 -1
- package/package.json +1 -1
- package/utils.js +7 -1
package/README.md
CHANGED
|
@@ -223,10 +223,15 @@ A general purpose modal component.
|
|
|
223
223
|
|
|
224
224
|
A component which can be used to guarantee that certain children components are always rendered at the same time (once they are loaded) to provide a smooth user experience.
|
|
225
225
|
|
|
226
|
+
### if-group
|
|
227
|
+
|
|
228
|
+
A modal component which exposes a `show-content` property which can be set to true or false to show or hide its content.
|
|
229
|
+
It's intended to be placed inside a `model-viewer`, `collection-browser` or `collection-reducer` component such that the true/false value of the `show-content` attribute can be computed using a template `{{expression}}` placeholder. Unlike `conditional-group`, this component requires a template and a viewport to be slotted in. The content of the template will not be processed unless the `show-content` condition is met.
|
|
230
|
+
|
|
226
231
|
### conditional-group
|
|
227
232
|
|
|
228
233
|
A modal component which exposes a `show-content` property which can be set to true or false to show or hide its content.
|
|
229
|
-
It's intended to be placed inside a `model-viewer`, `collection-browser` or `collection-reducer` component such that the true/false value of the `show-content` attribute can be computed using a template `{{expression}}` placeholder.
|
|
234
|
+
It's intended to be placed inside a `model-viewer`, `collection-browser` or `collection-reducer` component such that the true/false value of the `show-content` attribute can be computed using a template `{{expression}}` placeholder. Unlike `if-group`, this component does not require a template, however, the trade-off is that the slotted content will be pre-processed by the browser even when the expression is false. This may not be suitable if you want to (for example) render child images conditionally because the browser will preload images based on their `src` attributes, even if they are not shown.
|
|
230
235
|
|
|
231
236
|
### collection-adder-group
|
|
232
237
|
|
package/collection-adder.js
CHANGED
|
@@ -40,7 +40,10 @@ class CollectionAdder extends SocketConsumer {
|
|
|
40
40
|
'model-values',
|
|
41
41
|
'submit-button-label',
|
|
42
42
|
'hide-submit-button',
|
|
43
|
-
'success-message'
|
|
43
|
+
'success-message',
|
|
44
|
+
'autocapitalize',
|
|
45
|
+
'autocorrect',
|
|
46
|
+
'trim-spaces'
|
|
44
47
|
];
|
|
45
48
|
}
|
|
46
49
|
|
|
@@ -106,6 +109,8 @@ class CollectionAdder extends SocketConsumer {
|
|
|
106
109
|
}
|
|
107
110
|
}
|
|
108
111
|
|
|
112
|
+
let trimSpaces = this.hasAttribute('trim-spaces');
|
|
113
|
+
|
|
109
114
|
let newModelData = {
|
|
110
115
|
...this.modelFieldValues,
|
|
111
116
|
...radioData,
|
|
@@ -121,7 +126,11 @@ class CollectionAdder extends SocketConsumer {
|
|
|
121
126
|
} else {
|
|
122
127
|
value = input.value;
|
|
123
128
|
}
|
|
124
|
-
|
|
129
|
+
let sanitizedValue = Type(value);
|
|
130
|
+
if (trimSpaces && typeof sanitizedValue === 'string') {
|
|
131
|
+
sanitizedValue = sanitizedValue.trim();
|
|
132
|
+
}
|
|
133
|
+
return [ input.name, sanitizedValue ];
|
|
125
134
|
})
|
|
126
135
|
)
|
|
127
136
|
};
|
|
@@ -188,6 +197,15 @@ class CollectionAdder extends SocketConsumer {
|
|
|
188
197
|
fieldValues: optionLabels
|
|
189
198
|
} = this.getFieldDetails(this.getAttribute('option-labels'));
|
|
190
199
|
|
|
200
|
+
let autocapitalize = this.getAttribute('autocapitalize');
|
|
201
|
+
let autocorrect = this.getAttribute('autocorrect');
|
|
202
|
+
|
|
203
|
+
let extraAttributesString = `${
|
|
204
|
+
autocapitalize ? ` autocapitalize="${autocapitalize}"` : ''
|
|
205
|
+
}${
|
|
206
|
+
autocorrect ? ` autocorrect="${autocorrect}"` : ''
|
|
207
|
+
}`;
|
|
208
|
+
|
|
191
209
|
this.modelFieldValues = modelFieldValues;
|
|
192
210
|
|
|
193
211
|
if (this.collection) this.collection.destroy();
|
|
@@ -242,7 +260,7 @@ class CollectionAdder extends SocketConsumer {
|
|
|
242
260
|
field
|
|
243
261
|
}" placeholder="${
|
|
244
262
|
inputLabel
|
|
245
|
-
}" />
|
|
263
|
+
}"${extraAttributesString} />
|
|
246
264
|
<select class="collection-adder-select">
|
|
247
265
|
<option value="" selected disabled hidden>${optionLabel}</option>
|
|
248
266
|
${inputTypeParams.map(param => `<option value="${param}">${param}</option>`).join('')}
|
|
@@ -278,7 +296,7 @@ class CollectionAdder extends SocketConsumer {
|
|
|
278
296
|
field
|
|
279
297
|
}" placeholder="${
|
|
280
298
|
inputLabel
|
|
281
|
-
}"></textarea>`
|
|
299
|
+
}"${extraAttributesString}></textarea>`
|
|
282
300
|
);
|
|
283
301
|
} else {
|
|
284
302
|
items.push(
|
|
@@ -288,7 +306,7 @@ class CollectionAdder extends SocketConsumer {
|
|
|
288
306
|
field
|
|
289
307
|
}" placeholder="${
|
|
290
308
|
inputLabel
|
|
291
|
-
}" />`
|
|
309
|
+
}"${extraAttributesString} />`
|
|
292
310
|
);
|
|
293
311
|
}
|
|
294
312
|
}
|
package/conditional-group.js
CHANGED
|
@@ -23,7 +23,16 @@ class ConditionalGroup extends HTMLElement {
|
|
|
23
23
|
|
|
24
24
|
render() {
|
|
25
25
|
let showContent = this.getAttribute('show-content');
|
|
26
|
-
|
|
26
|
+
if (
|
|
27
|
+
!showContent ||
|
|
28
|
+
showContent === 'false' ||
|
|
29
|
+
showContent === 'null' ||
|
|
30
|
+
showContent === 'undefined'
|
|
31
|
+
) {
|
|
32
|
+
this.shadowRoot.innerHTML = '';
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
this.shadowRoot.innerHTML = '<slot></slot>';
|
|
27
36
|
}
|
|
28
37
|
}
|
|
29
38
|
|
package/if-group.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { debouncer } from './utils.js';
|
|
2
|
+
|
|
3
|
+
const DEBOUNCE_DELAY = 0;
|
|
4
|
+
|
|
5
|
+
class IfGroup extends HTMLElement {
|
|
6
|
+
constructor() {
|
|
7
|
+
super();
|
|
8
|
+
this.isReady = false;
|
|
9
|
+
this.attachShadow({ mode: 'open' });
|
|
10
|
+
this.shadowRoot.innerHTML = '<slot name="content"></slot><slot name="viewport"></slot>';
|
|
11
|
+
|
|
12
|
+
let debounce = debouncer();
|
|
13
|
+
|
|
14
|
+
this.processTemplates = () => {
|
|
15
|
+
let viewportSlot = this.shadowRoot.querySelector('slot[name="viewport"]');
|
|
16
|
+
let viewportNode = viewportSlot.assignedNodes()[0];
|
|
17
|
+
if (!viewportNode) return;
|
|
18
|
+
|
|
19
|
+
let showContent = this.getAttribute('show-content');
|
|
20
|
+
if (
|
|
21
|
+
!showContent ||
|
|
22
|
+
showContent === 'false' ||
|
|
23
|
+
showContent === 'null' ||
|
|
24
|
+
showContent === 'undefined'
|
|
25
|
+
) return;
|
|
26
|
+
|
|
27
|
+
let contentSlot = this.shadowRoot.querySelector('slot[name="content"]');
|
|
28
|
+
let contentNodes = contentSlot.assignedNodes();
|
|
29
|
+
if (!contentNodes.length) return;
|
|
30
|
+
|
|
31
|
+
let contentList = [];
|
|
32
|
+
for (let node of contentNodes) {
|
|
33
|
+
contentList.push(node.innerHTML);
|
|
34
|
+
}
|
|
35
|
+
viewportNode.innerHTML = contentList.join('');
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
this.debouncedProcessTemplates = debounce(this.processTemplates, DEBOUNCE_DELAY);
|
|
39
|
+
this.shadowRoot.addEventListener('slotchange', this.debouncedProcessTemplates);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
static get observedAttributes() {
|
|
43
|
+
return [
|
|
44
|
+
'show-content'
|
|
45
|
+
];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
attributeChangedCallback() {
|
|
49
|
+
if (!this.isReady) return;
|
|
50
|
+
this.processTemplates();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
connectedCallback() {
|
|
54
|
+
this.isReady = true;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
window.customElements.define('if-group', IfGroup);
|
package/input-provider.js
CHANGED
|
@@ -28,7 +28,9 @@ class InputProvider extends HTMLElement {
|
|
|
28
28
|
'debounce-delay',
|
|
29
29
|
'options',
|
|
30
30
|
'value',
|
|
31
|
-
'height'
|
|
31
|
+
'height',
|
|
32
|
+
'autocapitalize',
|
|
33
|
+
'autocorrect'
|
|
32
34
|
];
|
|
33
35
|
}
|
|
34
36
|
|
|
@@ -59,6 +61,8 @@ class InputProvider extends HTMLElement {
|
|
|
59
61
|
render() {
|
|
60
62
|
this.innerHTML = '';
|
|
61
63
|
let inputId = this.getAttribute('input-id');
|
|
64
|
+
let autocapitalize = this.getAttribute('autocapitalize');
|
|
65
|
+
let autocorrect = this.getAttribute('autocorrect');
|
|
62
66
|
let inputList = this.getAttribute('list');
|
|
63
67
|
let type = this.getAttribute('type') || 'text';
|
|
64
68
|
let placeholder = this.getAttribute('placeholder');
|
|
@@ -97,6 +101,12 @@ class InputProvider extends HTMLElement {
|
|
|
97
101
|
if (inputId) {
|
|
98
102
|
this.inputElement.setAttribute('id', inputId);
|
|
99
103
|
}
|
|
104
|
+
if (autocapitalize) {
|
|
105
|
+
this.inputElement.setAttribute('autocapitalize', autocapitalize);
|
|
106
|
+
}
|
|
107
|
+
if (autocorrect) {
|
|
108
|
+
this.inputElement.setAttribute('autocorrect', autocorrect);
|
|
109
|
+
}
|
|
100
110
|
if (placeholder) {
|
|
101
111
|
this.inputElement.setAttribute('placeholder', placeholder);
|
|
102
112
|
}
|
package/model-input.js
CHANGED
|
@@ -36,7 +36,9 @@ class ModelInput extends SocketConsumer {
|
|
|
36
36
|
'enable-rebound',
|
|
37
37
|
'options',
|
|
38
38
|
'height',
|
|
39
|
-
'hide-error-logs'
|
|
39
|
+
'hide-error-logs',
|
|
40
|
+
'autocapitalize',
|
|
41
|
+
'autocorrect'
|
|
40
42
|
];
|
|
41
43
|
}
|
|
42
44
|
|
|
@@ -71,6 +73,8 @@ class ModelInput extends SocketConsumer {
|
|
|
71
73
|
let modelInstanceProperty = this.getAttribute('model-instance-property');
|
|
72
74
|
let showErrorMessage = this.hasAttribute('show-error-message');
|
|
73
75
|
let inputId = this.getAttribute('input-id');
|
|
76
|
+
let autocapitalize = this.getAttribute('autocapitalize');
|
|
77
|
+
let autocorrect = this.getAttribute('autocorrect');
|
|
74
78
|
let inputList = this.getAttribute('list');
|
|
75
79
|
let type = this.getAttribute('type') || 'text';
|
|
76
80
|
let placeholder = this.getAttribute('placeholder');
|
|
@@ -188,6 +192,12 @@ class ModelInput extends SocketConsumer {
|
|
|
188
192
|
if (inputId) {
|
|
189
193
|
this.inputElement.setAttribute('id', inputId);
|
|
190
194
|
}
|
|
195
|
+
if (autocapitalize) {
|
|
196
|
+
this.inputElement.setAttribute('autocapitalize', autocapitalize);
|
|
197
|
+
}
|
|
198
|
+
if (autocorrect) {
|
|
199
|
+
this.inputElement.setAttribute('autocorrect', autocorrect);
|
|
200
|
+
}
|
|
191
201
|
if (placeholder) {
|
|
192
202
|
this.inputElement.setAttribute('placeholder', placeholder);
|
|
193
203
|
}
|
package/package.json
CHANGED
package/utils.js
CHANGED
|
@@ -18,6 +18,12 @@ export function toSafeHTML(text) {
|
|
|
18
18
|
return text;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
export function toExpression(html) {
|
|
22
|
+
return html.replace(/&/g, '&')
|
|
23
|
+
.replace(/</g, '<')
|
|
24
|
+
.replace(/>/g, '>');
|
|
25
|
+
}
|
|
26
|
+
|
|
21
27
|
export function debouncer() {
|
|
22
28
|
let debounceTimeout = null;
|
|
23
29
|
return function (callback, duration) {
|
|
@@ -213,7 +219,7 @@ export function renderTemplate(templateString, data, socket) {
|
|
|
213
219
|
try {
|
|
214
220
|
return toSafeHTML(
|
|
215
221
|
execExpression(
|
|
216
|
-
expString,
|
|
222
|
+
toExpression(expString),
|
|
217
223
|
options
|
|
218
224
|
)
|
|
219
225
|
);
|