tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit b3aaa061927951f2fb223f0c2a2f335c65a73db2
parent 3a3bf79d00190ea611d1085815a80f4d7b998464
Author: Florian Zia <zia.florian@gmail.com>
Date:   Tue,  9 Dec 2025 19:12:01 +0000

Bug 2002022, 2002315 - Setup Storybook for AI Window r=ai-frontend-reviewers,desktop-theme-reviewers,mstriemer,fluent-reviewers,bolsson,mlucks,ngrato

Differential Revision: https://phabricator.services.mozilla.com/D273857

Diffstat:
Mbrowser/components/aiwindow/ui/aiChatContent.html | 3+++
Abrowser/components/aiwindow/ui/assets/input-cta-arrow-icon.svg | 6++++++
Abrowser/components/aiwindow/ui/components/input-cta/input-cta.css | 31+++++++++++++++++++++++++++++++
Abrowser/components/aiwindow/ui/components/input-cta/input-cta.mjs | 107+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abrowser/components/aiwindow/ui/components/input-cta/input-cta.stories.mjs | 45+++++++++++++++++++++++++++++++++++++++++++++
Mbrowser/components/aiwindow/ui/jar.mn | 5+++--
Mbrowser/components/storybook/.storybook/main.js | 2++
Mbrowser/components/storybook/component-status/components.json | 2+-
Mbrowser/locales-preview/aiWindow.ftl | 6++++++
Mtoolkit/content/widgets/moz-button/moz-button.mjs | 7++++++-
10 files changed, 210 insertions(+), 4 deletions(-)

diff --git a/browser/components/aiwindow/ui/aiChatContent.html b/browser/components/aiwindow/ui/aiChatContent.html @@ -16,6 +16,9 @@ <title>AI Chat Content</title> <link rel="stylesheet" href="chrome://global/skin/in-content/common.css" /> <script src="chrome://browser/content/contentTheme.js"></script> + <!-- TODO: load appropriate component modules + "chrome://browser/content/aiwindow/ui/components/input-cta.mjs" + --> </head> <body id="ai-window-wrapper"> Placeholder for AI Chat Content diff --git a/browser/components/aiwindow/ui/assets/input-cta-arrow-icon.svg b/browser/components/aiwindow/ui/assets/input-cta-arrow-icon.svg @@ -0,0 +1,6 @@ +<!-- 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 https://mozilla.org/MPL/2.0/. --> +<svg width="14" height="12" viewBox="0 0 14 12" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M11.4391 6.75033H0V5.25033H11.4393L7.24967 1.06066L8.31033 0L13.7803 5.47C13.921 5.61066 14 5.80144 14 6.00036C14 6.19929 13.921 6.39006 13.7803 6.53071L8.31028 11.9997L7.24972 10.939L11.4391 6.75033Z" fill="#5b5b66"/> +</svg> diff --git a/browser/components/aiwindow/ui/components/input-cta/input-cta.css b/browser/components/aiwindow/ui/components/input-cta/input-cta.css @@ -0,0 +1,31 @@ +/* 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: inline-flex; +} + +moz-button.input-cta { + --button-background-color-disabled: var(--color-gray-20); + --button-text-color: white; + --button-text-color-disabled: white; + --button-text-color-hover: white; + --button-text-color-active: white; + --button-text-color-selected: white; + --button-border-radius: var(--border-radius-circle); + + border-radius: var(--button-border-radius); +} + +moz-button[type="default"].input-cta::part(button) { + padding-inline: var(--space-xxlarge); +} + +moz-button[type="split"].input-cta { + background: linear-gradient(260deg, rgba(255, 183, 148, 0.8) -45%, rgba(181, 62, 175, 0.8) 65%, rgba(131, 62, 181, 0.8) 150%); +} + +moz-button[type="split"].input-cta::part(chevron-button) { + padding-inline-end: var(--space-xsmall); +} diff --git a/browser/components/aiwindow/ui/components/input-cta/input-cta.mjs b/browser/components/aiwindow/ui/components/input-cta/input-cta.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, + ifDefined, + repeat, +} from "chrome://global/content/vendor/lit.all.mjs"; +import { MozLitElement } from "chrome://global/content/lit-utils.mjs"; +// eslint-disable-next-line import/no-unassigned-import +import "chrome://global/content/elements/moz-button.mjs"; + +/** + * Input CTA button with action menu extending `moz-button`. + * + * @property {string|null} action - Current action or null for initial state. + */ +export class InputCta extends MozLitElement { + static shadowRootOptions = { + ...MozLitElement.shadowRootOptions, + delegatesFocus: true, + }; + + static properties = { + action: { type: String, reflect: true }, + }; + + static ACTIONS = ["chat", "search", "navigate"]; + + constructor() { + super(); + this.action = null; + this._menuId = `actions-menu-${crypto.randomUUID()}`; + } + + get actionLabelId() { + return this.action ? `aiwindow-input-cta-label-${this.action}` : ""; + } + + #setAction(key) { + if (key === this.action || !InputCta.ACTIONS.includes(key)) { + return; + } + + this.action = key; + this.dispatchEvent( + new CustomEvent("aiwindow-input-cta:action-change", { + detail: { action: key }, + bubbles: true, + composed: true, + }) + ); + } + + willUpdate(changedProps) { + if ( + changedProps.has("action") && + this.action !== null && + !InputCta.ACTIONS.includes(this.action) + ) { + console.warn(`Invalid action: ${this.action}`); + this.action = null; + } + } + + render() { + const panelListTemplate = this.action + ? html`<panel-list id=${this._menuId}> + ${repeat( + InputCta.ACTIONS, + key => key, + key => + html`<panel-item + @click=${() => this.#setAction(key)} + data-l10n-id=${`aiwindow-input-cta-label-${key}`} + ></panel-item>` + )} + </panel-list>` + : null; + + return html` + <link + rel="stylesheet" + href="chrome://browser/content/aiwindow/ui/components/input-cta.css" + /> + <moz-button + type=${this.action ? "split" : "default"} + class="input-cta" + menuId=${ifDefined(this.action ? this._menuId : undefined)} + .iconSrc=${this.action + ? undefined + : "chrome://browser/content/aiwindow/ui/assets/input-cta-arrow-icon.svg"} + ?disabled=${!this.action} + > + <slot> + <span + data-l10n-id=${ifDefined(this.actionLabelId || undefined)} + ></span> + </slot> + </moz-button> + ${panelListTemplate} + `; + } +} + +customElements.define("input-cta", InputCta); diff --git a/browser/components/aiwindow/ui/components/input-cta/input-cta.stories.mjs b/browser/components/aiwindow/ui/components/input-cta/input-cta.stories.mjs @@ -0,0 +1,45 @@ +/* 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 "chrome://browser/content/aiwindow/ui/components/input-cta.mjs"; + +export default { + title: "Domain-specific UI Widgets/AI Window/Input CTA", + component: "input-cta", + parameters: { + fluent: ` +aiwindow-input-cta-label-chat = Chat +aiwindow-input-cta-label-search = Search +aiwindow-input-cta-label-navigate = Navigate + `, + }, + argTypes: { + action: { + options: [null, "chat", "search", "navigate"], + control: { type: "select" }, + }, + }, +}; + +const Template = ({ action }) => html` + <input-cta .action=${action}></input-cta> +`; + +export const Disabled = Template.bind({}); + +export const Chat = Template.bind({}); +Chat.args = { + action: "chat", +}; + +export const Search = Template.bind({}); +Search.args = { + action: "search", +}; + +export const Navigate = Template.bind({}); +Navigate.args = { + action: "navigate", +}; diff --git a/browser/components/aiwindow/ui/jar.mn b/browser/components/aiwindow/ui/jar.mn @@ -2,7 +2,8 @@ # 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/. -# This file was copied from browser/components/aiwindow/ui/moz.build. - browser.jar: content/browser/aiwindow/ui/aiChatContent.html + content/browser/aiwindow/ui/assets/input-cta-arrow-icon.svg (assets/input-cta-arrow-icon.svg) + content/browser/aiwindow/ui/components/input-cta.css (components/input-cta/input-cta.css) + content/browser/aiwindow/ui/components/input-cta.mjs (components/input-cta/input-cta.mjs) diff --git a/browser/components/storybook/.storybook/main.js b/browser/components/storybook/.storybook/main.js @@ -37,6 +37,8 @@ module.exports = { `${projectRoot}/toolkit/components/satchel/megalist/content/**/*.stories.mjs`, // WebRTC components stories `${projectRoot}/browser/components/webrtc/content/**/*.stories.mjs`, + // AI Window components stories + `${projectRoot}/browser/components/aiwindow/ui/**/*.stories.mjs`, // Everything else "../stories/**/*.stories.@(js|jsx|mjs|ts|tsx|md)", // Design system files diff --git a/browser/components/storybook/component-status/components.json b/browser/components/storybook/component-status/components.json @@ -1,5 +1,5 @@ { - "generatedAt": "2025-12-02T20:33:36.933Z", + "generatedAt": "2025-12-05T16:54:08.681Z", "count": 29, "items": [ { diff --git a/browser/locales-preview/aiWindow.ftl b/browser/locales-preview/aiWindow.ftl @@ -15,3 +15,9 @@ menu-file-new-ai-window = menu-file-new-classic-window = .label = New Classic Window + +## Input CTA + +aiwindow-input-cta-label-chat = Chat +aiwindow-input-cta-label-search = Search +aiwindow-input-cta-label-navigate = Navigate diff --git a/toolkit/content/widgets/moz-button/moz-button.mjs b/toolkit/content/widgets/moz-button/moz-button.mjs @@ -307,7 +307,12 @@ export default class MozButton extends MozLitElement { @click=${e => e.stopPropagation()} @mousedown=${e => e.stopPropagation()} > - <span class="button-background" type=${this.type} size=${this.size}> + <span + class="button-background" + part="chevron-button" + type=${this.type} + size=${this.size} + > <img src="chrome://global/skin/icons/arrow-down.svg" role="presentation"