@descope/web-components-ui 1.0.279 → 1.0.280

Sign up to get free protection for your applications and to get access to all the features.
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 };