Specialized components
World editor
Modal dialog management
26 min
overview the modal dialog management component is an essential element of the ir engine's world editor that handles focused user interactions through popup windows it provides a standardized system for requesting user input, confirming actions, and displaying important information while temporarily blocking interaction with the rest of the editor by implementing a centralized modal state service, this component ensures consistent behavior and appearance across all dialog interactions this chapter explores the implementation, workflow, and usage of modal dialogs within the world editor core concepts modal dialogs modal dialogs are popup windows that require user attention focus control temporarily blocks interaction with the rest of the editor user input collects specific information from the user decision points presents options for critical actions information display shows important messages or warnings workflow interruption ensures critical decisions are made consciously these dialogs create a clear interaction path for important user decisions centralized management the modal state service provides centralized dialog control single source of truth maintains the current state of modal dialogs standardized api offers consistent methods for opening and closing dialogs content flexibility accepts any component as dialog content global accessibility available to all parts of the editor state management tracks whether a dialog is currently active this centralized approach ensures consistent behavior across the editor dialog components dialog components define the content and behavior of modals self contained ui includes all necessary interface elements internal state manages its own data and validation action handlers contains logic for responding to user choices communication reports results back to the calling code styling consistency follows the editor's design patterns these components provide the actual content displayed within the modal framework implementation modal state service the modal state service manages dialog visibility and content // simplified from src/common/services/modalstate ts import { createstate, usestate } from '@hookstate/core'; import { reactnode } from 'react'; / state for modal dialogs / interface modalstatetype { // whether a modal is currently visible isopen boolean; // the content to display in the modal content reactnode | null; } // create the global state const modalstate = createstate\<modalstatetype>({ isopen false, content null }); / modal state service / export const modalstate = { / gets the current state @returns modal state hook / usestate () => usestate(modalstate), / checks if a modal is currently open @returns whether a modal is open / isopen () => modalstate value isopen, / gets the current modal content @returns modal content / getcontent () => modalstate value content, / opens a modal with the specified content @param content modal content / openmodal (content reactnode) => { modalstate set({ isopen true, content }); }, / closes the current modal / closemodal () => { modalstate set({ isopen false, content null }); } }; this service defines a state structure for tracking modal visibility and content creates a global state instance using a state management library provides methods for checking the current state implements functions for opening and closing modals makes the state accessible throughout the application dialog component example a typical dialog component implements its own ui and behavior // example dialog component src/components/dialogs/savescenedialog tsx import react, { usestate } from 'react'; import { button, input, dialog, dialogtitle, dialogcontent, dialogactions } from ' /ui/components'; import { modalstate } from ' / /common/services/modalstate'; / props for the save scene dialog / interface savescenedialogprops { // initial scene name initialname? string; // callback when save is confirmed onsave? (scenename string) => void; } / dialog for saving a scene @param props component props @returns dialog component / export function savescenedialog(props savescenedialogprops) { // local state for the scene name const \[scenename, setscenename] = usestate(props initialname || 'new scene'); // local state for validation const \[isvalid, setisvalid] = usestate(true); const \[errormessage, seterrormessage] = usestate(''); / validates the scene name @param name scene name to validate @returns whether the name is valid / const validatename = (name string) => { if (!name trim()) { setisvalid(false); seterrormessage('scene name cannot be empty'); return false; } if (name includes('/') || name includes('\\\\')) { setisvalid(false); seterrormessage('scene name cannot contain slashes'); return false; } setisvalid(true); seterrormessage(''); return true; }; / handles input changes @param e change event / const handlechange = (e react changeevent\<htmlinputelement>) => { const newname = e target value; setscenename(newname); validatename(newname); }; / handles save button click / const handlesave = () => { if (validatename(scenename)) { // call the onsave callback if provided if (props onsave) { props onsave(scenename); } // close the modal modalstate closemodal(); } }; / handles cancel button click / const handlecancel = () => { // just close the modal modalstate closemodal(); }; return ( \<dialog> \<dialogtitle>save scene\</dialogtitle> \<dialogcontent> \<div classname="form group"> \<label htmlfor="scene name">scene name \</label> \<input id="scene name" value={scenename} onchange={handlechange} error={!isvalid} autofocus /> {!isvalid && \<div classname="error message">{errormessage}\</div>} \</div> \</dialogcontent> \<dialogactions> \<button onclick={handlecancel} variant="secondary">cancel\</button> \<button onclick={handlesave} variant="primary" disabled={!isvalid}>save\</button> \</dialogactions> \</dialog> ); } this component manages its own internal state for the scene name and validation provides input validation with error messages handles user interactions like input changes and button clicks calls the provided callback when the save action is confirmed closes itself by calling modalstate closemodal() modal container the modal container renders the active dialog // simplified from src/components/modalcontainer tsx import react from 'react'; import { modalstate } from ' /common/services/modalstate'; / container for rendering modal dialogs @returns modal container component / export function modalcontainer() { // get the current modal state const modalstate = modalstate usestate(); // if no modal is open, render nothing if (!modalstate isopen value) { return null; } // get the content to render const content = modalstate content value; // render the modal overlay and content return ( \<div classname="modal overlay"> \<div classname="modal container"> {content} \</div> \</div> ); } this component subscribes to the modal state to detect changes renders nothing when no modal is active displays the modal content within a container when active provides the overlay that blocks interaction with the rest of the editor opening a dialog dialogs are opened by calling the modal state service // example of opening a dialog import { modalstate } from ' /common/services/modalstate'; import { savescenedialog } from ' /components/dialogs/savescenedialog'; / handles the "save as" action / function handlesaveas() { // define the save callback const onsave = (scenename string) => { console log(`saving scene as ${scenename}`); // actual save logic would go here savescene(scenename); }; // open the save dialog modalstate openmodal( \<savescenedialog initialname="my scene" onsave={onsave} /> ); } this code defines a callback function to handle the save action creates a savescenedialog component with props opens the modal with the dialog as content the dialog will be displayed until closed modal dialog workflow the complete modal dialog workflow follows this sequence sequencediagram participant editor as editor component participant modalstate as modal state service participant container as modal container participant dialog as dialog component participant user editor >>modalstate openmodal(dialogcomponent) modalstate >>modalstate set isopen=true, content=dialogcomponent modalstate >>container state updated container >>container render overlay and dialog container >>user dialog appears user >>dialog interacts (inputs data, clicks buttons) dialog >>dialog internal state updates, validation alt user confirms action user >>dialog clicks confirm button dialog >>editor call onconfirm callback dialog >>modalstate closemodal() else user cancels user >>dialog clicks cancel button dialog >>modalstate closemodal() end modalstate >>modalstate set isopen=false, content=null modalstate >>container state updated container >>user dialog disappears this diagram illustrates an editor component opens a modal with specific content the modal state service updates its internal state the modal container renders the dialog the user interacts with the dialog the dialog handles user input and validation the user confirms or cancels the action the dialog calls the appropriate callback and closes the modal state service updates its state the modal container removes the dialog from the screen common dialog types the world editor implements several types of modal dialogs confirmation dialogs dialogs that ask for confirmation before performing actions // example confirmation dialog import { modalstate } from ' /common/services/modalstate'; import { confirmationdialog } from ' /components/dialogs/confirmationdialog'; / asks for confirmation before deleting an object @param objectname name of the object to delete / function confirmdelete(objectname string) { const handleconfirm = () => { // perform the delete operation deleteobject(objectname); }; modalstate openmodal( \<confirmationdialog title="confirm delete" message={`are you sure you want to delete "${objectname}"? this action cannot be undone `} confirmlabel="delete" cancellabel="cancel" onconfirm={handleconfirm} danger={true} /> ); } these dialogs present a clear question to the user offer confirm and cancel options may highlight dangerous actions execute a callback when confirmed prevent accidental destructive actions input dialogs dialogs that collect specific information from the user // example input dialog import { modalstate } from ' /common/services/modalstate'; import { inputdialog } from ' /components/dialogs/inputdialog'; / prompts for a new folder name / function createnewfolder() { const handlecreate = (foldername string) => { // create the folder createfolder(foldername); }; modalstate openmodal( \<inputdialog title="create new folder" label="folder name " initialvalue="new folder" confirmlabel="create" cancellabel="cancel" onconfirm={handlecreate} validator={(value) => { if (!value trim()) return "folder name cannot be empty"; if (value includes('/')) return "folder name cannot contain slashes"; return null; // no error }} /> ); } these dialogs collect specific information from the user provide input validation display error messages for invalid input return the collected data via callback may have default values settings dialogs dialogs that present multiple configuration options // example settings dialog import { modalstate } from ' /common/services/modalstate'; import { importsettingsdialog } from ' /components/dialogs/importsettingsdialog'; / shows import settings for a model @param modelpath path to the model file / function showimportsettings(modelpath string) { const handleapply = (settings importsettings) => { // apply the import settings importmodel(modelpath, settings); }; modalstate openmodal( \<importsettingsdialog filepath={modelpath} initialsettings={getdefaultsettings(modelpath)} onapply={handleapply} /> ); } these dialogs present multiple configuration options may have sections or tabs for organization often include advanced settings apply settings when confirmed may have preset or default configurations integration with other components the modal dialog system integrates with several other components of the world editor editor ui framework modals are rendered within the editor ui framework // example of ui framework integration import react from 'react'; import { editorpanels } from ' /editorpanels'; import { toolbar } from ' /toolbar'; import { viewport } from ' /viewport'; import { statusbar } from ' /statusbar'; import { modalcontainer } from ' /modalcontainer'; / main editor layout @returns editor component / export function editor() { return ( \<div classname="editor layout"> \<toolbar /> \<div classname="editor main"> \<editorpanels /> \<viewport /> \</div> \<statusbar /> {/ modal container is rendered last to appear on top /} \<modalcontainer /> \</div> ); } this integration places the modal container at the top level of the ui ensures modals appear above all other ui elements maintains the modal's position during editor resizing provides a consistent appearance for all dialogs centralizes modal rendering logic editor global state modals interact with the editor's global state // example of global state integration import { modalstate } from ' /common/services/modalstate'; import { editorstate } from ' /common/services/editorstate'; import { savescenedialog } from ' /components/dialogs/savescenedialog'; / handles the save action / function handlesave() { const currentscene = editorstate getcurrentscene(); // if the scene has never been saved, show the save dialog if (!currentscene path) { modalstate openmodal( \<savescenedialog initialname={currentscene name} onsave={(name) => { // update the scene name in the global state editorstate savescene(name); }} /> ); } else { // scene already has a path, save directly editorstate savescene(); } } this integration accesses global state to determine dialog behavior updates global state based on dialog results coordinates between user input and application state ensures state consistency after modal interactions provides context for modal decisions editor systems modals are used by various editor systems // example of editor system integration import { modalstate } from ' /common/services/modalstate'; import { confirmationdialog } from ' /components/dialogs/confirmationdialog'; import { scenesystem } from ' /systems/scenesystem'; / handles the close scene action / function handleclosescene() { // check if there are unsaved changes if (scenesystem hasunsavedchanges()) { modalstate openmodal( \<confirmationdialog title="unsaved changes" message="the current scene has unsaved changes do you want to save before closing?" confirmlabel="save" cancellabel="don't save" alternatelabel="cancel" onconfirm={() => { // save and then close scenesystem savescene() then(() => { scenesystem closescene(); }); }} oncancel={() => { // close without saving scenesystem closescene(); }} // if alternate is clicked, do nothing (keep scene open) /> ); } else { // no unsaved changes, close directly scenesystem closescene(); } } this integration coordinates with editor systems to check conditions triggers system actions based on dialog results provides user control over system operations ensures proper sequence of operations prevents data loss through confirmation benefits of modal dialog management the modal dialog management component provides several key advantages focus control ensures important decisions receive dedicated attention consistency provides a uniform appearance and behavior for all dialogs reusability enables dialog components to be used across the editor separation of concerns isolates dialog ui from business logic centralized management simplifies dialog tracking and control user guidance creates clear decision points in complex workflows error prevention confirms potentially destructive actions before execution these benefits make modal dialog management an essential component for creating a robust and user friendly editor interface conclusion the modal dialog management component provides a standardized system for handling focused user interactions through popup windows by centralizing dialog control and providing a consistent framework for dialog components, it ensures that important decisions and user inputs are handled clearly and effectively throughout the editor this concludes our exploration of the ir engine's world editor we've covered the key components that make up this powerful editing environment, from the ui framework to modal dialog management each component plays a vital role in creating a flexible, intuitive, and powerful tool for world creation