UNPKG

@cell-x/caniuse-embed-element

Version:

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

403 lines (402 loc) 15.5 kB
import { css as P, LitElement as C, html as b } from "lit"; /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ const U = (i) => (t, e) => { e !== void 0 ? e.addInitializer((() => { customElements.define(i, t); })) : customElements.define(i, t); }; /** * @license * Copyright 2019 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ const u = globalThis, g = u.ShadowRoot && (u.ShadyCSS === void 0 || u.ShadyCSS.nativeShadow) && "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype, w = Symbol(), _ = /* @__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 (g && t === void 0) { const s = e !== void 0 && e.length === 1; s && (t = _.get(e)), t === void 0 && ((this.o = t = new CSSStyleSheet()).replaceSync(this.cssText), s && _.set(e, t)); } return t; } toString() { return this.cssText; } }; const A = (i) => new O(typeof i == "string" ? i : i + "", void 0, w), M = (i, t) => { if (g) i.adoptedStyleSheets = t.map(((e) => e instanceof CSSStyleSheet ? e : e.styleSheet)); else for (const e of t) { const s = document.createElement("style"), r = u.litNonce; r !== void 0 && s.setAttribute("nonce", r), s.textContent = e.cssText, i.appendChild(s); } }, E = g ? (i) => i : (i) => i instanceof CSSStyleSheet ? ((t) => { let e = ""; for (const s of t.cssRules) e += s.cssText; return A(e); })(i) : i; /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ const { is: L, defineProperty: x, getOwnPropertyDescriptor: R, getOwnPropertyNames: j, getOwnPropertySymbols: z, getPrototypeOf: k } = Object, m = globalThis, S = m.trustedTypes, D = S ? S.emptyScript : "", T = m.reactiveElementPolyfillSupport, p = (i, t) => i, f = { toAttribute(i, t) { switch (t) { case Boolean: i = i ? D : null; break; case Object: case Array: i = i == null ? i : JSON.stringify(i); } return i; }, fromAttribute(i, t) { let e = i; switch (t) { case Boolean: e = i !== null; break; case Number: e = i === null ? null : Number(i); break; case Object: case Array: try { e = JSON.parse(i); } catch { e = null; } } return e; } }, $ = (i, t) => !L(i, t), v = { attribute: !0, type: String, converter: f, reflect: !1, useDefault: !1, hasChanged: $ }; Symbol.metadata ??= Symbol("metadata"), m.litPropertyMetadata ??= /* @__PURE__ */ new WeakMap(); class d 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(), r = this.getPropertyDescriptor(t, s, e); r !== void 0 && x(this.prototype, t, r); } } static getPropertyDescriptor(t, e, s) { const { get: r, set: o } = R(this.prototype, t) ?? { get() { return this[e]; }, set(a) { this[e] = a; } }; return { get: r, set(a) { const n = r?.call(this); o?.call(this, a), this.requestUpdate(t, n, s); }, configurable: !0, enumerable: !0 }; } static getPropertyOptions(t) { return this.elementProperties.get(t) ?? v; } static _$Ei() { if (this.hasOwnProperty(p("elementProperties"))) return; const t = k(this); t.finalize(), t.l !== void 0 && (this.l = [...t.l]), this.elementProperties = new Map(t.elementProperties); } static finalize() { if (this.hasOwnProperty(p("finalized"))) return; if (this.finalized = !0, this._$Ei(), this.hasOwnProperty(p("properties"))) { const e = this.properties, s = [...j(e), ...z(e)]; for (const r of s) this.createProperty(r, e[r]); } const t = this[Symbol.metadata]; if (t !== null) { const e = litPropertyMetadata.get(t); if (e !== void 0) for (const [s, r] of e) this.elementProperties.set(s, r); } this._$Eh = /* @__PURE__ */ new Map(); for (const [e, s] of this.elementProperties) { const r = this._$Eu(e, s); r !== void 0 && this._$Eh.set(r, 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 r of s) e.unshift(E(r)); } else t !== void 0 && e.push(E(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), r = this.constructor._$Eu(t, s); if (r !== 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(r) : this.setAttribute(r, o), this._$Em = null; } } _$AK(t, e) { const s = this.constructor, r = s._$Eh.get(t); if (r !== void 0 && this._$Em !== r) { const o = s.getPropertyOptions(r), a = typeof o.converter == "function" ? { fromAttribute: o.converter } : o.converter?.fromAttribute !== void 0 ? o.converter : f; this._$Em = r; const n = a.fromAttribute(e, o.type); this[r] = n ?? this._$Ej?.get(r) ?? n, this._$Em = null; } } requestUpdate(t, e, s) { if (t !== void 0) { const r = this.constructor, o = this[t]; if (s ??= r.getPropertyOptions(t), !((s.hasChanged ?? $)(o, e) || s.useDefault && s.reflect && o === this._$Ej?.get(t) && !this.hasAttribute(r._$Eu(t, s)))) return; this.C(t, e, s); } this.isUpdatePending === !1 && (this._$ES = this._$EP()); } C(t, e, { useDefault: s, reflect: r, wrapped: o }, a) { s && !(this._$Ej ??= /* @__PURE__ */ new Map()).has(t) && (this._$Ej.set(t, a ?? e ?? this[t]), o !== !0 || a !== void 0) || (this._$AL.has(t) || (this.hasUpdated || s || (e = void 0), this._$AL.set(t, e)), r === !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 [r, o] of this._$Ep) this[r] = o; this._$Ep = void 0; } const s = this.constructor.elementProperties; if (s.size > 0) for (const [r, o] of s) { const { wrapped: a } = o, n = this[r]; a !== !0 || this._$AL.has(r) || n === void 0 || this.C(r, void 0, o, n); } } 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) { } } d.elementStyles = [], d.shadowRootOptions = { mode: "open" }, d[p("elementProperties")] = /* @__PURE__ */ new Map(), d[p("finalized")] = /* @__PURE__ */ new Map(), T?.({ ReactiveElement: d }), (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: $ }, N = (i = q, t, e) => { const { kind: s, metadata: r } = e; let o = globalThis.litPropertyMetadata.get(r); if (o === void 0 && globalThis.litPropertyMetadata.set(r, o = /* @__PURE__ */ new Map()), s === "setter" && ((i = Object.create(i)).wrapped = !0), o.set(e.name, i), s === "accessor") { const { name: a } = e; return { set(n) { const y = t.get.call(this); t.set.call(this, n), this.requestUpdate(a, y, i); }, init(n) { return n !== void 0 && this.C(a, void 0, i, n), n; } }; } if (s === "setter") { const { name: a } = e; return function(n) { const y = this[a]; t.call(this, n), this.requestUpdate(a, y, i); }; } throw Error("Unsupported decorator location: " + s); }; function l(i) { return (t, e) => typeof e == "object" ? N(i, t, e) : ((s, r, o) => { const a = r.hasOwnProperty(o); return r.constructor.createProperty(o, s), a ? Object.getOwnPropertyDescriptor(r, o) : void 0; })(i, t, e); } var H = Object.defineProperty, I = Object.getOwnPropertyDescriptor, c = (i, t, e, s) => { for (var r = s > 1 ? void 0 : s ? I(t, e) : t, o = i.length - 1, a; o >= 0; o--) (a = i[o]) && (r = (s ? a(t, e, r) : a(r)) || r); return s && r && H(t, e, r), r; }; 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.loaded = !1, this._iframeHeight = 500, this.handleMessage = (i) => { const t = this.parseData(i.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()); }, this.handleIframeLoad = () => { this.loaded = !0; }; } /** * 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(i) { try { return typeof i == "string" ? JSON.parse(i) : i; } 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 i = [ `meta=${this.meta}`, `past=${this.past}`, `future=${this.future}`, `theme=${this.theme}` ]; return `${this.origin}/${this.feature}#${i.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 i = this.generateSource(); return i ? b`<iframe class="ciu-embed-iframe" src="${i}" height="${this._iframeHeight}" allow="fullscreen" loading="${this.loading}" @load="${this.handleIframeLoad}"></iframe>` : (this.loaded = !0, b`<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%;position:relative}:host(:not([loaded]))::after{content:"Loading " attr(feature) " compatibility data";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:var(--text-secondary,#919191);font-size:14px;text-align:center;pointer-events:none;opacity:1;transition:opacity .3s ease;z-index:1;animation:loading-dots 1.5s infinite}@keyframes loading-dots{0%,20%{content:"Loading " attr(feature) " compatibility data"}40%{content:"Loading " attr(feature) " compatibility data."}60%{content:"Loading " attr(feature) " compatibility data.."}100%,80%{content:"Loading " attr(feature) " compatibility data..."}}:host([loaded])::after{opacity:0}.ciu-embed-iframe{display:block;width:100%;border:none;border-radius:0;opacity:0;transition:opacity .3s ease}:host([loaded]) .ciu-embed-iframe{opacity:1}.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); c([ l({ type: Boolean, reflect: !0 }) ], h.prototype, "loaded", 2); h = c([ U("caniuse-embed") ], h); export { h as CaniuseEmbedElement };