summaryrefslogtreecommitdiffstats
path: root/toolkit/content/widgets/moz-button-group
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/content/widgets/moz-button-group')
-rw-r--r--toolkit/content/widgets/moz-button-group/moz-button-group.css13
-rw-r--r--toolkit/content/widgets/moz-button-group/moz-button-group.mjs107
-rw-r--r--toolkit/content/widgets/moz-button-group/moz-button-group.stories.mjs57
3 files changed, 177 insertions, 0 deletions
diff --git a/toolkit/content/widgets/moz-button-group/moz-button-group.css b/toolkit/content/widgets/moz-button-group/moz-button-group.css
new file mode 100644
index 0000000000..f0cc0e5480
--- /dev/null
+++ b/toolkit/content/widgets/moz-button-group/moz-button-group.css
@@ -0,0 +1,13 @@
+/* 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/. */
+
+:host {
+ display: flex;
+ gap: 8px;
+ justify-content: flex-end;
+}
+
+::slotted(button) {
+ margin: 0 !important;
+}
diff --git a/toolkit/content/widgets/moz-button-group/moz-button-group.mjs b/toolkit/content/widgets/moz-button-group/moz-button-group.mjs
new file mode 100644
index 0000000000..04c75e5d10
--- /dev/null
+++ b/toolkit/content/widgets/moz-button-group/moz-button-group.mjs
@@ -0,0 +1,107 @@
+/* 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 { html } from "chrome://global/content/vendor/lit.all.mjs";
+import { MozLitElement } from "chrome://global/content/lit-utils.mjs";
+
+export const PLATFORM_LINUX = "linux";
+export const PLATFORM_MACOS = "macosx";
+export const PLATFORM_WINDOWS = "win";
+
+/**
+ * A grouping of buttons. Primary button order will be set automatically based
+ * on class="primary", type="submit" or autofocus attribute. Set slot="primary"
+ * on a primary button that does not have primary styling to set its position.
+ *
+ * @tagname moz-button-group
+ * @property {string} platform - The detected platform, set automatically.
+ */
+export default class MozButtonGroup extends MozLitElement {
+ static queries = {
+ defaultSlotEl: "slot:not([name])",
+ primarySlotEl: "slot[name=primary]",
+ };
+
+ static properties = {
+ platform: { state: true },
+ };
+
+ // Use a relative URL in storybook to get faster reloads on style changes.
+ static stylesheetUrl = window.IS_STORYBOOK
+ ? "./moz-button-group/moz-button-group.css"
+ : "chrome://global/content/elements/moz-button-group.css";
+
+ constructor() {
+ super();
+ this.#detectPlatform();
+ }
+
+ #detectPlatform() {
+ if (typeof AppConstants !== "undefined") {
+ this.platform = AppConstants.platform;
+ } else if (navigator.platform.includes("Linux")) {
+ this.platform = PLATFORM_LINUX;
+ } else if (navigator.platform.includes("Mac")) {
+ this.platform = PLATFORM_MACOS;
+ } else {
+ this.platform = PLATFORM_WINDOWS;
+ }
+ }
+
+ onSlotchange(e) {
+ for (let child of this.defaultSlotEl.assignedNodes()) {
+ if (!(child instanceof Element)) {
+ // Text nodes won't support classList or getAttribute.
+ continue;
+ }
+ // Bug 1791816: These should check moz-button instead of button.
+ if (
+ child.localName == "button" &&
+ (child.classList.contains("primary") ||
+ child.getAttribute("type") == "submit" ||
+ child.hasAttribute("autofocus") ||
+ child.hasAttribute("default"))
+ ) {
+ child.slot = "primary";
+ }
+ }
+ this.#reorderLightDom();
+ }
+
+ #reorderLightDom() {
+ let primarySlottedChildren = [...this.primarySlotEl.assignedNodes()];
+ if (this.platform == PLATFORM_WINDOWS) {
+ primarySlottedChildren.reverse();
+ for (let child of primarySlottedChildren) {
+ child.parentElement.prepend(child);
+ }
+ } else {
+ for (let child of primarySlottedChildren) {
+ // Ensure the primary buttons are at the end of the light DOM.
+ child.parentElement.append(child);
+ }
+ }
+ }
+
+ updated(changedProperties) {
+ if (changedProperties.has("platform")) {
+ this.#reorderLightDom();
+ }
+ }
+
+ render() {
+ let slots = [
+ html` <slot @slotchange=${this.onSlotchange}></slot> `,
+ html` <slot name="primary"></slot> `,
+ ];
+ if (this.platform == PLATFORM_WINDOWS) {
+ slots = [slots[1], slots[0]];
+ }
+ return html`
+ <link rel="stylesheet" href=${this.constructor.stylesheetUrl} />
+ ${slots}
+ `;
+ }
+}
+customElements.define("moz-button-group", MozButtonGroup);
diff --git a/toolkit/content/widgets/moz-button-group/moz-button-group.stories.mjs b/toolkit/content/widgets/moz-button-group/moz-button-group.stories.mjs
new file mode 100644
index 0000000000..444cc5373c
--- /dev/null
+++ b/toolkit/content/widgets/moz-button-group/moz-button-group.stories.mjs
@@ -0,0 +1,57 @@
+/* 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 { html } from "../vendor/lit.all.mjs";
+import {
+ PLATFORM_LINUX,
+ PLATFORM_MACOS,
+ PLATFORM_WINDOWS,
+} from "./moz-button-group.mjs";
+
+export default {
+ title: "UI Widgets/Button Group",
+ component: "moz-button-group",
+ argTypes: {
+ platform: {
+ options: [PLATFORM_LINUX, PLATFORM_MACOS, PLATFORM_WINDOWS],
+ control: { type: "select" },
+ },
+ },
+ parameters: {
+ status: "stable",
+ fluent: `
+moz-button-group-p = The button group is below. Card for emphasis.
+moz-button-group-ok = OK
+moz-button-group-cancel = Cancel
+ `,
+ },
+};
+
+const Template = ({ platform }) => html`
+ <div class="card card-no-hover" style="max-width: 400px">
+ <p data-l10n-id="moz-button-group-p"></p>
+ <moz-button-group .platform=${platform}>
+ <button class="primary" data-l10n-id="moz-button-group-ok"></button>
+ <button data-l10n-id="moz-button-group-cancel"></button>
+ </moz-button-group>
+ </div>
+`;
+
+export const Default = Template.bind({});
+Default.args = {
+ // Platform will auto-detected.
+};
+
+export const Windows = Template.bind({});
+Windows.args = {
+ platform: PLATFORM_WINDOWS,
+};
+export const Mac = Template.bind({});
+Mac.args = {
+ platform: PLATFORM_MACOS,
+};
+export const Linux = Template.bind({});
+Linux.args = {
+ platform: PLATFORM_LINUX,
+};