@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.
@@ -2,6 +2,7 @@
2
2
 
3
3
  var merge = require('lodash.merge');
4
4
  var Color = require('color');
5
+ var DOMPurify = require('dompurify');
5
6
  var MarkdownIt = require('markdown-it');
6
7
  require('lodash.debounce');
7
8
  var hljs = require('highlight.js');
@@ -2622,7 +2623,9 @@ const getFileExtension = (path) => {
2622
2623
  return match ? match[1] : null;
2623
2624
  };
2624
2625
 
2625
- const isSvg = (src) => getFileExtension(src) === 'svg' || src.indexOf('image/svg+xml') > -1;
2626
+ const base64Prefix = 'data:image/svg+xml;base64,';
2627
+
2628
+ const isBase64Svg = (src) => src.startsWith(base64Prefix);
2626
2629
 
2627
2630
  const createImgEle = (src) => {
2628
2631
  const ele = document.createElement('img');
@@ -2631,20 +2634,28 @@ const createImgEle = (src) => {
2631
2634
  };
2632
2635
 
2633
2636
  const createSvgEle = (text) => {
2637
+ // we want to purify the SVG to avoid XSS attacks
2638
+ const clean = DOMPurify.sanitize(text, { USE_PROFILES: { svg: true, svgFilters: true } });
2639
+
2634
2640
  const parser = new DOMParser();
2635
- const ele = parser.parseFromString(text, 'image/svg+xml').querySelector('svg');
2641
+ const ele = parser.parseFromString(clean, 'image/svg+xml').querySelector('svg');
2636
2642
  return ele;
2637
2643
  };
2638
2644
 
2639
2645
  const createIcon = async (src) => {
2640
2646
  try {
2641
2647
  let ele;
2642
-
2643
- if (isSvg(src)) {
2648
+ if (isBase64Svg(src)) {
2649
+ // handle base64 source
2650
+ const svgXml = atob(src.slice(base64Prefix.length));
2651
+ ele = createSvgEle(svgXml);
2652
+ } else if (getFileExtension(src) === 'svg') {
2653
+ // handle urls
2644
2654
  const fetchedSrc = await fetch(src);
2645
2655
  const text = await fetchedSrc.text();
2646
2656
  ele = createSvgEle(text);
2647
2657
  } else {
2658
+ // handle binary
2648
2659
  ele = createImgEle(src);
2649
2660
  }
2650
2661
 
@@ -13207,7 +13218,7 @@ const componentName$3 = getComponentName('list');
13207
13218
 
13208
13219
  class RawList extends createBaseClass({ componentName: componentName$3, baseSelector: '.wrapper' }) {
13209
13220
  static get observedAttributes() {
13210
- return ['variant'];
13221
+ return ['variant', 'readonly'];
13211
13222
  }
13212
13223
 
13213
13224
  constructor() {
@@ -13290,6 +13301,18 @@ class RawList extends createBaseClass({ componentName: componentName$3, baseSele
13290
13301
  observeChildren(this, () => {
13291
13302
  this.#handleEmptyState();
13292
13303
  this.#handleItemsVariant();
13304
+ this.#handleReadOnly();
13305
+ });
13306
+ }
13307
+
13308
+ get isReadOnly() {
13309
+ return this.getAttribute('readonly') === 'true';
13310
+ }
13311
+
13312
+ #handleReadOnly() {
13313
+ this.items.forEach((item) => {
13314
+ if (this.isReadOnly) item.setAttribute('inert', '');
13315
+ else item.removeAttribute('inert');
13293
13316
  });
13294
13317
  }
13295
13318
 
@@ -13300,6 +13323,8 @@ class RawList extends createBaseClass({ componentName: componentName$3, baseSele
13300
13323
 
13301
13324
  if (name === 'variant') {
13302
13325
  this.#handleItemsVariant();
13326
+ } else if (name === 'readonly') {
13327
+ this.#handleReadOnly();
13303
13328
  }
13304
13329
  }
13305
13330
  }
@@ -13513,16 +13538,51 @@ const createDynamicDataMixin =
13513
13538
  super.init?.();
13514
13539
 
13515
13540
  if (rerenderAttrsList.length) {
13516
- observeAttributes(this, () => this.#renderItems(), { includeAttrs: rerenderAttrsList });
13541
+ observeAttributes(
13542
+ this,
13543
+ (attrs) => {
13544
+ if (attrs.includes('data')) this.#handleDataAttr();
13545
+ if (attrs.some((attr) => attr !== 'data')) this.#renderItems();
13546
+ },
13547
+ { includeAttrs: [...rerenderAttrsList, 'data'] }
13548
+ );
13517
13549
  } else {
13518
13550
  this.#renderItems();
13519
13551
  }
13520
13552
  }
13553
+
13554
+ #handleDataAttr() {
13555
+ const dataAttr = this.getAttribute('data');
13556
+
13557
+ if (!dataAttr) return;
13558
+
13559
+ try {
13560
+ this.#data = JSON.parse(dataAttr);
13561
+ } catch (e) {
13562
+ // eslint-disable-next-line no-console
13563
+ console.warn('Invalid JSON data', dataAttr);
13564
+ }
13565
+ }
13566
+
13567
+ attributeChangedCallback(name, oldValue, newValue) {
13568
+ super.attributeChangedCallback?.(name, oldValue, newValue);
13569
+
13570
+ if (newValue === oldValue) return;
13571
+
13572
+ if (name === 'data') {
13573
+ try {
13574
+ this.data = JSON.parse(newValue);
13575
+ } catch (e) {
13576
+ // eslint-disable-next-line no-console
13577
+ console.warn('Invalid JSON data', newValue);
13578
+ }
13579
+ }
13580
+ }
13521
13581
  };
13522
13582
 
13523
13583
  const componentName$2 = getComponentName('apps-list');
13524
13584
 
13525
- const limitAbbreviation = (str, limit = 3) =>
13585
+ const limitAbbreviation = (str, limit = 2) =>
13526
13586
  str
13527
13587
  .trim()
13528
13588
  .split(' ')
@@ -13531,12 +13591,11 @@ const limitAbbreviation = (str, limit = 3) =>
13531
13591
  .join('');
13532
13592
 
13533
13593
  const itemRenderer = ({ name, icon, url }, _, ref) => `
13534
- <a href="${url}" target="_blank" title="${url}">
13594
+ <a ${url ? `href="${url}" title="${url}"` : ''} target="_blank">
13535
13595
  <descope-list-item>
13536
13596
  <descope-avatar
13537
- img="${icon}"
13538
- display-name="${name}"
13539
- abbr=${limitAbbreviation(name)}
13597
+ ${icon ? `img="${icon}"` : ''}
13598
+ ${name ? `display-name="${name}" abbr=${limitAbbreviation(name)}` : ''}
13540
13599
  size=${ref.size}
13541
13600
  ></descope-avatar>
13542
13601
  <descope-text
@@ -13582,7 +13641,7 @@ const AppsListClass = compose(
13582
13641
  createProxy({
13583
13642
  slots: ['empty-state'],
13584
13643
  wrappedEleName: 'descope-list',
13585
- excludeAttrsSync: ['tabindex', 'class'],
13644
+ excludeAttrsSync: ['tabindex', 'class', 'empty'],
13586
13645
  componentName: componentName$2,
13587
13646
  style: () => `
13588
13647
  :host {