@descope/web-components-ui 1.0.368 → 1.0.370

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.esm.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import '@vaadin/button';
2
2
  import 'element-internals-polyfill';
3
+ import DOMPurify from 'dompurify';
3
4
  import '@vaadin/checkbox';
4
5
  import '@vaadin/text-field';
5
6
  import '@vaadin/email-field';
@@ -1401,7 +1402,9 @@ const getFileExtension = (path) => {
1401
1402
  return match ? match[1] : null;
1402
1403
  };
1403
1404
 
1404
- const isSvg = (src) => getFileExtension(src) === 'svg' || src.indexOf('image/svg+xml') > -1;
1405
+ const base64Prefix = 'data:image/svg+xml;base64,';
1406
+
1407
+ const isBase64Svg = (src) => src.startsWith(base64Prefix);
1405
1408
 
1406
1409
  const createImgEle = (src) => {
1407
1410
  const ele = document.createElement('img');
@@ -1410,20 +1413,28 @@ const createImgEle = (src) => {
1410
1413
  };
1411
1414
 
1412
1415
  const createSvgEle = (text) => {
1416
+ // we want to purify the SVG to avoid XSS attacks
1417
+ const clean = DOMPurify.sanitize(text, { USE_PROFILES: { svg: true, svgFilters: true } });
1418
+
1413
1419
  const parser = new DOMParser();
1414
- const ele = parser.parseFromString(text, 'image/svg+xml').querySelector('svg');
1420
+ const ele = parser.parseFromString(clean, 'image/svg+xml').querySelector('svg');
1415
1421
  return ele;
1416
1422
  };
1417
1423
 
1418
1424
  const createIcon = async (src) => {
1419
1425
  try {
1420
1426
  let ele;
1421
-
1422
- if (isSvg(src)) {
1427
+ if (isBase64Svg(src)) {
1428
+ // handle base64 source
1429
+ const svgXml = atob(src.slice(base64Prefix.length));
1430
+ ele = createSvgEle(svgXml);
1431
+ } else if (getFileExtension(src) === 'svg') {
1432
+ // handle urls
1423
1433
  const fetchedSrc = await fetch(src);
1424
1434
  const text = await fetchedSrc.text();
1425
1435
  ele = createSvgEle(text);
1426
1436
  } else {
1437
+ // handle binary
1427
1438
  ele = createImgEle(src);
1428
1439
  }
1429
1440
 
@@ -11947,7 +11958,7 @@ const componentName$2 = getComponentName('list');
11947
11958
 
11948
11959
  class RawList extends createBaseClass({ componentName: componentName$2, baseSelector: '.wrapper' }) {
11949
11960
  static get observedAttributes() {
11950
- return ['variant'];
11961
+ return ['variant', 'readonly'];
11951
11962
  }
11952
11963
 
11953
11964
  constructor() {
@@ -12030,6 +12041,18 @@ class RawList extends createBaseClass({ componentName: componentName$2, baseSele
12030
12041
  observeChildren(this, () => {
12031
12042
  this.#handleEmptyState();
12032
12043
  this.#handleItemsVariant();
12044
+ this.#handleReadOnly();
12045
+ });
12046
+ }
12047
+
12048
+ get isReadOnly() {
12049
+ return this.getAttribute('readonly') === 'true';
12050
+ }
12051
+
12052
+ #handleReadOnly() {
12053
+ this.items.forEach((item) => {
12054
+ if (this.isReadOnly) item.setAttribute('inert', '');
12055
+ else item.removeAttribute('inert');
12033
12056
  });
12034
12057
  }
12035
12058
 
@@ -12040,6 +12063,8 @@ class RawList extends createBaseClass({ componentName: componentName$2, baseSele
12040
12063
 
12041
12064
  if (name === 'variant') {
12042
12065
  this.#handleItemsVariant();
12066
+ } else if (name === 'readonly') {
12067
+ this.#handleReadOnly();
12043
12068
  }
12044
12069
  }
12045
12070
  }
@@ -12157,16 +12182,51 @@ const createDynamicDataMixin =
12157
12182
  super.init?.();
12158
12183
 
12159
12184
  if (rerenderAttrsList.length) {
12160
- observeAttributes(this, () => this.#renderItems(), { includeAttrs: rerenderAttrsList });
12185
+ observeAttributes(
12186
+ this,
12187
+ (attrs) => {
12188
+ if (attrs.includes('data')) this.#handleDataAttr();
12189
+ if (attrs.some((attr) => attr !== 'data')) this.#renderItems();
12190
+ },
12191
+ { includeAttrs: [...rerenderAttrsList, 'data'] }
12192
+ );
12161
12193
  } else {
12162
12194
  this.#renderItems();
12163
12195
  }
12164
12196
  }
12197
+
12198
+ #handleDataAttr() {
12199
+ const dataAttr = this.getAttribute('data');
12200
+
12201
+ if (!dataAttr) return;
12202
+
12203
+ try {
12204
+ this.#data = JSON.parse(dataAttr);
12205
+ } catch (e) {
12206
+ // eslint-disable-next-line no-console
12207
+ console.warn('Invalid JSON data', dataAttr);
12208
+ }
12209
+ }
12210
+
12211
+ attributeChangedCallback(name, oldValue, newValue) {
12212
+ super.attributeChangedCallback?.(name, oldValue, newValue);
12213
+
12214
+ if (newValue === oldValue) return;
12215
+
12216
+ if (name === 'data') {
12217
+ try {
12218
+ this.data = JSON.parse(newValue);
12219
+ } catch (e) {
12220
+ // eslint-disable-next-line no-console
12221
+ console.warn('Invalid JSON data', newValue);
12222
+ }
12223
+ }
12224
+ }
12165
12225
  };
12166
12226
 
12167
12227
  const componentName$1 = getComponentName('apps-list');
12168
12228
 
12169
- const limitAbbreviation = (str, limit = 3) =>
12229
+ const limitAbbreviation = (str, limit = 2) =>
12170
12230
  str
12171
12231
  .trim()
12172
12232
  .split(' ')
@@ -12175,12 +12235,11 @@ const limitAbbreviation = (str, limit = 3) =>
12175
12235
  .join('');
12176
12236
 
12177
12237
  const itemRenderer = ({ name, icon, url }, _, ref) => `
12178
- <a href="${url}" target="_blank" title="${url}">
12238
+ <a ${url ? `href="${url}" title="${url}"` : ''} target="_blank">
12179
12239
  <descope-list-item>
12180
12240
  <descope-avatar
12181
- img="${icon}"
12182
- display-name="${name}"
12183
- abbr=${limitAbbreviation(name)}
12241
+ ${icon ? `img="${icon}"` : ''}
12242
+ ${name ? `display-name="${name}" abbr=${limitAbbreviation(name)}` : ''}
12184
12243
  size=${ref.size}
12185
12244
  ></descope-avatar>
12186
12245
  <descope-text
@@ -12226,7 +12285,7 @@ const AppsListClass = compose(
12226
12285
  createProxy({
12227
12286
  slots: ['empty-state'],
12228
12287
  wrappedEleName: 'descope-list',
12229
- excludeAttrsSync: ['tabindex', 'class'],
12288
+ excludeAttrsSync: ['tabindex', 'class', 'empty'],
12230
12289
  componentName: componentName$1,
12231
12290
  style: () => `
12232
12291
  :host {