From 728f2c8a049695a4d684b786914ee60e82b37c88 Mon Sep 17 00:00:00 2001 From: Chris Feijoo Date: Sat, 20 Dec 2025 03:55:40 +0100 Subject: [PATCH 1/3] Extract styles from all component files in Petrinaut --- .../petrinaut/src/components/menu.tsx | 32 +- .../src/components/segment-group.tsx | 83 +-- .../petrinaut/src/components/tooltip.tsx | 26 +- .../components/BottomPanel/bottom-panel.tsx | 10 +- .../BottomPanel/diagnostics-content.tsx | 100 +-- .../BottomPanel/parameters-content.tsx | 80 ++- .../differential-equations-section.tsx | 257 ++++---- .../components/LeftSideBar/floating-title.tsx | 36 +- .../components/LeftSideBar/hamburger-menu.tsx | 31 +- .../components/LeftSideBar/nodes-section.tsx | 234 +++---- .../components/LeftSideBar/types-section.tsx | 290 +++++---- .../PropertiesPanel/color-select.tsx | 165 +++-- .../differential-equation-properties.tsx | 464 ++++++++------ .../PropertiesPanel/initial-state-editor.tsx | 353 +++++----- .../PropertiesPanel/multiple-selection.tsx | 11 +- .../PropertiesPanel/parameter-properties.tsx | 106 +-- .../PropertiesPanel/place-properties.tsx | 483 +++++++------- .../PropertiesPanel/properties-panel.tsx | 54 +- .../PropertiesPanel/sortable-arc-item.tsx | 189 +++--- .../PropertiesPanel/transition-properties.tsx | 416 ++++++------ .../PropertiesPanel/type-properties.tsx | 601 ++++++++++-------- .../visualizer-error-boundary.tsx | 81 ++- .../src/views/Editor/editor-view.tsx | 49 +- .../src/views/SDCPN/components/arc.tsx | 40 +- .../SDCPN/components/transition-node.tsx | 165 ++--- .../petrinaut/src/views/SDCPN/sdcpn-view.tsx | 18 +- 26 files changed, 2448 insertions(+), 1926 deletions(-) diff --git a/libs/@hashintel/petrinaut/src/components/menu.tsx b/libs/@hashintel/petrinaut/src/components/menu.tsx index 2feda628a60..100b8dc38a8 100644 --- a/libs/@hashintel/petrinaut/src/components/menu.tsx +++ b/libs/@hashintel/petrinaut/src/components/menu.tsx @@ -2,19 +2,6 @@ import { Menu as ArkMenu } from "@ark-ui/react"; import { css } from "@hashintel/ds-helpers/css"; import type { ReactNode } from "react"; -export interface MenuItem { - id: string; - label: string | ReactNode; - onClick?: () => void; - disabled?: boolean; - submenu?: MenuItem[]; -} - -export interface MenuProps { - trigger: ReactNode; - items: MenuItem[]; -} - const menuContentStyle = css({ background: "[white]", borderRadius: "[6px]", @@ -52,6 +39,10 @@ const triggerItemStyle = css({ }, }); +const triggerItemArrowStyle = css({ + marginLeft: "[8px]", +}); + const itemStyle = css({ fontSize: "size.textsm", cursor: "pointer", @@ -67,6 +58,19 @@ const itemStyle = css({ }, }); +export interface MenuItem { + id: string; + label: string | ReactNode; + onClick?: () => void; + disabled?: boolean; + submenu?: MenuItem[]; +} + +export interface MenuProps { + trigger: ReactNode; + items: MenuItem[]; +} + export const Menu: React.FC = ({ trigger, items }) => { return ( @@ -81,7 +85,7 @@ export const Menu: React.FC = ({ trigger, items }) => { > {item.label} - + diff --git a/libs/@hashintel/petrinaut/src/components/segment-group.tsx b/libs/@hashintel/petrinaut/src/components/segment-group.tsx index 7a307b7599a..6ecbfcb1824 100644 --- a/libs/@hashintel/petrinaut/src/components/segment-group.tsx +++ b/libs/@hashintel/petrinaut/src/components/segment-group.tsx @@ -1,5 +1,48 @@ import { SegmentGroup as ArkSegmentGroup } from "@ark-ui/react/segment-group"; -import { css } from "@hashintel/ds-helpers/css"; +import { css, cva } from "@hashintel/ds-helpers/css"; + +const containerStyle = css({ + display: "flex", + backgroundColor: "core.gray.20", + borderRadius: "radius.8", + gap: "spacing.1", + position: "relative", + padding: "[4px]", +}); + +const indicatorStyle = css({ + backgroundColor: "core.gray.90", + borderRadius: "radius.6", + position: "absolute", + transition: "[all 0.2s ease]", + width: "var(--width)", + height: "var(--height)", + left: "var(--left)", + top: "var(--top)", +}); + +const itemStyle = cva({ + base: { + flex: "1", + fontSize: "[13px]", + fontWeight: 500, + textAlign: "center", + cursor: "pointer", + borderRadius: "radius.6", + transition: "[all 0.2s ease]", + position: "relative", + zIndex: 1, + padding: "[4px 6px]", + }, + variants: { + isSelected: { + true: { color: "core.gray.10" }, + false: { color: "core.gray.70" }, + }, + }, +}); + +// --- Component --- interface SegmentOption { value: string; @@ -26,45 +69,13 @@ export const SegmentGroup: React.FC = ({ } }} > -
- +
+ {options.map((option) => ( {option.label} diff --git a/libs/@hashintel/petrinaut/src/components/tooltip.tsx b/libs/@hashintel/petrinaut/src/components/tooltip.tsx index a537e5e570c..363185d6171 100644 --- a/libs/@hashintel/petrinaut/src/components/tooltip.tsx +++ b/libs/@hashintel/petrinaut/src/components/tooltip.tsx @@ -4,6 +4,18 @@ import type { SvgIconProps } from "@mui/material"; import { SvgIcon, Tooltip as MuiTooltip } from "@mui/material"; import type { FunctionComponent, ReactNode } from "react"; +const tooltipContentStyle = css({ + backgroundColor: "core.gray.90", + color: "core.gray.10", + borderRadius: "radius.6", + fontSize: "[13px]", + zIndex: "[10000]", + boxShadow: "[0 2px 8px rgba(0, 0, 0, 0.15)]", + padding: "[6px 10px]", +}); + +// --- Components --- + interface TooltipProps { content: string; children: ReactNode; @@ -18,19 +30,7 @@ export const Tooltip: React.FC = ({ content, children }) => { > {children} - + {content} diff --git a/libs/@hashintel/petrinaut/src/views/Editor/components/BottomPanel/bottom-panel.tsx b/libs/@hashintel/petrinaut/src/views/Editor/components/BottomPanel/bottom-panel.tsx index 47f665c1f86..fcc99ce0708 100644 --- a/libs/@hashintel/petrinaut/src/views/Editor/components/BottomPanel/bottom-panel.tsx +++ b/libs/@hashintel/petrinaut/src/views/Editor/components/BottomPanel/bottom-panel.tsx @@ -13,6 +13,12 @@ import { DiagnosticsContent } from "./diagnostics-content"; import { ParametersContent } from "./parameters-content"; import { SimulationSettingsContent } from "./simulation-settings-content"; +const glassPanelBaseStyle = css({ + position: "fixed", + zIndex: 999, + padding: "[4px]", +}); + const panelContainerStyle = css({ display: "flex", flexDirection: "column", @@ -136,14 +142,12 @@ export const BottomPanel: React.FC = () => { return ( { - if (typeof messageText === "string") { - return messageText; - } - return ts.flattenDiagnosticMessageText(messageText, "\n"); -}; - const emptyMessageStyle = css({ color: "core.gray.50", fontStyle: "italic", }); +const entityGroupStyle = css({ + marginBottom: "[8px]", +}); + const entityButtonStyle = css({ + display: "flex", + alignItems: "center", + gap: "[6px]", + width: "[100%]", + padding: "[4px 0]", + border: "none", + cursor: "pointer", + textAlign: "left", fontSize: "[12px]", fontWeight: "medium", color: "core.gray.80", - "&:hover": { + _hover: { color: "core.gray.90", }, }); @@ -38,18 +38,35 @@ const errorCountStyle = css({ fontWeight: "normal", }); +const expandedContentStyle = css({ + paddingLeft: "[16px]", + marginTop: "[4px]", +}); + +const itemGroupStyle = css({ + marginBottom: "[8px]", +}); + const subTypeStyle = css({ fontSize: "[11px]", fontWeight: "medium", color: "core.gray.60", + marginBottom: "[2px]", }); const diagnosticsListStyle = css({ margin: "[0]", + paddingLeft: "[12px]", listStyle: "none", }); +const diagnosticItemStyle = css({ + marginBottom: "[4px]", +}); + const diagnosticButtonStyle = css({ + marginLeft: "[8px]", + padding: "[2px 4px]", fontSize: "[11px]", fontFamily: "[ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace]", @@ -62,15 +79,36 @@ const diagnosticButtonStyle = css({ border: "none", textAlign: "left", width: "[100%]", - "&:hover": { + _hover: { backgroundColor: "[rgba(220, 38, 38, 0.08)]", }, }); +const bulletStyle = css({ + marginRight: "[4px]", +}); + const positionStyle = css({ color: "core.gray.50", + marginLeft: "[8px]", }); +// --- Helpers --- + +/** + * Formats a TypeScript diagnostic message to a readable string + */ +const formatDiagnosticMessage = ( + messageText: string | ts.DiagnosticMessageChain, +): string => { + if (typeof messageText === "string") { + return messageText; + } + return ts.flattenDiagnosticMessageText(messageText, "\n"); +}; + +// --- Types --- + type EntityType = "transition" | "differential-equation"; interface GroupedDiagnostics { @@ -183,22 +221,11 @@ export const DiagnosticsContent: React.FC = () => { : `Differential Equation: ${group.entityName}`; return ( -
+
{/* Collapsible entity header */}
-
+
{parameters.map((param) => { const isSelected = selectedResourceId === param.id; @@ -196,36 +231,15 @@ export const ParametersContent: React.FC = () => { setSelectedResourceId(param.id); } }} - style={{ - width: "100%", - display: "flex", - alignItems: "center", - justifyContent: "space-between", - padding: "4px 2px 4px 8px", - fontSize: 13, - borderRadius: 4, - backgroundColor: isSelected - ? "rgba(59, 130, 246, 0.15)" - : "#f9fafb", - cursor: "pointer", - }} - className={ - isSelected ? parameterRowSelectedStyle : parameterRowStyle - } + className={parameterRowStyle({ isSelected })} >
{param.name}
-
+                
                   {param.variableName}
                 
-
+
{isSimulationMode ? ( { const [isExpanded, setIsExpanded] = useState(true); @@ -31,42 +165,12 @@ export const DifferentialEquationsSection: React.FC = () => { simulationState === "Running" || simulationState === "Paused"; return ( -
-
+
+
{isExpanded && ( -
+
{differentialEquations.map((eq) => { const isSelected = selectedResourceId === eq.id; @@ -145,27 +229,9 @@ export const DifferentialEquationsSection: React.FC = () => { setSelectedResourceId(eq.id); } }} - style={{ - display: "flex", - alignItems: "center", - justifyContent: "space-between", - padding: "4px 2px 4px 8px", - fontSize: 13, - borderRadius: 4, - backgroundColor: isSelected - ? "rgba(59, 130, 246, 0.15)" - : "#f9fafb", - cursor: "pointer", - }} - className={css({ - _hover: { - backgroundColor: isSelected - ? "[rgba(59, 130, 246, 0.2)]" - : "[rgba(0, 0, 0, 0.05)]", - }, - })} + className={equationRowStyle({ isSelected })} > -
+
{eq.name}
)} diff --git a/libs/@hashintel/petrinaut/src/views/Editor/components/LeftSideBar/types-section.tsx b/libs/@hashintel/petrinaut/src/views/Editor/components/LeftSideBar/types-section.tsx index 1c7da6a059a..2cef5ab758f 100644 --- a/libs/@hashintel/petrinaut/src/views/Editor/components/LeftSideBar/types-section.tsx +++ b/libs/@hashintel/petrinaut/src/views/Editor/components/LeftSideBar/types-section.tsx @@ -1,4 +1,4 @@ -import { css } from "@hashintel/ds-helpers/css"; +import { css, cva } from "@hashintel/ds-helpers/css"; import { useState } from "react"; import { FaChevronDown, FaChevronRight } from "react-icons/fa6"; @@ -7,6 +7,149 @@ import { useEditorStore } from "../../../../state/editor-provider"; import { useSDCPNContext } from "../../../../state/sdcpn-provider"; import { useSimulationStore } from "../../../../state/simulation-provider"; +const sectionContainerStyle = css({ + display: "flex", + flexDirection: "column", + gap: "[8px]", + paddingBottom: "[16px]", + borderBottom: "[1px solid rgba(0, 0, 0, 0.1)]", +}); + +const headerRowStyle = css({ + display: "flex", + alignItems: "center", + justifyContent: "space-between", +}); + +const sectionToggleButtonStyle = css({ + display: "flex", + alignItems: "center", + gap: "[6px]", + fontWeight: 600, + fontSize: "[13px]", + color: "[#333]", + cursor: "pointer", + background: "[transparent]", + border: "none", + padding: "spacing.1", + borderRadius: "radius.4", + _hover: { + backgroundColor: "[rgba(0, 0, 0, 0.05)]", + }, +}); + +const addButtonStyle = css({ + display: "flex", + alignItems: "center", + justifyContent: "center", + padding: "spacing.1", + borderRadius: "radius.2", + cursor: "pointer", + fontSize: "[18px]", + color: "core.gray.60", + background: "[transparent]", + border: "none", + width: "[24px]", + height: "[24px]", + _hover: { + backgroundColor: "[rgba(0, 0, 0, 0.05)]", + color: "core.gray.90", + }, + _disabled: { + cursor: "not-allowed", + opacity: "[0.4]", + _hover: { + backgroundColor: "[transparent]", + color: "core.gray.60", + }, + }, +}); + +const listContainerStyle = css({ + display: "flex", + flexDirection: "column", + gap: "[2px]", + maxHeight: "[200px]", + overflowY: "auto", +}); + +const typeRowStyle = cva({ + base: { + display: "flex", + alignItems: "center", + gap: "[8px]", + padding: "[4px 2px 4px 8px]", + borderRadius: "[4px]", + cursor: "pointer", + }, + variants: { + isSelected: { + true: { + backgroundColor: "[rgba(59, 130, 246, 0.15)]", + _hover: { + backgroundColor: "[rgba(59, 130, 246, 0.2)]", + }, + }, + false: { + backgroundColor: "[transparent]", + _hover: { + backgroundColor: "[rgba(0, 0, 0, 0.05)]", + }, + }, + }, + }, +}); + +const colorDotStyle = css({ + width: "[12px]", + height: "[12px]", + borderRadius: "[50%]", + flexShrink: 0, +}); + +const typeNameStyle = css({ + flex: "[1]", + fontSize: "[13px]", + color: "[#374151]", + overflow: "hidden", + textOverflow: "ellipsis", + whiteSpace: "nowrap", +}); + +const deleteButtonStyle = css({ + display: "flex", + alignItems: "center", + justifyContent: "center", + padding: "spacing.1", + borderRadius: "radius.2", + cursor: "pointer", + fontSize: "[14px]", + color: "core.gray.40", + background: "[transparent]", + border: "none", + width: "[20px]", + height: "[20px]", + _hover: { + backgroundColor: "[rgba(239, 68, 68, 0.1)]", + color: "core.red.60", + }, + _disabled: { + cursor: "not-allowed", + opacity: "[0.3]", + _hover: { + backgroundColor: "[transparent]", + color: "core.gray.40", + }, + }, +}); + +const emptyMessageStyle = css({ + fontSize: "[13px]", + color: "[#9ca3af]", + padding: "spacing.4", + textAlign: "center", +}); + // Pool of 10 well-differentiated colors for types const TYPE_COLOR_POOL = [ "#3b82f6", // Blue @@ -73,41 +216,12 @@ export const TypesSection: React.FC = () => { simulationState === "Running" || simulationState === "Paused"; return ( -
-
+
+
{isExpanded && ( -
+
{types.map((type) => { const isSelected = selectedResourceId === type.id; @@ -205,46 +289,13 @@ export const TypesSection: React.FC = () => { setSelectedResourceId(type.id); } }} - style={{ - display: "flex", - alignItems: "center", - gap: 8, - padding: "4px 2px 4px 8px", - borderRadius: 4, - backgroundColor: isSelected - ? "rgba(59, 130, 246, 0.15)" - : "transparent", - cursor: "pointer", - }} - className={css({ - _hover: { - backgroundColor: isSelected - ? "[rgba(59, 130, 246, 0.2)]" - : "[rgba(0, 0, 0, 0.05)]", - }, - })} + className={typeRowStyle({ isSelected })} >
- - {type.name} - + {type.name}
)} diff --git a/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/color-select.tsx b/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/color-select.tsx index 3365d1f36ec..45fe2f6e244 100644 --- a/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/color-select.tsx +++ b/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/color-select.tsx @@ -1,7 +1,92 @@ import { Portal } from "@ark-ui/react/portal"; import { createListCollection, Select } from "@ark-ui/react/select"; +import { css, cva } from "@hashintel/ds-helpers/css"; import { TbChevronDown } from "react-icons/tb"; +const triggerStyle = cva({ + base: { + display: "flex", + alignItems: "center", + justifyContent: "space-between", + gap: "[8px]", + padding: "[6px 8px]", + border: "[1px solid rgba(0, 0, 0, 0.1)]", + borderRadius: "[4px]", + fontSize: "[14px]", + width: "[100%]", + }, + variants: { + isDisabled: { + true: { + backgroundColor: "[rgba(0, 0, 0, 0.05)]", + cursor: "not-allowed", + opacity: "[0.5]", + }, + false: { + backgroundColor: "[white]", + cursor: "pointer", + opacity: "[1]", + }, + }, + }, +}); + +const triggerValueContainerStyle = css({ + display: "flex", + alignItems: "center", + gap: "[8px]", +}); + +const colorSwatchStyle = css({ + width: "[20px]", + height: "[20px]", + borderRadius: "[3px]", + border: "[1px solid rgba(0, 0, 0, 0.1)]", + flexShrink: 0, +}); + +const colorCodeStyle = css({ + fontSize: "[12px]", + fontFamily: "[monospace]", +}); + +const indicatorIconStyle = css({ + fontSize: "[16px]", + color: "[#666]", +}); + +const contentStyle = css({ + backgroundColor: "[white]", + border: "[1px solid rgba(0, 0, 0, 0.1)]", + borderRadius: "[4px]", + boxShadow: "[0 4px 12px rgba(0, 0, 0, 0.15)]", + padding: "[4px]", + zIndex: 1000, +}); + +const itemStyle = css({ + display: "flex", + alignItems: "center", + justifyContent: "space-between", + gap: "[8px]", + padding: "[8px 10px]", + cursor: "pointer", + borderRadius: "[3px]", + fontSize: "[13px]", + transition: "[background-color 0.15s ease]", +}); + +const itemValueContainerStyle = css({ + display: "flex", + alignItems: "center", + gap: "[8px]", +}); + +const checkmarkStyle = css({ + fontSize: "[14px]", + color: "[#3b82f6]", +}); + // Pool of 10 well-differentiated colors for types const TYPE_COLOR_POOL = [ { value: "#3b82f6", label: "Blue" }, @@ -43,90 +128,36 @@ export const ColorSelect: React.FC = ({ positioning={{ sameWidth: true }} > - -
+ +
-
{value}
+
{value}
- + - + {collection.items.map((item) => ( - -
+ +
-
- {item.value} -
+
{item.value}
- + ))} diff --git a/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/differential-equation-properties.tsx b/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/differential-equation-properties.tsx index 0f3f02fa1db..5a8291a8f07 100644 --- a/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/differential-equation-properties.tsx +++ b/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/differential-equation-properties.tsx @@ -1,5 +1,6 @@ /* eslint-disable id-length */ +import { css, cva } from "@hashintel/ds-helpers/css"; import MonacoEditor from "@monaco-editor/react"; import { useState } from "react"; import { TbDotsVertical, TbSparkles } from "react-icons/tb"; @@ -18,6 +19,241 @@ import type { } from "../../../../core/types/sdcpn"; import { useSimulationStore } from "../../../../state/simulation-provider"; +const containerStyle = css({ + display: "flex", + flexDirection: "column", + height: "[100%]", + gap: "[12px]", +}); + +const headerTitleStyle = css({ + fontWeight: 600, + fontSize: "[16px]", + marginBottom: "[8px]", +}); + +const fieldLabelStyle = css({ + fontWeight: 500, + fontSize: "[12px]", + marginBottom: "[4px]", +}); + +const inputStyle = cva({ + base: { + fontSize: "[14px]", + padding: "[6px 8px]", + border: "[1px solid rgba(0, 0, 0, 0.1)]", + borderRadius: "[4px]", + width: "[100%]", + boxSizing: "border-box", + }, + variants: { + isReadOnly: { + true: { + backgroundColor: "[rgba(0, 0, 0, 0.05)]", + cursor: "not-allowed", + }, + false: { + backgroundColor: "[white]", + cursor: "text", + }, + }, + }, +}); + +const typeDropdownButtonStyle = cva({ + base: { + width: "[100%]", + fontSize: "[14px]", + padding: "[6px 8px]", + border: "[1px solid rgba(0, 0, 0, 0.1)]", + borderRadius: "[4px]", + display: "flex", + alignItems: "center", + gap: "[8px]", + textAlign: "left", + }, + variants: { + isReadOnly: { + true: { + backgroundColor: "[rgba(0, 0, 0, 0.05)]", + cursor: "not-allowed", + }, + false: { + backgroundColor: "[white]", + cursor: "pointer", + }, + }, + }, +}); + +const colorDotStyle = css({ + width: "[12px]", + height: "[12px]", + borderRadius: "[50%]", + flexShrink: 0, +}); + +const dropdownMenuStyle = css({ + position: "absolute", + top: "[100%]", + left: "[0]", + right: "[0]", + marginTop: "[4px]", + backgroundColor: "[white]", + border: "[1px solid rgba(0, 0, 0, 0.1)]", + borderRadius: "[4px]", + boxShadow: "[0 4px 16px rgba(0, 0, 0, 0.15)]", + maxHeight: "[300px]", + overflowY: "auto", + zIndex: 1000, +}); + +const dropdownItemStyle = css({ + width: "[100%]", + padding: "[8px 12px]", + border: "none", + cursor: "pointer", + display: "flex", + alignItems: "center", + gap: "[8px]", + fontSize: "[14px]", + textAlign: "left", +}); + +const confirmDialogOverlayStyle = css({ + position: "fixed", + top: "[0]", + left: "[0]", + right: "[0]", + bottom: "[0]", + backgroundColor: "[rgba(0, 0, 0, 0.5)]", + display: "flex", + alignItems: "center", + justifyContent: "center", + zIndex: 10000, +}); + +const confirmDialogStyle = css({ + backgroundColor: "[white]", + borderRadius: "[8px]", + padding: "[24px]", + maxWidth: "[400px]", + boxShadow: "[0 4px 16px rgba(0, 0, 0, 0.2)]", +}); + +const confirmDialogTitleStyle = css({ + fontWeight: 600, + fontSize: "[16px]", + marginBottom: "[12px]", +}); + +const confirmDialogTextStyle = css({ + fontSize: "[14px]", + color: "[#666]", + marginBottom: "[16px]", +}); + +const confirmDialogListStyle = css({ + fontSize: "[13px]", + color: "[#666]", + marginBottom: "[16px]", + paddingLeft: "[20px]", +}); + +const confirmDialogHintStyle = css({ + fontSize: "[13px]", + color: "[#999]", + marginBottom: "[20px]", +}); + +const confirmDialogButtonsStyle = css({ + display: "flex", + gap: "[8px]", + justifyContent: "flex-end", +}); + +const cancelButtonStyle = css({ + padding: "[8px 16px]", + border: "[1px solid rgba(0, 0, 0, 0.1)]", + borderRadius: "[4px]", + backgroundColor: "[white]", + cursor: "pointer", + fontSize: "[14px]", +}); + +const confirmButtonStyle = css({ + padding: "[8px 16px]", + border: "none", + borderRadius: "[4px]", + backgroundColor: "[#2563eb]", + color: "[white]", + cursor: "pointer", + fontSize: "[14px]", +}); + +const codeContainerStyle = css({ + display: "flex", + flexDirection: "column", + flex: "[1]", + minHeight: "[0]", +}); + +const codeHeaderStyle = css({ + display: "flex", + alignItems: "center", + justifyContent: "space-between", + marginBottom: "[8px]", +}); + +const codeHeaderLabelStyle = css({ + fontWeight: 500, + fontSize: "[12px]", +}); + +const menuButtonStyle = css({ + background: "[transparent]", + border: "none", + cursor: "pointer", + padding: "[4px]", + display: "flex", + alignItems: "center", + fontSize: "[18px]", + color: "[rgba(0, 0, 0, 0.6)]", +}); + +const editorContainerStyle = cva({ + base: { + border: "[1px solid rgba(0, 0, 0, 0.1)]", + borderRadius: "[4px]", + overflow: "hidden", + flex: "[1]", + minHeight: "[0]", + }, + variants: { + isReadOnly: { + true: { + filter: "[grayscale(20%) brightness(98%)]", + pointerEvents: "none", + }, + false: { + filter: "[none]", + pointerEvents: "auto", + }, + }, + }, +}); + +const aiMenuItemStyle = css({ + display: "flex", + alignItems: "center", + gap: "[6px]", +}); + +const aiIconStyle = css({ + fontSize: "[16px]", +}); + interface DifferentialEquationPropertiesProps { differentialEquation: DifferentialEquation; types: Color[]; @@ -25,7 +261,7 @@ interface DifferentialEquationPropertiesProps { globalMode: "edit" | "simulate"; updateDifferentialEquation: ( equationId: string, - updateFn: (equation: DifferentialEquation) => void, + updateFn: (equation: DifferentialEquation) => void ) => void; } @@ -48,7 +284,7 @@ export const DifferentialEquationProperties: React.FC< const isReadOnly = globalMode === "simulate" || isSimulationRunning; const associatedType = types.find( - (type) => type.id === differentialEquation.colorId, + (type) => type.id === differentialEquation.colorId ); // Find places that use this differential equation @@ -74,7 +310,7 @@ export const DifferentialEquationProperties: React.FC< differentialEquation.id, (existingEquation) => { existingEquation.colorId = newTypeId; - }, + } ); } }; @@ -85,7 +321,7 @@ export const DifferentialEquationProperties: React.FC< differentialEquation.id, (existingEquation) => { existingEquation.colorId = pendingTypeId; - }, + } ); } setShowConfirmDialog(false); @@ -98,24 +334,13 @@ export const DifferentialEquationProperties: React.FC< }; return ( -
+
-
- Differential Equation -
+
Differential Equation
-
- Name -
+
Name
{ existingEquation.name = event.target.value; - }, + } ); }} disabled={isReadOnly} - style={{ - fontSize: 14, - padding: "6px 8px", - border: "1px solid rgba(0, 0, 0, 0.1)", - borderRadius: 4, - width: "100%", - boxSizing: "border-box", - backgroundColor: isReadOnly ? "rgba(0, 0, 0, 0.05)" : "white", - cursor: isReadOnly ? "not-allowed" : "text", - }} + className={inputStyle({ isReadOnly })} />
-
- Associated Type -
+
Associated Type
{showTypeDropdown && !isReadOnly && ( -
+
{types.map((type) => ( @@ -254,36 +422,16 @@ export const DifferentialEquationProperties: React.FC< {/* Confirmation Dialog */} {showConfirmDialog && ( // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions -
+
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
ev.stopPropagation()} > -
+
Change Associated Type?
-
+
{placesUsingEquation.length === 1 ? ( <> 1 place is currently using this differential @@ -296,51 +444,27 @@ export const DifferentialEquationProperties: React.FC< )}
-
    +
      {placesUsingEquation.map((place) => (
    • {place.name}
    • ))}
    -
    +
    Changing the type may affect how these places behave. Are you sure you want to continue?
    -
    +
    @@ -349,39 +473,13 @@ export const DifferentialEquationProperties: React.FC<
    )} -
    -
    -
    Code
    +
    +
    +
    Code
    {!isReadOnly && ( + } @@ -392,7 +490,7 @@ export const DifferentialEquationProperties: React.FC< onClick: () => { // Get the associated type to generate appropriate default code const equationType = types.find( - (t) => t.id === differentialEquation.colorId, + (t) => t.id === differentialEquation.colorId ); updateDifferentialEquation( @@ -400,10 +498,10 @@ export const DifferentialEquationProperties: React.FC< (existingEquation) => { existingEquation.code = equationType ? generateDefaultDifferentialEquationCode( - equationType, + equationType ) : DEFAULT_DIFFERENTIAL_EQUATION_CODE; - }, + } ); }, }, @@ -411,14 +509,8 @@ export const DifferentialEquationProperties: React.FC< id: "generate-ai", label: ( -
    - +
    + Generate with AI
    @@ -432,17 +524,7 @@ export const DifferentialEquationProperties: React.FC< /> )}
    -
    +
    { existingEquation.code = newCode ?? ""; - }, + } ); }} path={`inmemory://sdcpn/differential-equations/${differentialEquation.id}.ts`} diff --git a/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/initial-state-editor.tsx b/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/initial-state-editor.tsx index 060adf44e4b..a3a02ed7159 100644 --- a/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/initial-state-editor.tsx +++ b/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/initial-state-editor.tsx @@ -1,3 +1,4 @@ +import { css, cva } from "@hashintel/ds-helpers/css"; import { useEffect, useRef, useState } from "react"; import { TbTrash } from "react-icons/tb"; @@ -5,6 +6,189 @@ import { InfoIconTooltip } from "../../../../components/tooltip"; import type { Color } from "../../../../core/types/sdcpn"; import { useSimulationStore } from "../../../../state/simulation-provider"; +const headerRowStyle = css({ + display: "flex", + alignItems: "center", + justifyContent: "space-between", + marginBottom: "[4px]", + height: "[20px]", +}); + +const headerLabelStyle = css({ + fontWeight: 500, + fontSize: "[12px]", +}); + +const clearButtonStyle = css({ + fontSize: "[11px]", + padding: "[2px 8px]", + border: "[1px solid rgba(0, 0, 0, 0.2)]", + borderRadius: "[3px]", + backgroundColor: "[white]", + cursor: "pointer", + color: "[#666]", + display: "flex", + alignItems: "center", + gap: "[4px]", +}); + +const tableContainerStyle = css({ + position: "relative", + border: "[1px solid rgba(0, 0, 0, 0.1)]", + borderRadius: "[4px]", + overflow: "auto", + width: "[100%]", + backgroundColor: "[#fafafa]", +}); + +const tableStyle = css({ + width: "[100%]", + borderCollapse: "collapse", + fontSize: "[12px]", + tableLayout: "fixed", +}); + +const rowNumberHeaderStyle = css({ + position: "sticky", + top: "[0]", + backgroundColor: "[#f5f5f5]", + borderBottom: "[1px solid rgba(0, 0, 0, 0.1)]", + borderRight: "[1px solid rgba(0, 0, 0, 0.1)]", + padding: "[4px 8px]", + textAlign: "center", + fontWeight: 500, + width: "[40px]", + minWidth: "[40px]", +}); + +const columnHeaderStyle = css({ + position: "sticky", + top: "[0]", + backgroundColor: "[#f5f5f5]", + borderBottom: "[1px solid rgba(0, 0, 0, 0.1)]", + padding: "[4px 8px]", + textAlign: "left", + fontWeight: 500, + fontFamily: "[monospace]", + minWidth: "[60px]", + overflow: "hidden", + textOverflow: "ellipsis", + whiteSpace: "nowrap", +}); + +const rowStyle = cva({ + base: { + height: "[28px]", + }, + variants: { + isSelected: { + true: { backgroundColor: "[rgba(59, 130, 246, 0.1)]" }, + false: { backgroundColor: "[white]" }, + }, + }, +}); + +const rowNumberCellStyle = cva({ + base: { + borderRight: "[1px solid rgba(0, 0, 0, 0.1)]", + borderBottom: "[1px solid rgba(0, 0, 0, 0.05)]", + padding: "[4px 8px]", + textAlign: "center", + fontWeight: 500, + outline: "none", + }, + variants: { + isSelected: { + true: { backgroundColor: "[rgba(59, 130, 246, 0.2)]" }, + false: { backgroundColor: "[#fafafa]" }, + }, + isPhantom: { + true: { color: "[#ccc]" }, + false: { color: "[#666]" }, + }, + hasSimulation: { + true: { cursor: "default" }, + false: { cursor: "pointer" }, + }, + }, +}); + +const cellContainerStyle = css({ + borderBottom: "[1px solid rgba(0, 0, 0, 0.05)]", + padding: "spacing.0", + height: "[28px]", +}); + +const readOnlyCellStyle = css({ + height: "[28px]", + display: "flex", + alignItems: "center", + fontFamily: "[monospace]", + fontSize: "[12px]", + padding: "[4px 8px]", + overflow: "hidden", + textOverflow: "ellipsis", + whiteSpace: "nowrap", +}); + +const editingInputStyle = css({ + width: "[100%]", + height: "[28px]", + border: "none", + padding: "[4px 8px]", + fontFamily: "[monospace]", + fontSize: "[12px]", + backgroundColor: "[rgba(59, 130, 246, 0.05)]", + outline: "[2px solid #3b82f6]", + outlineOffset: "[-2px]", + boxSizing: "border-box", +}); + +const cellButtonStyle = cva({ + base: { + width: "[100%]", + height: "[28px]", + padding: "[4px 8px]", + fontFamily: "[monospace]", + fontSize: "[12px]", + backgroundColor: "[transparent]", + outlineOffset: "[-2px]", + cursor: "default", + boxSizing: "border-box", + overflow: "hidden", + textOverflow: "ellipsis", + whiteSpace: "nowrap", + display: "flex", + alignItems: "center", + }, + variants: { + isFocused: { + true: { outline: "[2px solid #3b82f6]" }, + false: { outline: "none" }, + }, + }, +}); + +const resizeHandleStyle = cva({ + base: { + position: "absolute", + bottom: "[0]", + left: "[0]", + right: "[0]", + height: "[8px]", + cursor: "ns-resize", + border: "none", + padding: "spacing.0", + zIndex: 10, + }, + variants: { + isResizing: { + true: { backgroundColor: "[rgba(0, 0, 0, 0.1)]" }, + false: { backgroundColor: "[transparent]" }, + }, + }, +}); + /** * Hook to make an element resizable by dragging its bottom border */ @@ -50,6 +234,8 @@ const useResizable = (initialHeight: number) => { }; }; +// --- Component --- + /** * InitialStateEditor - A component for editing initial tokens in a place * Stores data in SimulationStore, not in the Place definition @@ -559,16 +745,8 @@ export const InitialStateEditor: React.FC = ({ return (
    -
    -
    +
    +
    {isSimulationNotRun ? "Initial State" : "State"} {isSimulationNotRun && ( @@ -578,18 +756,7 @@ export const InitialStateEditor: React.FC = ({
    - +
    - @@ -714,27 +827,11 @@ export const InitialStateEditor: React.FC = ({
    + {placeType.elements.map((element) => ( {element.name} @@ -671,33 +799,18 @@ export const InitialStateEditor: React.FC = ({
    handleRowClick(rowIndex)} onKeyDown={(event) => handleRowKeyDown(event, rowIndex)} tabIndex={0} - style={{ - borderRight: "1px solid rgba(0, 0, 0, 0.1)", - borderBottom: "1px solid rgba(0, 0, 0, 0.05)", - padding: "4px 8px", - textAlign: "center", - cursor: hasSimulation ? "default" : "pointer", - backgroundColor: - selectedRow === rowIndex - ? "rgba(59, 130, 246, 0.2)" - : "#fafafa", - fontWeight: 500, - color: rowIndex === tableData.length ? "#ccc" : "#666", - outline: "none", - }} + className={rowNumberCellStyle({ + isSelected: selectedRow === rowIndex, + isPhantom: rowIndex === tableData.length, + hasSimulation, + })} > {rowIndex === tableData.length ? "" : rowIndex + 1} {hasSimulation ? ( -
    +
    {isPhantomRow ? "" : value}
    ) : isEditing ? ( @@ -755,18 +852,7 @@ export const InitialStateEditor: React.FC = ({ setEditingCell(null); setEditingValue(""); }} - style={{ - width: "100%", - height: "28px", - border: "none", - padding: "4px 8px", - fontFamily: "monospace", - fontSize: 12, - backgroundColor: "rgba(59, 130, 246, 0.05)", - outline: "2px solid #3b82f6", - outlineOffset: -2, - boxSizing: "border-box", - }} + className={editingInputStyle} /> ) : (
    = ({ onKeyDown={(event) => handleKeyDown(event, rowIndex, colIndex) } - style={{ - width: "100%", - height: "28px", - padding: "4px 8px", - fontFamily: "monospace", - fontSize: 12, - backgroundColor: "transparent", - outline: isFocused ? "2px solid #3b82f6" : "none", - outlineOffset: -2, - cursor: "default", - boxSizing: "border-box", - overflow: "hidden", - textOverflow: "ellipsis", - whiteSpace: "nowrap", - display: "flex", - alignItems: "center", - }} + className={cellButtonStyle({ isFocused })} > {isPhantomRow ? "" : value}
    @@ -824,18 +894,7 @@ export const InitialStateEditor: React.FC = ({ type="button" aria-label="Resize table" onMouseDown={startResize} - style={{ - position: "absolute", - bottom: 0, - left: 0, - right: 0, - height: 8, - cursor: "ns-resize", - backgroundColor: isResizing ? "rgba(0, 0, 0, 0.1)" : "transparent", - border: "none", - padding: 0, - zIndex: 10, - }} + className={resizeHandleStyle({ isResizing })} />
    diff --git a/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/multiple-selection.tsx b/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/multiple-selection.tsx index 745cff3452e..c3b23ba4409 100644 --- a/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/multiple-selection.tsx +++ b/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/multiple-selection.tsx @@ -1,3 +1,10 @@ +import { css } from "@hashintel/ds-helpers/css"; + +const titleStyle = css({ + fontWeight: 600, + fontSize: "[14px]", +}); + /** * MultipleSelection - Displays info when multiple items are selected */ @@ -10,9 +17,7 @@ export const MultipleSelection: React.FC = ({ }) => { return (
    -
    - Multiple Items Selected ({count}) -
    +
    Multiple Items Selected ({count})
    ); }; diff --git a/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/parameter-properties.tsx b/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/parameter-properties.tsx index eed4631959e..49184886124 100644 --- a/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/parameter-properties.tsx +++ b/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/parameter-properties.tsx @@ -1,6 +1,58 @@ +import { css, cva } from "@hashintel/ds-helpers/css"; + import type { Parameter } from "../../../../core/types/sdcpn"; import { useSimulationStore } from "../../../../state/simulation-provider"; +const containerStyle = css({ + display: "flex", + flexDirection: "column", + gap: "[12px]", +}); + +const headerTitleStyle = css({ + fontWeight: 600, + fontSize: "[16px]", + marginBottom: "[8px]", +}); + +const fieldLabelStyle = css({ + fontWeight: 500, + fontSize: "[12px]", + marginBottom: "[4px]", +}); + +const inputStyle = cva({ + base: { + fontSize: "[14px]", + padding: "[6px 8px]", + border: "[1px solid rgba(0, 0, 0, 0.15)]", + borderRadius: "[4px]", + width: "[100%]", + }, + variants: { + isDisabled: { + true: { + backgroundColor: "[rgba(0, 0, 0, 0.02)]", + cursor: "not-allowed", + }, + false: { + backgroundColor: "[white]", + cursor: "text", + }, + }, + isMonospace: { + true: { + fontFamily: "[monospace]", + }, + false: {}, + }, + }, + defaultVariants: { + isDisabled: false, + isMonospace: false, + }, +}); + /** * Slugifies a string to a valid JavaScript identifier. * - Converts to lowercase @@ -8,7 +60,7 @@ import { useSimulationStore } from "../../../../state/simulation-provider"; * - Removes leading/trailing underscores * - Ensures it doesn't start with a number */ -function slugifyToIdentifier(str: string): string { +const slugifyToIdentifier = (str: string): string => { return ( str .toLowerCase() @@ -21,7 +73,7 @@ function slugifyToIdentifier(str: string): string { // Ensure it doesn't start with a number .replace(/^(\d)/, "_$1") ); -} +}; interface ParameterPropertiesProps { parameter: Parameter; @@ -88,56 +140,33 @@ export const ParameterProperties: React.FC = ({ }; return ( -
    +
    -
    - Parameter -
    +
    Parameter
    {/* Name field */}
    -
    - Name -
    +
    Name
    {/* Variable Name field */}
    -
    - Variable Name -
    +
    Variable Name
    @@ -145,24 +174,13 @@ export const ParameterProperties: React.FC = ({ {/* Default Value field */}
    -
    - Default Value -
    +
    Default Value
    diff --git a/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/place-properties.tsx b/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/place-properties.tsx index e80465afd75..1ec92d324fd 100644 --- a/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/place-properties.tsx +++ b/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/place-properties.tsx @@ -1,5 +1,5 @@ /* eslint-disable id-length */ -import { css } from "@hashintel/ds-helpers/css"; +import { css, cva } from "@hashintel/ds-helpers/css"; import MonacoEditor from "@monaco-editor/react"; import { useEffect, useMemo, useRef, useState } from "react"; import { @@ -33,6 +33,226 @@ import { useSimulationStore } from "../../../../state/simulation-provider"; import { InitialStateEditor } from "./initial-state-editor"; import { VisualizerErrorBoundary } from "./visualizer-error-boundary"; +const containerStyle = css({ + display: "flex", + flexDirection: "column", + gap: "[12px]", +}); + +const headerContainerStyle = css({ + display: "flex", + justifyContent: "space-between", + alignItems: "center", + marginBottom: "[8px]", +}); + +const headerTitleStyle = css({ + fontWeight: 600, + fontSize: "[16px]", +}); + +const deleteButtonStyle = css({ + display: "flex", + alignItems: "center", + justifyContent: "center", + width: "[24px]", + height: "[24px]", + padding: "spacing.0", + border: "none", + background: "[transparent]", + cursor: "pointer", + color: "core.gray.60", + borderRadius: "radius.4", + _hover: { + color: "core.red.60", + backgroundColor: "core.red.10", + }, +}); + +const fieldLabelStyle = css({ + fontWeight: 500, + fontSize: "[12px]", + marginBottom: "[4px]", +}); + +const fieldLabelWithTooltipStyle = css({ + fontWeight: 500, + fontSize: "[12px]", + marginBottom: "[4px]", + display: "flex", + alignItems: "center", +}); + +const inputStyle = cva({ + base: { + fontSize: "[14px]", + padding: "[6px 8px]", + borderRadius: "[4px]", + width: "[100%]", + boxSizing: "border-box", + }, + variants: { + isReadOnly: { + true: { + backgroundColor: "[rgba(0, 0, 0, 0.05)]", + cursor: "not-allowed", + }, + false: { + backgroundColor: "[white]", + cursor: "text", + }, + }, + hasError: { + true: { + border: "[1px solid #ef4444]", + }, + false: { + border: "[1px solid rgba(0, 0, 0, 0.1)]", + }, + }, + }, + defaultVariants: { + isReadOnly: false, + hasError: false, + }, +}); + +const errorMessageStyle = css({ + fontSize: "[12px]", + color: "[#ef4444]", + marginTop: "[4px]", +}); + +const selectStyle = cva({ + base: { + fontSize: "[14px]", + padding: "[6px 8px]", + border: "[1px solid rgba(0, 0, 0, 0.1)]", + borderRadius: "[4px]", + width: "[100%]", + boxSizing: "border-box", + }, + variants: { + isReadOnly: { + true: { + backgroundColor: "[rgba(0, 0, 0, 0.05)]", + cursor: "not-allowed", + }, + false: { + backgroundColor: "[white]", + cursor: "pointer", + }, + }, + hasMarginBottom: { + true: { + marginBottom: "[8px]", + }, + false: {}, + }, + }, +}); + +const jumpButtonContainerStyle = css({ + textAlign: "right", +}); + +const jumpButtonStyle = css({ + fontSize: "[12px]", + padding: "[4px 8px]", + border: "[1px solid rgba(0, 0, 0, 0.2)]", + borderRadius: "[4px]", + backgroundColor: "[white]", + cursor: "pointer", + color: "[#333]", + display: "inline-flex", + alignItems: "center", + gap: "[6px]", +}); + +const jumpIconStyle = css({ + fontSize: "[14px]", +}); + +const sectionContainerStyle = css({ + marginTop: "[10px]", +}); + +const switchRowStyle = css({ + display: "flex", + alignItems: "center", + gap: "[8px]", + marginBottom: "[8px]", +}); + +const switchContainerStyle = css({ + display: "flex", + alignItems: "center", +}); + +const hintTextStyle = css({ + fontSize: "[11px]", + color: "[#999]", + fontStyle: "italic", + marginTop: "[4px]", +}); + +const diffEqContainerStyle = css({ + marginBottom: "[25px]", +}); + +const menuButtonStyle = css({ + background: "[transparent]", + border: "none", + cursor: "pointer", + padding: "[4px]", + display: "flex", + alignItems: "center", + fontSize: "[18px]", + color: "[rgba(0, 0, 0, 0.6)]", +}); + +const codeHeaderStyle = css({ + display: "flex", + alignItems: "center", + justifyContent: "space-between", + marginBottom: "[4px]", +}); + +const codeHeaderLabelStyle = css({ + fontWeight: 500, + fontSize: "[12px]", +}); + +const editorBorderStyle = css({ + border: "[1px solid rgba(0, 0, 0, 0.1)]", + borderRadius: "[4px]", + overflow: "hidden", +}); + +const aiMenuItemStyle = css({ + display: "flex", + alignItems: "center", + gap: "[6px]", +}); + +const aiIconStyle = css({ + fontSize: "[16px]", +}); + +const visualizerMessageStyle = css({ + padding: "[12px]", + color: "[#666]", +}); + +const visualizerErrorStyle = css({ + padding: "[12px]", + color: "[#d32f2f]", +}); + +const spacerStyle = css({ + height: "[40px]", +}); + interface PlacePropertiesProps { place: Place; types: Color[]; @@ -173,20 +393,10 @@ export const PlaceProperties: React.FC = ({ const { removePlace } = useSDCPNContext(); return ( -
    +
    -
    -
    Place
    +
    +
    Place
    @@ -225,9 +419,7 @@ export const PlaceProperties: React.FC = ({
    -
    - Name -
    +
    Name
    = ({ handleNameBlur(); }} disabled={isReadOnly} - style={{ - fontSize: 14, - padding: "6px 8px", - border: `1px solid ${nameError ? "#ef4444" : "rgba(0, 0, 0, 0.1)"}`, - borderRadius: 4, - width: "100%", - boxSizing: "border-box", - backgroundColor: isReadOnly ? "rgba(0, 0, 0, 0.05)" : "white", - cursor: isReadOnly ? "not-allowed" : "text", - }} + className={inputStyle({ isReadOnly, hasError: !!nameError })} /> - {nameError && ( -
    - {nameError} -
    - )} + {nameError &&
    {nameError}
    }
    -
    +
    Accepted token type = ({ }); }} disabled={isReadOnly} - style={{ - fontSize: 14, - padding: "6px 8px", - border: "1px solid rgba(0, 0, 0, 0.1)", - borderRadius: 4, - width: "100%", - boxSizing: "border-box", - backgroundColor: isReadOnly ? "rgba(0, 0, 0, 0.05)" : "white", - cursor: isReadOnly ? "not-allowed" : "pointer", - marginBottom: place.colorId ? 8 : 0, - }} + className={selectStyle({ + isReadOnly, + hasMarginBottom: !!place.colorId, + })} > {types.map((type) => ( @@ -315,42 +481,24 @@ export const PlaceProperties: React.FC = ({ {place.colorId && ( -
    +
    )}
    -
    -
    -
    +
    +
    +
    = ({ }} />
    -
    +
    Dynamics
    {(place.colorId === null || availableDiffEqs.length === 0) && ( -
    +
    {place.colorId !== null ? "Create a differential equation for the selected type in the left-hand sidebar first" : availableTypes.length === 0 @@ -394,10 +528,8 @@ export const PlaceProperties: React.FC = ({ {place.colorId && place.dynamicsEnabled && availableDiffEqs.length > 0 && ( -
    -
    - Differential Equation -
    +
    +
    Differential Equation
    {place.differentialEquationId && ( -
    +
    )} @@ -483,19 +594,11 @@ export const PlaceProperties: React.FC = ({ return (
    -
    +
    {hasSimulationFrames ? "State" : "Initial State"}
    -
    - Token count -
    +
    Token count
    = ({ }); }} disabled={hasSimulationFrames} - style={{ - fontSize: 14, - padding: "6px 8px", - border: "1px solid rgba(0, 0, 0, 0.1)", - borderRadius: 4, - width: "100%", - boxSizing: "border-box", - backgroundColor: hasSimulationFrames - ? "rgba(0, 0, 0, 0.05)" - : "white", - cursor: hasSimulationFrames ? "not-allowed" : "text", - }} + className={inputStyle({ isReadOnly: hasSimulationFrames })} />
    @@ -541,16 +633,9 @@ export const PlaceProperties: React.FC = ({ {/* Visualizer section */} {globalMode === "edit" && ( -
    -
    -
    +
    +
    +
    { @@ -572,14 +657,7 @@ export const PlaceProperties: React.FC = ({ }} />
    -
    +
    Visualizer
    @@ -597,15 +675,8 @@ export const PlaceProperties: React.FC = ({ return ( <> -
    -
    +
    +
    {showVisualization ? "Visualizer Output" : "Visualizer Code"} @@ -613,19 +684,7 @@ export const PlaceProperties: React.FC = ({ {!showVisualization && ( + } @@ -652,14 +711,8 @@ export const PlaceProperties: React.FC = ({ -
    - +
    + Generate with AI
    @@ -673,13 +726,7 @@ export const PlaceProperties: React.FC = ({ /> )}
    -
    +
    {showVisualization ? ( // Show live token values and parameters during simulation (() => { @@ -690,7 +737,7 @@ export const PlaceProperties: React.FC = ({ if (!placeType) { return ( -
    +
    Place has no type set
    ); @@ -707,7 +754,7 @@ export const PlaceProperties: React.FC = ({ simulation.frames[currentlyViewedFrame]; if (!currentFrame) { return ( -
    +
    No frame data available
    ); @@ -716,7 +763,7 @@ export const PlaceProperties: React.FC = ({ const placeState = currentFrame.places.get(place.id); if (!placeState) { return ( -
    +
    Place not found in frame
    ); @@ -779,7 +826,7 @@ export const PlaceProperties: React.FC = ({ // Render the compiled visualizer component if (!VisualizerComponent) { return ( -
    +
    Failed to compile visualizer code. Check console for errors.
    @@ -830,7 +877,7 @@ export const PlaceProperties: React.FC = ({
    )} -
    +
    ); }; diff --git a/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/properties-panel.tsx b/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/properties-panel.tsx index 517042e3f69..e4b0eb6fbc1 100644 --- a/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/properties-panel.tsx +++ b/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/properties-panel.tsx @@ -16,6 +16,31 @@ import { PlaceProperties } from "./place-properties"; import { TransitionProperties } from "./transition-properties"; import { TypeProperties } from "./type-properties"; +const unknownItemStyle = css({ + padding: "[16px]", + textAlign: "center", + color: "[#999]", + fontSize: "[14px]", +}); + +const positionContainerStyle = css({ + display: "flex", + position: "fixed", + top: "[0]", + right: "[0]", + zIndex: 1000, + pointerEvents: "none", +}); + +const glassPanelHeightStyle = css({ + height: "[100%]", +}); + +const glassPanelContentStyle = css({ + padding: "[16px]", + overflowY: "auto", +}); + /** * PropertiesPanel displays properties and controls for the selected node/edge. */ @@ -167,18 +192,7 @@ export const PropertiesPanel: React.FC = () => { default: // Unknown item type - content = ( -
    - Unknown item selected -
    - ); + content =
    Unknown item selected
    ; } // Calculate bottom offset based on bottom panel visibility @@ -187,29 +201,19 @@ export const PropertiesPanel: React.FC = () => { return (
    = ({ isDragging, } = useSortable({ id, disabled }); - const style = { + const transformStyle = { transform: CSS.Transform.toString(transform), transition, opacity: isDragging ? 0.5 : 1, }; return ( -
    +
    {FEATURE_FLAGS.REORDER_TRANSITION_ARCS && (
    )} -
    - {placeName} -
    -
    - - weight - +
    {placeName}
    +
    + weight = ({ onWeightChange(newWeight); } }} - style={{ - width: 60, - fontSize: 14, - padding: "4px 8px", - border: "1px solid rgba(0, 0, 0, 0.1)", - borderRadius: 4, - boxSizing: "border-box", - backgroundColor: disabled ? "rgba(0, 0, 0, 0.05)" : "white", - cursor: disabled ? "not-allowed" : "text", - }} + className={weightInputStyle({ isDisabled: disabled })} />
    {onDelete && !disabled && ( - )} diff --git a/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/transition-properties.tsx b/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/transition-properties.tsx index a3cd84e63b0..c76b2536e24 100644 --- a/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/transition-properties.tsx +++ b/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/transition-properties.tsx @@ -15,7 +15,7 @@ import { sortableKeyboardCoordinates, verticalListSortingStrategy, } from "@dnd-kit/sortable"; -import { css } from "@hashintel/ds-helpers/css"; +import { css, cva } from "@hashintel/ds-helpers/css"; import MonacoEditor from "@monaco-editor/react"; import { TbDotsVertical, TbSparkles, TbTrash } from "react-icons/tb"; @@ -32,6 +32,203 @@ import { useSDCPNContext } from "../../../../state/sdcpn-provider"; import { useSimulationStore } from "../../../../state/simulation-provider"; import { SortableArcItem } from "./sortable-arc-item"; +const containerStyle = css({ + display: "flex", + flexDirection: "column", + gap: "[12px]", +}); + +const headerContainerStyle = css({ + display: "flex", + justifyContent: "space-between", + alignItems: "center", + marginBottom: "[8px]", +}); + +const headerTitleStyle = css({ + fontWeight: 600, + fontSize: "[16px]", +}); + +const deleteButtonStyle = css({ + display: "flex", + alignItems: "center", + justifyContent: "center", + width: "[24px]", + height: "[24px]", + padding: "spacing.0", + border: "none", + background: "[transparent]", + cursor: "pointer", + color: "core.gray.60", + borderRadius: "radius.4", + _hover: { + color: "core.red.60", + backgroundColor: "core.red.10", + }, +}); + +const fieldLabelStyle = css({ + fontWeight: 500, + fontSize: "[12px]", + marginBottom: "[4px]", +}); + +const inputStyle = cva({ + base: { + fontSize: "[14px]", + padding: "[6px 8px]", + border: "[1px solid rgba(0, 0, 0, 0.1)]", + borderRadius: "[4px]", + width: "[100%]", + boxSizing: "border-box", + }, + variants: { + isReadOnly: { + true: { + backgroundColor: "[rgba(0, 0, 0, 0.05)]", + cursor: "not-allowed", + }, + false: { + backgroundColor: "[white]", + cursor: "text", + }, + }, + }, +}); + +const sectionContainerStyle = css({ + marginTop: "[20px]", +}); + +const emptyArcMessageStyle = css({ + fontSize: "[12px]", + color: "[#999]", +}); + +const arcListContainerStyle = css({ + border: "[1px solid rgba(0, 0, 0, 0.1)]", + borderRadius: "[6px]", + overflow: "hidden", +}); + +const segmentGroupWrapperStyle = cva({ + base: {}, + variants: { + isReadOnly: { + true: { + opacity: "[0.6]", + pointerEvents: "none", + }, + false: { + opacity: "[1]", + pointerEvents: "auto", + }, + }, + }, +}); + +const infoBoxStyle = css({ + fontSize: "[12px]", + color: "[#666]", + backgroundColor: "[rgba(0, 0, 0, 0.03)]", + padding: "[8px]", + borderRadius: "[4px]", + lineHeight: "[1.5]", +}); + +const codeHeaderStyle = css({ + display: "flex", + alignItems: "center", + justifyContent: "space-between", + marginBottom: "[4px]", + height: "[30px]", +}); + +const codeHeaderLabelStyle = css({ + fontWeight: 500, + fontSize: "[12px]", +}); + +const menuButtonStyle = css({ + background: "[transparent]", + border: "none", + cursor: "pointer", + padding: "[4px]", + display: "flex", + alignItems: "center", + fontSize: "[18px]", + color: "[rgba(0, 0, 0, 0.6)]", +}); + +const editorContainerStyle = cva({ + base: { + border: "[1px solid rgba(0, 0, 0, 0.1)]", + borderRadius: "[4px]", + overflow: "hidden", + }, + variants: { + size: { + lambda: { height: "[340px]" }, + kernel: { height: "[400px]" }, + }, + isReadOnly: { + true: { + filter: "[grayscale(20%) brightness(98%)]", + pointerEvents: "none", + }, + false: { + filter: "none", + pointerEvents: "auto", + }, + }, + }, +}); + +const aiMenuItemStyle = css({ + display: "flex", + alignItems: "center", + gap: "[6px]", +}); + +const aiIconStyle = css({ + fontSize: "[16px]", +}); + +const sectionTitleStyle = css({ + fontWeight: 500, + fontSize: "[13px]", +}); + +const resultsHeaderStyle = css({ + display: "flex", + alignItems: "center", + justifyContent: "space-between", + marginBottom: "[4px]", + marginTop: "[20px]", + height: "[30px]", +}); + +const noOutputTypesBoxStyle = css({ + backgroundColor: "[rgba(0, 0, 0, 0.03)]", + border: "[1px solid rgba(0, 0, 0, 0.1)]", + borderRadius: "[4px]", + padding: "[12px]", + fontSize: "[12px]", + color: "[#666]", + lineHeight: "[1.5]", + marginTop: "[20px]", +}); + +const noOutputTitleStyle = css({ + fontWeight: 500, + marginBottom: "[4px]", +}); + +const spacerStyle = css({ + height: "[40px]", +}); + interface TransitionPropertiesProps { transition: Transition; places: Place[]; @@ -143,17 +340,10 @@ export const TransitionProperties: React.FC = ({ const { removeTransition } = useSDCPNContext(); return ( -
    +
    -
    -
    Transition
    +
    +
    Transition
    @@ -192,9 +366,7 @@ export const TransitionProperties: React.FC = ({
    -
    - Name -
    +
    Name
    = ({ }); }} disabled={isReadOnly} - style={{ - fontSize: 14, - padding: "6px 8px", - border: "1px solid rgba(0, 0, 0, 0.1)", - borderRadius: 4, - width: "100%", - boxSizing: "border-box", - backgroundColor: isReadOnly ? "rgba(0, 0, 0, 0.05)" : "white", - cursor: isReadOnly ? "not-allowed" : "text", - }} + className={inputStyle({ isReadOnly })} />
    -
    -
    - Input Arcs -
    +
    +
    Input Arcs
    {transition.inputArcs.length === 0 ? ( -
    +
    Connect inputs to the transition's left side.
    ) : ( -
    +
    = ({
    -
    - Output Arcs -
    +
    Output Arcs
    {transition.outputArcs.length === 0 ? ( -
    +
    Connect outputs to the transition's right side.
    ) : ( -
    +
    = ({ )}
    -
    -
    +
    +
    Firing time
    -
    +
    = ({
    -
    +
    {transition.lambdaType === "predicate" ? "For a simple predicate firing check, define a boolean guard condition that must be satisfied. The transition will fire when the function returns true, enabling discrete control flow." : "For a stochastic firing rate, return a value that represents the average rate per second at which the transition will fire."} @@ -373,21 +506,8 @@ export const TransitionProperties: React.FC = ({
    -
    -
    +
    +
    {transition.lambdaType === "predicate" ? "Predicate Firing Code" : "Stochastic Firing Rate Code"} @@ -395,19 +515,7 @@ export const TransitionProperties: React.FC = ({ {globalMode === "edit" && ( + } @@ -427,14 +535,8 @@ export const TransitionProperties: React.FC = ({ id: "generate-ai", label: ( -
    - +
    + Generate with AI
    @@ -448,16 +550,7 @@ export const TransitionProperties: React.FC = ({ /> )}
    -
    +
    `${a.placeId}:${a.weight}`) @@ -491,36 +584,15 @@ export const TransitionProperties: React.FC = ({ {/* Only show Transition Results if at least one output place has a type */} {hasOutputPlaceWithType ? (
    -
    -
    +
    +
    Transition Results
    {globalMode === "edit" && ( + } @@ -576,14 +648,8 @@ export const TransitionProperties: React.FC = ({ id: "generate-ai", label: ( -
    - +
    + Generate with AI
    @@ -597,16 +663,7 @@ export const TransitionProperties: React.FC = ({ /> )}
    -
    +
    `${a.placeId}:${a.weight}`) @@ -639,21 +696,8 @@ export const TransitionProperties: React.FC = ({
    ) : ( -
    -
    - Transition Results -
    +
    +
    Transition Results
    The Transition Results section is not available because none of the output places have a type defined. To enable this feature, assign a @@ -662,7 +706,7 @@ export const TransitionProperties: React.FC = ({
    )} -
    +
    ); }; diff --git a/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/type-properties.tsx b/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/type-properties.tsx index 48cd563ebf1..998b02a5b61 100644 --- a/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/type-properties.tsx +++ b/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/type-properties.tsx @@ -1,4 +1,4 @@ -import { css } from "@hashintel/ds-helpers/css"; +import { css, cva } from "@hashintel/ds-helpers/css"; import { useState } from "react"; import { v4 as uuidv4 } from "uuid"; @@ -6,6 +6,228 @@ import type { Color } from "../../../../core/types/sdcpn"; import { useSimulationStore } from "../../../../state/simulation-provider"; import { ColorSelect } from "./color-select"; +const containerStyle = css({ + display: "flex", + flexDirection: "column", + gap: "[12px]", +}); + +const headerTitleStyle = css({ + fontWeight: 600, + fontSize: "[16px]", + marginBottom: "[8px]", +}); + +const fieldLabelStyle = css({ + fontWeight: 500, + fontSize: "[12px]", + marginBottom: "[4px]", +}); + +const inputStyle = cva({ + base: { + fontSize: "[14px]", + padding: "[6px 8px]", + border: "[1px solid rgba(0, 0, 0, 0.1)]", + borderRadius: "[4px]", + width: "[100%]", + boxSizing: "border-box", + }, + variants: { + isDisabled: { + true: { + backgroundColor: "[rgba(0, 0, 0, 0.05)]", + cursor: "not-allowed", + }, + false: { + backgroundColor: "[white]", + cursor: "text", + }, + }, + }, +}); + +const dimensionsHeaderStyle = css({ + display: "flex", + alignItems: "center", + justifyContent: "space-between", + marginBottom: "[8px]", +}); + +const dimensionsLabelStyle = css({ + fontWeight: 500, + fontSize: "[12px]", +}); + +const dimensionsHintStyle = css({ + marginLeft: "[6px]", + fontSize: "[11px]", + color: "[#666]", + fontWeight: 400, +}); + +const addDimensionButtonStyle = cva({ + base: { + fontSize: "[16px]", + padding: "[2px 8px]", + borderRadius: "[4px]", + border: "[1px solid rgba(0, 0, 0, 0.1)]", + fontWeight: 600, + cursor: "pointer", + }, + variants: { + isDisabled: { + true: { + backgroundColor: "[rgba(0, 0, 0, 0.05)]", + color: "[#999]", + cursor: "not-allowed", + }, + false: { + backgroundColor: "[rgba(59, 130, 246, 0.1)]", + color: "[#3b82f6]", + cursor: "pointer", + }, + }, + }, +}); + +const emptyDimensionsStyle = css({ + fontSize: "[12px]", + color: "[#999]", + fontStyle: "italic", + padding: "[8px]", + backgroundColor: "[rgba(0, 0, 0, 0.02)]", + borderRadius: "[4px]", + textAlign: "center", +}); + +const dimensionsListStyle = css({ + display: "flex", + flexDirection: "column", + gap: "[6px]", +}); + +const dimensionRowStyle = cva({ + base: { + display: "flex", + alignItems: "center", + gap: "[6px]", + padding: "[6px]", + borderRadius: "[3px]", + transition: "[all 0.15s ease]", + }, + variants: { + isDragged: { + true: { + backgroundColor: "[rgba(59, 130, 246, 0.1)]", + border: "[1px solid rgba(0, 0, 0, 0.1)]", + }, + false: { + backgroundColor: "[rgba(0, 0, 0, 0.03)]", + border: "[1px solid rgba(0, 0, 0, 0.1)]", + }, + }, + isDragOver: { + true: { + backgroundColor: "[rgba(59, 130, 246, 0.05)]", + border: "[1px dashed #3b82f6]", + }, + false: {}, + }, + }, +}); + +const dragHandleStyle = cva({ + base: { + display: "flex", + flexDirection: "column", + gap: "[1.5px]", + opacity: "[0.4]", + flexShrink: 0, + }, + variants: { + isDisabled: { + true: { + cursor: "default", + }, + false: { + cursor: "grab", + }, + }, + }, +}); + +const dragHandleLineStyle = css({ + width: "[10px]", + height: "[1.5px]", + backgroundColor: "[#666]", + borderRadius: "[1px]", +}); + +const indexChipStyle = css({ + fontSize: "[11px]", + fontWeight: 600, + color: "[#666]", + backgroundColor: "[rgba(0, 0, 0, 0.08)]", + borderRadius: "[3px]", + width: "[24px]", + height: "[24px]", + display: "flex", + alignItems: "center", + justifyContent: "center", + flexShrink: 0, +}); + +const dimensionNameInputStyle = cva({ + base: { + fontSize: "[13px]", + padding: "[5px 8px]", + border: "[1px solid rgba(0, 0, 0, 0.15)]", + borderRadius: "[3px]", + flex: 1, + }, + variants: { + isDisabled: { + true: { + backgroundColor: "[rgba(0, 0, 0, 0.02)]", + cursor: "not-allowed", + }, + false: { + backgroundColor: "[white]", + cursor: "text", + }, + }, + }, +}); + +const deleteDimensionButtonStyle = css({ + fontSize: "[16px]", + width: "[28px]", + height: "[28px]", + borderRadius: "[3px]", + border: "[1px solid rgba(239, 68, 68, 0.2)]", + backgroundColor: "[rgba(239, 68, 68, 0.08)]", + color: "[#ef4444]", + cursor: "pointer", + fontWeight: 600, + lineHeight: "[1]", + transition: "[all 0.15s ease]", + flexShrink: 0, + display: "flex", + alignItems: "center", + justifyContent: "center", + _hover: { + backgroundColor: "[rgba(239, 68, 68, 0.15)]", + }, + _disabled: { + backgroundColor: "[rgba(0, 0, 0, 0.02)]", + color: "[#ccc]", + cursor: "not-allowed", + }, +}); + +// --- Helpers --- + /** * Slugify a string to make it a valid JavaScript identifier * - Converts to lowercase @@ -180,285 +402,130 @@ export const TypeProperties: React.FC = ({ }; return ( - <> - -
    -
    -
    - Type -
    -
    +
    +
    +
    Type
    +
    -
    -
    - Name -
    - { - updateType(type.id, (existingType) => { - existingType.name = event.target.value; - }); - }} - disabled={isDisabled} - style={{ - fontSize: 14, - padding: "6px 8px", - border: "1px solid rgba(0, 0, 0, 0.1)", - borderRadius: 4, - width: "100%", - boxSizing: "border-box", - backgroundColor: isDisabled ? "rgba(0, 0, 0, 0.05)" : "white", - cursor: isDisabled ? "not-allowed" : "text", - }} - /> -
    +
    +
    Name
    + { + updateType(type.id, (existingType) => { + existingType.name = event.target.value; + }); + }} + disabled={isDisabled} + className={inputStyle({ isDisabled })} + /> +
    -
    -
    - Color +
    +
    Color
    + { + updateType(type.id, (existingType) => { + existingType.displayColor = color; + }); + }} + disabled={isDisabled} + /> +
    + + {/* Dimensions Section - Editable with drag-to-reorder */} +
    +
    +
    + Dimensions + (order matters)
    - { - updateType(type.id, (existingType) => { - existingType.displayColor = color; - }); - }} +
    - {/* Dimensions Section - Editable with drag-to-reorder */} -
    -
    -
    - Dimensions - + No dimensions defined. Click + to add. +
    + ) : ( +
    + {type.elements.map((element, index) => ( +
    { + handleDragStart(index); }} + onDragOver={(event) => { + handleDragOver(event, index); + }} + onDrop={(event) => { + handleDrop(event, index); + }} + onDragEnd={handleDragEnd} + className={dimensionRowStyle({ + isDragged: draggedIndex === index, + isDragOver: dragOverIndex === index && draggedIndex !== index, + })} > - (order matters) - -
    - -
    + {/* Drag handle */} +
    +
    +
    +
    +
    - {type.elements.length === 0 ? ( -
    - No dimensions defined. Click + to add. -
    - ) : ( -
    - {type.elements.map((element, index) => ( -
    { - handleDragStart(index); - }} - onDragOver={(event) => { - handleDragOver(event, index); + {/* Index chip */} +
    {index}
    + + {/* Name input */} + { + handleUpdateElementName( + element.elementId, + event.target.value, + ); }} - onDrop={(event) => { - handleDrop(event, index); + onBlur={(event) => { + handleBlurElementName( + element.elementId, + event.target.value, + ); }} - onDragEnd={handleDragEnd} - style={{ - display: "flex", - alignItems: "center", - gap: 6, - padding: 6, - backgroundColor: - draggedIndex === index - ? "rgba(59, 130, 246, 0.1)" - : dragOverIndex === index - ? "rgba(59, 130, 246, 0.05)" - : "rgba(0, 0, 0, 0.03)", - borderRadius: 3, - border: - dragOverIndex === index - ? "1px dashed #3b82f6" - : "1px solid rgba(0, 0, 0, 0.1)", - transition: "all 0.15s ease", + disabled={isDisabled} + placeholder="dimension_name" + className={dimensionNameInputStyle({ isDisabled })} + /> + + {/* Delete button */} + -
    - ))} -
    - )} -
    + × + +
    + ))} +
    + )}
    - +
    ); }; diff --git a/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/visualizer-error-boundary.tsx b/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/visualizer-error-boundary.tsx index 7702dd431c2..e535d9b5042 100644 --- a/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/visualizer-error-boundary.tsx +++ b/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/visualizer-error-boundary.tsx @@ -1,5 +1,37 @@ +import { css } from "@hashintel/ds-helpers/css"; import { Component, type ErrorInfo, type ReactNode } from "react"; +const errorContainerStyle = css({ + padding: "[16px]", + backgroundColor: "[#ffebee]", + color: "[#c62828]", + borderRadius: "[4px]", + fontSize: "[12px]", + fontFamily: "[monospace]", + maxHeight: "[400px]", + overflow: "auto", +}); + +const errorTitleStyle = css({ + fontWeight: 600, + fontSize: "[14px]", + marginBottom: "[8px]", +}); + +const errorSectionStyle = css({ + marginBottom: "[8px]", +}); + +const stackPreStyle = css({ + margin: "[4px 0 0 0]", + padding: "[8px]", + backgroundColor: "[#ffcdd2]", + borderRadius: "[2px]", + fontSize: "[11px]", + whiteSpace: "pre-wrap", + wordBreak: "break-word", +}); + interface Props { children: ReactNode; } @@ -32,58 +64,21 @@ export class VisualizerErrorBoundary extends Component { if (hasError) { return ( -
    -
    - Visualizer Runtime Error -
    -
    +
    +
    Visualizer Runtime Error
    +
    Error: {error?.message}
    {error?.stack && ( -
    +
    Stack: -
    -                {error.stack}
    -              
    +
    {error.stack}
    )} {errorInfo?.componentStack && (
    Component Stack: -
    -                {errorInfo.componentStack}
    -              
    +
    {errorInfo.componentStack}
    )}
    diff --git a/libs/@hashintel/petrinaut/src/views/Editor/editor-view.tsx b/libs/@hashintel/petrinaut/src/views/Editor/editor-view.tsx index 440fc0b209c..da7f5dcbc8e 100644 --- a/libs/@hashintel/petrinaut/src/views/Editor/editor-view.tsx +++ b/libs/@hashintel/petrinaut/src/views/Editor/editor-view.tsx @@ -1,3 +1,5 @@ +import { css } from "@hashintel/ds-helpers/css"; + import { Box } from "../../components/box"; import { Stack } from "../../components/stack"; import { productionMachines } from "../../examples/broken-machines"; @@ -17,6 +19,31 @@ import { PropertiesPanel } from "./components/PropertiesPanel/properties-panel"; import { exportSDCPN } from "./lib/export-sdcpn"; import { importSDCPN } from "./lib/import-sdcpn"; +const fullHeightStyle = css({ + height: "[100%]", +}); + +const rowContainerStyle = css({ + height: "[100%]", + userSelect: "none", +}); + +const canvasContainerStyle = css({ + width: "[100%]", + position: "relative", + flexGrow: 1, +}); + +const modeSelectorPositionStyle = css({ + position: "absolute", + top: "[24px]", + left: "[50%]", + transform: "translateX(-50%)", + zIndex: 1000, +}); + +// --- Component --- + /** * EditorView is responsible for the overall editor UI layout and controls. * It relies on sdcpn-store and editor-store for state, and uses SDCPNView for visualization. @@ -95,25 +122,11 @@ export const EditorView = ({ } return ( - - - + + + {/* Floating Mode Selector - Top Center */} -
    +
    diff --git a/libs/@hashintel/petrinaut/src/views/SDCPN/components/arc.tsx b/libs/@hashintel/petrinaut/src/views/SDCPN/components/arc.tsx index 57e3fdc662d..6da29152b0f 100644 --- a/libs/@hashintel/petrinaut/src/views/SDCPN/components/arc.tsx +++ b/libs/@hashintel/petrinaut/src/views/SDCPN/components/arc.tsx @@ -1,7 +1,28 @@ +import { css } from "@hashintel/ds-helpers/css"; +import type { CSSProperties } from "react"; import { BaseEdge, type EdgeProps, getBezierPath } from "reactflow"; import { useEditorStore } from "../../../state/editor-provider"; +const selectionIndicatorStyle: CSSProperties = { + stroke: "rgba(249, 115, 22, 0.4)", + strokeWidth: 8, +}; + +const symbolTextStyle = css({ + fontSize: "[13px]", + fontWeight: "[400]", + fill: "[#999]", + pointerEvents: "none", +}); + +const weightTextStyle = css({ + fontSize: "[14px]", + fontWeight: "[600]", + fill: "[#333]", + pointerEvents: "none", +}); + interface ArcData { tokenWeights: { [tokenTypeId: string]: number; @@ -42,10 +63,7 @@ export const Arc: React.FC> = ({ )} @@ -78,12 +96,7 @@ export const Arc: React.FC> = ({ y="0" textAnchor="middle" dominantBaseline="middle" - style={{ - fontSize: 13, - fontWeight: 400, - fill: "#999", - pointerEvents: "none", - }} + className={symbolTextStyle} > × @@ -93,12 +106,7 @@ export const Arc: React.FC> = ({ y="0" textAnchor="middle" dominantBaseline="middle" - style={{ - fontSize: 14, - fontWeight: 600, - fill: "#333", - pointerEvents: "none", - }} + className={weightTextStyle} > {weight} diff --git a/libs/@hashintel/petrinaut/src/views/SDCPN/components/transition-node.tsx b/libs/@hashintel/petrinaut/src/views/SDCPN/components/transition-node.tsx index 0d8b73d04eb..3425112ae20 100644 --- a/libs/@hashintel/petrinaut/src/views/SDCPN/components/transition-node.tsx +++ b/libs/@hashintel/petrinaut/src/views/SDCPN/components/transition-node.tsx @@ -1,4 +1,4 @@ -import { css } from "@hashintel/ds-helpers/css"; +import { css, cva } from "@hashintel/ds-helpers/css"; import { TbBolt, TbLambda } from "react-icons/tb"; import { Handle, type NodeProps, Position } from "reactflow"; @@ -7,6 +7,82 @@ import { useSimulationStore } from "../../../state/simulation-provider"; import type { TransitionNodeData } from "../../../state/types-for-editor-to-remove"; import { handleStyling } from "../styles/styling"; +const containerStyle = css({ + position: "relative", + background: "[transparent]", +}); + +const transitionBoxStyle = cva({ + base: { + padding: "spacing.4", + borderRadius: "radius.8", + width: "[160px]", + height: "[80px]", + display: "flex", + flexDirection: "column", + justifyContent: "center", + alignItems: "center", + background: "core.gray.20", + border: "2px solid", + borderColor: "core.gray.50", + fontSize: "[15px]", + boxSizing: "border-box", + position: "relative", + cursor: "default", + transition: "[all 0.2s ease]", + _hover: { + borderColor: "core.gray.70", + boxShadow: "0 0 0 4px rgba(59, 130, 246, 0.1)", + }, + }, + variants: { + selection: { + resource: { + boxShadow: + "0 0 0 3px rgba(59, 178, 246, 0.4), 0 0 0 5px rgba(59, 190, 246, 0.2)", + }, + reactflow: { + boxShadow: + "0 0 0 4px rgba(249, 115, 22, 0.4), 0 0 0 6px rgba(249, 115, 22, 0.2)", + }, + none: {}, + }, + }, + defaultVariants: { + selection: "none", + }, +}); + +const stochasticIconStyle = css({ + position: "absolute", + top: "[8px]", + left: "[0px]", + width: "[100%]", + display: "flex", + alignItems: "center", + justifyContent: "center", + color: "core.blue.60", + fontSize: "[18px]", +}); + +const contentWrapperStyle = css({ + display: "flex", + flexDirection: "column", + alignItems: "center", + gap: "spacing.2", +}); + +const labelStyle = css({ + textAlign: "center", +}); + +const firingIndicatorStyle = css({ + fontSize: "[16px]", + color: "core.yellow.60", + display: "flex", + alignItems: "center", +}); + export const TransitionNode: React.FC> = ({ id, data, @@ -35,95 +111,30 @@ export const TransitionNode: React.FC> = ({ // Determine selection state const isSelectedByResource = selectedResourceId === id; + const selectionVariant = isSelectedByResource + ? "resource" + : selected + ? "reactflow" + : "none"; return ( -
    +
    -
    +
    {data.lambdaType === "stochastic" && ( -
    +
    )} -
    -
    - {label} -
    +
    +
    {label}
    {justFired && ( -
    +
    )} diff --git a/libs/@hashintel/petrinaut/src/views/SDCPN/sdcpn-view.tsx b/libs/@hashintel/petrinaut/src/views/SDCPN/sdcpn-view.tsx index 814f058c47b..7e40301fb16 100644 --- a/libs/@hashintel/petrinaut/src/views/SDCPN/sdcpn-view.tsx +++ b/libs/@hashintel/petrinaut/src/views/SDCPN/sdcpn-view.tsx @@ -32,6 +32,15 @@ const REACTFLOW_EDGE_TYPES = { default: Arc, }; +const canvasContainerStyle = css({ + width: "[100%]", + height: "[100%]", + position: "relative", + "& .react-flow__pane": { + cursor: `var(--pane-cursor) !important`, + }, +}); + /** * SDCPNView is responsible for rendering the SDCPN using ReactFlow. * It reads from sdcpn-store and editor-store, and handles all ReactFlow interactions. @@ -295,18 +304,11 @@ export const SDCPNView: React.FC = () => { // eslint-disable-next-line jsx-a11y/no-static-element-interactions
    { // Quick-and-dirty way to delete selected items with keyboard // with two different keys (Delete and Backspace), not possible with ReactFlow `deleteKeyCode` prop From 453d163f0a77d0f625ff475d839783b1ff64b430 Mon Sep 17 00:00:00 2001 From: Chris Feijoo Date: Sat, 20 Dec 2025 04:07:09 +0100 Subject: [PATCH 2/3] Remove LLM comments --- .../src/components/segment-group.tsx | 2 -- .../petrinaut/src/components/tooltip.tsx | 2 -- .../differential-equations-section.tsx | 8 ++--- .../components/LeftSideBar/floating-title.tsx | 2 -- .../components/LeftSideBar/hamburger-menu.tsx | 2 -- .../components/LeftSideBar/nodes-section.tsx | 6 ++-- .../PropertiesPanel/initial-state-editor.tsx | 32 +++++++++---------- .../src/views/Editor/editor-view.tsx | 4 +-- 8 files changed, 21 insertions(+), 37 deletions(-) diff --git a/libs/@hashintel/petrinaut/src/components/segment-group.tsx b/libs/@hashintel/petrinaut/src/components/segment-group.tsx index 6ecbfcb1824..451da7efc20 100644 --- a/libs/@hashintel/petrinaut/src/components/segment-group.tsx +++ b/libs/@hashintel/petrinaut/src/components/segment-group.tsx @@ -42,8 +42,6 @@ const itemStyle = cva({ }, }); -// --- Component --- - interface SegmentOption { value: string; label: string; diff --git a/libs/@hashintel/petrinaut/src/components/tooltip.tsx b/libs/@hashintel/petrinaut/src/components/tooltip.tsx index 363185d6171..05e22ac9e0b 100644 --- a/libs/@hashintel/petrinaut/src/components/tooltip.tsx +++ b/libs/@hashintel/petrinaut/src/components/tooltip.tsx @@ -14,8 +14,6 @@ const tooltipContentStyle = css({ padding: "[6px 10px]", }); -// --- Components --- - interface TooltipProps { content: string; children: ReactNode; diff --git a/libs/@hashintel/petrinaut/src/views/Editor/components/LeftSideBar/differential-equations-section.tsx b/libs/@hashintel/petrinaut/src/views/Editor/components/LeftSideBar/differential-equations-section.tsx index 16ca90b231c..a42e2b93fc4 100644 --- a/libs/@hashintel/petrinaut/src/views/Editor/components/LeftSideBar/differential-equations-section.tsx +++ b/libs/@hashintel/petrinaut/src/views/Editor/components/LeftSideBar/differential-equations-section.tsx @@ -141,8 +141,6 @@ const emptyMessageStyle = css({ textAlign: "center", }); -// --- Component --- - export const DifferentialEquationsSection: React.FC = () => { const [isExpanded, setIsExpanded] = useState(true); @@ -153,10 +151,10 @@ export const DifferentialEquationsSection: React.FC = () => { } = useSDCPNContext(); const selectedResourceId = useEditorStore( - (state) => state.selectedResourceId, + (state) => state.selectedResourceId ); const setSelectedResourceId = useEditorStore( - (state) => state.setSelectedResourceId, + (state) => state.setSelectedResourceId ); // Check if simulation is running or paused @@ -241,7 +239,7 @@ export const DifferentialEquationsSection: React.FC = () => { if ( // eslint-disable-next-line no-alert window.confirm( - `Delete equation "${eq.name}"? Any places referencing this equation will have their differential equation reset.`, + `Delete equation "${eq.name}"? Any places referencing this equation will have their differential equation reset.` ) ) { removeDifferentialEquation(eq.id); diff --git a/libs/@hashintel/petrinaut/src/views/Editor/components/LeftSideBar/floating-title.tsx b/libs/@hashintel/petrinaut/src/views/Editor/components/LeftSideBar/floating-title.tsx index c76f71724ef..deaf404e0e2 100644 --- a/libs/@hashintel/petrinaut/src/views/Editor/components/LeftSideBar/floating-title.tsx +++ b/libs/@hashintel/petrinaut/src/views/Editor/components/LeftSideBar/floating-title.tsx @@ -17,8 +17,6 @@ const floatingTitleInputStyle = css({ }, }); -// --- Component --- - export interface FloatingTitleProps { value: string; onChange: (value: string) => void; diff --git a/libs/@hashintel/petrinaut/src/views/Editor/components/LeftSideBar/hamburger-menu.tsx b/libs/@hashintel/petrinaut/src/views/Editor/components/LeftSideBar/hamburger-menu.tsx index 85d469f1703..ea96f1ca435 100644 --- a/libs/@hashintel/petrinaut/src/views/Editor/components/LeftSideBar/hamburger-menu.tsx +++ b/libs/@hashintel/petrinaut/src/views/Editor/components/LeftSideBar/hamburger-menu.tsx @@ -14,8 +14,6 @@ const menuButtonStyle = css({ }, }); -// --- Component --- - export interface HamburgerMenuProps { menuItems: MenuItem[]; } diff --git a/libs/@hashintel/petrinaut/src/views/Editor/components/LeftSideBar/nodes-section.tsx b/libs/@hashintel/petrinaut/src/views/Editor/components/LeftSideBar/nodes-section.tsx index 5e12d1de0fc..de237b2eda5 100644 --- a/libs/@hashintel/petrinaut/src/views/Editor/components/LeftSideBar/nodes-section.tsx +++ b/libs/@hashintel/petrinaut/src/views/Editor/components/LeftSideBar/nodes-section.tsx @@ -116,18 +116,16 @@ const emptyMessageStyle = css({ textAlign: "center", }); -// --- Component --- - export const NodesSection: React.FC = () => { const [isExpanded, setIsExpanded] = useState(true); const { petriNetDefinition: { places, transitions }, } = useSDCPNContext(); const selectedResourceId = useEditorStore( - (state) => state.selectedResourceId, + (state) => state.selectedResourceId ); const setSelectedResourceId = useEditorStore( - (state) => state.setSelectedResourceId, + (state) => state.setSelectedResourceId ); const handleLayerClick = (id: string) => { diff --git a/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/initial-state-editor.tsx b/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/initial-state-editor.tsx index a3a02ed7159..31157388bc2 100644 --- a/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/initial-state-editor.tsx +++ b/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/initial-state-editor.tsx @@ -234,8 +234,6 @@ const useResizable = (initialHeight: number) => { }; }; -// --- Component --- - /** * InitialStateEditor - A component for editing initial tokens in a place * Stores data in SimulationStore, not in the Place definition @@ -252,16 +250,16 @@ export const InitialStateEditor: React.FC = ({ const { height, isResizing, containerRef, startResize } = useResizable(250); const isSimulationNotRun = useSimulationStore( - (state) => state.state === "NotRun", + (state) => state.state === "NotRun" ); const initialMarking = useSimulationStore((state) => state.initialMarking); const setInitialMarking = useSimulationStore( - (state) => state.setInitialMarking, + (state) => state.setInitialMarking ); const simulation = useSimulationStore((state) => state.simulation); const currentlyViewedFrame = useSimulationStore( - (state) => state.currentlyViewedFrame, + (state) => state.currentlyViewedFrame ); // Determine if we should show current simulation state or initial marking @@ -307,7 +305,7 @@ export const InitialStateEditor: React.FC = ({ const tokenValues: number[] = []; for (let colIndex = 0; colIndex < dimensions; colIndex++) { tokenValues.push( - currentMarking.values[i * dimensions + colIndex] ?? 0, + currentMarking.values[i * dimensions + colIndex] ?? 0 ); } tokens.push(tokenValues); @@ -340,7 +338,7 @@ export const InitialStateEditor: React.FC = ({ const tokenValues: number[] = []; for (let colIndex = 0; colIndex < dimensions; colIndex++) { tokenValues.push( - currentMarking.values[i * dimensions + colIndex] ?? 0, + currentMarking.values[i * dimensions + colIndex] ?? 0 ); } tokens.push(tokenValues); @@ -383,7 +381,7 @@ export const InitialStateEditor: React.FC = ({ } } else { newData = prev.map((rowData, index) => - index === row ? [...rowData] : rowData, + index === row ? [...rowData] : rowData ); if (newData[row]) { newData[row][col] = value; @@ -408,7 +406,7 @@ export const InitialStateEditor: React.FC = ({ // Focus the row number cell after state update setTimeout(() => { const rowCell = document.querySelector( - `td[data-row="${newData.length - 1}"]`, + `td[data-row="${newData.length - 1}"]` ); if (rowCell instanceof HTMLElement) { rowCell.focus(); @@ -420,7 +418,7 @@ export const InitialStateEditor: React.FC = ({ // Focus the row number cell after state update setTimeout(() => { const rowCell = document.querySelector( - `td[data-row="${rowIndex}"]`, + `td[data-row="${rowIndex}"]` ); if (rowCell instanceof HTMLElement) { rowCell.focus(); @@ -446,7 +444,7 @@ export const InitialStateEditor: React.FC = ({ const handleKeyDown = ( event: React.KeyboardEvent, row: number, - col: number, + col: number ) => { if (hasSimulation) { return; @@ -516,7 +514,7 @@ export const InitialStateEditor: React.FC = ({ }); setTimeout(() => { const prevCell = cellRefs.current.get( - `${row - 1}-${placeType.elements.length - 1}`, + `${row - 1}-${placeType.elements.length - 1}` ); prevCell?.focus(); }, 0); @@ -609,7 +607,7 @@ export const InitialStateEditor: React.FC = ({ setFocusedCell({ row: row - 1, col: placeType.elements.length - 1 }); setTimeout(() => { const prevCell = cellRefs.current.get( - `${row - 1}-${placeType.elements.length - 1}`, + `${row - 1}-${placeType.elements.length - 1}` ); prevCell?.focus(); }, 0); @@ -720,7 +718,7 @@ export const InitialStateEditor: React.FC = ({ setEditingCell(null); // Focus the next row number cell const nextRowCell = document.querySelector( - `td[data-row="${rowIndex + 1}"]`, + `td[data-row="${rowIndex + 1}"]` ); if (nextRowCell instanceof HTMLElement) { nextRowCell.focus(); @@ -733,7 +731,7 @@ export const InitialStateEditor: React.FC = ({ setEditingCell(null); // Focus the previous row number cell const prevRowCell = document.querySelector( - `td[data-row="${rowIndex - 1}"]`, + `td[data-row="${rowIndex - 1}"]` ); if (prevRowCell instanceof HTMLElement) { prevRowCell.focus(); @@ -860,11 +858,11 @@ export const InitialStateEditor: React.FC = ({ if (el) { cellRefs.current.set( `${rowIndex}-${colIndex}`, - el, + el ); } else { cellRefs.current.delete( - `${rowIndex}-${colIndex}`, + `${rowIndex}-${colIndex}` ); } }} diff --git a/libs/@hashintel/petrinaut/src/views/Editor/editor-view.tsx b/libs/@hashintel/petrinaut/src/views/Editor/editor-view.tsx index da7f5dcbc8e..fdf98b67124 100644 --- a/libs/@hashintel/petrinaut/src/views/Editor/editor-view.tsx +++ b/libs/@hashintel/petrinaut/src/views/Editor/editor-view.tsx @@ -42,8 +42,6 @@ const modeSelectorPositionStyle = css({ zIndex: 1000, }); -// --- Component --- - /** * EditorView is responsible for the overall editor UI layout and controls. * It relies on sdcpn-store and editor-store for state, and uses SDCPNView for visualization. @@ -73,7 +71,7 @@ export const EditorView = ({ // Get simulation store method to initialize parameter values const initializeParameterValuesFromDefaults = useSimulationStore( - (state) => state.initializeParameterValuesFromDefaults, + (state) => state.initializeParameterValuesFromDefaults ); // Handler for mode change that initializes parameter values when switching to simulate mode From 5e052995fbbd8f2a103ef94f9bb8969e4f1152be Mon Sep 17 00:00:00 2001 From: Chris Feijoo Date: Sat, 20 Dec 2025 04:07:35 +0100 Subject: [PATCH 3/3] Fix format --- .../differential-equations-section.tsx | 6 ++-- .../components/LeftSideBar/nodes-section.tsx | 4 +-- .../differential-equation-properties.tsx | 18 +++++------ .../PropertiesPanel/initial-state-editor.tsx | 30 +++++++++---------- .../src/views/Editor/editor-view.tsx | 2 +- 5 files changed, 30 insertions(+), 30 deletions(-) diff --git a/libs/@hashintel/petrinaut/src/views/Editor/components/LeftSideBar/differential-equations-section.tsx b/libs/@hashintel/petrinaut/src/views/Editor/components/LeftSideBar/differential-equations-section.tsx index a42e2b93fc4..e9f2ba9f846 100644 --- a/libs/@hashintel/petrinaut/src/views/Editor/components/LeftSideBar/differential-equations-section.tsx +++ b/libs/@hashintel/petrinaut/src/views/Editor/components/LeftSideBar/differential-equations-section.tsx @@ -151,10 +151,10 @@ export const DifferentialEquationsSection: React.FC = () => { } = useSDCPNContext(); const selectedResourceId = useEditorStore( - (state) => state.selectedResourceId + (state) => state.selectedResourceId, ); const setSelectedResourceId = useEditorStore( - (state) => state.setSelectedResourceId + (state) => state.setSelectedResourceId, ); // Check if simulation is running or paused @@ -239,7 +239,7 @@ export const DifferentialEquationsSection: React.FC = () => { if ( // eslint-disable-next-line no-alert window.confirm( - `Delete equation "${eq.name}"? Any places referencing this equation will have their differential equation reset.` + `Delete equation "${eq.name}"? Any places referencing this equation will have their differential equation reset.`, ) ) { removeDifferentialEquation(eq.id); diff --git a/libs/@hashintel/petrinaut/src/views/Editor/components/LeftSideBar/nodes-section.tsx b/libs/@hashintel/petrinaut/src/views/Editor/components/LeftSideBar/nodes-section.tsx index de237b2eda5..57446169287 100644 --- a/libs/@hashintel/petrinaut/src/views/Editor/components/LeftSideBar/nodes-section.tsx +++ b/libs/@hashintel/petrinaut/src/views/Editor/components/LeftSideBar/nodes-section.tsx @@ -122,10 +122,10 @@ export const NodesSection: React.FC = () => { petriNetDefinition: { places, transitions }, } = useSDCPNContext(); const selectedResourceId = useEditorStore( - (state) => state.selectedResourceId + (state) => state.selectedResourceId, ); const setSelectedResourceId = useEditorStore( - (state) => state.setSelectedResourceId + (state) => state.setSelectedResourceId, ); const handleLayerClick = (id: string) => { diff --git a/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/differential-equation-properties.tsx b/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/differential-equation-properties.tsx index 5a8291a8f07..91b2700b072 100644 --- a/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/differential-equation-properties.tsx +++ b/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/differential-equation-properties.tsx @@ -261,7 +261,7 @@ interface DifferentialEquationPropertiesProps { globalMode: "edit" | "simulate"; updateDifferentialEquation: ( equationId: string, - updateFn: (equation: DifferentialEquation) => void + updateFn: (equation: DifferentialEquation) => void, ) => void; } @@ -284,7 +284,7 @@ export const DifferentialEquationProperties: React.FC< const isReadOnly = globalMode === "simulate" || isSimulationRunning; const associatedType = types.find( - (type) => type.id === differentialEquation.colorId + (type) => type.id === differentialEquation.colorId, ); // Find places that use this differential equation @@ -310,7 +310,7 @@ export const DifferentialEquationProperties: React.FC< differentialEquation.id, (existingEquation) => { existingEquation.colorId = newTypeId; - } + }, ); } }; @@ -321,7 +321,7 @@ export const DifferentialEquationProperties: React.FC< differentialEquation.id, (existingEquation) => { existingEquation.colorId = pendingTypeId; - } + }, ); } setShowConfirmDialog(false); @@ -349,7 +349,7 @@ export const DifferentialEquationProperties: React.FC< differentialEquation.id, (existingEquation) => { existingEquation.name = event.target.value; - } + }, ); }} disabled={isReadOnly} @@ -490,7 +490,7 @@ export const DifferentialEquationProperties: React.FC< onClick: () => { // Get the associated type to generate appropriate default code const equationType = types.find( - (t) => t.id === differentialEquation.colorId + (t) => t.id === differentialEquation.colorId, ); updateDifferentialEquation( @@ -498,10 +498,10 @@ export const DifferentialEquationProperties: React.FC< (existingEquation) => { existingEquation.code = equationType ? generateDefaultDifferentialEquationCode( - equationType + equationType, ) : DEFAULT_DIFFERENTIAL_EQUATION_CODE; - } + }, ); }, }, @@ -533,7 +533,7 @@ export const DifferentialEquationProperties: React.FC< differentialEquation.id, (existingEquation) => { existingEquation.code = newCode ?? ""; - } + }, ); }} path={`inmemory://sdcpn/differential-equations/${differentialEquation.id}.ts`} diff --git a/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/initial-state-editor.tsx b/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/initial-state-editor.tsx index 31157388bc2..e41aaaf899c 100644 --- a/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/initial-state-editor.tsx +++ b/libs/@hashintel/petrinaut/src/views/Editor/components/PropertiesPanel/initial-state-editor.tsx @@ -250,16 +250,16 @@ export const InitialStateEditor: React.FC = ({ const { height, isResizing, containerRef, startResize } = useResizable(250); const isSimulationNotRun = useSimulationStore( - (state) => state.state === "NotRun" + (state) => state.state === "NotRun", ); const initialMarking = useSimulationStore((state) => state.initialMarking); const setInitialMarking = useSimulationStore( - (state) => state.setInitialMarking + (state) => state.setInitialMarking, ); const simulation = useSimulationStore((state) => state.simulation); const currentlyViewedFrame = useSimulationStore( - (state) => state.currentlyViewedFrame + (state) => state.currentlyViewedFrame, ); // Determine if we should show current simulation state or initial marking @@ -305,7 +305,7 @@ export const InitialStateEditor: React.FC = ({ const tokenValues: number[] = []; for (let colIndex = 0; colIndex < dimensions; colIndex++) { tokenValues.push( - currentMarking.values[i * dimensions + colIndex] ?? 0 + currentMarking.values[i * dimensions + colIndex] ?? 0, ); } tokens.push(tokenValues); @@ -338,7 +338,7 @@ export const InitialStateEditor: React.FC = ({ const tokenValues: number[] = []; for (let colIndex = 0; colIndex < dimensions; colIndex++) { tokenValues.push( - currentMarking.values[i * dimensions + colIndex] ?? 0 + currentMarking.values[i * dimensions + colIndex] ?? 0, ); } tokens.push(tokenValues); @@ -381,7 +381,7 @@ export const InitialStateEditor: React.FC = ({ } } else { newData = prev.map((rowData, index) => - index === row ? [...rowData] : rowData + index === row ? [...rowData] : rowData, ); if (newData[row]) { newData[row][col] = value; @@ -406,7 +406,7 @@ export const InitialStateEditor: React.FC = ({ // Focus the row number cell after state update setTimeout(() => { const rowCell = document.querySelector( - `td[data-row="${newData.length - 1}"]` + `td[data-row="${newData.length - 1}"]`, ); if (rowCell instanceof HTMLElement) { rowCell.focus(); @@ -418,7 +418,7 @@ export const InitialStateEditor: React.FC = ({ // Focus the row number cell after state update setTimeout(() => { const rowCell = document.querySelector( - `td[data-row="${rowIndex}"]` + `td[data-row="${rowIndex}"]`, ); if (rowCell instanceof HTMLElement) { rowCell.focus(); @@ -444,7 +444,7 @@ export const InitialStateEditor: React.FC = ({ const handleKeyDown = ( event: React.KeyboardEvent, row: number, - col: number + col: number, ) => { if (hasSimulation) { return; @@ -514,7 +514,7 @@ export const InitialStateEditor: React.FC = ({ }); setTimeout(() => { const prevCell = cellRefs.current.get( - `${row - 1}-${placeType.elements.length - 1}` + `${row - 1}-${placeType.elements.length - 1}`, ); prevCell?.focus(); }, 0); @@ -607,7 +607,7 @@ export const InitialStateEditor: React.FC = ({ setFocusedCell({ row: row - 1, col: placeType.elements.length - 1 }); setTimeout(() => { const prevCell = cellRefs.current.get( - `${row - 1}-${placeType.elements.length - 1}` + `${row - 1}-${placeType.elements.length - 1}`, ); prevCell?.focus(); }, 0); @@ -718,7 +718,7 @@ export const InitialStateEditor: React.FC = ({ setEditingCell(null); // Focus the next row number cell const nextRowCell = document.querySelector( - `td[data-row="${rowIndex + 1}"]` + `td[data-row="${rowIndex + 1}"]`, ); if (nextRowCell instanceof HTMLElement) { nextRowCell.focus(); @@ -731,7 +731,7 @@ export const InitialStateEditor: React.FC = ({ setEditingCell(null); // Focus the previous row number cell const prevRowCell = document.querySelector( - `td[data-row="${rowIndex - 1}"]` + `td[data-row="${rowIndex - 1}"]`, ); if (prevRowCell instanceof HTMLElement) { prevRowCell.focus(); @@ -858,11 +858,11 @@ export const InitialStateEditor: React.FC = ({ if (el) { cellRefs.current.set( `${rowIndex}-${colIndex}`, - el + el, ); } else { cellRefs.current.delete( - `${rowIndex}-${colIndex}` + `${rowIndex}-${colIndex}`, ); } }} diff --git a/libs/@hashintel/petrinaut/src/views/Editor/editor-view.tsx b/libs/@hashintel/petrinaut/src/views/Editor/editor-view.tsx index fdf98b67124..4b4ba77e23c 100644 --- a/libs/@hashintel/petrinaut/src/views/Editor/editor-view.tsx +++ b/libs/@hashintel/petrinaut/src/views/Editor/editor-view.tsx @@ -71,7 +71,7 @@ export const EditorView = ({ // Get simulation store method to initialize parameter values const initializeParameterValuesFromDefaults = useSimulationStore( - (state) => state.initializeParameterValuesFromDefaults + (state) => state.initializeParameterValuesFromDefaults, ); // Handler for mode change that initializes parameter values when switching to simulate mode