@descope/web-components-ui 1.0.279 → 1.0.280

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 (47) hide show
  1. package/dist/cjs/index.cjs.js +1123 -890
  2. package/dist/cjs/index.cjs.js.map +1 -1
  3. package/dist/index.d.ts +1 -0
  4. package/dist/index.esm.js +1581 -964
  5. package/dist/index.esm.js.map +1 -1
  6. package/dist/umd/1000.js +1 -1
  7. package/dist/umd/1438.js +2 -2
  8. package/dist/umd/{9558.js → 1621.js} +117 -117
  9. package/dist/umd/2066.js +1 -1
  10. package/dist/umd/3280.js +197 -0
  11. package/dist/umd/3280.js.LICENSE.txt +29 -0
  12. package/dist/umd/{6542.js → 3951.js} +6 -6
  13. package/dist/umd/{6542.js.LICENSE.txt → 3951.js.LICENSE.txt} +0 -6
  14. package/dist/umd/422.js +1 -1
  15. package/dist/umd/5806.js +1 -1
  16. package/dist/umd/6770.js +1 -1
  17. package/dist/umd/6977.js +2 -0
  18. package/dist/umd/6977.js.LICENSE.txt +5 -0
  19. package/dist/umd/7056.js +1 -1
  20. package/dist/umd/7531.js +2 -2
  21. package/dist/umd/7583.js +2 -2
  22. package/dist/umd/8725.js +1 -1
  23. package/dist/umd/9092.js +2 -2
  24. package/dist/umd/9437.js +1 -1
  25. package/dist/umd/descope-combo-box-index-js.js +1 -1
  26. package/dist/umd/descope-notification-descope-notification-card-index-js.js +1 -1
  27. package/dist/umd/descope-notification-index-js.js +1 -1
  28. package/dist/umd/index.js +1 -1
  29. package/dist/umd/mapping-fields-descope-mappings-field-descope-mapping-item-index-js.js +1 -0
  30. package/dist/umd/mapping-fields-descope-mappings-field-descope-mappings-field-internal-index-js.js +1 -0
  31. package/dist/umd/mapping-fields-descope-mappings-field-index-js.js +1 -0
  32. package/package.json +4 -1
  33. package/src/components/descope-combo-box/ComboBoxClass.js +4 -0
  34. package/src/components/mapping-fields/descope-mappings-field/MappingsFieldClass.js +159 -0
  35. package/src/components/mapping-fields/descope-mappings-field/descope-mapping-item/MappingItem.js +158 -0
  36. package/src/components/mapping-fields/descope-mappings-field/descope-mapping-item/index.js +3 -0
  37. package/src/components/mapping-fields/descope-mappings-field/descope-mappings-field-internal/MappingsFieldInternal.js +232 -0
  38. package/src/components/mapping-fields/descope-mappings-field/descope-mappings-field-internal/index.js +3 -0
  39. package/src/components/mapping-fields/descope-mappings-field/index.js +14 -0
  40. package/src/index.cjs.js +1 -0
  41. package/src/index.d.ts +1 -0
  42. package/src/index.js +1 -0
  43. package/src/mixins/inputValidationMixin.js +8 -0
  44. package/src/mixins/proxyInputMixin.js +48 -6
  45. package/src/theme/components/index.js +2 -0
  46. package/src/theme/components/mappingsField.js +25 -0
  47. /package/dist/umd/{9558.js.LICENSE.txt → 1621.js.LICENSE.txt} +0 -0
@@ -0,0 +1,232 @@
1
+ import { createBaseInputClass } from '../../../../baseClasses/createBaseInputClass';
2
+ import { getComponentName, forwardAttrs } from '../../../../helpers/componentHelpers';
3
+
4
+ export const componentName = getComponentName('mappings-field-internal');
5
+
6
+ const BaseInputClass = createBaseInputClass({ componentName, baseSelector: 'div' });
7
+
8
+ class MappingsFieldInternal extends BaseInputClass {
9
+ #errorItem;
10
+
11
+ static get observedAttributes() {
12
+ return [].concat(BaseInputClass.observedAttributes || [], [
13
+ 'label-value',
14
+ 'label-attr',
15
+ 'button-label',
16
+ 'invalid',
17
+ 'readonly',
18
+ 'disabled',
19
+ ]);
20
+ }
21
+
22
+ // eslint-disable-next-line class-methods-use-this
23
+ isValidDataType(data) {
24
+ try {
25
+ return data.every(
26
+ (obj) =>
27
+ typeof obj === 'object' &&
28
+ !Array.isArray(obj) &&
29
+ Object.getOwnPropertyNames(obj).length === 1 &&
30
+ typeof obj[Object.keys(obj)[0]] === 'string' &&
31
+ obj[Object.keys(obj)[0]].trim() !== ''
32
+ );
33
+ } catch (e) {
34
+ return false;
35
+ }
36
+ }
37
+
38
+ get labelValue() {
39
+ return this.getAttribute('label-value') || 'Value';
40
+ }
41
+
42
+ get labelAttr() {
43
+ return this.getAttribute('label-attr') || 'Attribute';
44
+ }
45
+
46
+ get buttonLabel() {
47
+ return this.getAttribute('button-label') || 'Add mapping';
48
+ }
49
+
50
+ get options() {
51
+ return this.getAttribute('options') || [];
52
+ }
53
+
54
+ addNewMappingItem() {
55
+ const newMappingItem = document.createElement('descope-mapping-item');
56
+ newMappingItem.setAttribute('bordered', 'true');
57
+ this.mappingsContainerEle.appendChild(newMappingItem);
58
+ forwardAttrs(this, newMappingItem, {
59
+ includeAttrs: ['size', 'full-width', 'separator', 'options', 'disabled'],
60
+ });
61
+ // This needs to be done with the timeout, otherwise the validation is performed
62
+ // before the new item is added and thus returns a wrong result
63
+ setTimeout(() => {
64
+ this.setCustomValidity('');
65
+ newMappingItem.addEventListener('mapping-item-removed', (e) => {
66
+ // If the removed item was the one that was invalid, we need to reset the invalid indication for the internal
67
+ if (newMappingItem === this.#errorItem) {
68
+ this.resetInvalidIndication();
69
+ this.#errorItem = undefined;
70
+ }
71
+ newMappingItem.remove();
72
+ this.setCustomValidity('');
73
+ e.stopPropagation();
74
+ });
75
+ }, 0);
76
+ return newMappingItem;
77
+ }
78
+
79
+ get items() {
80
+ return Array.from(this.mappingsContainerEle.querySelectorAll('descope-mapping-item'));
81
+ }
82
+
83
+ get value() {
84
+ return this.items.reduce((acc, item) => {
85
+ if (!item.value) {
86
+ return acc;
87
+ }
88
+
89
+ return [...acc, item.value];
90
+ }, []);
91
+ }
92
+
93
+ set value(mappings) {
94
+ if (!this.isValidDataType(mappings)) {
95
+ // eslint-disable-next-line no-console
96
+ console.error(
97
+ 'received invalid value to set - should be an array of objects with one key-value pair'
98
+ );
99
+ return;
100
+ }
101
+
102
+ const currentItems = this.items;
103
+
104
+ // Remove extra mapping items we don't need
105
+ if (currentItems.length > mappings.length) {
106
+ for (let i = mappings.length; i < currentItems.length; i++) {
107
+ this.mappingsContainerEle.removeChild(currentItems[i]);
108
+ }
109
+ }
110
+
111
+ // Add or update items
112
+ mappings.forEach((mapping, index) => {
113
+ const mappingItem = currentItems[index];
114
+ if (mappingItem) {
115
+ // Set existing item value
116
+ mappingItem.value = mapping;
117
+ } else {
118
+ // Add new item
119
+ const newMappingItem = this.addNewMappingItem();
120
+ // Setting the new item value needs to be done with the timeout,
121
+ // otherwise the value is not set correctly
122
+ setTimeout(() => {
123
+ newMappingItem.value = mapping;
124
+ }, 0);
125
+ }
126
+ });
127
+ }
128
+
129
+ constructor() {
130
+ super();
131
+
132
+ this.innerHTML = `
133
+ <div class="labels-container" part="labels"></div>
134
+ <div class="mappings-container"></div>
135
+ <div class="button-container"></div>
136
+ `;
137
+
138
+ this.labelsEle = this.querySelector('.labels-container');
139
+ this.mappingsContainerEle = this.querySelector('.mappings-container');
140
+ this.buttonContainer = this.querySelector('.button-container');
141
+ }
142
+
143
+ initLabels() {
144
+ this.labelsEle.innerHTML = `
145
+ <descope-text variant="body2" part="value-label">${this.labelValue}</descope-text>
146
+ <descope-text variant="body2" part="attr-label">${this.labelAttr}</descope-text>
147
+ `;
148
+ }
149
+
150
+ initAddButton() {
151
+ this.buttonContainer.innerHTML = `
152
+ <descope-button variant="link" mode="primary" disabled="${this.isDisabled}">
153
+ <vaadin-icon icon="vaadin:plus"></vaadin-icon>
154
+ ${this.buttonLabel}
155
+ </descope-button>
156
+ `;
157
+ const button = this.querySelector('descope-button');
158
+ button.onclick = () => {
159
+ this.addNewMappingItem();
160
+ };
161
+ forwardAttrs(this, button, {
162
+ includeAttrs: ['disabled'],
163
+ });
164
+ }
165
+
166
+ init() {
167
+ // This event listener needs to be placed before the super.init() call
168
+ this.addEventListener('focus', (e) => {
169
+ // we want to ignore focus events we are dispatching
170
+ if (e.isTrusted) {
171
+ const focusedElement =
172
+ this.#errorItem || this.items[0] || this.querySelector('descope-button');
173
+ focusedElement.focus();
174
+ }
175
+ });
176
+
177
+ super.init?.();
178
+ this.initLabels();
179
+ this.initAddButton();
180
+
181
+ // This event listener is responsible for removing the invalid attribute
182
+ // from the internal once the invalid item turns valid
183
+ this.addEventListener('input', () => {
184
+ const isErrorItemMounted = this.mappingsContainerEle.contains(this.#errorItem);
185
+ if (isErrorItemMounted && this.#errorItem?.checkValidity()) {
186
+ // Item has changed, it was invalid before and now it's valid
187
+ this.resetInvalidIndication();
188
+ this.#errorItem.removeAttribute('invalid');
189
+ this.#errorItem = undefined;
190
+ }
191
+ });
192
+ }
193
+
194
+ resetInvalidIndication() {
195
+ this.removeAttribute('invalid');
196
+ }
197
+
198
+ getValidity() {
199
+ const errorItem = this.items.find((item) => !item.checkValidity());
200
+ if (errorItem) {
201
+ return errorItem.validity;
202
+ }
203
+
204
+ return {};
205
+ }
206
+
207
+ #handleInvalidMappings(isInvalid) {
208
+ if (isInvalid) {
209
+ this.#errorItem = this.items.find((item) => !item.checkValidity());
210
+ this.#errorItem?.reportValidity();
211
+ this.#errorItem?.setAttribute('invalid', 'true');
212
+ }
213
+ }
214
+
215
+ attributeChangedCallback(attrName, oldValue, newValue) {
216
+ super.attributeChangedCallback?.(attrName, oldValue, newValue);
217
+ if (attrName === 'label-value' || attrName === 'label-attr') {
218
+ this.initLabels();
219
+ }
220
+ if (attrName === 'button-label') {
221
+ this.initAddButton();
222
+ }
223
+ if (attrName === 'invalid') {
224
+ this.#handleInvalidMappings(newValue === 'true');
225
+ }
226
+ if (attrName === 'readonly') {
227
+ this.toggleAttribute('inert', newValue === 'true');
228
+ }
229
+ }
230
+ }
231
+
232
+ export default MappingsFieldInternal;
@@ -0,0 +1,3 @@
1
+ import MappingsFieldInternal, { componentName } from './MappingsFieldInternal';
2
+
3
+ customElements.define(componentName, MappingsFieldInternal);
@@ -0,0 +1,14 @@
1
+ import '@vaadin/custom-field';
2
+ import '@vaadin/icon';
3
+ import '@vaadin/icons';
4
+ import { componentName, MappingsFieldClass } from './MappingsFieldClass';
5
+ import '../../descope-text';
6
+ import '../../descope-button';
7
+ import '../../descope-text-field';
8
+ import '../../descope-combo-box';
9
+ import './descope-mappings-field-internal';
10
+ import './descope-mapping-item';
11
+
12
+ customElements.define(componentName, MappingsFieldClass);
13
+
14
+ export { MappingsFieldClass };
package/src/index.cjs.js CHANGED
@@ -37,3 +37,4 @@ export { NotificationClass } from './components/descope-notification/Notificatio
37
37
  export { GridClass } from './components/descope-grid/GridClass';
38
38
  export { BadgeClass } from './components/descope-badge/BadgeClass';
39
39
  export { MultiSelectComboBoxClass } from './components/descope-multi-select-combo-box/MultiSelectComboBoxClass';
40
+ export { MappingsFieldClass } from './components/mapping-fields/descope-mappings-field/MappingsFieldClass';
package/src/index.d.ts CHANGED
@@ -42,6 +42,7 @@ export { ModalClass } from './components/descope-modal/ModalClass';
42
42
  export { NotificationClass } from './components/descope-notification/';
43
43
  export { BadgeClass } from './components/descope-badge/';
44
44
  export { MultiSelectComboBoxClass } from './components/descope-multi-select-combo-box/';
45
+ export { MappingsFieldClass } from './components/mapping-fields/descope-mappings-field/';
45
46
 
46
47
  export type Theme = {
47
48
  globals: {
package/src/index.js CHANGED
@@ -31,6 +31,7 @@ export * from './components/descope-multi-select-combo-box';
31
31
  export * from './components/descope-badge';
32
32
  export * from './components/descope-modal';
33
33
  export * from './components/descope-notification';
34
+ export * from './components/mapping-fields/descope-mappings-field';
34
35
 
35
36
  export {
36
37
  globalsThemeToStyle,
@@ -20,6 +20,14 @@ export const inputValidationMixin = (superclass) =>
20
20
 
21
21
  #internals;
22
22
 
23
+ get internals() {
24
+ return this.#internals;
25
+ }
26
+
27
+ set internals(value) {
28
+ this.#internals = value;
29
+ }
30
+
23
31
  constructor() {
24
32
  super();
25
33
 
@@ -38,7 +38,10 @@ const proxyInputMixin =
38
38
  ({
39
39
  proxyProps = [],
40
40
  // allows us to set the event that should trigger validation
41
+ // it can be either a string or an array of strings (for multiple events)
41
42
  inputEvent = 'input',
43
+ // Proxies all validations from the parent component to the input element
44
+ proxyParentValidation = false,
42
45
  }) =>
43
46
  (superclass) =>
44
47
  class ProxyInputMixinClass extends inputValidationMixin(superclass) {
@@ -128,12 +131,16 @@ const proxyInputMixin =
128
131
  // on some cases the base element is not ready so the inputElement is empty
129
132
  // we are deferring this section to make sure the base element is ready
130
133
  setTimeout(() => {
131
- this.baseElement?.addEventListener(inputEvent, () => {
132
- if (!this.baseElement.checkValidity()) {
133
- this.#handleErrorMessage();
134
- } else {
135
- this.removeAttribute('invalid');
136
- }
134
+ const validationEvents = Array.isArray(inputEvent) ? inputEvent : [inputEvent];
135
+
136
+ validationEvents.forEach((e) => {
137
+ this.baseElement?.addEventListener(e, () => {
138
+ if (!this.baseElement.checkValidity()) {
139
+ this.#handleErrorMessage();
140
+ } else {
141
+ this.removeAttribute('invalid');
142
+ }
143
+ });
137
144
  });
138
145
 
139
146
  this.baseElement.addEventListener('change', () => {
@@ -156,6 +163,41 @@ const proxyInputMixin =
156
163
 
157
164
  forwardAttrs(this, this.inputElement, { includeAttrs: ['inputmode'] });
158
165
  });
166
+
167
+ if (proxyParentValidation) {
168
+ // All functions called on the inputElement internals will be applied to the parent
169
+ // component internals as well. As a result, there's no need to add outer mechanisms
170
+ // to update the parent component's validity state based on the input elements validity.
171
+ const inputElementInternals = this.inputElement.internals;
172
+ const parentThis = this;
173
+ this.inputElement.internals = new Proxy(inputElementInternals, {
174
+ get: (target, prop) => {
175
+ if (typeof target[prop] === 'function' && prop === 'setValidity') {
176
+ return (...args) => {
177
+ // If we're calling setValidity with 3 args, then the validationTarget
178
+ // needs to be swapped to be the inputElement
179
+ if (args.length === 3) {
180
+ const newArgs = args.slice(0, args.length - 1);
181
+ newArgs.push(parentThis.inputElement);
182
+ parentThis.internals[prop](...newArgs);
183
+ } else {
184
+ parentThis.internals[prop](...args);
185
+ }
186
+ return target[prop](...args);
187
+ };
188
+ }
189
+
190
+ if (typeof target[prop] === 'function') {
191
+ return (...args) => {
192
+ parentThis.internals[prop](...args);
193
+ return target[prop](...args);
194
+ };
195
+ }
196
+
197
+ return target[prop];
198
+ },
199
+ });
200
+ }
159
201
  }
160
202
  };
161
203
 
@@ -30,6 +30,7 @@ import * as grid from './grid';
30
30
  import * as notificationCard from './notificationCard';
31
31
  import * as multiSelectComboBox from './multiSelectComboBox';
32
32
  import * as badge from './badge';
33
+ import * as mappingsField from './mappingsField';
33
34
 
34
35
  const components = {
35
36
  button,
@@ -65,6 +66,7 @@ const components = {
65
66
  notificationCard,
66
67
  multiSelectComboBox,
67
68
  badge,
69
+ mappingsField,
68
70
  };
69
71
 
70
72
  const theme = Object.keys(components).reduce(
@@ -0,0 +1,25 @@
1
+ import globals from '../globals';
2
+ import { MappingsFieldClass } from '../../components/mapping-fields/descope-mappings-field/MappingsFieldClass';
3
+ import { getThemeRefs } from '../../helpers/themeHelpers';
4
+ import { refs } from './inputWrapper';
5
+
6
+ const globalRefs = getThemeRefs(globals);
7
+
8
+ const vars = MappingsFieldClass.cssVarList;
9
+
10
+ export const mappingsField = {
11
+ [vars.hostWidth]: refs.width,
12
+ [vars.hostDirection]: refs.direction,
13
+ [vars.fontSize]: refs.fontSize,
14
+ [vars.fontFamily]: refs.fontFamily,
15
+ [vars.separatorFontSize]: '14px',
16
+ [vars.labelTextColor]: refs.labelTextColor,
17
+ [vars.itemMarginBottom]: '1em',
18
+ // To be positioned correctly, the min width has to match the text field min width
19
+ [vars.valueLabelMinWidth]: refs.minWidth,
20
+ // To be positioned correctly, the min width has to match the combo box field min width
21
+ [vars.attrLabelMinWidth]: `calc(12em + 2 * ${globalRefs.border.xs})`,
22
+ };
23
+
24
+ export default mappingsField;
25
+ export { vars };