improve text editor toolbar
All checks were successful
Deploy Sokko G / deploy (push) Successful in 7s

This commit is contained in:
Shinuwa 2026-07-29 20:24:00 +02:00
parent de1b8a5638
commit 896ae23ff2
6 changed files with 148 additions and 11 deletions

View file

@ -1,5 +1,6 @@
// Rôle : fournit l'outil bloc-notes riche avec annotations dessinées.
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { CompactDropdown } from "../../../components/CompactDropdown.jsx";
import { DrawingControls, FormattingColorDropdown } from "./DrawingControls.jsx";
import { DrawingOverlay } from "./DrawingOverlay.jsx";
@ -56,6 +57,56 @@ function ToolbarButton({ active, title, children, onClick }) {
);
}
function ListTypeDropdown({ textContent, activeFormats, onCommand }) {
return (
<CompactDropdown
className="notepad-list-dropdown"
menuClassName="notepad-list-menu"
label={textContent.listGroupLabel || "Listes"}
closeOnMouseLeave
preventMouseDown
renderTrigger={({ toggle }) => (
<button
className={`notepad-toolbar-button ${activeFormats.bulletList || activeFormats.numberList ? "active" : ""}`}
type="button"
aria-pressed={activeFormats.bulletList || activeFormats.numberList}
title={textContent.listGroupLabel || "Listes"}
onClick={toggle}
>
<span className="notepad-list-icon" aria-hidden="true" />
</button>
)}
>
{({ close }) => (
<>
<button
className={`notepad-list-option ${activeFormats.bulletList ? "active" : ""}`}
type="button"
aria-pressed={activeFormats.bulletList}
onClick={() => {
onCommand("insertUnorderedList");
close();
}}
>
</button>
<button
className={`notepad-list-option ${activeFormats.numberList ? "active" : ""}`}
type="button"
aria-pressed={activeFormats.numberList}
onClick={() => {
onCommand("insertOrderedList");
close();
}}
>
1.
</button>
</>
)}
</CompactDropdown>
);
}
export function NotepadModule({ toolboxId, moduleId, context }) {
const storedData = context.getModuleData(toolboxId, moduleId, { text: "" });
const normalizedData = useMemo(() => context.normalizeNotepadData(storedData), [context, storedData]);
@ -76,7 +127,7 @@ export function NotepadModule({ toolboxId, moduleId, context }) {
bold: false,
italic: false,
underline: false,
paragraph: false,
strikeThrough: false,
heading: false,
bulletList: false,
numberList: false
@ -104,7 +155,7 @@ export function NotepadModule({ toolboxId, moduleId, context }) {
const selection = document.getSelection();
if (!editor || !selection?.rangeCount || !editor.contains(selection.anchorNode)) {
setActiveFormats((current) => Object.values(current).some(Boolean)
? { bold: false, italic: false, underline: false, paragraph: false, heading: false, bulletList: false, numberList: false }
? { bold: false, italic: false, underline: false, strikeThrough: false, heading: false, bulletList: false, numberList: false }
: current);
return;
}
@ -113,7 +164,7 @@ export function NotepadModule({ toolboxId, moduleId, context }) {
bold: queryCommandState("bold"),
italic: queryCommandState("italic"),
underline: queryCommandState("underline"),
paragraph: block === "p" || block === "div",
strikeThrough: queryCommandState("strikeThrough"),
heading: block === "h3" || block === "heading 3",
bulletList: queryCommandState("insertUnorderedList"),
numberList: queryCommandState("insertOrderedList")
@ -206,6 +257,10 @@ export function NotepadModule({ toolboxId, moduleId, context }) {
runCommand("formatBlock", tag);
}
function toggleHeading() {
applyBlock(activeFormats.heading ? "p" : "h3");
}
function applyTextColor(color) {
setTextColor(color);
runCommand("foreColor", color);
@ -253,12 +308,11 @@ export function NotepadModule({ toolboxId, moduleId, context }) {
<ToolbarButton active={activeFormats.bold} title={textContent.boldTitle || "Gras"} onClick={() => runCommand("bold")}>B</ToolbarButton>
<ToolbarButton active={activeFormats.italic} title={textContent.italicTitle || "Italique"} onClick={() => runCommand("italic")}><em>I</em></ToolbarButton>
<ToolbarButton active={activeFormats.underline} title={textContent.underlineTitle || "Souligné"} onClick={() => runCommand("underline")}><u>U</u></ToolbarButton>
<ToolbarButton active={activeFormats.paragraph} title={textContent.paragraphTitle || "Paragraphe"} onClick={() => applyBlock("p")}>P</ToolbarButton>
<ToolbarButton active={activeFormats.heading} title={textContent.headingTitle || "Titre"} onClick={() => applyBlock("h3")}>H</ToolbarButton>
<ToolbarButton active={activeFormats.bulletList} title={textContent.bulletListTitle || "Liste à puces"} onClick={() => runCommand("insertUnorderedList")}></ToolbarButton>
<ToolbarButton active={activeFormats.numberList} title={textContent.numberListTitle || "Liste numérotée"} onClick={() => runCommand("insertOrderedList")}>1.</ToolbarButton>
<ToolbarButton active={activeFormats.strikeThrough} title={textContent.strikeTitle || "Barré"} onClick={() => runCommand("strikeThrough")}><s>S</s></ToolbarButton>
<ToolbarButton active={activeFormats.heading} title={textContent.headingTitle || "Titre"} onClick={toggleHeading}>T</ToolbarButton>
</div>
<div className="notepad-toolbar-group" role="group" aria-label={textContent.colorGroupLabel || "Couleurs"}>
<ListTypeDropdown textContent={textContent} activeFormats={activeFormats} onCommand={runCommand} />
<FormattingColorDropdown
label={textContent.colorGroupLabel || "Couleurs"}
sections={[

View file

@ -2,7 +2,7 @@
const ID_PREFIXES = { tbx: "t", mod: "m", item: "i", section: "g", image: "s", link: "l", counter: "c", calc: "r", marker: "k", timer: "z", task: "a", relation: "e", stroke: "d" };
const ID_ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789";
const NOTEPAD_ALLOWED_COLORS = new Set(["#f5f7ff", "#b4bdd3", "#f6c453", "#22d3ee", "#8b5cf6", "#d946ef", "#101426", "#202745"]);
const NOTEPAD_ALLOWED_TAGS = new Set(["p", "div", "br", "strong", "b", "em", "i", "u", "ul", "ol", "li", "h3", "h4", "span", "mark"]);
const NOTEPAD_ALLOWED_TAGS = new Set(["p", "div", "br", "strong", "b", "em", "i", "u", "s", "strike", "ul", "ol", "li", "h3", "h4", "span", "mark"]);
const NOTEPAD_RGB_COLOR_MAP = {
"rgb(245, 247, 255)": "#f5f7ff",
"rgb(180, 189, 211)": "#b4bdd3",