@descope/web-components-ui 1.0.363 → 1.0.365

Sign up to get free protection for your applications and to get access to all the features.
@@ -2614,11 +2614,57 @@ const inputEventsDispatchingMixin = (superclass) =>
2614
2614
  }
2615
2615
  };
2616
2616
 
2617
+ const getFileExtension = (path) => {
2618
+ const match = path.match(/\.([0-9a-z]+)(?:[\\?#]|$)/i);
2619
+ return match ? match[1] : null;
2620
+ };
2621
+
2622
+ const isSvg = (src) => getFileExtension(src) === 'svg' || src.indexOf('image/svg+xml') > -1;
2623
+
2624
+ const createImgEle = (src) => {
2625
+ const ele = document.createElement('img');
2626
+ ele.setAttribute('src', src);
2627
+ return ele;
2628
+ };
2629
+
2630
+ const createSvgEle = (text) => {
2631
+ const parser = new DOMParser();
2632
+ const ele = parser.parseFromString(text, 'image/svg+xml').querySelector('svg');
2633
+ return ele;
2634
+ };
2635
+
2636
+ const createIcon = async (src) => {
2637
+ try {
2638
+ let ele;
2639
+
2640
+ if (isSvg(src)) {
2641
+ const fetchedSrc = await fetch(src);
2642
+ const text = await fetchedSrc.text();
2643
+ ele = createSvgEle(text);
2644
+ } else {
2645
+ ele = createImgEle(src);
2646
+ }
2647
+
2648
+ ele.style.setProperty('width', '100%');
2649
+ ele.style.setProperty('height', '100%');
2650
+
2651
+ return ele;
2652
+ } catch {
2653
+ return null;
2654
+ }
2655
+ };
2656
+
2617
2657
  /* eslint-disable no-use-before-define */
2618
2658
 
2619
2659
  const componentName$S = getComponentName('icon');
2620
2660
 
2621
2661
  class RawIcon extends createBaseClass({ componentName: componentName$S, baseSelector: 'slot' }) {
2662
+ static get observedAttributes() {
2663
+ return ['src', 'fill-color'];
2664
+ }
2665
+
2666
+ #icon;
2667
+
2622
2668
  constructor() {
2623
2669
  super();
2624
2670
 
@@ -2629,7 +2675,7 @@ class RawIcon extends createBaseClass({ componentName: componentName$S, baseSele
2629
2675
  width: 100%;
2630
2676
  height: 100%;
2631
2677
  display: flex;
2632
- overflow: auto;
2678
+ overflow: hidden;
2633
2679
  }
2634
2680
  :host {
2635
2681
  display: inline-block;
@@ -2639,30 +2685,53 @@ class RawIcon extends createBaseClass({ componentName: componentName$S, baseSele
2639
2685
  `;
2640
2686
  }
2641
2687
 
2642
- get items() {
2643
- return this.shadowRoot.querySelector('slot').assignedNodes();
2688
+ get fillColor() {
2689
+ return this.getAttribute('fill-color') === 'true';
2644
2690
  }
2645
2691
 
2646
- #onChildrenChange() {
2647
- // force hide icon if empty.
2648
- if (this.items?.length > 0) {
2649
- this.shadowRoot.host.style.setProperty('display', 'inline-block');
2650
- } else {
2651
- this.shadowRoot.host.style.setProperty('display', 'none');
2692
+ get src() {
2693
+ return this.getAttribute('src');
2694
+ }
2695
+
2696
+ // in order to fill an SVG with `currentColor` override all of its `fill` and `path` nodes
2697
+ // with the value from the `st-fill` attribute
2698
+ updateFillColor() {
2699
+ if (this.#icon && this.fillColor) {
2700
+ const fillCssVar = (selector) => {
2701
+ this.querySelectorAll(selector).forEach((ele) =>
2702
+ ele.setAttribute(
2703
+ 'fill',
2704
+ `var(${IconClass.cssVarList.fill}, ${ele.getAttribute('fill') || "''"})`
2705
+ )
2706
+ );
2707
+ };
2708
+
2709
+ fillCssVar('*[fill]');
2710
+ fillCssVar('path');
2652
2711
  }
2712
+ }
2653
2713
 
2654
- // set fill for all inner svgs to fill var and a fallback
2655
- const elems = this.querySelectorAll('*[fill]');
2656
- elems.forEach((ele) =>
2657
- ele.setAttribute(
2658
- 'fill',
2659
- `var(${IconClass.cssVarList.fill}, ${ele.getAttribute('fill') || "''"})`
2660
- )
2661
- );
2714
+ resetIcon() {
2715
+ if (!this.#icon) return;
2716
+ this.innerHTML = '';
2717
+ this.appendChild(this.#icon.cloneNode(true));
2662
2718
  }
2663
2719
 
2664
- init() {
2665
- observeChildren(this, this.#onChildrenChange.bind(this));
2720
+ attributeChangedCallback(attrName, oldValue, newValue) {
2721
+ super.attributeChangedCallback?.(attrName, oldValue, newValue);
2722
+
2723
+ if (oldValue === newValue) return;
2724
+
2725
+ if (attrName === 'src') {
2726
+ createIcon(this.src).then((res) => {
2727
+ this.#icon = res;
2728
+ this.resetIcon();
2729
+ this.updateFillColor();
2730
+ });
2731
+ } else if (attrName === 'fill-color') {
2732
+ this.resetIcon();
2733
+ this.updateFillColor();
2734
+ }
2666
2735
  }
2667
2736
  }
2668
2737
 
@@ -2725,9 +2794,10 @@ const iconStyles = `
2725
2794
 
2726
2795
  const editorOverrides = `vaadin-button::part(label) { pointer-events: none; }`;
2727
2796
 
2728
- const { host: host$n, label: label$a } = {
2797
+ const { host: host$n, label: label$a, slottedIcon } = {
2729
2798
  host: { selector: () => ':host' },
2730
2799
  label: { selector: '::part(label)' },
2800
+ slottedIcon: { selector: () => '::slotted(descope-icon)' },
2731
2801
  };
2732
2802
 
2733
2803
  let loadingIndicatorStyles;
@@ -2768,6 +2838,11 @@ const ButtonClass = compose(
2768
2838
  labelTextDecoration: { ...label$a, property: 'text-decoration' },
2769
2839
  labelSpacing: { ...label$a, property: 'gap' },
2770
2840
  textAlign: { ...label$a, property: 'justify-content', fallback: 'center' },
2841
+
2842
+ iconSize: [
2843
+ { ...slottedIcon, property: 'width' },
2844
+ { ...slottedIcon, property: 'height' },
2845
+ ],
2771
2846
  },
2772
2847
  }),
2773
2848
  clickableMixin,
@@ -2879,6 +2954,9 @@ const button = {
2879
2954
  [compVars$5.outlineStyle]: 'solid',
2880
2955
  [compVars$5.outlineColor]: 'transparent',
2881
2956
 
2957
+ [compVars$5.iconSize]: '1.5em',
2958
+ [compVars$5.iconColor]: 'currentColor',
2959
+
2882
2960
  size: {
2883
2961
  xs: { [compVars$5.fontSize]: '12px' },
2884
2962
  sm: { [compVars$5.fontSize]: '14px' },