From 938336f5d4ef11b967e103c6e9cf84568109d865 Mon Sep 17 00:00:00 2001 From: NovaBot <154629622+NovaBot13@users.noreply.github.com> Date: Tue, 23 Apr 2024 00:38:02 -0400 Subject: [PATCH] [MIRROR] Converts ListInputModal to actually be a Modal | Adds ListInputWindow which uses it (#2139) * Converts ListInputModal to actually be a Modal | Adds ListInputWindow which uses it (#82792) ## About The Pull Request If we say something is a Modal it should actually be a Modal ## Why It's Good For The Game You can now use this system in other windows if you want. Fixed the misnomer. --------- Co-authored-by: Jeremiah <42397676+jlsnow301@users.noreply.github.com> * Converts ListInputModal to actually be a Modal | Adds ListInputWindow which uses it --------- Co-authored-by: Zephyr <12817816+ZephyrTFA@users.noreply.github.com> Co-authored-by: Jeremiah <42397676+jlsnow301@users.noreply.github.com> --- code/modules/tgui_input/list.dm | 2 +- .../{ => ListInputWindow}/ListInputModal.tsx | 172 ++++++++---------- .../tgui/interfaces/ListInputWindow/index.tsx | 44 +++++ .../tgui/interfaces/common/InputButtons.tsx | 23 ++- 4 files changed, 144 insertions(+), 97 deletions(-) rename tgui/packages/tgui/interfaces/{ => ListInputWindow}/ListInputModal.tsx (57%) create mode 100644 tgui/packages/tgui/interfaces/ListInputWindow/index.tsx diff --git a/code/modules/tgui_input/list.dm b/code/modules/tgui_input/list.dm index 174f16fc7b5..22c6d48edfc 100644 --- a/code/modules/tgui_input/list.dm +++ b/code/modules/tgui_input/list.dm @@ -111,7 +111,7 @@ /datum/tgui_list_input/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, "ListInputModal") + ui = new(user, src, "ListInputWindow") ui.open() /datum/tgui_list_input/ui_close(mob/user) diff --git a/tgui/packages/tgui/interfaces/ListInputModal.tsx b/tgui/packages/tgui/interfaces/ListInputWindow/ListInputModal.tsx similarity index 57% rename from tgui/packages/tgui/interfaces/ListInputModal.tsx rename to tgui/packages/tgui/interfaces/ListInputWindow/ListInputModal.tsx index 8695ac842f7..a56363f2310 100644 --- a/tgui/packages/tgui/interfaces/ListInputModal.tsx +++ b/tgui/packages/tgui/interfaces/ListInputWindow/ListInputModal.tsx @@ -7,35 +7,26 @@ import { KEY_ESCAPE, KEY_UP, KEY_Z, -} from '../../common/keycodes'; -import { useBackend } from '../backend'; -import { Autofocus, Button, Input, Section, Stack } from '../components'; -import { Window } from '../layouts'; -import { InputButtons } from './common/InputButtons'; -import { Loader } from './common/Loader'; +} from '../../../common/keycodes'; +import { useBackend } from '../../backend'; +import { Autofocus, Button, Input, Section, Stack } from '../../components'; +import { InputButtons } from '../common/InputButtons'; -type ListInputData = { - init_value: string; +type ListInputModalProps = { items: string[]; - large_buttons: boolean; + default_item: string; message: string; - timeout: number; - title: string; + on_selected: (entry: string) => void; + on_cancel: () => void; }; -export const ListInputModal = (props) => { - const { act, data } = useBackend(); - const { - items = [], - message = '', - init_value, - large_buttons, - timeout, - title, - } = data; - const [selected, setSelected] = useState(items.indexOf(init_value)); +export const ListInputModal = (props: ListInputModalProps) => { + const { items = [], default_item, message, on_selected, on_cancel } = props; + + const [selected, setSelected] = useState(items.indexOf(default_item)); const [searchBarVisible, setSearchBarVisible] = useState(items.length > 9); const [searchQuery, setSearchQuery] = useState(''); + // User presses up or down on keyboard // Simulates clicking an item const onArrowKey = (key: number) => { @@ -99,82 +90,77 @@ export const ListInputModal = (props) => { const filteredItems = items.filter((item) => item?.toLowerCase().includes(searchQuery.toLowerCase()), ); - // Dynamically changes the window height based on the message. - const windowHeight = - 325 + Math.ceil(message.length / 3) + (large_buttons ? 5 : 0); // Grabs the cursor when no search bar is visible. if (!searchBarVisible) { setTimeout(() => document!.getElementById(selected.toString())?.focus(), 1); } return ( - - {timeout && } - { - const keyCode = window.event ? event.which : event.keyCode; - if (keyCode === KEY_DOWN || keyCode === KEY_UP) { - event.preventDefault(); - onArrowKey(keyCode); - } - if (keyCode === KEY_ENTER) { - event.preventDefault(); - act('submit', { entry: filteredItems[selected] }); - } - if (!searchBarVisible && keyCode >= KEY_A && keyCode <= KEY_Z) { - event.preventDefault(); - onLetterSearch(keyCode); - } - if (keyCode === KEY_ESCAPE) { - event.preventDefault(); - act('cancel'); - } - }} - > -
onSearchBarToggle()} - /> +
{ + const keyCode = window.event ? event.which : event.keyCode; + if (keyCode === KEY_DOWN || keyCode === KEY_UP) { + event.preventDefault(); + onArrowKey(keyCode); + } + if (keyCode === KEY_ENTER) { + event.preventDefault(); + on_selected(filteredItems[selected]); + } + if (!searchBarVisible && keyCode >= KEY_A && keyCode <= KEY_Z) { + event.preventDefault(); + onLetterSearch(keyCode); + } + if (keyCode === KEY_ESCAPE) { + event.preventDefault(); + on_cancel(); + } + }} + buttons={ +
- - + tooltipPosition="left" + onClick={() => onSearchBarToggle()} + /> + } + className="ListInput__Section" + fill + title={message} + > + + + + + {searchBarVisible && ( + + )} + + on_selected(filteredItems[selected])} + on_cancel={on_cancel} + /> + + +
); }; @@ -183,7 +169,7 @@ export const ListInputModal = (props) => { * If a search query is provided, filters the items. */ const ListDisplay = (props) => { - const { act } = useBackend(); + const { act } = useBackend(); const { filteredItems, onClick, onFocusSearch, searchBarVisible, selected } = props; @@ -227,7 +213,7 @@ const ListDisplay = (props) => { * Closing the bar defaults input to an empty string. */ const SearchBar = (props) => { - const { act } = useBackend(); + const { act } = useBackend(); const { filteredItems, onSearch, searchQuery, selected } = props; return ( diff --git a/tgui/packages/tgui/interfaces/ListInputWindow/index.tsx b/tgui/packages/tgui/interfaces/ListInputWindow/index.tsx new file mode 100644 index 00000000000..29355ff5d21 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ListInputWindow/index.tsx @@ -0,0 +1,44 @@ +import { useBackend } from '../../backend'; +import { Window } from '../../layouts'; +import { Loader } from '../common/Loader'; +import { ListInputModal } from './ListInputModal'; + +type ListInputData = { + init_value: string; + items: string[]; + large_buttons: boolean; + message: string; + timeout: number; + title: string; +}; + +export const ListInputWindow = () => { + const { act, data } = useBackend(); + const { + items = [], + message = '', + init_value, + large_buttons, + timeout, + title, + } = data; + + // Dynamically changes the window height based on the message. + const windowHeight = + 325 + Math.ceil(message.length / 3) + (large_buttons ? 5 : 0); + + return ( + + {timeout && } + + act('submit', { entry })} + on_cancel={() => act('cancel')} + /> + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/common/InputButtons.tsx b/tgui/packages/tgui/interfaces/common/InputButtons.tsx index aad3d92f081..aa74ff1fdc0 100644 --- a/tgui/packages/tgui/interfaces/common/InputButtons.tsx +++ b/tgui/packages/tgui/interfaces/common/InputButtons.tsx @@ -8,19 +8,36 @@ type InputButtonsData = { type InputButtonsProps = { input: string | number | string[]; + on_submit?: () => void; + on_cancel?: () => void; message?: string; }; export const InputButtons = (props: InputButtonsProps) => { const { act, data } = useBackend(); const { large_buttons, swapped_buttons } = data; - const { input, message } = props; + const { input, message, on_submit, on_cancel } = props; + + let on_submit_actual = on_submit; + if (!on_submit_actual) { + on_submit_actual = () => { + act('submit', { entry: input }); + }; + } + + let on_cancel_actual = on_cancel; + if (!on_cancel_actual) { + on_cancel_actual = () => { + act('cancel'); + }; + } + const submitButton = (