From 9dfc098cff6f261abb91d0606ebf31d9c0eba561 Mon Sep 17 00:00:00 2001
From: Jeremiah <42397676+jlsnow301@users.noreply.github.com>
Date: Thu, 4 Jan 2024 16:59:20 -0800
Subject: [PATCH] Fixes some character prefs issues (#80721)
## About The Pull Request
Issue with #80719 was resolved by using `TrackOutsideClicks` component
rather than the new `onOutsideClick` prop on `Popper`. I think it was
getting confused due to the fact it's nested - first the popup, then the
dropdown. The dropdown selection is working.
Issue #80689 was resolved by fixing the props on `Dropdown` &
`RandomizationButton`. Width and color specifically.
Now for why I'm asking for GBP for this...
#79251 added features to quirks which allowed for dropdown
customization. It's a cool concept, but its implementation is very
complex. I extracted components out of this into a simpler format which
I think is wholly better than calling useState within .map. Even with
some props drilling now in its place - I think it's a better
alternative.
## Why It's Good For The Game
Bug fixes
Fixes #80719
Fixes #80689
## Changelog
:cl:
fix: Randomization button in prefs should look normal again.
fix: Quirk customization shouldn't close immediately.
/:cl:
---
tgui/packages/tgui/components/Dropdown.tsx | 12 +-
.../interfaces/PreferencesMenu/QuirksPage.tsx | 456 ++++++++++--------
.../PreferencesMenu/RandomizationButton.tsx | 38 +-
3 files changed, 282 insertions(+), 224 deletions(-)
diff --git a/tgui/packages/tgui/components/Dropdown.tsx b/tgui/packages/tgui/components/Dropdown.tsx
index c77cead33d7..ba385db8e03 100644
--- a/tgui/packages/tgui/components/Dropdown.tsx
+++ b/tgui/packages/tgui/components/Dropdown.tsx
@@ -1,7 +1,7 @@
import { classes } from 'common/react';
import { ReactNode, useState } from 'react';
-import { BoxProps } from './Box';
+import { Box, BoxProps } from './Box';
import { Button } from './Button';
import { Icon } from './Icon';
import { Popper } from './Popper';
@@ -55,6 +55,7 @@ export function Dropdown(props: Props) {
options = [],
over,
selected,
+ width,
} = props;
const [open, setOpen] = useState(false);
@@ -129,12 +130,7 @@ export function Dropdown(props: Props) {
}
>
-
+
);
}
diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/QuirksPage.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/QuirksPage.tsx
index 67f8584e04f..5b63d4b8ec6 100644
--- a/tgui/packages/tgui/interfaces/PreferencesMenu/QuirksPage.tsx
+++ b/tgui/packages/tgui/interfaces/PreferencesMenu/QuirksPage.tsx
@@ -1,13 +1,22 @@
import { filterMap } from 'common/collections';
+import { useState } from 'react';
-import { useBackend, useLocalState } from '../../backend';
-import { Box, Button, Icon, Popper, Stack, Tooltip } from '../../components';
+import { useBackend } from '../../backend';
+import {
+ Box,
+ Button,
+ Icon,
+ Popper,
+ Stack,
+ Tooltip,
+ TrackOutsideClicks,
+} from '../../components';
import { PreferencesMenuData, Quirk, RandomSetting, ServerData } from './data';
import { getRandomization, PreferenceList } from './MainPage';
import { ServerPreferencesFetcher } from './ServerPreferencesFetcher';
import { useRandomToggleState } from './useRandomToggleState';
-const getValueClass = (value: number): string => {
+function getValueClass(value: number) {
if (value > 0) {
return 'positive';
} else if (value < 0) {
@@ -15,12 +24,12 @@ const getValueClass = (value: number): string => {
} else {
return 'neutral';
}
-};
+}
-const getCorrespondingPreferences = (
+function getCorrespondingPreferences(
customization_options: string[],
relevant_preferences: Record,
-): Record => {
+) {
return Object.fromEntries(
filterMap(Object.keys(relevant_preferences), (key) => {
if (!customization_options.includes(key)) {
@@ -30,202 +39,256 @@ const getCorrespondingPreferences = (
return [key, relevant_preferences[key]];
}),
);
+}
+
+type QuirkEntry = [string, Quirk & { failTooltip?: string }];
+
+type QuirkListProps = {
+ quirks: QuirkEntry[];
};
-const QuirkList = (props: {
- quirks: [
- string,
- Quirk & {
- failTooltip?: string;
- },
- ][];
+type QuirkProps = {
+ // eslint-disable-next-line react/no-unused-prop-types
onClick: (quirkName: string, quirk: Quirk) => void;
+ randomBodyEnabled: boolean;
selected: boolean;
serverData: ServerData;
- randomBodyEnabled: boolean;
-}) => {
- const { act, data } = useBackend();
+};
+
+function QuirkList(props: QuirkProps & QuirkListProps) {
+ const {
+ quirks = [],
+ selected,
+ onClick,
+ serverData,
+ randomBodyEnabled,
+ } = props;
return (
// Stack is not used here for a variety of IE flex bugs
- {props.quirks.map(([quirkKey, quirk]) => {
- const [customizationExpanded, setCustomizationExpanded] =
- useLocalState(quirk.name + ' customization', false);
-
- const className = 'PreferencesMenu__Quirks__QuirkList__quirk';
-
- const hasExpandableCustomization =
- quirk.customizable &&
- props.selected &&
- customizationExpanded &&
- quirk.customization_options &&
- Object.entries(quirk.customization_options).length > 0;
-
- const child = (
- {
- if (props.selected) {
- setCustomizationExpanded(false);
- }
- props.onClick(quirkKey, quirk);
- }}
- >
-
-
-
-
-
-
-
-
-
-
-
-
- {quirk.name}
-
-
-
- {quirk.value}
-
-
-
-
-
- {quirk.description}
- {!!quirk.customizable && (
- {
- setCustomizationExpanded(false);
- }}
- popperContent={
-
- {!!quirk.customization_options &&
- hasExpandableCustomization && (
-
- {
- e.stopPropagation();
- }}
- maxWidth="300px"
- backgroundColor="black"
- px="5px"
- py="3px"
- >
-
-
-
-
-
- )}
-
- }
- >
- {props.selected && (
- {
- e.stopPropagation();
-
- setCustomizationExpanded(!customizationExpanded);
- }}
- style={{
- float: 'right',
- }}
- />
- )}
-
- )}
-
-
-
-
-
- );
-
- if (quirk.failTooltip) {
- return (
-
- {child}
-
- );
- } else {
- return child;
- }
- })}
+ {quirks.map(([quirkKey, quirk]) => (
+
+ ))}
);
-};
+}
+
+type QuirkDisplayProps = {
+ quirk: Quirk & { failTooltip?: string };
+ // bugged
+ // eslint-disable-next-line react/no-unused-prop-types
+ quirkKey: string;
+} & QuirkProps;
+
+function QuirkDisplay(props: QuirkDisplayProps) {
+ const { quirk, quirkKey, onClick, selected } = props;
+ const { icon, value, name, description, customizable, failTooltip } = quirk;
+
+ const [customizationExpanded, setCustomizationExpanded] = useState(false);
+
+ const className = 'PreferencesMenu__Quirks__QuirkList__quirk';
+
+ const child = (
+ {
+ event.stopPropagation();
+ if (selected) {
+ setCustomizationExpanded(false);
+ }
+
+ onClick(quirkKey, quirk);
+ }}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+ {name}
+
+
+
+ {value}
+
+
+
+
+
+ {description}
+ {!!customizable && (
+
+ )}
+
+
+
+
+
+ );
+
+ if (failTooltip) {
+ return {child} ;
+ } else {
+ return child;
+ }
+}
+
+type QuirkPopperProps = {
+ customizationExpanded: boolean;
+ setCustomizationExpanded: (expanded: boolean) => void;
+} & QuirkDisplayProps;
+
+function QuirkPopper(props: QuirkPopperProps) {
+ const { act, data } = useBackend();
+ const {
+ customizationExpanded,
+ quirk,
+ randomBodyEnabled,
+ selected,
+ serverData,
+ setCustomizationExpanded,
+ } = props;
+
+ const { customizable, customization_options } = quirk;
+
+ const { character_preferences } = data;
+
+ const hasExpandableCustomization =
+ customizable &&
+ selected &&
+ customizationExpanded &&
+ customization_options &&
+ Object.entries(customization_options).length > 0;
+
+ return (
+ setCustomizationExpanded(false)}
+ >
+
+ {!!customization_options && hasExpandableCustomization && (
+
+ {
+ e.stopPropagation();
+ }}
+ maxWidth="300px"
+ backgroundColor="black"
+ px="5px"
+ py="3px"
+ >
+
+
+
+
+
+ )}
+
+
+ }
+ >
+ {selected && (
+ {
+ e.stopPropagation();
+ setCustomizationExpanded(!customizationExpanded);
+ }}
+ style={{
+ float: 'right',
+ }}
+ />
+ )}
+
+ );
+}
+
+function StatDisplay(props) {
+ const { children } = props;
-const StatDisplay = (props) => {
return (
{
px={3}
py={0.5}
>
- {props.children}
+ {children}
);
-};
+}
-export const QuirksPage = (props) => {
+export function QuirksPage(props) {
const { act, data } = useBackend();
// this is mainly just here to copy from MainPage.tsx
@@ -249,10 +312,7 @@ export const QuirksPage = (props) => {
data.character_preferences.non_contextual.random_body !==
RandomSetting.Disabled || randomToggleEnabled;
- const [selectedQuirks, setSelectedQuirks] = useLocalState(
- `selectedQuirks_${data.active_slot}`,
- data.selected_quirks,
- );
+ const [selectedQuirks, setSelectedQuirks] = useState(data.selected_quirks);
return (
{
}}
/>
);
-};
+}
diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/RandomizationButton.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/RandomizationButton.tsx
index e2471e17c36..4152e2d77c1 100644
--- a/tgui/packages/tgui/interfaces/PreferencesMenu/RandomizationButton.tsx
+++ b/tgui/packages/tgui/interfaces/PreferencesMenu/RandomizationButton.tsx
@@ -3,6 +3,23 @@ import { exhaustiveCheck } from 'common/exhaustive';
import { Dropdown, Icon } from '../../components';
import { RandomSetting } from './data';
+const options = [
+ {
+ displayText: 'Do not randomize',
+ value: RandomSetting.Disabled,
+ },
+
+ {
+ displayText: 'Always randomize',
+ value: RandomSetting.Enabled,
+ },
+
+ {
+ displayText: 'Randomize when antagonist',
+ value: RandomSetting.AntagOnly,
+ },
+];
+
export const RandomizationButton = (props: {
dropdownProps?: Record;
setValue: (newValue: RandomSetting) => void;
@@ -28,30 +45,15 @@ export const RandomizationButton = (props: {
return (
}
- options={[
- {
- displayText: 'Do not randomize',
- value: RandomSetting.Disabled,
- },
-
- {
- displayText: 'Always randomize',
- value: RandomSetting.Enabled,
- },
-
- {
- displayText: 'Randomize when antagonist',
- value: RandomSetting.AntagOnly,
- },
- ]}
+ options={options}
noChevron
onSelected={setValue}
menuWidth="120px"
- width="auto"
+ width={1.85}
/>
);
};