Grabbed dndbeyond's source code

```
~/go/bin/sourcemapper -output ddb -jsurl https://media.dndbeyond.com/character-app/static/js/main.90aa78c5.js
```
This commit is contained in:
2025-05-28 11:50:03 -07:00
commit 8df9031d27
3592 changed files with 319051 additions and 0 deletions
@@ -0,0 +1,220 @@
import React from "react";
import { connect, DispatchProp } from "react-redux";
import { Collapsible, Select } from "@dndbeyond/character-components/es";
import {
characterActions,
CharacterPreferences,
Constants,
CustomSpeedContract,
CustomSpeedLookup,
HelperUtils,
HtmlSelectOption,
SpeedInfo,
RuleData,
RuleDataUtils,
rulesEngineSelectors,
CharacterTheme,
} from "@dndbeyond/character-rules-engine/es";
import { HtmlContent } from "~/components/HtmlContent";
import { NumberDisplay } from "~/components/NumberDisplay";
import { Header } from "~/subApps/sheet/components/Sidebar/components/Header";
import { Heading } from "~/subApps/sheet/components/Sidebar/components/Heading";
import { MOVEMENT_TYPE_LIST } from "../../../constants/App";
import * as appEnvSelectors from "../../../selectors/appEnv";
import { SharedAppState } from "../../../stores/typings";
import SpeedManagePaneCustomizeItem from "./SpeedManagePaneCustomizeItem";
interface Props extends DispatchProp {
movements: SpeedInfo;
customSpeedLookup: CustomSpeedLookup;
customSpeeds: Array<CustomSpeedContract>;
preferences: CharacterPreferences;
ruleData: RuleData;
isReadonly: boolean;
theme: CharacterTheme;
}
class SpeedManagePane extends React.PureComponent<Props> {
handleMovementDisplayChange = (value: string): void => {
const { dispatch } = this.props;
dispatch(
characterActions.preferenceChoose(
"primaryMovement",
HelperUtils.parseInputInt(value)
)
);
};
handleOverrideUpdate = (
id: number,
distance: number | null,
source: string | null
): void => {
const { dispatch, customSpeeds } = this.props;
if (distance !== null || source !== null) {
let foundSpeed: CustomSpeedContract | undefined = customSpeeds.find(
(speed) => speed.movementId === id
);
if (foundSpeed) {
dispatch(
characterActions.movementSet({
...foundSpeed,
distance,
source,
})
);
} else {
let newSpeed: CustomSpeedContract = {
movementId: id,
distance,
source,
};
dispatch(characterActions.movementAdd(newSpeed));
}
} else {
dispatch(characterActions.movementRemove(id));
}
};
renderCustomize = (): React.ReactNode => {
const { customSpeedLookup, preferences, isReadonly, ruleData } = this.props;
if (isReadonly) {
return;
}
let movementOptions: Array<HtmlSelectOption> = MOVEMENT_TYPE_LIST.map(
(key) => ({
label: RuleDataUtils.getMovementDescription(key, ruleData),
value: key,
})
);
return (
<Collapsible
layoutType={"minimal"}
header="Customize"
className="ct-speed-manage-pane__customize"
>
<Heading>Override Speeds</Heading>
<div className="ct-speed-manage-pane__customize-header">
<div className="ct-speed-manage-pane__customize-header-label" />
<div className="ct-speed-manage-pane__customize-header-input">
Speed (ft.)
</div>
<div className="ct-speed-manage-pane__customize-header-source">
Source/Notes
</div>
</div>
{movementOptions.map((option: HtmlSelectOption) => {
const override = customSpeedLookup[option.value];
return (
<SpeedManagePaneCustomizeItem
key={option.value as number}
id={option.value as number}
label={option.label}
initialValue={override ? override.distance : null}
initialSource={override ? override.source : null}
minimumValue={0}
onUpdate={this.handleOverrideUpdate}
/>
);
})}
<Heading>Set Movement Display</Heading>
<Select
options={movementOptions}
onChange={this.handleMovementDisplayChange}
initialOptionRemoved={true}
value={preferences.primaryMovement}
/>
</Collapsible>
);
};
renderDescription = (): React.ReactNode => {
const { ruleData } = this.props;
let rule = RuleDataUtils.getRule(Constants.RuleKeyEnum.SPEED, ruleData);
if (rule === null || rule.description === null) {
return null;
}
return (
<HtmlContent
className="ct-speed-manage-pane__description"
html={rule.description}
withoutTooltips
/>
);
};
render() {
const { movements, customSpeedLookup, ruleData, theme } = this.props;
return (
<div className="ct-speed-manage-pane">
<Header>Speed</Header>
<div className="ct-speed-manage-pane__speeds">
{Object.keys(movements).map(
(movementKey: Constants.SpeedMovementKeyEnum) => {
const movementAmount = movements[movementKey];
if (movementAmount === null || movementAmount === 0) {
return null;
}
let movementType =
RuleDataUtils.getMovementTypeBySpeedMovementKey(movementKey);
let customSpeed: CustomSpeedContract | null | undefined =
movementType === null ? null : customSpeedLookup[movementType];
let source: string =
customSpeed && customSpeed.source ? customSpeed.source : "";
return (
<div className="ct-speed-manage-pane__speed" key={movementKey}>
<span className="ct-speed-manage-pane__speed-label">
{RuleDataUtils.getSpeedMovementKeyLabel(
movementKey,
ruleData
)}
</span>
<span className="ct-speed-manage-pane__speed-amount">
<NumberDisplay
type="distanceInFt"
number={movementAmount}
/>
</span>
{source && (
<span className="ct-speed-manage-pane__speed-source">
({source})
</span>
)}
</div>
);
}
)}
</div>
{this.renderCustomize()}
{this.renderDescription()}
</div>
);
}
}
function mapStateToProps(state: SharedAppState) {
return {
movements: rulesEngineSelectors.getCurrentCarriedWeightSpeed(state),
preferences: rulesEngineSelectors.getCharacterPreferences(state),
customSpeedLookup: rulesEngineSelectors.getCustomSpeedLookup(state),
customSpeeds: rulesEngineSelectors.getCustomSpeeds(state),
ruleData: rulesEngineSelectors.getRuleData(state),
isReadonly: appEnvSelectors.getIsReadonly(state),
theme: rulesEngineSelectors.getCharacterTheme(state),
};
}
export default connect(mapStateToProps)(SpeedManagePane);
@@ -0,0 +1,115 @@
import React from "react";
import { HelperUtils } from "@dndbeyond/character-rules-engine/es";
interface Props {
id: number;
label: string | null;
initialValue: number | null;
initialSource: string | null;
onUpdate: (id: number, value: number | null, source: string | null) => void;
enableSource: boolean;
minimumValue: number | null;
className: string;
}
interface State {
value: number | null;
source: string | null;
isDirty: boolean;
}
export default class SpeedManagePaneCustomizeItem extends React.PureComponent<
Props,
State
> {
static defaultProps = {
className: "",
enableSource: true,
minimumValue: null,
};
constructor(props: Props) {
super(props);
this.state = {
value: props.initialValue,
source: props.initialSource,
isDirty: false,
};
}
handleUpdate = (): void => {
const { onUpdate, id } = this.props;
const { value, source, isDirty } = this.state;
if (isDirty && onUpdate) {
onUpdate(id, value, source);
this.setState({
isDirty: false,
});
}
};
handleValueBlur = (evt: React.FocusEvent<HTMLInputElement>): void => {
const { minimumValue } = this.props;
let value = evt.target.value;
this.setState((prevState) => {
let parsedValue = HelperUtils.parseInputInt(value);
let clampedInt: number | null = parsedValue;
if (minimumValue !== null && parsedValue !== null) {
clampedInt = HelperUtils.clampInt(parsedValue, minimumValue);
}
return {
value: clampedInt,
};
}, this.handleUpdate);
};
handleValueChange = (evt: React.ChangeEvent<HTMLInputElement>): void => {
this.setState({
value: HelperUtils.parseInputInt(evt.target.value),
isDirty: true,
});
};
handleSourceChange = (evt: React.ChangeEvent<HTMLInputElement>): void => {
this.setState({
source: evt.target.value,
isDirty: true,
});
};
render() {
const { value, source } = this.state;
const { label, enableSource, minimumValue, className } = this.props;
return (
<div className={`ct-speed-manage-pane__customize-item ${className}`}>
<div className="ct-speed-manage-pane__customize-item-label">
{label}
</div>
<div className="ct-speed-manage-pane__customize-item-input">
<input
type="number"
min={minimumValue === null ? undefined : minimumValue}
onChange={this.handleValueChange}
onBlur={this.handleValueBlur}
value={value === null ? "" : value}
/>
</div>
{enableSource && (
<div className="ct-speed-manage-pane__customize-item-source">
<input
type="text"
onChange={this.handleSourceChange}
onBlur={this.handleUpdate}
value={source === null ? "" : source}
/>
</div>
)}
</div>
);
//`
}
}
@@ -0,0 +1,4 @@
import SpeedManagePaneCustomizeItem from "./SpeedManagePaneCustomizeItem";
export default SpeedManagePaneCustomizeItem;
export { SpeedManagePaneCustomizeItem };
@@ -0,0 +1,5 @@
import SpeedManagePane from "./SpeedManagePane";
import SpeedManagePaneCustomizeItem from "./SpeedManagePaneCustomizeItem";
export default SpeedManagePane;
export { SpeedManagePane, SpeedManagePaneCustomizeItem };