Share toolbox components and fix image and calendar updates
Some checks failed
Deploy Sokko G / deploy (push) Failing after 2s

This commit is contained in:
Shinuwa 2026-09-10 14:19:55 +02:00
parent 865a4ffd97
commit 34524d2961
13 changed files with 117 additions and 93 deletions

View file

@ -4,7 +4,7 @@ import { Icon } from "../../../components/Icon.jsx";
import { useGroupedReorder } from "../../../hooks/useGroupedReorder.js";
import { useInlineEdit } from "../../../hooks/useInlineEdit.js";
import { supportsTextExchange } from "./textImport.js";
import { LAZY_MODULE_TYPES, MODULE_COMPONENTS } from "./toolboxModuleComponents.jsx";
import { MODULE_COMPONENTS } from "./toolboxModuleComponents.jsx";
const MODULE_COLUMN_IDS = ["left", "right"];
@ -263,13 +263,9 @@ function ModuleShell({ toolbox, module, context, reorder, itemGroup = "", onRena
</div>
</header>
<div className={`module-content ${scrollable ? "is-scrollable legacy-scrollbar" : ""}`}>
{LAZY_MODULE_TYPES.has(module.type) ? (
<Suspense fallback={<ModuleLoadingFallback label={label} />}>
<Component {...componentProps} />
</Suspense>
) : (
<Suspense fallback={<ModuleLoadingFallback label={label} />}>
<Component {...componentProps} />
)}
</Suspense>
</div>
</article>
);

View file

@ -2,4 +2,4 @@
export { TOOLBOX_MODULES } from "../toolboxModuleRegistry.js";
export { AddToolControls } from "./AddToolControls.jsx";
export { ToolboxModules } from "./ToolboxModules.jsx";
export { LAZY_MODULE_TYPES, MODULE_COMPONENTS } from "./toolboxModuleComponents.jsx";
export { MODULE_COMPONENTS } from "./toolboxModuleComponents.jsx";

View file

@ -1,44 +1,8 @@
// Rôle : associe les types d'outils toolbox à leurs composants React, synchrones ou lazy.
/* eslint-disable react-refresh/only-export-components -- registre de composants toolbox consommé par le shell. */
// Rôle : partage les composants lazy des outils entre toolbox et librairie.
import { lazy } from "react";
import { TOOLBOX_MODULE_DEFINITIONS } from "../toolboxModuleRegistry.js";
import { CalculatorModule } from "./CalculatorModule.jsx";
import { ChecklistModule } from "./ChecklistModule.jsx";
import { CountersModule } from "./CountersModule.jsx";
import { ImageAnnotationModule } from "./ImageAnnotationModule.jsx";
import { ImagesModule } from "./ImagesModule.jsx";
import { LinksModule } from "./LinksModule.jsx";
import { MemosModule } from "./MemosModule.jsx";
import { NotepadModule } from "./NotepadModule.jsx";
import { RandomizerModule } from "./RandomizerModule.jsx";
import { RngSimulatorModule } from "./RngSimulatorModule.jsx";
import { TableModule } from "./TableModule.jsx";
import { TaskPlannerModule } from "./TaskPlannerModule.jsx";
import { TimerModule } from "./TimerModule.jsx";
import { TOOLBOX_MODULE_DEFINITIONS, TOOLBOX_MODULE_LOADERS } from "../toolboxModuleRegistry.js";
const CombosModule = lazy(() => import("./CombosModule.jsx").then((module) => ({ default: module.CombosModule })));
const CalendarModule = lazy(() => import("./CalendarModule.jsx").then((module) => ({ default: module.CalendarModule })));
const GoalTreeModule = lazy(() => import("./GoalTreeModule.jsx").then((module) => ({ default: module.GoalTreeModule })));
const EquipmentPlannerModule = lazy(() => import("./EquipmentPlannerModule.jsx").then((module) => ({ default: module.EquipmentPlannerModule })));
export const MODULE_COMPONENTS = {
notepad: { ...TOOLBOX_MODULE_DEFINITIONS.notepad, Component: NotepadModule },
memos: { ...TOOLBOX_MODULE_DEFINITIONS.memos, Component: MemosModule },
checklist: { ...TOOLBOX_MODULE_DEFINITIONS.checklist, Component: ChecklistModule },
images: { ...TOOLBOX_MODULE_DEFINITIONS.images, Component: ImagesModule },
links: { ...TOOLBOX_MODULE_DEFINITIONS.links, Component: LinksModule },
counters: { ...TOOLBOX_MODULE_DEFINITIONS.counters, Component: CountersModule },
randomizer: { ...TOOLBOX_MODULE_DEFINITIONS.randomizer, Component: RandomizerModule },
rngSimulator: { ...TOOLBOX_MODULE_DEFINITIONS.rngSimulator, Component: RngSimulatorModule },
combos: { ...TOOLBOX_MODULE_DEFINITIONS.combos, Component: CombosModule },
calculator: { ...TOOLBOX_MODULE_DEFINITIONS.calculator, Component: CalculatorModule },
calendar: { ...TOOLBOX_MODULE_DEFINITIONS.calendar, Component: CalendarModule },
table: { ...TOOLBOX_MODULE_DEFINITIONS.table, Component: TableModule },
goalTree: { ...TOOLBOX_MODULE_DEFINITIONS.goalTree, Component: GoalTreeModule },
timer: { ...TOOLBOX_MODULE_DEFINITIONS.timer, Component: TimerModule },
taskPlanner: { ...TOOLBOX_MODULE_DEFINITIONS.taskPlanner, Component: TaskPlannerModule },
equipmentPlanner: { ...TOOLBOX_MODULE_DEFINITIONS.equipmentPlanner, Component: EquipmentPlannerModule },
imageAnnotation: { ...TOOLBOX_MODULE_DEFINITIONS.imageAnnotation, Component: ImageAnnotationModule }
};
export const LAZY_MODULE_TYPES = new Set(["combos", "calendar", "goalTree", "equipmentPlanner"]);
export const MODULE_COMPONENTS = Object.fromEntries(Object.entries(TOOLBOX_MODULE_LOADERS).map(([type, loader]) => [
type,
{ ...TOOLBOX_MODULE_DEFINITIONS[type], Component: lazy(loader) }
]));

View file

@ -142,12 +142,9 @@ export function useCalendarController({ data, context, toolboxId, moduleId, edit
}
function handleSlotPointerEnter(event, dayIndex, slotIndex) {
if (event.buttons !== 1) return;
setSelection((current) => {
if (!current || current.dayIndex !== dayIndex) return current;
applySelection(dayIndex, current.startSlot, slotIndex);
return { ...current, endSlot: slotIndex };
});
if (event.buttons !== 1 || !selection || selection.dayIndex !== dayIndex) return;
applySelection(dayIndex, selection.startSlot, slotIndex);
setSelection({ ...selection, endSlot: slotIndex });
}
function handleMonthPointerDown(dateKey) {
@ -158,12 +155,9 @@ export function useCalendarController({ data, context, toolboxId, moduleId, edit
}
function handleMonthPointerEnter(event, dateKey) {
if (event.buttons !== 1) return;
setMonthSelection((current) => {
if (!current) return current;
applyMonthSelection(current.startDate, dateKey);
return { ...current, endDate: dateKey };
});
if (event.buttons !== 1 || !monthSelection) return;
applyMonthSelection(monthSelection.startDate, dateKey);
setMonthSelection({ ...monthSelection, endDate: dateKey });
}
function editEvent(event, occurrence = null) {

View file

@ -86,7 +86,6 @@ export function useToolboxActions({ store, notify, creationTemplate, setConfirmM
async function addImageFiles(toolboxId, moduleId, files) {
const imageFiles = [...files].filter((file) => file?.type?.startsWith("image/"));
if (!imageFiles.length) return false;
const data = store.getModuleData(toolboxId, moduleId, { images: [] });
const images = [];
for (const file of imageFiles) {
const image = { id: uid("image"), dataUrl: await compressImage(file) };
@ -94,6 +93,7 @@ export function useToolboxActions({ store, notify, creationTemplate, setConfirmM
if (label) image.label = label;
images.unshift(image);
}
const data = store.getModuleData(toolboxId, moduleId, { images: [] });
return store.updateModuleData(toolboxId, moduleId, {
...data,
images: [...images, ...(Array.isArray(data.images) ? data.images : [])]

View file

@ -1,7 +1,8 @@
// Rôle : affiche la librairie des outils avec des exemples locaux non persistés.
import { lazy, Suspense, useEffect, useMemo, useRef, useState } from "react";
import { Suspense, useEffect, useMemo, useRef, useState } from "react";
import { Icon } from "../components/Icon.jsx";
import { LIBRARY_CATEGORY_DEFINITIONS, getToolboxModuleDefinition, TOOLBOX_MODULE_LOADERS } from "../features/toolboxes/toolboxModuleRegistry.js";
import { LIBRARY_CATEGORY_DEFINITIONS, getToolboxModuleDefinition } from "../features/toolboxes/toolboxModuleRegistry.js";
import { MODULE_COMPONENTS } from "../features/toolboxes/modules/toolboxModuleComponents.jsx";
import {
clampQty,
hostnameFromUrl,
@ -29,8 +30,6 @@ import {
const LIBRARY_TOOLBOX_ID = "library";
const LIBRARY_ANCHOR_RETRY_DELAYS = [0, 80, 240, 600];
const MODULE_COMPONENTS = Object.fromEntries(Object.entries(TOOLBOX_MODULE_LOADERS).map(([type, loader]) => [type, lazy(loader)]));
function cloneData(value) {
if (value === undefined) return {};
if (typeof structuredClone === "function") return structuredClone(value);
@ -326,7 +325,7 @@ function LibraryDocNav({ content, categories, activeCategoryKey, onSelectCategor
function LibraryToolExample({ module, sourceData, description, categoryTitle, docs, featureHeading, advancedHeading, advancedCopyLabel, advancedCopySuccess, controlLegendHeading, context }) {
const definition = getToolboxModuleDefinition(module.type);
const Component = MODULE_COMPONENTS[module.type] || MODULE_COMPONENTS.notepad;
const { Component } = MODULE_COMPONENTS[module.type] || MODULE_COMPONENTS.notepad;
const [scrollable, setScrollable] = useState(false);
const [editing, setEditing] = useState(false);
const title = module.title || definition.label || "Outil";