UNPKG

@cell-x/caniuse-embed-element

Version:

A custom web component that embeds caniuse.com browser compatibility data for a specific feature.

398 lines (397 loc) 14.6 kB
import { css as P, LitElement as C, html as _ } from "lit"; /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ const U = (r) => (t, e) => { e !== void 0 ? e.addInitializer(() => { customElements.define(r, t); }) : customElements.define(r, t); }; /** * @license * Copyright 2019 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ const u = globalThis, $ = u.ShadowRoot && (u.ShadyCSS === void 0 || u.ShadyCSS.nativeShadow) && "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype, w = Symbol(), E = /* @__PURE__ */ new WeakMap(); let O = class { constructor(t, e, s) { if (this._$cssResult$ = !0, s !== w) throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead."); this.cssText = t, this.t = e; } get styleSheet() { let t = this.o; const e = this.t; if ($ && t === void 0) { const s = e !== void 0 && e.length === 1; s && (t = E.get(e)), t === void 0 && ((this.o = t = new CSSStyleSheet()).replaceSync(this.cssText), s && E.set(e, t)); } return t; } toString() { return this.cssText; } }; const A = (r) => new O(typeof r == "string" ? r : r + "", void 0, w), M = (r, t) => { if ($) r.adoptedStyleSheets = t.map((e) => e instanceof CSSStyleSheet ? e : e.styleSheet); else for (const e of t) { const s = document.createElement("style"), i = u.litNonce; i !== void 0 && s.setAttribute("nonce", i), s.textContent = e.cssText, r.appendChild(s); } }, b = $ ? (r) => r : (r) => r instanceof CSSStyleSheet ? ((t) => { let e = ""; for (const s of t.cssRules) e += s.cssText; return A(e); })(r) : r; /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ const { is: R, defineProperty: j, getOwnPropertyDescriptor: x, getOwnPropertyNames: z, getOwnPropertySymbols: D, getPrototypeOf: T } = Object, m = globalThis, S = m.trustedTypes, k = S ? S.emptyScript : "", L = m.reactiveElementPolyfillSupport, d = (r, t) => r, f = { toAttribute(r, t) { switch (t) { case Boolean: r = r ? k : null; break; case Object: case Array: r = r == null ? r : JSON.stringify(r); } return r; }, fromAttribute(r, t) { let e = r; switch (t) { case Boolean: e = r !== null; break; case Number: e = r === null ? null : Number(r); break; case Object: case Array: try { e = JSON.parse(r); } catch { e = null; } } return e; } }, g = (r, t) => !R(r, t), v = { attribute: !0, type: String, converter: f, reflect: !1, useDefault: !1, hasChanged: g }; Symbol.metadata ??= Symbol("metadata"), m.litPropertyMetadata ??= /* @__PURE__ */ new WeakMap(); class p extends HTMLElement { static addInitializer(t) { this._$Ei(), (this.l ??= []).push(t); } static get observedAttributes() { return this.finalize(), this._$Eh && [...this._$Eh.keys()]; } static createProperty(t, e = v) { if (e.state && (e.attribute = !1), this._$Ei(), this.prototype.hasOwnProperty(t) && ((e = Object.create(e)).wrapped = !0), this.elementProperties.set(t, e), !e.noAccessor) { const s = Symbol(), i = this.getPropertyDescriptor(t, s, e); i !== void 0 && j(this.prototype, t, i); } } static getPropertyDescriptor(t, e, s) { const { get: i, set: o } = x(this.prototype, t) ?? { get() { return this[e]; }, set(n) { this[e] = n; } }; return { get: i, set(n) { const a = i?.call(this); o?.call(this, n), this.requestUpdate(t, a, s); }, configurable: !0, enumerable: !0 }; } static getPropertyOptions(t) { return this.elementProperties.get(t) ?? v; } static _$Ei() { if (this.hasOwnProperty(d("elementProperties"))) return; const t = T(this); t.finalize(), t.l !== void 0 && (this.l = [...t.l]), this.elementProperties = new Map(t.elementProperties); } static finalize() { if (this.hasOwnProperty(d("finalized"))) return; if (this.finalized = !0, this._$Ei(), this.hasOwnProperty(d("properties"))) { const e = this.properties, s = [...z(e), ...D(e)]; for (const i of s) this.createProperty(i, e[i]); } const t = this[Symbol.metadata]; if (t !== null) { const e = litPropertyMetadata.get(t); if (e !== void 0) for (const [s, i] of e) this.elementProperties.set(s, i); } this._$Eh = /* @__PURE__ */ new Map(); for (const [e, s] of this.elementProperties) { const i = this._$Eu(e, s); i !== void 0 && this._$Eh.set(i, e); } this.elementStyles = this.finalizeStyles(this.styles); } static finalizeStyles(t) { const e = []; if (Array.isArray(t)) { const s = new Set(t.flat(1 / 0).reverse()); for (const i of s) e.unshift(b(i)); } else t !== void 0 && e.push(b(t)); return e; } static _$Eu(t, e) { const s = e.attribute; return s === !1 ? void 0 : typeof s == "string" ? s : typeof t == "string" ? t.toLowerCase() : void 0; } constructor() { super(), this._$Ep = void 0, this.isUpdatePending = !1, this.hasUpdated = !1, this._$Em = null, this._$Ev(); } _$Ev() { this._$ES = new Promise((t) => this.enableUpdating = t), this._$AL = /* @__PURE__ */ new Map(), this._$E_(), this.requestUpdate(), this.constructor.l?.forEach((t) => t(this)); } addController(t) { (this._$EO ??= /* @__PURE__ */ new Set()).add(t), this.renderRoot !== void 0 && this.isConnected && t.hostConnected?.(); } removeController(t) { this._$EO?.delete(t); } _$E_() { const t = /* @__PURE__ */ new Map(), e = this.constructor.elementProperties; for (const s of e.keys()) this.hasOwnProperty(s) && (t.set(s, this[s]), delete this[s]); t.size > 0 && (this._$Ep = t); } createRenderRoot() { const t = this.shadowRoot ?? this.attachShadow(this.constructor.shadowRootOptions); return M(t, this.constructor.elementStyles), t; } connectedCallback() { this.renderRoot ??= this.createRenderRoot(), this.enableUpdating(!0), this._$EO?.forEach((t) => t.hostConnected?.()); } enableUpdating(t) { } disconnectedCallback() { this._$EO?.forEach((t) => t.hostDisconnected?.()); } attributeChangedCallback(t, e, s) { this._$AK(t, s); } _$ET(t, e) { const s = this.constructor.elementProperties.get(t), i = this.constructor._$Eu(t, s); if (i !== void 0 && s.reflect === !0) { const o = (s.converter?.toAttribute !== void 0 ? s.converter : f).toAttribute(e, s.type); this._$Em = t, o == null ? this.removeAttribute(i) : this.setAttribute(i, o), this._$Em = null; } } _$AK(t, e) { const s = this.constructor, i = s._$Eh.get(t); if (i !== void 0 && this._$Em !== i) { const o = s.getPropertyOptions(i), n = typeof o.converter == "function" ? { fromAttribute: o.converter } : o.converter?.fromAttribute !== void 0 ? o.converter : f; this._$Em = i; const a = n.fromAttribute(e, o.type); this[i] = a ?? this._$Ej?.get(i) ?? a, this._$Em = null; } } requestUpdate(t, e, s) { if (t !== void 0) { const i = this.constructor, o = this[t]; if (s ??= i.getPropertyOptions(t), !((s.hasChanged ?? g)(o, e) || s.useDefault && s.reflect && o === this._$Ej?.get(t) && !this.hasAttribute(i._$Eu(t, s)))) return; this.C(t, e, s); } this.isUpdatePending === !1 && (this._$ES = this._$EP()); } C(t, e, { useDefault: s, reflect: i, wrapped: o }, n) { s && !(this._$Ej ??= /* @__PURE__ */ new Map()).has(t) && (this._$Ej.set(t, n ?? e ?? this[t]), o !== !0 || n !== void 0) || (this._$AL.has(t) || (this.hasUpdated || s || (e = void 0), this._$AL.set(t, e)), i === !0 && this._$Em !== t && (this._$Eq ??= /* @__PURE__ */ new Set()).add(t)); } async _$EP() { this.isUpdatePending = !0; try { await this._$ES; } catch (e) { Promise.reject(e); } const t = this.scheduleUpdate(); return t != null && await t, !this.isUpdatePending; } scheduleUpdate() { return this.performUpdate(); } performUpdate() { if (!this.isUpdatePending) return; if (!this.hasUpdated) { if (this.renderRoot ??= this.createRenderRoot(), this._$Ep) { for (const [i, o] of this._$Ep) this[i] = o; this._$Ep = void 0; } const s = this.constructor.elementProperties; if (s.size > 0) for (const [i, o] of s) { const { wrapped: n } = o, a = this[i]; n !== !0 || this._$AL.has(i) || a === void 0 || this.C(i, void 0, o, a); } } let t = !1; const e = this._$AL; try { t = this.shouldUpdate(e), t ? (this.willUpdate(e), this._$EO?.forEach((s) => s.hostUpdate?.()), this.update(e)) : this._$EM(); } catch (s) { throw t = !1, this._$EM(), s; } t && this._$AE(e); } willUpdate(t) { } _$AE(t) { this._$EO?.forEach((e) => e.hostUpdated?.()), this.hasUpdated || (this.hasUpdated = !0, this.firstUpdated(t)), this.updated(t); } _$EM() { this._$AL = /* @__PURE__ */ new Map(), this.isUpdatePending = !1; } get updateComplete() { return this.getUpdateComplete(); } getUpdateComplete() { return this._$ES; } shouldUpdate(t) { return !0; } update(t) { this._$Eq &&= this._$Eq.forEach((e) => this._$ET(e, this[e])), this._$EM(); } updated(t) { } firstUpdated(t) { } } p.elementStyles = [], p.shadowRootOptions = { mode: "open" }, p[d("elementProperties")] = /* @__PURE__ */ new Map(), p[d("finalized")] = /* @__PURE__ */ new Map(), L?.({ ReactiveElement: p }), (m.reactiveElementVersions ??= []).push("2.1.1"); /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ const q = { attribute: !0, type: String, converter: f, reflect: !1, hasChanged: g }, N = (r = q, t, e) => { const { kind: s, metadata: i } = e; let o = globalThis.litPropertyMetadata.get(i); if (o === void 0 && globalThis.litPropertyMetadata.set(i, o = /* @__PURE__ */ new Map()), s === "setter" && ((r = Object.create(r)).wrapped = !0), o.set(e.name, r), s === "accessor") { const { name: n } = e; return { set(a) { const y = t.get.call(this); t.set.call(this, a), this.requestUpdate(n, y, r); }, init(a) { return a !== void 0 && this.C(n, void 0, r, a), a; } }; } if (s === "setter") { const { name: n } = e; return function(a) { const y = this[n]; t.call(this, a), this.requestUpdate(n, y, r); }; } throw Error("Unsupported decorator location: " + s); }; function l(r) { return (t, e) => typeof e == "object" ? N(r, t, e) : ((s, i, o) => { const n = i.hasOwnProperty(o); return i.constructor.createProperty(o, s), n ? Object.getOwnPropertyDescriptor(i, o) : void 0; })(r, t, e); } var H = Object.defineProperty, J = Object.getOwnPropertyDescriptor, c = (r, t, e, s) => { for (var i = s > 1 ? void 0 : s ? J(t, e) : t, o = r.length - 1, n; o >= 0; o--) (n = r[o]) && (i = (s ? n(t, e, i) : n(i)) || i); return s && i && H(t, e, i), i; }; let h = class extends C { constructor() { super(...arguments), this.feature = "", this.past = 2, this.future = 1, this.origin = "https://caniuse.lruihao.cn", this.theme = "auto", this.loading = "lazy", this.meta = Math.random().toString(36).slice(2), this._iframeHeight = 500, this.handleMessage = (r) => { const t = this.parseData(r.data), { type: e, payload: s = {} } = t; e === "ciu_embed" && s.feature === this.feature && s.meta === this.meta && (this._iframeHeight = Math.ceil(s.height), this.requestUpdate()); }; } /** * Called when the element is added to the DOM. * Sets up the message listener for iframe communication. */ connectedCallback() { super.connectedCallback(), this.setupMessageListener(); } /** * Called when the element is removed from the DOM. * Cleans up the message event listener to prevent memory leaks. */ disconnectedCallback() { super.disconnectedCallback(), window.removeEventListener("message", this.handleMessage); } /** * Sets up the global message event listener for iframe communication. * This allows the component to receive height updates from the embedded iframe. * @private */ setupMessageListener() { window.addEventListener("message", this.handleMessage); } /** * Safely parses incoming message data, handling both string and object formats. * @param data - The raw data from a postMessage event * @returns Parsed data object or empty object if parsing fails * @private */ parseData(r) { try { return typeof r == "string" ? JSON.parse(r) : r; } catch { return {}; } } /** * Generates the iframe source URL based on current component properties. * Constructs the URL with feature, meta, theme, and past version parameters. * @returns The complete URL for the iframe source, or empty string if no feature is specified * @private */ generateSource() { if (!this.feature) return ""; const r = [ `meta=${this.meta}`, `past=${this.past}`, `future=${this.future}`, `theme=${this.theme}` ]; return `${this.origin}/${this.feature}#${r.join("&")}`; } /** * Renders the component's HTML template. * Shows either an iframe with caniuse data or a placeholder message when no feature is specified. * @returns The HTML template for this component */ render() { const r = this.generateSource(); return r ? _`<iframe class="ciu-embed-iframe" src="${r}" height="${this._iframeHeight}" allow="fullscreen" loading="${this.loading}"></iframe>` : _`<p class="ciu-embed-empty"><span>Data on support for the features across the major browsers from <a href="https://caniuse.com" target="_blank">caniuse.com</a>.</span><br><span>[ The feature parameter is required! ]</span></p>`; } }; h.styles = P`:host { display: block; width: 100%; }.ciu-embed-iframe { display: block; width: 100%; border: none; border-radius: 0; }.ciu-embed-empty { color: var(--text-secondary, #919191); text-align: center; font-size: 12px; }.ciu-embed-empty a { color: inherit; text-decoration: none; }.ciu-embed-empty a:hover { text-decoration: underline; }`; c([ l() ], h.prototype, "feature", 2); c([ l({ type: Number }) ], h.prototype, "past", 2); c([ l({ type: Number }) ], h.prototype, "future", 2); c([ l() ], h.prototype, "origin", 2); c([ l({ type: String }) ], h.prototype, "theme", 2); c([ l() ], h.prototype, "loading", 2); c([ l() ], h.prototype, "meta", 2); h = c([ U("caniuse-embed") ], h); export { h as CaniuseEmbedElement };