saasufy-components 2.15.2 → 2.16.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 CHANGED
@@ -356,6 +356,7 @@ Used for displaying and editing a single field of a model instance in real time.
356
356
  - `type`: The type of the input component; can be `text`, `number`, `select`, `textarea` or `checkbox`.
357
357
  - `placeholder`: Can be used to set the placeholder text on the inner input element.
358
358
  - `consumers`: This allows you to connect this `model-input` to other elements on your page which share the same parent element. It takes a list of selectors with optional attributes to target. For example `.my-input:value` will find all elements with a `my-input` class and update their `value` attributes with the value of the `model-input` component in real-time. 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.
359
+ - `provider-template`: A template string within which the `{{value}}` can be injected before passing to consumers.
359
360
  - `show-error-message`: If this attribute is present, an error message will be displayed above the input if it fails to update the value.
360
361
  - `options`: A comma-separated list of options to provide - This only works if the input type is `select`.
361
362
  - `height`: Allows you to set the height of the inner `input` element programmatically.
@@ -426,7 +427,6 @@ Used for rendering a single model resource using a template. This is the single-
426
427
  An input component which can pass data to other components (or HTML elements) via custom attributes.
427
428
  A common use case for it is to pass user input to `collection-browser` or `model-viewer` components to then fetch data from Saasufy.
428
429
  This component can be configured to provide its data to multiple components (consumers) via custom attributes.
429
- Note that an `input-provider` only targets elements which are downstream from its parent element in the HTML hierarchy.
430
430
 
431
431
  **Example usage**
432
432
 
@@ -446,6 +446,7 @@ Note that an `input-provider` only targets elements which are downstream from it
446
446
  - `type`: The type of the input component; can be `text`, `number`, `select`, `textarea` or `checkbox`.
447
447
  - `placeholder`: Can be used to set the placeholder text on the inner input element.
448
448
  - `consumers`: This allows you to connect this `input-provider` to other elements on your page which share the same parent element. It takes a list of selectors with optional attributes to target. For example `.my-input:value` will find all elements with a `my-input` class and update their `value` attributes with the value of the `input-provider` component in real-time. 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.
449
+ - `provider-template`: A template string within which the `{{value}}` can be injected before passing to consumers.
449
450
  - `debounce-delay`: The delay in milliseconds to wait before triggering a change event. This is useful to batch multiple updates together (as is common when user is typing). Default is 800ms.
450
451
  - `options`: A comma-separated list of options to provide - This only works if the input type is `select`.
451
452
  - `height`: Allows you to set the height of the inner `input` element programmatically.
package/input-provider.js CHANGED
@@ -135,20 +135,21 @@ class InputProvider extends HTMLElement {
135
135
 
136
136
  let onInputChange = (event) => {
137
137
  debounce(async () => {
138
+ let providerTemplate = this.getAttribute('provider-template');
138
139
  if (event.target.value === this.lastValue) return;
139
140
  if (inputElement.type === 'checkbox') {
140
141
  let checked = !!inputElement.checked;
141
142
  this.lastValue = checked;
142
- updateConsumerElements(this.parentElement, consumers, checked);
143
+ updateConsumerElements(consumers, checked, providerTemplate);
143
144
  return;
144
145
  }
145
146
  this.lastValue = event.target.value;
146
147
  if (event.target.value === '') {
147
- updateConsumerElements(this.parentElement, consumers, '');
148
+ updateConsumerElements(consumers, '', providerTemplate);
148
149
  } else {
149
150
  let targetValue = inputElement.type === 'number' ?
150
151
  Number(event.target.value) : event.target.value;
151
- updateConsumerElements(this.parentElement, consumers, targetValue);
152
+ updateConsumerElements(consumers, targetValue, providerTemplate);
152
153
  }
153
154
  }, debounceDelay);
154
155
  };
@@ -158,14 +159,15 @@ class InputProvider extends HTMLElement {
158
159
  if (inputElement.type !== 'checkbox') {
159
160
  onInputKeyUp = async (event) => {
160
161
  debounce(async () => {
162
+ let providerTemplate = this.getAttribute('provider-template');
161
163
  if (event.target.value === this.lastValue) return;
162
164
  this.lastValue = event.target.value;
163
165
  if (event.target.value === '') {
164
- updateConsumerElements(this.parentElement, consumers, '');
166
+ updateConsumerElements(consumers, '', providerTemplate);
165
167
  } else {
166
168
  let targetValue = inputElement.type === 'number' ?
167
169
  Number(event.target.value) : event.target.value;
168
- updateConsumerElements(this.parentElement, consumers, targetValue);
170
+ updateConsumerElements(consumers, targetValue, providerTemplate);
169
171
  }
170
172
  }, debounceDelay);
171
173
  };
package/model-input.js CHANGED
@@ -248,14 +248,15 @@ class ModelInput extends SocketConsumer {
248
248
 
249
249
  updateInputElement(inputElement, fieldValue) {
250
250
  let consumers = this.getAttribute('consumers');
251
+ let providerTemplate = this.getAttribute('provider-template');
251
252
  if (inputElement.type === 'checkbox') {
252
253
  let checked = !!fieldValue;
253
254
  inputElement.checked = checked;
254
- updateConsumerElements(this.parentElement, consumers, checked);
255
+ updateConsumerElements(consumers, checked, providerTemplate);
255
256
  } else {
256
257
  let defaultValue = this.getAttribute('default-value') || '';
257
258
  inputElement.value = fieldValue == null ? defaultValue : fieldValue;
258
- updateConsumerElements(this.parentElement, consumers, inputElement.value);
259
+ updateConsumerElements(consumers, inputElement.value, providerTemplate);
259
260
  }
260
261
  }
261
262
 
@@ -305,10 +306,11 @@ class ModelInput extends SocketConsumer {
305
306
  let onInputChange = (event) => {
306
307
  if (event.target.value === String(model.value[fieldName])) return;
307
308
  debounce(async () => {
309
+ let providerTemplate = this.getAttribute('provider-template');
308
310
  try {
309
311
  if (inputElement.type === 'checkbox') {
310
312
  let checked = !!inputElement.checked;
311
- updateConsumerElements(this.parentElement, consumers, checked);
313
+ updateConsumerElements(consumers, checked, providerTemplate);
312
314
  await model.update(fieldName, checked);
313
315
  inputElement.classList.remove(errorStyleClass);
314
316
  inputElement.classList.add(successStyleClass);
@@ -316,12 +318,12 @@ class ModelInput extends SocketConsumer {
316
318
  return;
317
319
  }
318
320
  if (event.target.value === '') {
319
- updateConsumerElements(this.parentElement, consumers, '');
321
+ updateConsumerElements(consumers, '', providerTemplate);
320
322
  await model.delete(fieldName);
321
323
  } else {
322
324
  let targetValue = inputElement.type === 'number' ?
323
325
  Number(event.target.value) : event.target.value;
324
- updateConsumerElements(this.parentElement, consumers, targetValue);
326
+ updateConsumerElements(consumers, targetValue, providerTemplate);
325
327
  await model.update(fieldName, targetValue);
326
328
  }
327
329
  inputElement.classList.remove(errorStyleClass);
@@ -340,14 +342,15 @@ class ModelInput extends SocketConsumer {
340
342
  if (inputElement.type !== 'checkbox' && inputElement.type !== 'select') {
341
343
  onInputKeyUp = async (event) => {
342
344
  debounce(async () => {
345
+ let providerTemplate = this.getAttribute('provider-template');
343
346
  try {
344
347
  if (event.target.value === '') {
345
348
  await model.delete(fieldName);
346
- updateConsumerElements(this.parentElement, consumers, '');
349
+ updateConsumerElements(consumers, '', providerTemplate);
347
350
  } else {
348
351
  let targetValue = inputElement.type === 'number' ?
349
352
  Number(event.target.value) : event.target.value;
350
- updateConsumerElements(this.parentElement, consumers, targetValue);
353
+ updateConsumerElements(consumers, targetValue, providerTemplate);
351
354
  await model.update(fieldName, targetValue);
352
355
  }
353
356
  inputElement.classList.remove(errorStyleClass);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "saasufy-components",
3
- "version": "2.15.2",
3
+ "version": "2.16.0",
4
4
  "description": "Components for Saasufy.",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/utils.js CHANGED
@@ -232,8 +232,8 @@ export function renderTemplate(templateString, data, socket) {
232
232
  });
233
233
  }
234
234
 
235
- export function updateConsumerElements(parentElement, consumers, value) {
236
- if (parentElement && consumers) {
235
+ export function updateConsumerElements(consumers, value, template) {
236
+ if (consumers) {
237
237
  let consumerParts = consumers.split(',')
238
238
  .filter(part => part)
239
239
  .map(part => {
@@ -242,8 +242,15 @@ export function updateConsumerElements(parentElement, consumers, value) {
242
242
  })
243
243
  .filter(([ selector, attributeName ]) => selector);
244
244
 
245
+ if (template) {
246
+ value = renderTemplate(
247
+ template,
248
+ { value }
249
+ );
250
+ }
251
+
245
252
  for (let [ selector, attributeName ] of consumerParts) {
246
- let matchingElements = parentElement.querySelectorAll(selector);
253
+ let matchingElements = document.querySelectorAll(selector);
247
254
  if (attributeName) {
248
255
  for (let element of matchingElements) {
249
256
  if (typeof value === 'boolean') {