@descope/web-components-ui 1.0.290 → 1.0.292

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. package/dist/cjs/index.cjs.js +1336 -912
  2. package/dist/cjs/index.cjs.js.map +1 -1
  3. package/dist/index.d.ts +2 -0
  4. package/dist/index.esm.js +1565 -967
  5. package/dist/index.esm.js.map +1 -1
  6. package/dist/umd/1000.js +1 -1
  7. package/dist/umd/descope-grid-index-js.js +1 -1
  8. package/dist/umd/descope-new-password-descope-new-password-internal-index-js.js +1 -1
  9. package/dist/umd/descope-new-password-index-js.js +1 -1
  10. package/dist/umd/descope-policy-validation-index-js.js +1 -0
  11. package/dist/umd/index.js +1 -1
  12. package/dist/umd/mapping-fields-descope-mappings-field-descope-mapping-item-index-js.js +1 -1
  13. package/dist/umd/mapping-fields-descope-mappings-field-descope-mappings-field-internal-index-js.js +1 -1
  14. package/dist/umd/mapping-fields-descope-mappings-field-index-js.js +2 -2
  15. package/dist/umd/mapping-fields-descope-saml-group-mappings-descope-saml-group-mappings-internal-index-js.js +1 -0
  16. package/dist/umd/mapping-fields-descope-saml-group-mappings-index-js.js +1 -0
  17. package/package.json +1 -1
  18. package/src/components/descope-new-password/NewPasswordClass.js +30 -2
  19. package/src/components/descope-new-password/descope-new-password-internal/NewPasswordInternal.js +51 -3
  20. package/src/components/descope-new-password/index.js +1 -0
  21. package/src/components/descope-policy-validation/PolicyValidationClass.js +220 -0
  22. package/src/components/descope-policy-validation/helpers.js +2 -0
  23. package/src/components/descope-policy-validation/index.js +5 -0
  24. package/src/components/mapping-fields/descope-mappings-field/MappingsFieldClass.js +14 -1
  25. package/src/components/mapping-fields/descope-mappings-field/descope-mapping-item/MappingItem.js +1 -1
  26. package/src/components/mapping-fields/descope-mappings-field/descope-mappings-field-internal/MappingsFieldInternal.js +2 -2
  27. package/src/components/mapping-fields/descope-saml-group-mappings/SamlGroupMappingsClass.js +110 -0
  28. package/src/components/mapping-fields/descope-saml-group-mappings/descope-saml-group-mappings-internal/SamlGroupMappingsInternal.js +136 -0
  29. package/src/components/mapping-fields/descope-saml-group-mappings/descope-saml-group-mappings-internal/index.js +3 -0
  30. package/src/components/mapping-fields/descope-saml-group-mappings/index.js +10 -0
  31. package/src/index.cjs.js +2 -0
  32. package/src/index.d.ts +2 -0
  33. package/src/index.js +2 -0
  34. package/src/mixins/proxyInputMixin.js +7 -0
  35. package/src/theme/components/index.js +4 -0
  36. package/src/theme/components/inputWrapper.js +3 -1
  37. package/src/theme/components/mappingsField.js +3 -1
  38. package/src/theme/components/newPassword.js +5 -0
  39. package/src/theme/components/policyValidation.js +29 -0
  40. package/src/theme/components/samlGroupMappings.js +13 -0
@@ -0,0 +1 @@
1
+ "use strict";(self.webpackChunkDescopeUI=self.webpackChunkDescopeUI||[]).push([[9476,9656],{6867:(e,t,i)=>{i.d(t,{Z:()=>p,f:()=>a});var n=i(3878),s=i(4567);const a=(0,s.iY)("saml-group-mappings-internal"),l=(0,n.P)({componentName:a,baseSelector:""}),p=class extends l{static get observedAttributes(){return["invalid"].concat(l.observedAttributes||[])}constructor(){super(),this.innerHTML='\n <descope-text-field variant="body2" bordered="true"></descope-text-field>\n <descope-mappings-field></descope-mappings-field>\n ',this.groupInputElement=this.querySelector("descope-text-field"),this.mappingsElement=this.querySelector("descope-mappings-field")}resetInvalidIndication(){this.removeAttribute("invalid")}handleMappingsInvalidChange(e){e.includes("invalid")&&(this.mappingsElement.hasAttribute("invalid")||this.resetInvalidIndication())}initFocusHandler(){this.addEventListener("focus",(e=>{e.isTrusted&&(this.mappingsElement.checkValidity()?this.groupInputElement:this.mappingsElement).focus()}))}init(){this.initFocusHandler(),super.init?.(),(0,s.oP)(this,this.groupInputElement,{mapAttrs:{"label-group":"label"},includeAttrs:["size","label-group","readonly","disabled"]}),(0,s.oP)(this,this.mappingsElement,{includeAttrs:["size","full-width","label-value","label-attr","button-label","separator","options","readonly","disabled","data-errormessage-pattern-mismatch"]}),(0,s.FX)(this.mappingsElement,this.handleMappingsInvalidChange.bind(this),{includeAttrs:["invalid"]})}get value(){return{group:this.groupInputElement.value,mappings:this.mappingsElement.value}}set value(e){e?.group&&"string"==typeof e.group&&(this.groupInputElement.value=e.group),Array.isArray(e?.mappings)&&(this.mappingsElement.value=e.mappings)}getValidity(){return this.groupInputElement.checkValidity()?this.mappingsElement.checkValidity()?{}:this.mappingsElement.validity:this.groupInputElement.validity}#e(e){if(e){if(!this.groupInputElement.checkValidity())return void this.groupInputElement.setAttribute("invalid","true");this.mappingsElement.checkValidity()||this.mappingsElement.setAttribute("invalid","true")}}attributeChangedCallback(e,t,i){super.attributeChangedCallback?.(e,t,i),"invalid"===e&&this.#e("true"===i)}}},4115:(e,t,i)=>{i.r(t);var n=i(6867);customElements.define(n.f,n.Z)},3277:(e,t,i)=>{i.r(t),i.d(t,{SamlGroupMappingsClass:()=>d}),i(9381);var n=i(1e3),s=i(2061),a=i(4567),l=i(6867);const p=(0,a.iY)("saml-group-mappings"),{host:r,groupInput:o}={host:{selector:()=>":host"},groupInput:{selector:"descope-text-field"}},d=(0,s.qC)((0,n.yk)({mappings:{hostWidth:{...r,property:"width"},hostDirection:{...r,property:"direction"},groupNameInputMarginBottom:{...o,property:"margin-bottom"}}}),n.e4,(0,n.dj)({proxyProps:["value","selectionStart"],inputEvent:"input",triggerValidationEvents:["mapping-item-added","mapping-item-removed"],proxyParentValidation:!0}),n.Ae,(e=>class extends e{init(){super.init?.();const e=document.createElement("template");e.innerHTML=`\n <${l.f}\n tabindex="-1"\n ></${l.f}>\n `,this.baseElement.appendChild(e.content.cloneNode(!0)),this.inputElement=this.shadowRoot.querySelector(l.f),(0,a.oP)(this,this.inputElement,{includeAttrs:["size","full-width","label-group","label-value","label-attr","button-label","separator","options","readonly","disabled"]}),(0,a.tg)(this,this.inputElement,{includeAttrs:["invalid"]})}}))((0,n.DM)({slots:[],wrappedEleName:"vaadin-custom-field",style:()=>"\n :host {\n display: inline-flex;\n max-width: 100%;\n direction: ltr;\n }\n\n vaadin-custom-field {\n line-height: unset;\n width: 100%;\n }\n\n descope-text-field {\n width: auto;\n }\n\n descope-mappings-field {\n display: block;\n }\n ",excludeAttrsSync:["tabindex","label-group","label-value","label-attr","button-label","separator","options","error-message"],componentName:p}));i(9357),i(5894),i(4115),customElements.define(p,d)}}]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@descope/web-components-ui",
3
- "version": "1.0.290",
3
+ "version": "1.0.292",
4
4
  "description": "",
5
5
  "main": "dist/cjs/index.cjs.js",
6
6
  "module": "dist/index.esm.js",
@@ -4,9 +4,12 @@ import { createStyleMixin, proxyInputMixin, draggableMixin, createProxy } from '
4
4
  import { componentName as descopeInternalComponentName } from './descope-new-password-internal/componentName';
5
5
  import { PasswordClass } from '../descope-password/PasswordClass';
6
6
  import { useHostExternalPadding } from '../../helpers/themeHelpers/resetHelpers';
7
+ import { PolicyValidationClass } from '../descope-policy-validation';
7
8
 
8
9
  export const componentName = getComponentName('new-password');
9
10
 
11
+ const policyPreviewVars = PolicyValidationClass.cssVarList;
12
+
10
13
  const customMixin = (superclass) =>
11
14
  class NewPasswordMixinClass extends superclass {
12
15
  init() {
@@ -40,18 +43,32 @@ const customMixin = (superclass) =>
40
43
  'invalid',
41
44
  'readonly',
42
45
  'draggable',
46
+ 'has-validation',
47
+ 'policy-label',
48
+ 'active-policies',
49
+ 'available-policies',
50
+ 'data-password-policy-value-minlength',
43
51
  ],
44
52
  });
45
53
  }
46
54
  };
47
55
 
48
- const { host, label, internalInputsWrapper, errorMessage, helperText, passwordInput } = {
56
+ const {
57
+ host,
58
+ label,
59
+ internalInputsWrapper,
60
+ errorMessage,
61
+ helperText,
62
+ passwordInput,
63
+ policyPreview,
64
+ } = {
49
65
  host: { selector: () => ':host' },
50
66
  label: { selector: '::part(label)' },
51
67
  internalInputsWrapper: { selector: 'descope-new-password-internal .wrapper' },
52
68
  helperText: { selector: '::part(helper-text)' },
53
69
  errorMessage: { selector: '::part(error-message)' },
54
70
  passwordInput: { selector: 'descope-password' },
71
+ policyPreview: { selector: 'descope-policy-validation' },
55
72
  };
56
73
 
57
74
  export const NewPasswordClass = compose(
@@ -75,6 +92,11 @@ export const NewPasswordClass = compose(
75
92
  ],
76
93
  inputsRequiredIndicator: { ...host, property: 'content' },
77
94
  spaceBetweenInputs: { ...internalInputsWrapper, property: 'gap' },
95
+ policyPreviewBackgroundColor: {
96
+ ...policyPreview,
97
+ property: policyPreviewVars.backgroundColor,
98
+ },
99
+ policyPreviewPadding: { ...policyPreview, property: policyPreviewVars.padding },
78
100
  },
79
101
  }),
80
102
  draggableMixin,
@@ -113,7 +135,6 @@ export const NewPasswordClass = compose(
113
135
  -webkit-mask-image: none;
114
136
  min-height: 0;
115
137
  width: 100%;
116
- height: 100%;
117
138
  padding: 0;
118
139
  }
119
140
  descope-new-password-internal > .wrapper {
@@ -129,6 +150,13 @@ export const NewPasswordClass = compose(
129
150
  descope-new-password-internal vaadin-password-field::before {
130
151
  height: initial;
131
152
  }
153
+ descope-policy-validation {
154
+ margin-top: 8px;
155
+ display: flex;
156
+ }
157
+ descope-policy-validation.hidden {
158
+ display: none;
159
+ }
132
160
  `,
133
161
  excludeAttrsSync: ['tabindex'],
134
162
  componentName,
@@ -1,5 +1,5 @@
1
1
  import { createBaseInputClass } from '../../../baseClasses/createBaseInputClass';
2
- import { observeAttributes } from '../../../helpers/componentHelpers';
2
+ import { forwardAttrs, observeAttributes } from '../../../helpers/componentHelpers';
3
3
  import { NewPasswordClass } from '../NewPasswordClass';
4
4
  import { componentName } from './componentName';
5
5
 
@@ -10,6 +10,7 @@ const removeAttrPrefix = (attr, prefix) => attr.replace(prefix, '');
10
10
 
11
11
  const passwordInputAttrs = ['password-label', 'password-placeholder'];
12
12
  const confirmInputAttrs = ['confirm-label', 'confirm-placeholder'];
13
+ const policyPanelAttrs = ['has-validation'];
13
14
  const commonAttrs = [
14
15
  'disabled',
15
16
  'bordered',
@@ -22,7 +23,12 @@ const commonAttrs = [
22
23
  'autocomplete',
23
24
  ];
24
25
 
25
- const inputRelatedAttrs = [].concat(commonAttrs, passwordInputAttrs, confirmInputAttrs);
26
+ const inputRelatedAttrs = [].concat(
27
+ commonAttrs,
28
+ passwordInputAttrs,
29
+ confirmInputAttrs,
30
+ policyPanelAttrs
31
+ );
26
32
 
27
33
  const BaseInputClass = createBaseInputClass({ componentName, baseSelector: 'div' });
28
34
 
@@ -54,7 +60,15 @@ class NewPasswordInternal extends BaseInputClass {
54
60
  return this.getAttribute('has-confirm') === 'true';
55
61
  }
56
62
 
63
+ get hasValidation() {
64
+ return this.getAttribute('has-validation') === 'true';
65
+ }
66
+
57
67
  getValidity() {
68
+ if (!this.policyPanel.isValid) {
69
+ return { patternMismatch: true };
70
+ }
71
+
58
72
  if (this.isRequired && !this.value) {
59
73
  return { valueMissing: true };
60
74
  }
@@ -85,7 +99,12 @@ class NewPasswordInternal extends BaseInputClass {
85
99
  }
86
100
 
87
101
  renderInputs(shouldRenderConfirm) {
88
- let template = `<descope-password data-id="password"></descope-password>`;
102
+ let template = `
103
+ <div>
104
+ <descope-password data-id="password"></descope-password>
105
+ <descope-policy-validation></descope-policy-validation>
106
+ </div>
107
+ `;
89
108
 
90
109
  if (shouldRenderConfirm) {
91
110
  template += `<descope-password data-id="confirm"></descope-password>`;
@@ -95,6 +114,7 @@ class NewPasswordInternal extends BaseInputClass {
95
114
 
96
115
  this.passwordInput = this.querySelector('[data-id="password"]');
97
116
  this.confirmInput = this.querySelector('[data-id="confirm"]');
117
+ this.policyPanel = this.querySelector('descope-policy-validation');
98
118
 
99
119
  this.inputs = [this.passwordInput, this.confirmInput];
100
120
 
@@ -105,6 +125,23 @@ class NewPasswordInternal extends BaseInputClass {
105
125
  [...passwordInputAttrs, ...confirmInputAttrs, ...commonAttrs].forEach((attr) => {
106
126
  this.attributeChangedCallback(attr, null, this.getAttribute(attr));
107
127
  });
128
+
129
+ this.passwordInput.addEventListener('input', (e) => {
130
+ this.policyPanel.setAttribute('value', e.target.value);
131
+ });
132
+
133
+ forwardAttrs(this, this.policyPanel, {
134
+ includeAttrs: [
135
+ 'policy-label',
136
+ 'available-policies',
137
+ 'active-policies',
138
+ 'data-password-policy-value-minlength',
139
+ ],
140
+ mapAttrs: {
141
+ 'policy-label': 'label',
142
+ 'available-policies': 'data',
143
+ },
144
+ });
108
145
  }
109
146
 
110
147
  // the inputs are not required but we still want it to have a required
@@ -164,6 +201,14 @@ class NewPasswordInternal extends BaseInputClass {
164
201
  value === null ? ele?.removeAttribute(name) : ele?.setAttribute(name, value);
165
202
  }
166
203
 
204
+ hidePolicy() {
205
+ this.policyPanel.classList.add('hidden');
206
+ }
207
+
208
+ showPolicy() {
209
+ this.policyPanel.classList.remove('hidden');
210
+ }
211
+
167
212
  attributeChangedCallback(attrName, oldValue, newValue) {
168
213
  super.attributeChangedCallback?.(attrName, oldValue, newValue);
169
214
 
@@ -185,6 +230,9 @@ class NewPasswordInternal extends BaseInputClass {
185
230
  newValue
186
231
  );
187
232
  }
233
+ if (attrName === 'has-validation') {
234
+ newValue === 'true' ? this.showPolicy() : this.hidePolicy();
235
+ }
188
236
  }
189
237
  }
190
238
  }
@@ -1,6 +1,7 @@
1
1
  import { componentName, NewPasswordClass } from './NewPasswordClass';
2
2
  import '../descope-text-field';
3
3
  import '../descope-password';
4
+ import '../descope-policy-validation';
4
5
  import './descope-new-password-internal';
5
6
 
6
7
  customElements.define(componentName, NewPasswordClass);
@@ -0,0 +1,220 @@
1
+ // eslint-disable-next-line max-classes-per-file
2
+ import { createStyleMixin, draggableMixin, componentNameValidationMixin } from '../../mixins';
3
+ import { createBaseClass } from '../../baseClasses/createBaseClass';
4
+ import { compose } from '../../helpers';
5
+ import { getComponentName } from '../../helpers/componentHelpers';
6
+ import { interpolateString } from './helpers';
7
+
8
+ export const componentName = getComponentName('policy-validation');
9
+
10
+ const overrideAttrs = ['data-password-policy-value-minlength'];
11
+ const dataAttrs = ['data', 'active-policies', 'overrides', ...overrideAttrs];
12
+ const policyAttrs = ['label', 'value', ...dataAttrs];
13
+
14
+ class RawPolicyValidation extends createBaseClass({ componentName, baseSelector: ':host > div' }) {
15
+ #availablePolicies;
16
+
17
+ #activePolicies = [];
18
+
19
+ #overrides;
20
+
21
+ static get observedAttributes() {
22
+ return policyAttrs;
23
+ }
24
+
25
+ constructor() {
26
+ super();
27
+
28
+ this.attachShadow({ mode: 'open' }).innerHTML = `
29
+ <div>
30
+ <div class="label"></div>
31
+ <ul></ul>
32
+ </div>
33
+ <style>
34
+ :host > div {
35
+ width: 100%;
36
+ display: flex;
37
+ flex-direction: column;
38
+ box-sizing: border-box;
39
+ }
40
+ .label {
41
+ max-width: 100%;
42
+ text-wrap: wrap;
43
+ overflow-wrap: break-word;
44
+ }
45
+ .hide-label .label {
46
+ display: none;
47
+ }
48
+ ul {
49
+ display: flex;
50
+ flex-direction: column;
51
+ padding: 0;
52
+ margin: 0;
53
+ }
54
+ ul, li {
55
+ margin: 0;
56
+ padding: 0;
57
+ list-style: none;
58
+ }
59
+ li::before {
60
+ display: inline-block;
61
+ width: 1em;
62
+ text-align: center;
63
+ }
64
+ </style>
65
+ `;
66
+
67
+ this.panel = this.shadowRoot.querySelector(':host > div');
68
+ this.label = this.shadowRoot.querySelector('.label');
69
+ this.list = this.shadowRoot.querySelector('ul');
70
+ }
71
+
72
+ attributeChangedCallback(attrName, oldValue, newValue) {
73
+ super.attributeChangedCallback?.(attrName, oldValue, newValue);
74
+ if (oldValue !== newValue) {
75
+ if (attrName === 'label') {
76
+ this.updateLabel(newValue);
77
+ }
78
+
79
+ // we're don't know the order in which the attributes are forwarded, so we're trying to render every time
80
+ // once `data` and `active-policies` are populated, the render will be executed.
81
+ // once the `overrides` object is updated, we want to re-render the panel.
82
+ if (dataAttrs.includes(attrName)) {
83
+ if (attrName === 'data') {
84
+ try {
85
+ this.availablePolicies = JSON.parse(newValue);
86
+ } catch {
87
+ // eslint-disable-next-line no-console
88
+ console.error('Failed to set available policies');
89
+ }
90
+ }
91
+ if (attrName === 'active-policies') {
92
+ this.#activePolicies = (newValue || '').split(',');
93
+ }
94
+
95
+ if (attrName === 'data-password-policy-value-minlength') {
96
+ const ln = Number(newValue);
97
+ if (!Number.isNaN(ln) && ln > 0) {
98
+ this.#overrides = { ...this.#overrides, minlength: { value: `${ln}` } };
99
+ }
100
+ }
101
+ }
102
+
103
+ this.renderItems(this.#availablePolicies, this.#activePolicies, this.#overrides);
104
+ }
105
+ }
106
+
107
+ get availablePolicies() {
108
+ return this.#availablePolicies || [];
109
+ }
110
+
111
+ set availablePolicies(val) {
112
+ this.#availablePolicies = val;
113
+ }
114
+
115
+ get value() {
116
+ return this.getAttribute('value') || '';
117
+ }
118
+
119
+ validate() {
120
+ let policies = this.#availablePolicies;
121
+
122
+ if (this.#overrides) {
123
+ policies = this.#availablePolicies.map((policy) =>
124
+ this.#overrides[policy.id] ? { ...policy, data: this.#overrides[policy.id] } : policy
125
+ );
126
+ }
127
+
128
+ return this.#activePolicies.reduce((results, id) => {
129
+ const policy = policies.find((p) => p.id === id);
130
+
131
+ if (!policy) {
132
+ return results;
133
+ }
134
+
135
+ const { pattern, message, data } = policy;
136
+
137
+ if (!pattern || !message) {
138
+ return results;
139
+ }
140
+
141
+ const exp = new RegExp(interpolateString(pattern, data));
142
+
143
+ const validationResult = {
144
+ valid: exp.test(this.value),
145
+ message: interpolateString(message, data),
146
+ id,
147
+ };
148
+
149
+ results.push(validationResult);
150
+
151
+ return results;
152
+ }, []);
153
+ }
154
+
155
+ get isValid() {
156
+ return !this.validate().some(({ valid }) => valid === false);
157
+ }
158
+
159
+ getValidationItemTemplate({ valid, message }) {
160
+ const status = !this.value ? 'none' : valid;
161
+ return `
162
+ <li class="item" data-valid="${status}">
163
+ <span class="message">${message}</span>
164
+ </li>
165
+ `;
166
+ }
167
+
168
+ renderItems(availablePolicies, activePolicies) {
169
+ if (!availablePolicies || !activePolicies.length) {
170
+ return;
171
+ }
172
+
173
+ this.list.innerHTML = this.validate().map(this.getValidationItemTemplate.bind(this)).join('');
174
+ }
175
+
176
+ updateLabel(val) {
177
+ if (!val) {
178
+ this.classList.add('hide-label');
179
+ this.label.innerHTML = '';
180
+ } else {
181
+ this.label.innerHTML = val;
182
+ this.classList.remove('hide-label');
183
+ }
184
+ }
185
+ }
186
+
187
+ const { host, item, symbolDefault, symbolSuccess, symbolError } = {
188
+ host: { selector: () => ':host > div' },
189
+ item: { selector: () => '.item' },
190
+ symbolDefault: { selector: () => '.item[data-valid="none"]::before' },
191
+ symbolSuccess: { selector: () => '.item[data-valid="true"]::before' },
192
+ symbolError: { selector: () => '.item[data-valid="false"]::before' },
193
+ };
194
+
195
+ export const PolicyValidationClass = compose(
196
+ createStyleMixin({ componentNameOverride: getComponentName('input-wrapper') }),
197
+ createStyleMixin({
198
+ mappings: {
199
+ hostDirection: { selector: () => ':host', property: 'direction' },
200
+ fontSize: {},
201
+ fontFamily: {},
202
+ padding: {},
203
+ borderWidth: { ...host, property: 'border-width' },
204
+ borderStyle: { ...host, property: 'border-style' },
205
+ borderColor: { ...host, property: 'border-color' },
206
+ borderRadius: { ...host, property: 'border-radius' },
207
+ backgroundColor: { ...host, property: 'background-color' },
208
+ textColor: { property: 'color' },
209
+ labelMargin: { ...host, property: 'gap' },
210
+ itemsSpacing: { ...item, property: 'line-height' },
211
+ itemSymbolSuccessColor: { ...symbolSuccess, property: 'color' },
212
+ itemSymbolErrorColor: { ...symbolError, property: 'color' },
213
+ itemSymbolDefault: { ...symbolDefault, property: 'content' },
214
+ itemSymbolSuccess: { ...symbolSuccess, property: 'content' },
215
+ itemSymbolError: { ...symbolError, property: 'content' },
216
+ },
217
+ }),
218
+ draggableMixin,
219
+ componentNameValidationMixin
220
+ )(RawPolicyValidation);
@@ -0,0 +1,2 @@
1
+ export const interpolateString = (template, values) =>
2
+ template.replace(/{{(\w+)+}}/g, (match, key) => values?.[key] || match);
@@ -0,0 +1,5 @@
1
+ import { componentName, PolicyValidationClass } from './PolicyValidationClass';
2
+
3
+ customElements.define(componentName, PolicyValidationClass);
4
+
5
+ export { PolicyValidationClass };
@@ -7,7 +7,7 @@ import {
7
7
  } from '../../../mixins';
8
8
  import { TextClass } from '../../descope-text/TextClass';
9
9
  import { compose } from '../../../helpers';
10
- import { forwardAttrs, getComponentName } from '../../../helpers/componentHelpers';
10
+ import { forwardAttrs, getComponentName, syncAttrs } from '../../../helpers/componentHelpers';
11
11
  import { componentName as descopeInternalComponentName } from './descope-mappings-field-internal/MappingsFieldInternal';
12
12
 
13
13
  export const componentName = getComponentName('mappings-field');
@@ -64,6 +64,10 @@ const customMixin = (superclass) =>
64
64
  ],
65
65
  });
66
66
 
67
+ // This is required since when we remove the invalid attribute from the internal mappings field,
68
+ // we want to reflect the change in the parent component
69
+ syncAttrs(this, this.inputElement, { includeAttrs: ['invalid'] });
70
+
67
71
  this.setDefaultValues();
68
72
  }
69
73
  };
@@ -74,6 +78,7 @@ const {
74
78
  errorMessage,
75
79
  mappingItem,
76
80
  labels,
81
+ labelsText,
77
82
  valueLabel,
78
83
  attrLabel,
79
84
  separator,
@@ -84,6 +89,9 @@ const {
84
89
  errorMessage: { selector: '::part(error-message)' },
85
90
  mappingItem: { selector: 'descope-mapping-item::part(wrapper)' },
86
91
  labels: { selector: 'descope-mappings-field-internal [part="labels"] descope-text' },
92
+ labelsText: {
93
+ selector: 'descope-mappings-field-internal [part="labels"] descope-text::part(text-wrapper)',
94
+ },
87
95
  valueLabel: { selector: 'descope-mappings-field-internal [part="labels"] [part="value-label"]' },
88
96
  attrLabel: { selector: 'descope-mappings-field-internal [part="labels"] [part="attr-label"]' },
89
97
  separator: { selector: 'descope-mapping-item::part(separator)' },
@@ -99,6 +107,11 @@ export const MappingsFieldClass = compose(
99
107
  fontSize: [{}, host, { ...separator, property: 'margin-top' }],
100
108
  fontFamily: [helperText, errorMessage, labels],
101
109
  separatorFontSize: { ...separator, property: 'font-size' },
110
+ labelsFontSize: { ...labelsText, property: 'font-size' },
111
+ labelsLineHeight: [
112
+ { ...labelsText, property: 'line-height' },
113
+ { ...labels, property: 'line-height' },
114
+ ],
102
115
  labelTextColor: { ...labels, property: TextClass.cssVarList.textColor },
103
116
  itemMarginBottom: { ...mappingItem, property: 'margin-bottom' },
104
117
  valueLabelMinWidth: { ...valueLabel, property: 'min-width' },
@@ -92,7 +92,7 @@ class MappingItem extends BaseInputClass {
92
92
 
93
93
  initRemoveButton() {
94
94
  this.removeButton.addEventListener('click', () =>
95
- this.dispatchEvent(new CustomEvent('mapping-item-removed'))
95
+ this.dispatchEvent(new CustomEvent('mapping-item-removed', { bubbles: true, composed: true }))
96
96
  );
97
97
  }
98
98
 
@@ -66,7 +66,7 @@ class MappingsFieldInternal extends BaseInputClass {
66
66
  // before the new item is added and thus returns a wrong result
67
67
  setTimeout(() => {
68
68
  this.setCustomValidity('');
69
- newMappingItem.addEventListener('mapping-item-removed', (e) => {
69
+ newMappingItem.addEventListener('mapping-item-removed', () => {
70
70
  // If the removed item was the one that was invalid, we need to reset the invalid indication for the internal
71
71
  if (newMappingItem === this.#errorItem) {
72
72
  this.resetInvalidIndication();
@@ -74,8 +74,8 @@ class MappingsFieldInternal extends BaseInputClass {
74
74
  }
75
75
  newMappingItem.remove();
76
76
  this.setCustomValidity('');
77
- e.stopPropagation();
78
77
  });
78
+ this.dispatchEvent(new CustomEvent('mapping-item-added', { bubbles: true, composed: true }));
79
79
  if (focusNewItem) {
80
80
  newMappingItem.focus();
81
81
  }
@@ -0,0 +1,110 @@
1
+ import {
2
+ createStyleMixin,
3
+ draggableMixin,
4
+ createProxy,
5
+ proxyInputMixin,
6
+ componentNameValidationMixin,
7
+ } from '../../../mixins';
8
+ import { compose } from '../../../helpers';
9
+ import { forwardAttrs, getComponentName, syncAttrs } from '../../../helpers/componentHelpers';
10
+ import { componentName as descopeInternalComponentName } from './descope-saml-group-mappings-internal/SamlGroupMappingsInternal';
11
+
12
+ export const componentName = getComponentName('saml-group-mappings');
13
+
14
+ const customMixin = (superclass) =>
15
+ class SamlGroupMappingsMixinClass extends superclass {
16
+ init() {
17
+ super.init?.();
18
+
19
+ const template = document.createElement('template');
20
+
21
+ template.innerHTML = `
22
+ <${descopeInternalComponentName}
23
+ tabindex="-1"
24
+ ></${descopeInternalComponentName}>
25
+ `;
26
+
27
+ this.baseElement.appendChild(template.content.cloneNode(true));
28
+
29
+ this.inputElement = this.shadowRoot.querySelector(descopeInternalComponentName);
30
+
31
+ forwardAttrs(this, this.inputElement, {
32
+ includeAttrs: [
33
+ 'size',
34
+ 'full-width',
35
+ 'label-group',
36
+ 'label-value',
37
+ 'label-attr',
38
+ 'button-label',
39
+ 'separator',
40
+ 'options',
41
+ 'readonly',
42
+ 'disabled',
43
+ ],
44
+ });
45
+
46
+ syncAttrs(this, this.inputElement, { includeAttrs: ['invalid'] });
47
+ }
48
+ };
49
+
50
+ const { host, groupInput } = {
51
+ host: { selector: () => ':host' },
52
+ groupInput: { selector: 'descope-text-field' },
53
+ };
54
+
55
+ export const SamlGroupMappingsClass = compose(
56
+ createStyleMixin({
57
+ mappings: {
58
+ hostWidth: { ...host, property: 'width' },
59
+ hostDirection: { ...host, property: 'direction' },
60
+ groupNameInputMarginBottom: { ...groupInput, property: 'margin-bottom' },
61
+ },
62
+ }),
63
+ draggableMixin,
64
+ proxyInputMixin({
65
+ proxyProps: ['value', 'selectionStart'],
66
+ inputEvent: 'input',
67
+ triggerValidationEvents: ['mapping-item-added', 'mapping-item-removed'],
68
+ proxyParentValidation: true,
69
+ }),
70
+ componentNameValidationMixin,
71
+ customMixin
72
+ )(
73
+ createProxy({
74
+ slots: [],
75
+ wrappedEleName: 'vaadin-custom-field',
76
+ style: () => `
77
+ :host {
78
+ display: inline-flex;
79
+ max-width: 100%;
80
+ direction: ltr;
81
+ }
82
+
83
+ vaadin-custom-field {
84
+ line-height: unset;
85
+ width: 100%;
86
+ }
87
+
88
+ descope-text-field {
89
+ width: auto;
90
+ }
91
+
92
+ descope-mappings-field {
93
+ display: block;
94
+ }
95
+ `,
96
+ excludeAttrsSync: [
97
+ 'tabindex',
98
+ 'label-group',
99
+ 'label-value',
100
+ 'label-attr',
101
+ 'button-label',
102
+ 'separator',
103
+ 'options',
104
+ 'error-message',
105
+ ],
106
+ componentName,
107
+ })
108
+ );
109
+
110
+ export default SamlGroupMappingsClass;