@waggylabs/yumekit 0.4.0-beta.28 → 0.4.0-beta.30

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.
@@ -650,89 +650,22 @@ if (!customElements.get("y-button")) {
650
650
 
651
651
  // Allowlist-based SVG sanitizer — only known-safe elements and attributes are kept.
652
652
  const ALLOWED_ELEMENTS = new Set([
653
- "svg",
654
- "g",
655
- "path",
656
- "circle",
657
- "ellipse",
658
- "rect",
659
- "line",
660
- "polyline",
661
- "polygon",
662
- "text",
663
- "tspan",
664
- "defs",
665
- "clippath",
666
- "mask",
667
- "lineargradient",
668
- "radialgradient",
669
- "stop",
670
- "symbol",
671
- "title",
672
- "desc",
673
- "metadata",
653
+ "svg", "g", "path", "circle", "ellipse", "rect", "line", "polyline",
654
+ "polygon", "text", "tspan", "defs", "clippath", "mask", "lineargradient",
655
+ "radialgradient", "stop", "symbol", "title", "desc", "metadata",
674
656
  ]);
675
657
 
676
658
  const ALLOWED_ATTRS = new Set([
677
- "viewbox",
678
- "xmlns",
679
- "fill",
680
- "stroke",
681
- "stroke-width",
682
- "stroke-linecap",
683
- "stroke-linejoin",
684
- "stroke-dasharray",
685
- "stroke-dashoffset",
686
- "stroke-miterlimit",
687
- "stroke-opacity",
688
- "fill-opacity",
689
- "fill-rule",
690
- "clip-rule",
691
- "opacity",
692
- "d",
693
- "cx",
694
- "cy",
695
- "r",
696
- "rx",
697
- "ry",
698
- "x",
699
- "x1",
700
- "x2",
701
- "y",
702
- "y1",
703
- "y2",
704
- "width",
705
- "height",
706
- "points",
707
- "transform",
708
- "id",
709
- "class",
710
- "clip-path",
711
- "mask",
712
- "offset",
713
- "stop-color",
714
- "stop-opacity",
715
- "gradient-units",
716
- "gradienttransform",
717
- "gradientunits",
718
- "spreadmethod",
719
- "patternunits",
720
- "patterntransform",
721
- "font-size",
722
- "font-family",
723
- "font-weight",
724
- "text-anchor",
725
- "dominant-baseline",
726
- "alignment-baseline",
727
- "dx",
728
- "dy",
729
- "rotate",
730
- "textlength",
731
- "lengthadjust",
732
- "display",
733
- "visibility",
734
- "color",
735
- "vector-effect",
659
+ "viewbox", "xmlns", "fill", "stroke", "stroke-width", "stroke-linecap",
660
+ "stroke-linejoin", "stroke-dasharray", "stroke-dashoffset", "stroke-miterlimit",
661
+ "stroke-opacity", "fill-opacity", "fill-rule", "clip-rule", "opacity",
662
+ "d", "cx", "cy", "r", "rx", "ry", "x", "x1", "x2", "y", "y1", "y2",
663
+ "width", "height", "points", "transform", "id", "class", "clip-path", "mask",
664
+ "offset", "stop-color", "stop-opacity", "gradient-units", "gradienttransform",
665
+ "gradientunits", "spreadmethod", "patternunits", "patterntransform",
666
+ "font-size", "font-family", "font-weight", "text-anchor", "dominant-baseline",
667
+ "alignment-baseline", "dx", "dy", "rotate", "textlength", "lengthadjust",
668
+ "display", "visibility", "color", "vector-effect",
736
669
  ]);
737
670
 
738
671
  function sanitizeSvg(raw) {
@@ -770,9 +703,7 @@ function sanitizeSvg(raw) {
770
703
  const sanitizedSvgCache = new Map();
771
704
 
772
705
  function getCachedSvg(name) {
773
- if (sanitizedSvgCache.has(name)) {
774
- return sanitizedSvgCache.get(name);
775
- }
706
+ if (sanitizedSvgCache.has(name)) return sanitizedSvgCache.get(name);
776
707
  const result = sanitizeSvg(getIcon(name));
777
708
  sanitizedSvgCache.set(name, result);
778
709
  return result;
@@ -783,6 +714,10 @@ class YumeIcon extends HTMLElement {
783
714
  return ["name", "size", "color", "label", "weight"];
784
715
  }
785
716
 
717
+ // -------------------------------------------------------------------------
718
+ // Lifecycle
719
+ // -------------------------------------------------------------------------
720
+
786
721
  constructor() {
787
722
  super();
788
723
  this.attachShadow({ mode: "open" });
@@ -797,76 +732,99 @@ class YumeIcon extends HTMLElement {
797
732
  this.render();
798
733
  }
799
734
 
800
- /** The registered icon name to display. */
801
- get name() {
802
- return this.getAttribute("name") || "";
803
- }
804
- set name(val) {
805
- this.setAttribute("name", val);
806
- }
807
-
808
- /** Icon size: "x-small" | "small" | "medium" | "large" | "x-large" (default "medium"). */
809
- get size() {
810
- return this.getAttribute("size") || "medium";
811
- }
812
- set size(val) {
813
- this.setAttribute("size", val);
814
- }
735
+ // -------------------------------------------------------------------------
736
+ // Getters / Setters
737
+ // -------------------------------------------------------------------------
815
738
 
816
739
  /** Color theme: "base" | "primary" | "secondary" | "success" | "warning" | "error" | "help". */
817
- get color() {
818
- return this.getAttribute("color") || "";
819
- }
740
+ get color() { return this.getAttribute("color") || ""; }
820
741
  set color(val) {
821
742
  if (val) this.setAttribute("color", val);
822
743
  else this.removeAttribute("color");
823
744
  }
824
745
 
825
746
  /** Accessible label for the icon. When set, the icon gets role="img". */
826
- get label() {
827
- return this.getAttribute("label") || "";
828
- }
747
+ get label() { return this.getAttribute("label") || ""; }
829
748
  set label(val) {
830
749
  if (val) this.setAttribute("label", val);
831
750
  else this.removeAttribute("label");
832
751
  }
833
752
 
753
+ /** The registered icon name to display. */
754
+ get name() { return this.getAttribute("name") || ""; }
755
+ set name(val) { this.setAttribute("name", val); }
756
+
757
+ /** Icon size: "x-small" | "small" | "medium" | "large" | "x-large" (default "medium"). */
758
+ get size() { return this.getAttribute("size") || "medium"; }
759
+ set size(val) { this.setAttribute("size", val); }
760
+
834
761
  /** Stroke weight: "thin" | "regular" | "thick". */
835
- get weight() {
836
- return this.getAttribute("weight") || "regular";
837
- }
762
+ get weight() { return this.getAttribute("weight") || "regular"; }
838
763
  set weight(val) {
839
764
  if (val) this.setAttribute("weight", val);
840
765
  else this.removeAttribute("weight");
841
766
  }
842
767
 
768
+ // -------------------------------------------------------------------------
769
+ // Public
770
+ // -------------------------------------------------------------------------
771
+
772
+ render() {
773
+ const svg = getCachedSvg(this.name);
774
+ const sizeVal = this._getSize(this.size);
775
+ const colorVal = this.color ? this._getColor(this.color) : "inherit";
776
+ const weightVal = this._getWeight(this.weight);
777
+
778
+ this._updateAria();
779
+
780
+ this.shadowRoot.innerHTML = `
781
+ <style>
782
+ :host {
783
+ display: inline-flex;
784
+ align-items: center;
785
+ justify-content: center;
786
+ width: ${sizeVal};
787
+ height: ${sizeVal};
788
+ color: ${colorVal};
789
+ line-height: 0;
790
+ }
791
+ .icon-wrapper svg {
792
+ width: 100%;
793
+ height: 100%;
794
+ }
795
+ ${this._getWeightCSS(weightVal)}
796
+ </style>
797
+ <span class="icon-wrapper" part="icon">${svg}</span>
798
+ `;
799
+ }
800
+
801
+ // -------------------------------------------------------------------------
802
+ // Private
803
+ // -------------------------------------------------------------------------
804
+
843
805
  _getColor(color) {
844
806
  const map = {
845
- base: "var(--base-content--, #f7f7fa)",
846
- primary: "var(--primary-content--, #0576ff)",
807
+ base: "var(--base-content--, #f7f7fa)",
808
+ primary: "var(--primary-content--, #0576ff)",
847
809
  secondary: "var(--secondary-content--, #04b8b8)",
848
- success: "var(--success-content--, #2dba73)",
849
- warning: "var(--warning-content--, #d17f04)",
850
- error: "var(--error-content--, #b80421)",
851
- help: "var(--help-content--, #5405ff)",
810
+ success: "var(--success-content--, #2dba73)",
811
+ warning: "var(--warning-content--, #d17f04)",
812
+ error: "var(--error-content--, #b80421)",
813
+ help: "var(--help-content--, #5405ff)",
852
814
  };
853
815
  if (map[color]) return map[color];
854
- if (
855
- color &&
856
- (color.startsWith("#") ||
857
- color.startsWith("rgb") ||
858
- color.startsWith("hsl"))
859
- )
816
+ if (color && (color.startsWith("#") || color.startsWith("rgb") || color.startsWith("hsl"))) {
860
817
  return color;
818
+ }
861
819
  return map.base;
862
820
  }
863
821
 
864
822
  _getSize(size) {
865
823
  const map = {
866
824
  "x-small": "var(--component-icon-size-x-small, 10px)",
867
- small: "var(--component-icon-size-small, 14px)",
868
- medium: "var(--component-icon-size-medium, 18px)",
869
- large: "var(--component-icon-size-large, 22px)",
825
+ small: "var(--component-icon-size-small, 14px)",
826
+ medium: "var(--component-icon-size-medium, 18px)",
827
+ large: "var(--component-icon-size-large, 22px)",
870
828
  "x-large": "var(--component-icon-size-x-large, 28px)",
871
829
  };
872
830
  return map[size] || map.medium;
@@ -874,56 +832,31 @@ class YumeIcon extends HTMLElement {
874
832
 
875
833
  _getWeight(weight) {
876
834
  const map = {
877
- "x-thin": "1",
878
- thin: "1.5",
879
- regular: "2",
880
- thick: "2.5",
835
+ "x-thin": "1",
836
+ thin: "1.5",
837
+ regular: "2",
838
+ thick: "2.5",
881
839
  "x-thick": "3",
882
840
  };
883
841
  return map[weight] || "";
884
842
  }
885
843
 
886
- render() {
887
- const svg = getCachedSvg(this.name);
888
- const sizeVal = this._getSize(this.size);
889
- const colorVal = this.color ? this._getColor(this.color) : "inherit";
890
- const weightVal = this._getWeight(this.weight);
891
- const label = this.label;
844
+ _getWeightCSS(weightVal) {
845
+ if (!weightVal) return "";
846
+ return `.icon-wrapper svg,
847
+ .icon-wrapper svg * { stroke-width: ${weightVal} !important; }`;
848
+ }
892
849
 
893
- if (label) {
850
+ _updateAria() {
851
+ if (this.label) {
894
852
  this.setAttribute("role", "img");
895
- this.setAttribute("aria-label", label);
853
+ this.setAttribute("aria-label", this.label);
896
854
  this.removeAttribute("aria-hidden");
897
855
  } else {
898
856
  this.setAttribute("aria-hidden", "true");
899
857
  this.removeAttribute("role");
900
858
  this.removeAttribute("aria-label");
901
859
  }
902
-
903
- const weightCSS = weightVal
904
- ? `.icon-wrapper svg,
905
- .icon-wrapper svg * { stroke-width: ${weightVal} !important; }`
906
- : "";
907
-
908
- this.shadowRoot.innerHTML = `
909
- <style>
910
- :host {
911
- display: inline-flex;
912
- align-items: center;
913
- justify-content: center;
914
- width: ${sizeVal};
915
- height: ${sizeVal};
916
- color: ${colorVal};
917
- line-height: 0;
918
- }
919
- .icon-wrapper svg {
920
- width: 100%;
921
- height: 100%;
922
- }
923
- ${weightCSS}
924
- </style>
925
- <span class="icon-wrapper" part="icon">${svg}</span>
926
- `;
927
860
  }
928
861
  }
929
862
 
@@ -17,9 +17,9 @@ export class YumeBadge extends HTMLElement {
17
17
  set value(val: string);
18
18
  /** The text content displayed inside the badge. */
19
19
  get value(): string;
20
- getBadgeColors(color: any): any;
21
- getBadgePosition(position: any, alignment: any): string;
22
- getSizeAttributes(size: any): any;
23
- hasTargetContent(): boolean;
24
20
  render(): void;
21
+ _getBadgeColors(color: any): any;
22
+ _getBadgePosition(position: any, alignment: any): string;
23
+ _getSizeAttributes(size: any): any;
24
+ _hasTargetContent(): boolean;
25
25
  }
@@ -5,6 +5,10 @@ class YumeBadge extends HTMLElement {
5
5
  return ["value", "position", "alignment", "color", "size"];
6
6
  }
7
7
 
8
+ // -------------------------------------------------------------------------
9
+ // Lifecycle
10
+ // -------------------------------------------------------------------------
11
+
8
12
  constructor() {
9
13
  super();
10
14
  this.attachShadow({ mode: "open" });
@@ -16,118 +20,44 @@ class YumeBadge extends HTMLElement {
16
20
  }
17
21
 
18
22
  attributeChangedCallback(name, oldValue, newValue) {
19
- if (oldValue !== newValue) {
20
- this.render();
21
- }
23
+ if (oldValue !== newValue) this.render();
22
24
  }
23
25
 
26
+ // -------------------------------------------------------------------------
27
+ // Getters / Setters
28
+ // -------------------------------------------------------------------------
29
+
24
30
  /** Horizontal alignment of the badge: "left" | "right" (default "right"). */
25
- get alignment() {
26
- return this.getAttribute("alignment") || "right";
27
- }
28
- set alignment(val) {
29
- this.setAttribute("alignment", val);
30
- }
31
+ get alignment() { return this.getAttribute("alignment") || "right"; }
32
+ set alignment(val) { this.setAttribute("alignment", val); }
31
33
 
32
34
  /** Color theme: "primary" | "secondary" | "base" | "success" | "warning" | "error" | "help". */
33
- get color() {
34
- return this.getAttribute("color") || "primary";
35
- }
36
- set color(val) {
37
- this.setAttribute("color", val);
38
- }
35
+ get color() { return this.getAttribute("color") || "primary"; }
36
+ set color(val) { this.setAttribute("color", val); }
39
37
 
40
38
  /** Vertical position of the badge: "top" | "bottom" (default "top"). */
41
- get position() {
42
- return this.getAttribute("position") || "top";
43
- }
44
- set position(val) {
45
- this.setAttribute("position", val);
46
- }
39
+ get position() { return this.getAttribute("position") || "top"; }
40
+ set position(val) { this.setAttribute("position", val); }
47
41
 
48
42
  /** Badge size: "small" | "medium" | "large" (default "small"). */
49
- get size() {
50
- return this.getAttribute("size") || "small";
51
- }
52
- set size(val) {
53
- this.setAttribute("size", val);
54
- }
43
+ get size() { return this.getAttribute("size") || "small"; }
44
+ set size(val) { this.setAttribute("size", val); }
55
45
 
56
46
  /** The text content displayed inside the badge. */
57
- get value() {
58
- return this.getAttribute("value") || "";
59
- }
60
- set value(val) {
61
- this.setAttribute("value", val);
62
- }
63
-
64
- getBadgeColors(color) {
65
- const colorMap = {
66
- primary: ["var(--primary-content--)", "var(--primary-content-inverse)"],
67
- secondary: ["var(--secondary-content--)", "var(--secondary-content-inverse)"],
68
- base: ["var(--base-content--)", "var(--base-content-inverse)"],
69
- success: ["var(--success-content--)", "var(--success-content-inverse)"],
70
- warning: ["var(--warning-content--)", "var(--warning-content-inverse)"],
71
- error: ["var(--error-content--)", "var(--error-content-inverse)"],
72
- help: ["var(--help-content--)", "var(--help-content-inverse)"],
73
- };
74
- return colorMap[color] || [color, contrastTextColor(color)];
75
- }
76
-
77
- getBadgePosition(position, alignment) {
78
- const offset = "var(--spacing-small, 6px)";
79
- const vertical =
80
- position === "top"
81
- ? `top: calc(${offset} * -1);`
82
- : `bottom: calc(${offset} * -1);`;
83
- const horizontal =
84
- alignment === "right"
85
- ? `right: calc(${offset} * -1);`
86
- : `left: calc(${offset} * -1);`;
87
- return `${vertical} ${horizontal}`;
88
- }
89
-
90
- getSizeAttributes(size) {
91
- const sizeMap = {
92
- small: {
93
- fontSize: "var(--font-size-small, 0.8em)",
94
- padding: "var(--component-badge-padding-small)",
95
- minSize: "var(--component-badge-size-small)",
96
- },
97
- medium: {
98
- fontSize: "var(--font-size-label, 0.83em)",
99
- padding: "var(--component-badge-padding-medium)",
100
- minSize: "var(--component-badge-size-medium)",
101
- },
102
- large: {
103
- fontSize: "var(--font-size-paragraph, 1em)",
104
- padding: "var(--component-badge-padding-large)",
105
- minSize: "var(--component-badge-size-large)",
106
- },
107
- };
108
- return sizeMap[size] || sizeMap.small;
109
- }
47
+ get value() { return this.getAttribute("value") || ""; }
48
+ set value(val) { this.setAttribute("value", val); }
110
49
 
111
- hasTargetContent() {
112
- return Array.from(this.childNodes).some((node) => {
113
- if (node.nodeType === Node.ELEMENT_NODE) return true;
114
- if (node.nodeType === Node.TEXT_NODE) {
115
- return node.textContent.trim() !== "";
116
- }
117
- return false;
118
- });
119
- }
50
+ // -------------------------------------------------------------------------
51
+ // Public
52
+ // -------------------------------------------------------------------------
120
53
 
121
54
  render() {
122
- const [badgeColor, badgeTextColor] = this.getBadgeColors(this.color);
123
- const { fontSize, padding, minSize } = this.getSizeAttributes(
124
- this.size,
125
- );
126
- const positionStyles = this.getBadgePosition(
127
- this.position,
128
- this.alignment,
129
- );
130
- const hasTarget = this.hasTargetContent();
55
+ const [badgeColor, badgeTextColor] = this._getBadgeColors(this.color);
56
+ const { fontSize, padding, minSize } = this._getSizeAttributes(this.size);
57
+ const hasTarget = this._hasTargetContent();
58
+ const positionCSS = hasTarget
59
+ ? this._getBadgePosition(this.position, this.alignment)
60
+ : "";
131
61
 
132
62
  this.shadowRoot.innerHTML = `
133
63
  <style>
@@ -138,7 +68,7 @@ class YumeBadge extends HTMLElement {
138
68
  }
139
69
  .badge {
140
70
  position: ${hasTarget ? "absolute" : "static"};
141
- ${hasTarget ? positionStyles : ""}
71
+ ${positionCSS}
142
72
  background: ${badgeColor};
143
73
  color: ${badgeTextColor};
144
74
  font-size: ${fontSize};
@@ -162,6 +92,63 @@ class YumeBadge extends HTMLElement {
162
92
  <div class="badge" part="badge">${this.value}</div>
163
93
  `;
164
94
  }
95
+
96
+ // -------------------------------------------------------------------------
97
+ // Private
98
+ // -------------------------------------------------------------------------
99
+
100
+ _getBadgeColors(color) {
101
+ const colorMap = {
102
+ primary: ["var(--primary-content--)", "var(--primary-content-inverse)"],
103
+ secondary: ["var(--secondary-content--)", "var(--secondary-content-inverse)"],
104
+ base: ["var(--base-content--)", "var(--base-content-inverse)"],
105
+ success: ["var(--success-content--)", "var(--success-content-inverse)"],
106
+ warning: ["var(--warning-content--)", "var(--warning-content-inverse)"],
107
+ error: ["var(--error-content--)", "var(--error-content-inverse)"],
108
+ help: ["var(--help-content--)", "var(--help-content-inverse)"],
109
+ };
110
+ return colorMap[color] || [color, contrastTextColor(color)];
111
+ }
112
+
113
+ _getBadgePosition(position, alignment) {
114
+ const offset = "var(--spacing-small, 6px)";
115
+ const vertical = position === "top"
116
+ ? `top: calc(${offset} * -1);`
117
+ : `bottom: calc(${offset} * -1);`;
118
+ const horizontal = alignment === "right"
119
+ ? `right: calc(${offset} * -1);`
120
+ : `left: calc(${offset} * -1);`;
121
+ return `${vertical} ${horizontal}`;
122
+ }
123
+
124
+ _getSizeAttributes(size) {
125
+ const sizeMap = {
126
+ small: {
127
+ fontSize: "var(--font-size-small, 0.8em)",
128
+ padding: "var(--component-badge-padding-small)",
129
+ minSize: "var(--component-badge-size-small)",
130
+ },
131
+ medium: {
132
+ fontSize: "var(--font-size-label, 0.83em)",
133
+ padding: "var(--component-badge-padding-medium)",
134
+ minSize: "var(--component-badge-size-medium)",
135
+ },
136
+ large: {
137
+ fontSize: "var(--font-size-paragraph, 1em)",
138
+ padding: "var(--component-badge-padding-large)",
139
+ minSize: "var(--component-badge-size-large)",
140
+ },
141
+ };
142
+ return sizeMap[size] || sizeMap.small;
143
+ }
144
+
145
+ _hasTargetContent() {
146
+ return Array.from(this.childNodes).some((node) => {
147
+ if (node.nodeType === Node.ELEMENT_NODE) return true;
148
+ if (node.nodeType === Node.TEXT_NODE) return node.textContent.trim() !== "";
149
+ return false;
150
+ });
151
+ }
165
152
  }
166
153
 
167
154
  if (!customElements.get("y-badge")) {
@@ -2,7 +2,15 @@ export class YumeCard extends HTMLElement {
2
2
  static get observedAttributes(): string[];
3
3
  connectedCallback(): void;
4
4
  attributeChangedCallback(name: any, oldValue: any, newValue: any): void;
5
- updateColorStyles(): void;
6
- updateElevationStyles(): void;
5
+ set color(val: string);
6
+ /** Color theme for the card surface. */
7
+ get color(): string;
8
+ set raised(val: boolean);
9
+ /** Whether the card uses a raised shadow instead of a border. */
10
+ get raised(): boolean;
7
11
  render(): void;
12
+ _bindSlotListeners(slotsConfig: any): void;
13
+ _buildStyleSheet(): CSSStyleSheet;
14
+ _updateColorStyles(): void;
15
+ _updateElevationStyles(): void;
8
16
  }