diff --git a/.changeset/fix-firefox-selection-copy.md b/.changeset/fix-firefox-selection-copy.md
new file mode 100644
index 0000000..d15697a
--- /dev/null
+++ b/.changeset/fix-firefox-selection-copy.md
@@ -0,0 +1,5 @@
+---
+"@jmfederico/pi-web": patch
+---
+
+Let Firefox copy only the selected chat text instead of replacing selections with the full message.
diff --git a/src/client/src/components/FormattedText.ts b/src/client/src/components/FormattedText.ts
index 1369307..259204b 100644
--- a/src/client/src/components/FormattedText.ts
+++ b/src/client/src/components/FormattedText.ts
@@ -9,7 +9,7 @@ export class FormattedText extends LitElement {
@property() text = "";
override render() {
- return html`
${unsafeHTML(toSafeMarkdownHtml(this.text))}
`;
+ return html`${unsafeHTML(toSafeMarkdownHtml(this.text))}
`;
}
override updated(): void {
@@ -48,13 +48,6 @@ export class FormattedText extends LitElement {
void this.copyCode(code.textContent, button);
};
- private readonly onFormattedCopy = (event: ClipboardEvent): void => {
- if (event.clipboardData === null || !hasSelectedText(currentSelection(this))) return;
- event.clipboardData.setData("text/plain", this.text);
- event.preventDefault();
- event.stopPropagation();
- };
-
private async copyCode(text: string, button: HTMLButtonElement): Promise {
const ok = await writeClipboard(text);
this.setCopyButtonState(button, ok ? "copied" : "failed");
@@ -74,20 +67,6 @@ export class FormattedText extends LitElement {
static override styles = formattedTextStyles;
}
-function currentSelection(element: Element): Selection | null {
- const root = element.getRootNode();
- if (typeof ShadowRoot !== "undefined" && root instanceof ShadowRoot && hasRootSelection(root)) return root.getSelection();
- return element.ownerDocument.getSelection();
-}
-
-function hasRootSelection(root: Node): root is Node & { getSelection: () => Selection | null } {
- return "getSelection" in root && typeof root.getSelection === "function";
-}
-
-function hasSelectedText(selection: Selection | null): boolean {
- return selection !== null && !selection.isCollapsed && selection.toString() !== "";
-}
-
async function writeClipboard(text: string): Promise {
try {
await navigator.clipboard.writeText(text);