@descope/web-components-ui 1.0.369 → 1.0.371

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';
@@ -1412,8 +1413,11 @@ const createImgEle = (src) => {
1412
1413
  };
1413
1414
 
1414
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
+
1415
1419
  const parser = new DOMParser();
1416
- const ele = parser.parseFromString(text, 'image/svg+xml').querySelector('svg');
1420
+ const ele = parser.parseFromString(clean, 'image/svg+xml').querySelector('svg');
1417
1421
  return ele;
1418
1422
  };
1419
1423
 
@@ -1449,7 +1453,7 @@ const componentName$_ = getComponentName('icon');
1449
1453
 
1450
1454
  class RawIcon extends createBaseClass({ componentName: componentName$_, baseSelector: 'slot' }) {
1451
1455
  static get observedAttributes() {
1452
- return ['src', 'fill-color'];
1456
+ return ['src'];
1453
1457
  }
1454
1458
 
1455
1459
  #icon;
@@ -1474,36 +1478,23 @@ class RawIcon extends createBaseClass({ componentName: componentName$_, baseSele
1474
1478
  `;
1475
1479
  }
1476
1480
 
1477
- get fillColor() {
1478
- return this.getAttribute('fill-color') === 'true';
1479
- }
1480
-
1481
1481
  get src() {
1482
1482
  return this.getAttribute('src');
1483
1483
  }
1484
1484
 
1485
1485
  // in order to fill an SVG with `currentColor` override all of its `fill` and `path` nodes
1486
1486
  // with the value from the `st-fill` attribute
1487
- updateFillColor() {
1488
- if (this.#icon && this.fillColor) {
1489
- const fillCssVar = (selector) => {
1490
- this.querySelectorAll(selector).forEach((ele) =>
1491
- ele.setAttribute(
1492
- 'fill',
1493
- `var(${IconClass.cssVarList.fill}, ${ele.getAttribute('fill') || "''"})`
1494
- )
1495
- );
1496
- };
1497
-
1498
- fillCssVar('*[fill]');
1499
- fillCssVar('path');
1500
- }
1501
- }
1502
-
1503
- resetIcon() {
1504
- if (!this.#icon) return;
1505
- this.innerHTML = '';
1506
- this.appendChild(this.#icon.cloneNode(true));
1487
+ // eslint-disable-next-line class-methods-use-this
1488
+ updateFillColor(node) {
1489
+ // set fill to root node and all its relevant selectors
1490
+ const elementsToReplace = [node, ...node.querySelectorAll('*[fill]')];
1491
+
1492
+ elementsToReplace.forEach((ele) => {
1493
+ ele.setAttribute(
1494
+ 'fill',
1495
+ `var(${IconClass.cssVarList.fill}, ${ele.getAttribute('fill') || "''"})`
1496
+ );
1497
+ });
1507
1498
  }
1508
1499
 
1509
1500
  attributeChangedCallback(attrName, oldValue, newValue) {
@@ -1513,13 +1504,13 @@ class RawIcon extends createBaseClass({ componentName: componentName$_, baseSele
1513
1504
 
1514
1505
  if (attrName === 'src') {
1515
1506
  createIcon(this.src).then((res) => {
1516
- this.#icon = res;
1517
- this.resetIcon();
1518
- this.updateFillColor();
1507
+ this.innerHTML = '';
1508
+ if (res) {
1509
+ const clonedNode = res.cloneNode(true);
1510
+ this.updateFillColor(clonedNode);
1511
+ this.appendChild(clonedNode);
1512
+ }
1519
1513
  });
1520
- } else if (attrName === 'fill-color') {
1521
- this.resetIcon();
1522
- this.updateFillColor();
1523
1514
  }
1524
1515
  }
1525
1516
  }
@@ -11954,7 +11945,7 @@ const componentName$2 = getComponentName('list');
11954
11945
 
11955
11946
  class RawList extends createBaseClass({ componentName: componentName$2, baseSelector: '.wrapper' }) {
11956
11947
  static get observedAttributes() {
11957
- return ['variant'];
11948
+ return ['variant', 'readonly'];
11958
11949
  }
11959
11950
 
11960
11951
  constructor() {
@@ -12037,6 +12028,18 @@ class RawList extends createBaseClass({ componentName: componentName$2, baseSele
12037
12028
  observeChildren(this, () => {
12038
12029
  this.#handleEmptyState();
12039
12030
  this.#handleItemsVariant();
12031
+ this.#handleReadOnly();
12032
+ });
12033
+ }
12034
+
12035
+ get isReadOnly() {
12036
+ return this.getAttribute('readonly') === 'true';
12037
+ }
12038
+
12039
+ #handleReadOnly() {
12040
+ this.items.forEach((item) => {
12041
+ if (this.isReadOnly) item.setAttribute('inert', '');
12042
+ else item.removeAttribute('inert');
12040
12043
  });
12041
12044
  }
12042
12045
 
@@ -12047,6 +12050,8 @@ class RawList extends createBaseClass({ componentName: componentName$2, baseSele
12047
12050
 
12048
12051
  if (name === 'variant') {
12049
12052
  this.#handleItemsVariant();
12053
+ } else if (name === 'readonly') {
12054
+ this.#handleReadOnly();
12050
12055
  }
12051
12056
  }
12052
12057
  }
@@ -12164,16 +12169,51 @@ const createDynamicDataMixin =
12164
12169
  super.init?.();
12165
12170
 
12166
12171
  if (rerenderAttrsList.length) {
12167
- observeAttributes(this, () => this.#renderItems(), { includeAttrs: rerenderAttrsList });
12172
+ observeAttributes(
12173
+ this,
12174
+ (attrs) => {
12175
+ if (attrs.includes('data')) this.#handleDataAttr();
12176
+ if (attrs.some((attr) => attr !== 'data')) this.#renderItems();
12177
+ },
12178
+ { includeAttrs: [...rerenderAttrsList, 'data'] }
12179
+ );
12168
12180
  } else {
12169
12181
  this.#renderItems();
12170
12182
  }
12171
12183
  }
12184
+
12185
+ #handleDataAttr() {
12186
+ const dataAttr = this.getAttribute('data');
12187
+
12188
+ if (!dataAttr) return;
12189
+
12190
+ try {
12191
+ this.#data = JSON.parse(dataAttr);
12192
+ } catch (e) {
12193
+ // eslint-disable-next-line no-console
12194
+ console.warn('Invalid JSON data', dataAttr);
12195
+ }
12196
+ }
12197
+
12198
+ attributeChangedCallback(name, oldValue, newValue) {
12199
+ super.attributeChangedCallback?.(name, oldValue, newValue);
12200
+
12201
+ if (newValue === oldValue) return;
12202
+
12203
+ if (name === 'data') {
12204
+ try {
12205
+ this.data = JSON.parse(newValue);
12206
+ } catch (e) {
12207
+ // eslint-disable-next-line no-console
12208
+ console.warn('Invalid JSON data', newValue);
12209
+ }
12210
+ }
12211
+ }
12172
12212
  };
12173
12213
 
12174
12214
  const componentName$1 = getComponentName('apps-list');
12175
12215
 
12176
- const limitAbbreviation = (str, limit = 3) =>
12216
+ const limitAbbreviation = (str, limit = 2) =>
12177
12217
  str
12178
12218
  .trim()
12179
12219
  .split(' ')
@@ -12182,12 +12222,11 @@ const limitAbbreviation = (str, limit = 3) =>
12182
12222
  .join('');
12183
12223
 
12184
12224
  const itemRenderer = ({ name, icon, url }, _, ref) => `
12185
- <a href="${url}" target="_blank" title="${url}">
12225
+ <a ${url ? `href="${url}" title="${url}"` : ''} target="_blank">
12186
12226
  <descope-list-item>
12187
12227
  <descope-avatar
12188
- img="${icon}"
12189
- display-name="${name}"
12190
- abbr=${limitAbbreviation(name)}
12228
+ ${icon ? `img="${icon}"` : ''}
12229
+ ${name ? `display-name="${name}" abbr=${limitAbbreviation(name)}` : ''}
12191
12230
  size=${ref.size}
12192
12231
  ></descope-avatar>
12193
12232
  <descope-text
@@ -12233,7 +12272,7 @@ const AppsListClass = compose(
12233
12272
  createProxy({
12234
12273
  slots: ['empty-state'],
12235
12274
  wrappedEleName: 'descope-list',
12236
- excludeAttrsSync: ['tabindex', 'class'],
12275
+ excludeAttrsSync: ['tabindex', 'class', 'empty'],
12237
12276
  componentName: componentName$1,
12238
12277
  style: () => `
12239
12278
  :host {
@@ -12739,7 +12778,6 @@ const button = {
12739
12778
  [compVars$6.outlineColor]: 'transparent',
12740
12779
 
12741
12780
  [compVars$6.iconSize]: '1.5em',
12742
- [compVars$6.iconColor]: 'currentColor',
12743
12781
 
12744
12782
  size: {
12745
12783
  xs: { [compVars$6.fontSize]: '12px' },