@descope/web-components-ui 1.0.368 → 1.0.370

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.
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 {