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,80 @@
import React from "react";
import { connect, DispatchProp } from "react-redux";
import {
ApiRequestHelpers,
rulesEngineSelectors,
characterActions,
SpellSlotContract,
} from "@dndbeyond/character-rules-engine/es";
import { appEnvSelectors } from "../../../Shared/selectors";
import { SheetAppState } from "../../typings";
import SpellSlotManagerGroup from "./SpellSlotManagerGroup";
interface Props extends DispatchProp {
spellSlots: Array<SpellSlotContract>;
pactSlots: Array<SpellSlotContract>;
isReadonly: boolean;
}
class SpellSlotManager extends React.PureComponent<Props> {
handleSlotSet = (level: number, used: number): void => {
const { dispatch } = this.props;
const spellLevelSpellSlotRequestsDataKey =
ApiRequestHelpers.getSpellLevelSpellSlotRequestsDataKey(level);
if (spellLevelSpellSlotRequestsDataKey !== null) {
dispatch(
characterActions.spellLevelSpellSlotsSet({
[spellLevelSpellSlotRequestsDataKey]: used,
})
);
}
};
handlePactSet = (level: number, used: number): void => {
const { dispatch } = this.props;
const spellLevelPactMagicRequestsDataKey =
ApiRequestHelpers.getSpellLevelPactMagicRequestsDataKey(level);
if (spellLevelPactMagicRequestsDataKey !== null) {
dispatch(
characterActions.spellLevelPactMagicSlotsSet({
[spellLevelPactMagicRequestsDataKey]: used,
})
);
}
};
render() {
const { spellSlots, pactSlots, isReadonly } = this.props;
return (
<div className="ct-spell-slot-manager">
<SpellSlotManagerGroup
heading="Spell Slots"
slots={spellSlots}
onSlotSet={this.handleSlotSet}
isReadonly={isReadonly}
/>
<SpellSlotManagerGroup
heading="Pact Magic"
slots={pactSlots}
onSlotSet={this.handlePactSet}
isReadonly={isReadonly}
/>
</div>
);
}
}
function mapStateToProps(state: SheetAppState) {
return {
spellSlots: rulesEngineSelectors.getSpellSlots(state),
pactSlots: rulesEngineSelectors.getPactMagicSlots(state),
isReadonly: appEnvSelectors.getIsReadonly(state),
};
}
export default connect(mapStateToProps)(SpellSlotManager);
@@ -0,0 +1,77 @@
import React from "react";
import {
Collapsible,
CollapsibleHeaderContent,
} from "@dndbeyond/character-components/es";
import {
FormatUtils,
SpellSlotContract,
} from "@dndbeyond/character-rules-engine/es";
import SpellSlotManagerLevel from "../SpellSlotManagerLevel";
interface Props {
heading: string;
slots: Array<SpellSlotContract>;
onSlotSet?: (level: number, used: number) => void;
isReadonly: boolean;
}
export default class SpellSlotManagerGroup extends React.PureComponent<Props> {
renderCallout = (): React.ReactNode => {
const { slots } = this.props;
return (
<div className="ct-spell-slot-manager__group-summary">
{slots.map((levelSlots) => (
<div
className="ct-spell-slot-manager__group-level"
key={levelSlots.level}
>
<div className="ct-spell-slot-manager__group-level-name">
{FormatUtils.ordinalize(levelSlots.level)}
</div>
<div className="ct-spell-slot-manager__group-level-available">
{levelSlots.available === 0 ? "-" : levelSlots.available}
</div>
</div>
))}
</div>
);
};
render() {
const { slots, onSlotSet, heading, isReadonly } = this.props;
let headerNode: React.ReactNode = (
<CollapsibleHeaderContent
heading={heading}
callout={this.renderCallout()}
/>
);
if (!slots.length) {
return null;
}
return (
<Collapsible header={headerNode} className="ct-spell-slot-manager__group">
<div className="ct-spell-slot-manager__levels">
{slots.map((levelSlots) => {
if (levelSlots.available === 0) {
return null;
}
return (
<SpellSlotManagerLevel
key={levelSlots.level}
{...levelSlots}
onSlotSet={onSlotSet}
isInteractive={!isReadonly}
/>
);
})}
</div>
</Collapsible>
);
}
}
@@ -0,0 +1,4 @@
import SpellSlotManagerGroup from "./SpellSlotManagerGroup";
export default SpellSlotManagerGroup;
export { SpellSlotManagerGroup };
@@ -0,0 +1,41 @@
import React from "react";
import { FormatUtils } from "@dndbeyond/character-rules-engine/es";
import SlotManager from "../../../../Shared/components/SlotManager";
interface Props {
level: number;
available: number;
used: number;
onSlotSet?: (level: number, used: number) => void;
isInteractive: boolean;
}
export default class SpellSlotManagerLevel extends React.PureComponent<Props> {
handleSlotSet = (used: number): void => {
const { onSlotSet, level } = this.props;
if (onSlotSet) {
onSlotSet(level, used);
}
};
render() {
let { level, available, used, isInteractive } = this.props;
return (
<div className="ct-spell-slot-manager__level">
<div className="ct-spell-slot-manager__level-name">
{FormatUtils.ordinalize(level)} Level
</div>
<SlotManager
available={available}
used={used}
onSet={this.handleSlotSet}
size="small"
isInteractive={isInteractive}
/>
</div>
);
}
}
@@ -0,0 +1,4 @@
import SpellSlotManagerLevel from "./SpellSlotManagerLevel";
export default SpellSlotManagerLevel;
export { SpellSlotManagerLevel };
@@ -0,0 +1,6 @@
import SpellSlotManager from "./SpellSlotManager";
import SpellSlotManagerGroup from "./SpellSlotManagerGroup";
import SpellSlotManagerLevel from "./SpellSlotManagerLevel";
export default SpellSlotManager;
export { SpellSlotManager, SpellSlotManagerGroup, SpellSlotManagerLevel };