Extract combo editor and table grid
All checks were successful
Deploy Sokko G / deploy (push) Successful in 16s
All checks were successful
Deploy Sokko G / deploy (push) Successful in 16s
This commit is contained in:
parent
9455b31438
commit
e512eef232
5 changed files with 360 additions and 217 deletions
|
|
@ -1,20 +1,17 @@
|
|||
// Rôle : fournit l'outil Combos avec palettes d'inputs, rendu visuel et échange texte.
|
||||
import { useMemo, useState } from "react";
|
||||
import { Icon } from "../../../components/Icon.jsx";
|
||||
import {
|
||||
applyGroupedReorderOperation,
|
||||
getGroupedEntries,
|
||||
useGroupedReorder
|
||||
} from "../../../hooks/useGroupedReorder.js";
|
||||
import { TextExchangeActions } from "./TextExchangeActions.jsx";
|
||||
import { ComboInputToken, ComboSequence } from "./CombosParts.jsx";
|
||||
import { CombosEditor } from "./CombosEditor.jsx";
|
||||
import { CombosList } from "./CombosList.jsx";
|
||||
import {
|
||||
DEVICE_OPTIONS,
|
||||
createCombo,
|
||||
createInput,
|
||||
getComboCategory,
|
||||
getHoldSeconds,
|
||||
getPaletteColumns,
|
||||
getPaletteGroups,
|
||||
normalizeCustomKey,
|
||||
|
|
@ -326,155 +323,45 @@ export function CombosModule({ toolboxId, moduleId, context, editing, textExchan
|
|||
return (
|
||||
<div className="combos-module">
|
||||
{(editing || editingComboId) && (
|
||||
<div className="module-add-panel combos-editor">
|
||||
<div className="combos-device-row">
|
||||
<label>
|
||||
<span>{textContent.deviceLabel || "Périphérique"}</span>
|
||||
<select value={data.device} onChange={(event) => updateDevice(event.target.value)}>
|
||||
{DEVICE_OPTIONS.map((device) => (
|
||||
<option key={device.value} value={device.value}>{device.label}</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
{data.device === "keyboardMouse" && (
|
||||
<div className="combos-keyboard-layout-switch" role="group" aria-label={textContent.keyboardLayoutLabel || "Disposition clavier"}>
|
||||
{[
|
||||
{ value: "azerty", label: "AZERTY" },
|
||||
{ value: "qwerty", label: "QWERTY" }
|
||||
].map((layout) => (
|
||||
<button
|
||||
key={layout.value}
|
||||
type="button"
|
||||
className={keyboardLayout === layout.value ? "active" : ""}
|
||||
onClick={() => setKeyboardLayout(layout.value)}
|
||||
aria-pressed={keyboardLayout === layout.value}
|
||||
>
|
||||
{layout.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<form className="combos-add-form" onSubmit={saveCombo}>
|
||||
<div className="combos-form-grid">
|
||||
<label>
|
||||
<span>{textContent.targetCategoryLabel || "Catégorie"}</span>
|
||||
<input value={comboCategory} onChange={(event) => setComboCategory(event.target.value)} placeholder={textContent.noCategoryLabel || "Sans catégorie"} />
|
||||
</label>
|
||||
<label>
|
||||
<span>{textContent.comboNameLabel || "Nom"}</span>
|
||||
<input value={comboName} onChange={(event) => setComboName(event.target.value)} placeholder={textContent.comboNamePlaceholder || "Nom du combo"} />
|
||||
</label>
|
||||
</div>
|
||||
<div className="combos-palette" aria-label={textContent.paletteLabel || "Palette de touches"}>
|
||||
{paletteColumns.map((columnGroups, columnIndex) => (
|
||||
<div className="combos-palette-column" key={columnIndex}>
|
||||
{columnGroups.map((group) => (
|
||||
<div className={`combos-palette-group ${group.kind === "directions" ? "is-direction-grid" : ""}`} key={group.title}>
|
||||
<span>{group.title}</span>
|
||||
<div>
|
||||
{group.inputs.map((input, inputIndex) => {
|
||||
if (!input) return <span className="combo-palette-empty-cell" key={`empty-${inputIndex}`} aria-hidden="true" />;
|
||||
const [kind, value] = input;
|
||||
return (
|
||||
<ComboInputToken
|
||||
key={`${kind}-${value}`}
|
||||
input={createInput(kind, value)}
|
||||
device={data.device}
|
||||
palette
|
||||
onClick={() => addDraftInput(kind, value)}
|
||||
onDragStart={(event) => dragPaletteInput(event, kind, value)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{data.device === "keyboardMouse" && (
|
||||
<div className="inline-form combos-custom-key-form">
|
||||
<input value={customKey} onChange={(event) => setCustomKey(event.target.value)} placeholder={textContent.customKeyPlaceholder || "Touche personnalisée"} />
|
||||
<button type="button" onClick={addCustomKey}>{textContent.addCustomKeyButton || "Ajouter touche"}</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="combo-draft-panel">
|
||||
<ComboSequence
|
||||
inputs={draftInputs}
|
||||
device={data.device}
|
||||
emptyLabel={textContent.emptyDraft || "Aucune touche sélectionnée."}
|
||||
activeStepIndex={activeStepIndex}
|
||||
selectedInput={selectedInput}
|
||||
onSelectStep={selectDraftStep}
|
||||
onSelectInput={(stepIndex, inputIndex) => {
|
||||
setActiveStepIndex(stepIndex);
|
||||
setSelectedInput({ stepIndex, inputIndex });
|
||||
}}
|
||||
onDropInput={dropInputOnStep}
|
||||
onDropNewStep={dropInputAsNewStep}
|
||||
onDragInput={dragDraftInput}
|
||||
/>
|
||||
<div className="combo-draft-actions">
|
||||
<label className="combo-hold-field">
|
||||
<span className="combo-hold-controls">
|
||||
<button
|
||||
type="button"
|
||||
className={selectedDraftInput?.hold || selectedDraftInput?.holdMs ? "active" : ""}
|
||||
onClick={toggleSelectedInputHold}
|
||||
disabled={!selectedDraftInput}
|
||||
aria-pressed={Boolean(selectedDraftInput?.hold || selectedDraftInput?.holdMs)}
|
||||
>
|
||||
{textContent.holdToggleLabel || "Hold"}
|
||||
</button>
|
||||
<input
|
||||
type="number"
|
||||
min="0"
|
||||
max="99"
|
||||
step="1"
|
||||
inputMode="numeric"
|
||||
value={selectedDraftInput ? getHoldSeconds(selectedDraftInput) || "" : ""}
|
||||
onChange={(event) => updateSelectedInputHold(event.target.value)}
|
||||
disabled={!selectedDraftInput}
|
||||
placeholder="0"
|
||||
aria-label={textContent.holdLabel || "Maintien en secondes"}
|
||||
/>
|
||||
</span>
|
||||
</label>
|
||||
<button
|
||||
type="button"
|
||||
className={`combos-simultaneous-toggle ${simultaneousMode ? "active" : ""}`}
|
||||
onClick={() => setSimultaneousMode((enabled) => !enabled)}
|
||||
aria-pressed={simultaneousMode}
|
||||
title={textContent.simultaneousModeTitle || "Ajout simultané"}
|
||||
aria-label={textContent.simultaneousModeTitle || "Ajout simultané"}
|
||||
>
|
||||
<span className={!simultaneousMode ? "active" : ""}>{textContent.successiveModeLabel || "A › B"}</span>
|
||||
<span className={simultaneousMode ? "active" : ""}>{textContent.simultaneousModeLabel || "A + B"}</span>
|
||||
</button>
|
||||
<button type="button" className="notepad-toolbar-button" onClick={removeLastInput} disabled={!cleanDraftInputs.length} title={textContent.removeLastInputTitle || "Retirer la dernière touche"} aria-label={textContent.removeLastInputTitle || "Retirer la dernière touche"}>
|
||||
<Icon name="back" />
|
||||
</button>
|
||||
<button type="button" className="notepad-toolbar-button danger" onClick={removeActiveStep} disabled={draftInputs.length <= 1} title={textContent.removeStepTitle || "Supprimer l'étape"} aria-label={textContent.removeStepTitle || "Supprimer l'étape"}>
|
||||
<Icon name="trash" />
|
||||
</button>
|
||||
<div className="combo-save-actions">
|
||||
{editingComboId && (
|
||||
<button type="button" className="combo-cancel-button" onClick={cancelComboEdit}>
|
||||
{textContent.cancelEditButton || "Annuler"}
|
||||
</button>
|
||||
)}
|
||||
<button className="primary" disabled={!comboName.trim() && !cleanDraftInputs.length}>
|
||||
{editingComboId ? textContent.saveComboButton || "Enregistrer" : textContent.addComboButton || "Ajouter le combo"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<CombosEditor
|
||||
data={data}
|
||||
textContent={textContent}
|
||||
comboCategory={comboCategory}
|
||||
comboName={comboName}
|
||||
customKey={customKey}
|
||||
keyboardLayout={keyboardLayout}
|
||||
paletteColumns={paletteColumns}
|
||||
draftInputs={draftInputs}
|
||||
cleanDraftInputs={cleanDraftInputs}
|
||||
activeStepIndex={activeStepIndex}
|
||||
selectedInput={selectedInput}
|
||||
selectedDraftInput={selectedDraftInput}
|
||||
simultaneousMode={simultaneousMode}
|
||||
editingComboId={editingComboId}
|
||||
onDeviceChange={updateDevice}
|
||||
onKeyboardLayoutChange={setKeyboardLayout}
|
||||
onComboCategoryChange={setComboCategory}
|
||||
onComboNameChange={setComboName}
|
||||
onCustomKeyChange={setCustomKey}
|
||||
onCustomKeyAdd={addCustomKey}
|
||||
onComboSave={saveCombo}
|
||||
onDraftInputAdd={addDraftInput}
|
||||
onPaletteInputDrag={dragPaletteInput}
|
||||
onDraftInputDrag={dragDraftInput}
|
||||
onInputDrop={dropInputOnStep}
|
||||
onNewStepDrop={dropInputAsNewStep}
|
||||
onStepSelect={selectDraftStep}
|
||||
onInputSelect={(stepIndex, inputIndex) => {
|
||||
setActiveStepIndex(stepIndex);
|
||||
setSelectedInput({ stepIndex, inputIndex });
|
||||
}}
|
||||
onSelectedInputHoldToggle={toggleSelectedInputHold}
|
||||
onSelectedInputHoldChange={updateSelectedInputHold}
|
||||
onSimultaneousModeToggle={() => setSimultaneousMode((enabled) => !enabled)}
|
||||
onLastInputRemove={removeLastInput}
|
||||
onActiveStepRemove={removeActiveStep}
|
||||
onComboEditCancel={cancelComboEdit}
|
||||
/>
|
||||
)}
|
||||
{textExchangeOpen && (
|
||||
<div className="module-text-exchange-panel">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue