diff --git a/webapp/src/components/NameManager/NameManagerDialog.tsx b/webapp/src/components/NameManager/NameManagerDialog.tsx index 9da2d3c..2f2e042 100644 --- a/webapp/src/components/NameManager/NameManagerDialog.tsx +++ b/webapp/src/components/NameManager/NameManagerDialog.tsx @@ -14,33 +14,49 @@ import { t } from "i18next"; import { BookOpen, Plus, X } from "lucide-react"; import { useEffect, useState } from "react"; import { getFullRangeToString } from "../util"; -import NamedRange from "./NamedRange"; +import NamedRangeActive from "./NamedRangeActive"; +import NamedRangeInactive from "./NamedRangeInactive"; interface NameManagerDialogProperties { - onClose: () => void; - onNamesChanged: () => void; open: boolean; model: Model; + onClose: () => void; + onNamesChanged: () => void; } function NameManagerDialog(properties: NameManagerDialogProperties) { - const { onClose, open, model, onNamesChanged } = properties; - - const [showNewName, setShowNewName] = useState(false); + const { open, model, onClose, onNamesChanged } = properties; + // If editingNameIndex is -1, then we are adding a new name + // If editingNameIndex is -2, then we are not editing any name + // If editingNameIndex is a positive number, then we are editing that index + const [editingNameIndex, setEditingNameIndex] = useState(-2); const [showOptions, setShowOptions] = useState(true); + const worksheets = model.getWorksheetsProperties(); + const definedNameList = model.getDefinedNameList(); + // reset modal state in case editing was in progress useEffect(() => { - setShowNewName(false); - setShowOptions(true); - }, []); + if (open) { + setEditingNameIndex(-2); + } + }, [open]); + + // enable/disable options while editing + useEffect(() => { + if (editingNameIndex !== -2) { + setShowOptions(false); + } else { + setShowOptions(true); + } + }, [editingNameIndex]); const handleNewName = () => { - toggleShowNewName(); - toggleOptions(); + setEditingNameIndex(-1); }; - const handleCreate = () => { - toggleShowNewName(); + const handleSave = () => { + setEditingNameIndex(-2); + onNamesChanged(); }; const handleDelete = () => { @@ -54,22 +70,11 @@ function NameManagerDialog(properties: NameManagerDialogProperties) { return getFullRangeToString(selectedView, worksheetNames); }; - const toggleOptions = () => { - setShowOptions(!showOptions); - }; - - const toggleShowNewName = () => { - setShowNewName(!showNewName); - }; - - const worksheets = model.getWorksheetsProperties(); - const definedNameList = model.getDefinedNameList(); - return ( {t("name_manager_dialog.title")} - onClose()}> + @@ -79,29 +84,45 @@ function NameManagerDialog(properties: NameManagerDialogProperties) { {t("name_manager_dialog.range")} {t("name_manager_dialog.scope")} - {definedNameList.map((definedName) => ( - - ))} - {showNewName && ( - + {definedNameList.map((definedName, index) => { + if (index === editingNameIndex) { + return ( + setEditingNameIndex(-2)} + /> + ); + } + return ( + setEditingNameIndex(index)} + onDelete={handleDelete} + /> + ); + })} + + {editingNameIndex === -1 && ( + setEditingNameIndex(-2)} /> )} @@ -118,7 +139,7 @@ function NameManagerDialog(properties: NameManagerDialogProperties) { disableElevation sx={{ textTransform: "none" }} startIcon={} - disabled={!showOptions} + disabled={editingNameIndex > -2} > {t("name_manager_dialog.new")} @@ -143,6 +164,11 @@ align-items: center; justify-content: space-between; `; +const NameListWrapper = styled(Stack)` + overflow-y: auto; + gap: 12px; +`; + const StyledBox = styled(Box)` width: 171px; `; diff --git a/webapp/src/components/NameManager/NamedRange.tsx b/webapp/src/components/NameManager/NamedRangeActive.tsx similarity index 55% rename from webapp/src/components/NameManager/NamedRange.tsx rename to webapp/src/components/NameManager/NamedRangeActive.tsx index 80dc30f..5df5c12 100644 --- a/webapp/src/components/NameManager/NamedRange.tsx +++ b/webapp/src/components/NameManager/NamedRangeActive.tsx @@ -8,8 +8,8 @@ import { styled, } from "@mui/material"; import { t } from "i18next"; -import { Check, PencilLine, Trash2, X } from "lucide-react"; -import { useEffect, useState } from "react"; +import { Check, X } from "lucide-react"; +import { useState } from "react"; interface NamedRangeProperties { model: Model; @@ -17,91 +17,39 @@ interface NamedRangeProperties { name: string; scope?: number; formula: string; - onCreate?: () => void; + onSave: () => void; onDelete?: () => void; - toggleShowNewName?: () => void; - toggleOptions: () => void; - showOptions?: boolean; + onCancel?: () => void; } -function NamedRange(properties: NamedRangeProperties) { - const { - model, - worksheets, - name, - scope, - formula, - onCreate, - onDelete, - toggleShowNewName, - toggleOptions, - showOptions, - } = properties; - +function NamedRangeActive(properties: NamedRangeProperties) { + const { model, worksheets, name, scope, formula, onSave, onCancel } = + properties; const [newName, setNewName] = useState(name); const [newScope, setNewScope] = useState(scope); const [newFormula, setNewFormula] = useState(formula); - const [readOnly, setReadOnly] = useState(true); - const [showEditDelete, setShowEditDelete] = useState(false); // todo: add error messages for validations const [nameError, setNameError] = useState(false); const [formulaError, setFormulaError] = useState(false); - useEffect(() => { - // set state for new name - const definedNamesModel = model.getDefinedNameList(); - if (!definedNamesModel.find((n) => n.name === newName)) { - setReadOnly(false); - setShowEditDelete(true); - } - }, [newName, model]); - - const handleCreateUpdate = () => { + const handleSaveUpdate = () => { const definedNamesModel = model.getDefinedNameList(); if (definedNamesModel.find((n) => n.name === name)) { - // update try { model.updateDefinedName(name, scope, newName, newScope, newFormula); } catch (error) { console.log("DefinedName update failed", error); } } else { - // create try { model.newDefinedName(newName, newScope, newFormula); } catch (error) { console.log("DefinedName save failed", error); } - onCreate?.(); } - setShowEditDelete(false); - toggleOptions(); - }; - - const handleCancel = () => { - setReadOnly(true); - setShowEditDelete(false); - toggleOptions(); - setNewName(name); - setNewScope(scope); - toggleShowNewName?.(); // if it's newName remove it from modal - }; - - const handleEdit = () => { - setReadOnly(false); - setShowEditDelete(true); - toggleOptions(); - }; - - const handleDelete = () => { - try { - model.deleteDefinedName(newName, newScope); - } catch (error) { - console.log("DefinedName delete failed", error); - } - onDelete?.(); + onSave(); }; return ( @@ -113,7 +61,6 @@ function NamedRange(properties: NamedRangeProperties) { size="small" margin="none" fullWidth - InputProps={{ readOnly: readOnly }} error={nameError} value={newName} onChange={(event) => setNewName(event.target.value)} @@ -129,7 +76,6 @@ function NamedRange(properties: NamedRangeProperties) { size="small" margin="none" fullWidth - InputProps={{ readOnly: readOnly }} value={newScope ?? "global"} onChange={(event) => { event.target.value === "global" @@ -152,7 +98,6 @@ function NamedRange(properties: NamedRangeProperties) { size="small" margin="none" fullWidth - InputProps={{ readOnly: readOnly }} error={formulaError} value={newFormula} onChange={(event) => setNewFormula(event.target.value)} @@ -161,34 +106,14 @@ function NamedRange(properties: NamedRangeProperties) { }} onClick={(event) => event.stopPropagation()} /> - - {showEditDelete ? ( - // save cancel - <> - theme.palette.success.main }} - > - - - theme.palette.error.main }} - > - - - - ) : ( - // edit delete - <> - - - - - - - - )} + <> + + + + + + + @@ -205,6 +130,11 @@ const StyledTextField = styled(TextField)(() => ({ "& .MuiInputBase-root": { height: "28px", margin: 0, + fontFamily: "Inter", + fontSize: "12px", + }, + "& .MuiInputBase-input": { + padding: "8px", }, })); @@ -216,4 +146,8 @@ const StyledIconButton = styled(IconButton)(({ theme }) => ({ }, })); -export default NamedRange; +const StyledCheck = styled(Check)(({ theme }) => ({ + color: theme.palette.success.main, +})); + +export default NamedRangeActive; diff --git a/webapp/src/components/NameManager/NamedRangeInactive.tsx b/webapp/src/components/NameManager/NamedRangeInactive.tsx new file mode 100644 index 0000000..4f198ec --- /dev/null +++ b/webapp/src/components/NameManager/NamedRangeInactive.tsx @@ -0,0 +1,93 @@ +import type { Model, WorksheetProperties } from "@ironcalc/wasm"; +import { Box, Divider, IconButton, styled } from "@mui/material"; +import { t } from "i18next"; +import { PencilLine, Trash2 } from "lucide-react"; + +interface NamedRangeInactiveProperties { + model: Model; + worksheets: WorksheetProperties[]; + name: string; + scope?: number; + formula: string; + onDelete: () => void; + onEdit: () => void; + showOptions: boolean; +} + +function NamedRangeInactive(properties: NamedRangeInactiveProperties) { + const { + model, + worksheets, + name, + scope, + formula, + onDelete, + onEdit, + showOptions, + } = properties; + + const handleDelete = () => { + try { + model.deleteDefinedName(name, scope); + } catch (error) { + console.log("DefinedName delete failed", error); + } + onDelete(); + }; + + const scopeName = + worksheets.find((sheet, index) => index === scope)?.name || + t("name_manager_dialog.workbook"); + + return ( + <> + + {name} + {scopeName} + {formula} + + + + + + + + + + + + ); +} + +const StyledIconButtonBlack = styled(IconButton)(({ theme }) => ({ + color: theme.palette.common.black, +})); + +const StyledIconButtonRed = styled(IconButton)(({ theme }) => ({ + color: theme.palette.error.main, + "&.Mui-disabled": { + opacity: 0.6, + color: theme.palette.error.light, + }, +})); + +const WrappedLine = styled(Box)({ + display: "flex", + height: "28px", + alignItems: "center", +}); + +const StyledDiv = styled("div")(({ theme }) => ({ + fontFamily: theme.typography.fontFamily, + fontSize: "12px", + fontWeight: "400", + color: theme.palette.common.black, + width: "171px", +})); + +const WrappedIcons = styled(Box)({ + display: "flex", + gap: "0px", +}); + +export default NamedRangeInactive; diff --git a/webapp/src/locale/en_us.json b/webapp/src/locale/en_us.json index be49c37..ee4d93c 100644 --- a/webapp/src/locale/en_us.json +++ b/webapp/src/locale/en_us.json @@ -59,12 +59,14 @@ "num_fmt": { "title": "Custom number format", "label": "Number format", + "close": "Close dialog", "save": "Save" }, "sheet_rename": { "rename": "Save", "label": "New name", - "title": "Rename Sheet" + "title": "Rename Sheet", + "close": "Close dialog" }, "formula_input": { "update": "Update",