``` ~/go/bin/sourcemapper -output ddb -jsurl https://media.dndbeyond.com/character-app/static/js/main.90aa78c5.js ```
196 lines
6.8 KiB
TypeScript
196 lines
6.8 KiB
TypeScript
import { visuallyHidden } from "@mui/utils";
|
|
import { useContext } from "react";
|
|
import { Tooltip } from "@dndbeyond/character-common-components/es";
|
|
import {
|
|
AbilityManager,
|
|
CharacterTheme,
|
|
FormatUtils,
|
|
SituationalSavingThrowInfo,
|
|
SituationalSavingThrowInfoLookup,
|
|
} from "@dndbeyond/character-rules-engine/es";
|
|
import { DiceTools, IRollContext, RollType } from "@dndbeyond/dice";
|
|
import { GameLogContext } from "@dndbeyond/game-log-components";
|
|
import BoxBackground from "../BoxBackground";
|
|
import { ProficiencyLevelIcon } from "../Icons";
|
|
import {
|
|
ThemedSavingThrowSelectionBoxSvg,
|
|
ThemedSavingThrowSelectionSmallBoxSvg,
|
|
ThemedSavingThrowRowBoxSvg,
|
|
ThemedSavingThrowRowSmallBoxSvg,
|
|
NegativeBonusNegativeSvg,
|
|
PositiveBonusPositiveSvg,
|
|
DarkModePositiveBonusPositiveSvg,
|
|
DarkModeNegativeBonusNegativeSvg,
|
|
} from "../Svg";
|
|
import { isNotNullOrUndefined } from "../utils/TypeScriptUtils";
|
|
import { DigitalDiceWrapper } from "../Dice";
|
|
import { NumberDisplay } from "~/components/NumberDisplay";
|
|
|
|
interface Props {
|
|
abilities: Array<AbilityManager>;
|
|
situationalBonusSavingThrowsLookup: SituationalSavingThrowInfoLookup;
|
|
onClick?: (ability: AbilityManager) => void;
|
|
rowStyle?: "small" | "normal";
|
|
className?: string;
|
|
diceEnabled?: boolean;
|
|
theme: CharacterTheme;
|
|
rollContext: IRollContext;
|
|
};
|
|
|
|
export default function SavingThrowsSummary({
|
|
abilities,
|
|
situationalBonusSavingThrowsLookup,
|
|
onClick = (ability: AbilityManager) => {},
|
|
theme,
|
|
rollContext,
|
|
className = "",
|
|
diceEnabled = false,
|
|
rowStyle = "normal",
|
|
}: Props) {
|
|
const handleClick = (
|
|
ability: AbilityManager,
|
|
evt: React.MouseEvent
|
|
): void => {
|
|
if (onClick) {
|
|
evt.stopPropagation();
|
|
evt.nativeEvent.stopImmediatePropagation();
|
|
onClick(ability);
|
|
}
|
|
};
|
|
|
|
const [{ messageTargetOptions, defaultMessageTargetOption, userId }] =
|
|
useContext(GameLogContext);
|
|
|
|
return (
|
|
<div className="ddbc-saving-throws-summary">
|
|
{abilities.map((ability) => {
|
|
let situationalBonusSavingThrows: Array<SituationalSavingThrowInfo> =
|
|
[];
|
|
let maxOptBonus: number = 0;
|
|
|
|
if (situationalBonusSavingThrowsLookup) {
|
|
situationalBonusSavingThrows =
|
|
situationalBonusSavingThrowsLookup[ability.getId()];
|
|
if (
|
|
situationalBonusSavingThrows &&
|
|
situationalBonusSavingThrows.length
|
|
) {
|
|
let situationalBonusSavingThrowsValues: Array<number> =
|
|
situationalBonusSavingThrows.map((optBonus) => optBonus.value);
|
|
maxOptBonus = Math.max(...situationalBonusSavingThrowsValues);
|
|
}
|
|
}
|
|
|
|
let situationalBonusClasses: Array<string> = [
|
|
"ddbc-saving-throws-summary__ability-situational",
|
|
];
|
|
let IconComponent: React.ComponentType<any> | null = null;
|
|
if (maxOptBonus < 0) {
|
|
situationalBonusClasses.push(
|
|
"ddbc-saving-throws-summary__ability-situational--bonus-neg"
|
|
);
|
|
IconComponent = theme?.isDarkMode
|
|
? DarkModeNegativeBonusNegativeSvg
|
|
: NegativeBonusNegativeSvg;
|
|
} else {
|
|
situationalBonusClasses.push(
|
|
"ddbc-saving-throws-summary__ability-situational--bonus-pos"
|
|
);
|
|
IconComponent = theme?.isDarkMode
|
|
? DarkModePositiveBonusPositiveSvg
|
|
: PositiveBonusPositiveSvg;
|
|
}
|
|
|
|
let StyleComponent: React.ComponentType<any> =
|
|
ThemedSavingThrowRowBoxSvg;
|
|
let SelectionBox = ThemedSavingThrowSelectionBoxSvg;
|
|
if (rowStyle === "small") {
|
|
StyleComponent = ThemedSavingThrowRowSmallBoxSvg;
|
|
SelectionBox = ThemedSavingThrowSelectionSmallBoxSvg;
|
|
}
|
|
|
|
return (
|
|
<div
|
|
key={ability.getStatKey()}
|
|
className={`ddbc-saving-throws-summary__ability ddbc-saving-throws-summary__ability--${FormatUtils.slugify(
|
|
ability.getStatKey()
|
|
)}`}
|
|
onClick={(event) => handleClick(ability, event)}
|
|
>
|
|
<BoxBackground
|
|
StyleComponent={StyleComponent}
|
|
theme={{
|
|
...theme,
|
|
themeColor: `${theme.themeColor}80`,
|
|
}}
|
|
/>
|
|
<h3 style={visuallyHidden}>{ability.getLabel()} Saving Throw</h3>
|
|
<div className="ddbc-saving-throws-summary__ability-proficiency">
|
|
<ProficiencyLevelIcon
|
|
proficiencyLevel={ability.getProficiencyLevel()}
|
|
isModified={ability.getIsSaveProficiencyModified()}
|
|
theme={theme}
|
|
/>
|
|
</div>
|
|
<div
|
|
className={`ddbc-saving-throws-summary__ability-name ${
|
|
theme.isDarkMode
|
|
? "ddbc-saving-throws-summary__ability-name--dark-mode"
|
|
: ""
|
|
}`}
|
|
>
|
|
<abbr
|
|
title={ability.getLabel() ?? "Unknown Saving Throw"}
|
|
aria-hidden={true}
|
|
>
|
|
{ability.getName()}
|
|
</abbr>
|
|
</div>
|
|
<div className="ddbc-saving-throws-summary__ability-modifier">
|
|
<DigitalDiceWrapper
|
|
diceNotation={DiceTools.CustomD20(ability.getSave())}
|
|
rollType={RollType.Save}
|
|
rollAction={ability.getName()}
|
|
diceEnabled={diceEnabled}
|
|
themeColor={theme.themeColor}
|
|
rollContext={rollContext}
|
|
rollTargetOptions={
|
|
messageTargetOptions?.entities
|
|
? Object.values(messageTargetOptions.entities).filter(
|
|
isNotNullOrUndefined
|
|
)
|
|
: undefined
|
|
}
|
|
rollTargetDefault={defaultMessageTargetOption}
|
|
userId={Number(userId)}
|
|
>
|
|
<NumberDisplay
|
|
number={ability.getSave()}
|
|
type="signed"
|
|
isModified={ability.getIsSaveModifierModified()}
|
|
/>
|
|
</DigitalDiceWrapper>
|
|
<SelectionBox
|
|
theme={theme}
|
|
className={`ddbc-saving-throws-summary__ability-modifier-background`}
|
|
/>
|
|
</div>
|
|
{situationalBonusSavingThrows &&
|
|
situationalBonusSavingThrows.length > 0 && (
|
|
<Tooltip
|
|
className={situationalBonusClasses.join(" ")}
|
|
isDarkMode={theme.isDarkMode}
|
|
title={`Situational Bonus${
|
|
situationalBonusSavingThrows.length !== 1 ? "es" : ""
|
|
}`}
|
|
>
|
|
<IconComponent className="ddbc-saving-throws-summary__ability-situational-icon" />
|
|
</Tooltip>
|
|
)}
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
);
|
|
};
|