main
js 70 lines 1.81 KB
Raw
1 const ICON_TAG = "x-icon";
2 const ICON_NAME_PATTERN = /^[a-z0-9][a-z0-9_]*$/;
3
4 export const ICON_SELECTOR = `${ICON_TAG}, .material-symbols-outlined, .material-icons-outlined`;
5
6 export function normalizeIconName(value) {
7 const name = String(value ?? "").trim();
8 return ICON_NAME_PATTERN.test(name) ? name : "";
9 }
10
11 export function getIconName(element) {
12 if (!element) return "";
13 if (element.localName === ICON_TAG) {
14 return normalizeIconName(element.getAttribute("name"));
15 }
16 return normalizeIconName(element.textContent);
17 }
18
19 export function setIconName(element, value) {
20 if (!element) return;
21 const name = normalizeIconName(value);
22 if (element.localName === ICON_TAG) {
23 if (name) element.setAttribute("name", name);
24 else element.removeAttribute("name");
25 return;
26 }
27 element.textContent = name;
28 }
29
30 if (!customElements.get(ICON_TAG)) {
31 customElements.define(
32 ICON_TAG,
33 class extends HTMLElement {
34 static get observedAttributes() {
35 return ["name"];
36 }
37
38 get name() {
39 return normalizeIconName(this.getAttribute("name"));
40 }
41
42 set name(value) {
43 setIconName(this, value);
44 }
45
46 connectedCallback() {
47 // Preserve selectors used by older third-party plugin styles while
48 // first-party markup uses the semantic custom element.
49 this.classList.add("material-symbols-outlined");
50 if (
51 !this.hasAttribute("aria-hidden") &&
52 !this.hasAttribute("aria-label") &&
53 !this.hasAttribute("aria-labelledby")
54 ) {
55 this.setAttribute("aria-hidden", "true");
56 }
57 this.render();
58 }
59
60 attributeChangedCallback() {
61 this.render();
62 }
63
64 render() {
65 const name = this.name;
66 if (this.textContent !== name) this.textContent = name;
67 }
68 },
69 );
70 }