diff options
Diffstat (limited to 'browser/components/firefoxview/card-container.mjs')
-rw-r--r-- | browser/components/firefoxview/card-container.mjs | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/browser/components/firefoxview/card-container.mjs b/browser/components/firefoxview/card-container.mjs new file mode 100644 index 0000000000..b58f42204a --- /dev/null +++ b/browser/components/firefoxview/card-container.mjs @@ -0,0 +1,208 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import { + classMap, + html, + ifDefined, + when, +} from "chrome://global/content/vendor/lit.all.mjs"; +import { MozLitElement } from "chrome://global/content/lit-utils.mjs"; + +/** + * A collapsible card container to be used throughout Firefox View + * + * @property {string} sectionLabel - The aria-label used for the section landmark if the header is hidden with hideHeader + * @property {boolean} hideHeader - Optional property given if the card container should not display a header + * @property {boolean} isEmptyState - Optional property given if the card is used within an empty state + * @property {boolean} isInnerCard - Optional property given if the card a nested card within another card and given a border rather than box-shadow + * @property {boolean} preserveCollapseState - Whether or not the expanded/collapsed state should persist + * @property {string} shortPageName - Page name that the 'View all' link will navigate to and the preserveCollapseState pref will use + * @property {boolean} showViewAll - True if you need to display a 'View all' header link to navigate + * @property {boolean} toggleDisabled - Optional property given if the card container should not be collapsible + * @property {boolean} removeBlockEndMargin - True if you need to remove the block end margin on the card container + */ +class CardContainer extends MozLitElement { + constructor() { + super(); + this.initiallyExpanded = true; + this.isExpanded = false; + this.visible = false; + } + + static properties = { + sectionLabel: { type: String }, + hideHeader: { type: Boolean }, + isExpanded: { type: Boolean }, + isEmptyState: { type: Boolean }, + isInnerCard: { type: Boolean }, + preserveCollapseState: { type: Boolean }, + shortPageName: { type: String }, + showViewAll: { type: Boolean }, + toggleDisabled: { type: Boolean }, + removeBlockEndMargin: { type: Boolean }, + visible: { type: Boolean }, + }; + + static queries = { + detailsEl: "details", + mainSlot: "slot[name=main]", + summaryEl: "summary", + viewAllLink: ".view-all-link", + }; + + get detailsExpanded() { + return this.detailsEl.hasAttribute("open"); + } + + get detailsOpenPrefValue() { + const prefName = this.shortPageName + ? `browser.tabs.firefox-view.ui-state.${this.shortPageName}.open` + : null; + if (prefName && Services.prefs.prefHasUserValue(prefName)) { + return Services.prefs.getBoolPref(prefName); + } + return null; + } + + connectedCallback() { + super.connectedCallback(); + this.isExpanded = this.detailsOpenPrefValue ?? this.initiallyExpanded; + } + + onToggleContainer() { + if (this.isExpanded == this.detailsExpanded) { + return; + } + this.isExpanded = this.detailsExpanded; + + this.updateTabLists(); + + if (!this.shortPageName) { + return; + } + + if (this.preserveCollapseState) { + const prefName = this.shortPageName + ? `browser.tabs.firefox-view.ui-state.${this.shortPageName}.open` + : null; + Services.prefs.setBoolPref(prefName, this.isExpanded); + } + + // Record telemetry + Services.telemetry.recordEvent( + "firefoxview_next", + this.isExpanded ? "card_expanded" : "card_collapsed", + "card_container", + null, + { + data_type: this.shortPageName, + } + ); + } + + viewAllClicked() { + this.dispatchEvent( + new CustomEvent("card-container-view-all", { + bubbles: true, + composed: true, + }) + ); + } + + willUpdate(changes) { + if (changes.has("visible")) { + this.updateTabLists(); + } + } + + updateTabLists() { + let tabLists = this.querySelectorAll("fxview-tab-list"); + if (tabLists) { + tabLists.forEach(tabList => { + tabList.updatesPaused = !this.visible || !this.isExpanded; + }); + } + } + + render() { + return html` + <link + rel="stylesheet" + href="chrome://browser/content/firefoxview/card-container.css" + /> + <section + aria-labelledby="header" + aria-label=${ifDefined(this.sectionLabel)} + > + ${when( + this.toggleDisabled, + () => html`<div + class=${classMap({ + "card-container": true, + inner: this.isInnerCard, + "empty-state": this.isEmptyState && !this.isInnerCard, + })} + > + <span + id="header" + class="card-container-header" + ?hidden=${ifDefined(this.hideHeader)} + toggleDisabled + ?withViewAll=${this.showViewAll} + > + <slot name="header"></slot> + <slot name="secondary-header"></slot> + </span> + <a + href="about:firefoxview#${this.shortPageName}" + @click=${this.viewAllClicked} + class="view-all-link" + data-l10n-id="firefoxview-view-all-link" + ?hidden=${!this.showViewAll} + ></a> + <slot name="main"></slot> + <slot name="footer" class="card-container-footer"></slot> + </div>`, + () => html`<details + class=${classMap({ + "card-container": true, + inner: this.isInnerCard, + "empty-state": this.isEmptyState && !this.isInnerCard, + })} + ?open=${this.isExpanded} + ?isOpenTabsView=${this.removeBlockEndMargin} + @toggle=${this.onToggleContainer} + > + <summary + id="header" + class="card-container-header" + ?hidden=${ifDefined(this.hideHeader)} + ?withViewAll=${this.showViewAll} + > + <span + class="icon chevron-icon" + aria-role="presentation" + data-l10n-id="firefoxview-collapse-button-${this.isExpanded + ? "hide" + : "show"}" + ></span> + <slot name="header"></slot> + </summary> + <a + href="about:firefoxview#${this.shortPageName}" + @click=${this.viewAllClicked} + class="view-all-link" + data-l10n-id="firefoxview-view-all-link" + ?hidden=${!this.showViewAll} + ></a> + <slot name="main"></slot> + <slot name="footer" class="card-container-footer"></slot> + </details>` + )} + </section> + `; + } +} +customElements.define("card-container", CardContainer); |