fxview-empty-state.mjs (5194B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 import { 6 html, 7 classMap, 8 repeat, 9 } from "chrome://global/content/vendor/lit.all.mjs"; 10 import { MozLitElement } from "chrome://global/content/lit-utils.mjs"; 11 import { navigateToLink } from "chrome://browser/content/firefoxview/helpers.mjs"; 12 13 /** 14 * An empty state card to be used throughout Firefox View 15 * 16 * @property {string} headerLabel - (Optional) The l10n id for the header text for the empty/error state 17 * @property {object} headerArgs - (Optional) The l10n args for the header text for the empty/error state 18 * @property {string} isInnerCard - (Optional) True if the card is displayed within another card and needs a border instead of box shadow 19 * @property {boolean} isSelectedTab - (Optional) True if the component is the selected navigation tab - defaults to false 20 * @property {Array} descriptionLabels - (Optional) An array of l10n ids for the secondary description text for the empty/error state 21 * @property {object} descriptionLink - (Optional) An object describing the l10n name and url needed within a description label 22 * @property {string} mainImageUrl - (Optional) The chrome:// url for the main image of the empty/error state 23 * @property {string} errorGrayscale - (Optional) The image should be shown in gray scale 24 * @property {boolean} openLinkInParentWindow - (Optional) The link, when clicked, should be opened programatically in the parent window. 25 */ 26 class FxviewEmptyState extends MozLitElement { 27 constructor() { 28 super(); 29 this.isSelectedTab = false; 30 this.descriptionLabels = []; 31 this.headerArgs = {}; 32 } 33 34 static properties = { 35 headerLabel: { type: String }, 36 headerArgs: { type: Object }, 37 isInnerCard: { type: Boolean }, 38 isSelectedTab: { type: Boolean }, 39 descriptionLabels: { type: Array }, 40 desciptionLink: { type: Object }, 41 mainImageUrl: { type: String }, 42 errorGrayscale: { type: Boolean }, 43 openLinkInParentWindow: { type: Boolean }, 44 }; 45 46 static queries = { 47 headerEl: ".header", 48 descriptionEls: { all: ".description" }, 49 }; 50 51 linkTemplate(descriptionLink) { 52 if (!descriptionLink) { 53 return html``; 54 } 55 return html`<a 56 data-l10n-name=${descriptionLink.name} 57 href=${descriptionLink.url} 58 target=${descriptionLink?.sameTarget ? "_self" : "_blank"} 59 ></a>`; 60 } 61 62 render() { 63 return html` 64 <link 65 rel="stylesheet" 66 href="chrome://browser/content/firefoxview/fxview-empty-state.css" 67 /> 68 <card-container 69 hideHeader="true" 70 exportparts="image" 71 ?isInnerCard=${this.isInnerCard} 72 id="card-container" 73 isEmptyState="true" 74 role="group" 75 aria-labelledby="header" 76 aria-describedby="description" 77 > 78 <div 79 slot="main" 80 part="container" 81 class=${classMap({ 82 selectedTab: this.isSelectedTab, 83 imageHidden: !this.mainImageUrl, 84 })} 85 > 86 <div class="image-container" part="image-container"> 87 <img 88 class=${classMap({ 89 image: true, 90 greyscale: this.errorGrayscale, 91 })} 92 part="image" 93 role="presentation" 94 alt="" 95 ?hidden=${!this.mainImageUrl} 96 src=${this.mainImageUrl} 97 /> 98 </div> 99 <div class="main" part="main"> 100 <h2 101 part="header" 102 id="header" 103 class="header heading-large" 104 ?hidden=${!this.headerLabel} 105 > 106 <span 107 data-l10n-id=${this.headerLabel} 108 data-l10n-args=${JSON.stringify(this.headerArgs)} 109 > 110 </span> 111 </h2> 112 <span id="description"> 113 ${repeat( 114 this.descriptionLabels, 115 descLabel => descLabel, 116 (descLabel, index) => 117 html`<p 118 class=${classMap({ 119 description: true, 120 secondary: index !== 0, 121 })} 122 data-l10n-id=${descLabel} 123 @click=${this.openLinkInParentWindow && 124 this.linkActionHandler} 125 @keydown=${this.openLinkInParentWindow && 126 this.linkActionHandler} 127 > 128 ${this.linkTemplate(this.descriptionLink)} 129 </p>` 130 )} 131 </span> 132 <slot name="primary-action"></slot> 133 </div> 134 </div> 135 </card-container> 136 `; 137 } 138 139 linkActionHandler(e) { 140 const shouldNavigate = 141 (e.type == "click" && !e.altKey) || 142 (e.type == "keydown" && e.code == "Enter") || 143 (e.type == "keydown" && e.code == "Space"); 144 if (shouldNavigate && e.target.href) { 145 navigateToLink(e, e.target.href); 146 e.preventDefault(); 147 } 148 } 149 } 150 customElements.define("fxview-empty-state", FxviewEmptyState);