Bug 1944416: Restore individual tabs from closed groups in closed windows r=dao,sessi...
[gecko.git] / browser / components / firefoxview / fxview-empty-state.mjs
blobc9253abb5e7253f82bff131708d5f678ba275b6c
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/. */
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";
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   }
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   };
46   static queries = {
47     headerEl: ".header",
48     descriptionEls: { all: ".description" },
49   };
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     />`;
60   }
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   }
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   }
150 customElements.define("fxview-empty-state", FxviewEmptyState);