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,6 @@
import * as React from "react";
import InfusionChoicePaneStore from "../InfusionChoicePaneStore";
import withAvailableItems from "../withAvailableItems";
export default withAvailableItems(InfusionChoicePaneStore);
@@ -0,0 +1,4 @@
import InfusionChoicePaneNewStore from "./InfusionChoicePaneNewStore";
export default InfusionChoicePaneNewStore;
export { InfusionChoicePaneNewStore };
@@ -0,0 +1,39 @@
import * as React from "react";
interface Props {
header: React.ReactNode;
extra?: React.ReactNode;
onClick?: () => void;
}
export class InfusionChoicePaneStep extends React.PureComponent<Props> {
handleClick = (evt: React.MouseEvent): void => {
const { onClick } = this.props;
if (onClick) {
evt.stopPropagation();
evt.nativeEvent.stopImmediatePropagation();
onClick();
}
};
render() {
const { header, extra, children } = this.props;
return (
<div className="ct-infusion-choice-pane__step" onClick={this.handleClick}>
<div className="ct-infusion-choice-pane__step-primary">
<div className="ct-infusion-choice-pane__step-header">{header}</div>
<div className="ct-infusion-choice-pane__step-content">
{children}
</div>
</div>
{extra && (
<div className="ct-infusion-choice-pane__step-extra">{extra}</div>
)}
</div>
);
}
}
export default InfusionChoicePaneStep;
@@ -0,0 +1,4 @@
import InfusionChoicePaneStep from "./InfusionChoicePaneStep";
export default InfusionChoicePaneStep;
export { InfusionChoicePaneStep };
@@ -0,0 +1,146 @@
import { orderBy } from "lodash";
import * as React from "react";
import {
Collapsible,
CollapsibleHeaderContent,
LoadingPlaceholder,
} from "@dndbeyond/character-components/es";
import {
CharacterTheme,
InfusionChoice,
InfusionChoiceUtils,
InfusionUtils,
Item,
ItemUtils,
KnownInfusionUtils,
RuleData,
} from "@dndbeyond/character-rules-engine/es";
import { ItemName } from "~/components/ItemName";
import ItemDetail from "../../../../components/ItemDetail";
import { ThemeButton } from "../../../../components/common/Button";
import DataLoadingStatusEnum from "../../../../constants/DataLoadingStatusEnum";
interface Props {
itemLoadingStatus: DataLoadingStatusEnum;
items: Array<Item>;
itemCanBeAddedLookup: Record<number, boolean>;
infusionChoice: InfusionChoice;
onItemSelected: (item: Item) => void;
ruleData: RuleData;
proficiencyBonus: number;
theme: CharacterTheme;
}
export class InfusionChoicePaneStore extends React.PureComponent<Props> {
static defaultProps = {
items: [],
itemLoadingStatus: DataLoadingStatusEnum.NOT_INITIALIZED,
itemCanBeAddedLookup: {},
};
renderLoading = (): React.ReactNode => {
return <LoadingPlaceholder />;
};
renderEmpty = (): React.ReactNode => {
return (
<div className="ct-infusion-choice-pane__inventory-empty">
There are no items that match the requirements for infusion.
</div>
);
};
render() {
const {
infusionChoice,
itemCanBeAddedLookup,
itemLoadingStatus,
items,
onItemSelected,
ruleData,
proficiencyBonus,
theme,
} = this.props;
if (
itemLoadingStatus !== DataLoadingStatusEnum.NOT_INITIALIZED &&
itemLoadingStatus !== DataLoadingStatusEnum.LOADED
) {
return this.renderLoading();
}
const knownInfusion = InfusionChoiceUtils.getKnownInfusion(infusionChoice);
if (knownInfusion === null) {
return null;
}
const simulatedInfusion =
KnownInfusionUtils.getSimulatedInfusion(knownInfusion);
if (simulatedInfusion === null) {
return null;
}
const availableItems = InfusionUtils.filterAvailableItems(
items,
simulatedInfusion,
KnownInfusionUtils.getItemId(knownInfusion),
itemCanBeAddedLookup
);
const orderedItems = orderBy(availableItems, (item) =>
ItemUtils.getName(item)
);
if (!orderedItems.length) {
return this.renderEmpty();
}
return (
<div className="ct-infusion-choice-pane__inventory">
{orderedItems.map((item) => {
let headerNode = (
<CollapsibleHeaderContent
heading={<ItemName item={item} showLegacy={true} />}
callout={
<ThemeButton
onClick={onItemSelected.bind(this, item)}
size="small"
data-testid={`infusion-choose-item-button-${ItemUtils.getName(
item
)}`
.toLowerCase()
.replace(/\s/g, "-")}
>
Choose
</ThemeButton>
}
/>
);
return (
<Collapsible
key={ItemUtils.getId(item)}
layoutType="minimal"
header={headerNode}
className="ct-infusion-choice-pane__item"
>
<ItemDetail
theme={theme}
item={item}
ruleData={ruleData}
showCustomize={false}
showActions={false}
showImage={false}
showAbilities={false}
proficiencyBonus={proficiencyBonus}
/>
</Collapsible>
);
})}
</div>
);
}
}
export default InfusionChoicePaneStore;
@@ -0,0 +1,4 @@
import InfusionChoicePaneStore from "./InfusionChoicePaneStore";
export default InfusionChoicePaneStore;
export { InfusionChoicePaneStore };
@@ -0,0 +1,14 @@
import InfusionChoicePane from "./InfusionChoicePane";
import InfusionChoicePaneNewStore from "./InfusionChoicePaneNewStore";
import InfusionChoicePaneStep from "./InfusionChoicePaneStep";
import InfusionChoicePaneStore from "./InfusionChoicePaneStore";
import withAvailableItems from "./withAvailableItems";
export default InfusionChoicePane;
export {
InfusionChoicePane,
InfusionChoicePaneNewStore,
InfusionChoicePaneStep,
InfusionChoicePaneStore,
withAvailableItems,
};
@@ -0,0 +1,126 @@
import axios, { Canceler } from "axios";
import * as React from "react";
import {
CharacterTheme,
ContainerManager,
InfusionChoice,
InventoryManager,
Item,
ItemUtils,
RuleData,
} from "@dndbeyond/character-rules-engine/es";
import DataLoadingStatusEnum from "../../../../constants/DataLoadingStatusEnum";
import { AppLoggerUtils } from "../../../../utils";
function getDisplayName(WrappedComponent: React.ComponentType) {
return WrappedComponent.displayName || WrappedComponent.name || "Component";
}
export interface RequiredWithAvailableItemsProps {
inventoryManager: InventoryManager;
theme?: CharacterTheme;
infusionChoice: InfusionChoice;
onItemSelected: (item: Item) => void;
ruleData: RuleData;
}
interface State {
loadingStatus: DataLoadingStatusEnum;
availableItems: Array<Item>;
}
export function withAvailableItems<
C extends React.ComponentType<React.ComponentProps<C>>,
ResolvedProps = JSX.LibraryManagedAttributes<C, React.ComponentProps<C>>
>(WrappedComponent) {
return class withAvailableItems extends React.PureComponent<
ResolvedProps & RequiredWithAvailableItemsProps,
State
> {
static displayName = `withAvailableItems(${getDisplayName(
WrappedComponent
)})`;
loadAvailableItemsCanceler: null | Canceler = null;
constructor(props) {
super(props);
this.state = {
loadingStatus: DataLoadingStatusEnum.NOT_LOADED,
availableItems: [],
};
}
componentDidMount() {
const { loadingStatus } = this.state;
const { inventoryManager } = this.props;
if (loadingStatus === DataLoadingStatusEnum.NOT_LOADED) {
this.setState({
loadingStatus: DataLoadingStatusEnum.LOADING,
});
inventoryManager
.getInventoryShoppe({
onSuccess: (shoppeContainer: ContainerManager) => {
const storeItems = shoppeContainer
.getInventoryItems()
.items.map((item) => item.getItem());
this.setState({
availableItems: storeItems,
loadingStatus: DataLoadingStatusEnum.LOADED,
});
},
additionalApiConfig: {
cancelToken: new axios.CancelToken((c) => {
this.loadAvailableItemsCanceler = c;
}),
},
})
.then((res) => {
this.loadAvailableItemsCanceler = null;
return res;
})
.catch(AppLoggerUtils.handleAdhocApiError);
} else {
this.setState({
loadingStatus: DataLoadingStatusEnum.LOADED,
});
}
}
componentWillUnmount(): void {
if (this.loadAvailableItemsCanceler !== null) {
this.loadAvailableItemsCanceler();
}
}
render() {
const { loadingStatus, availableItems } = this.state;
let itemCanBeAddedLookup: Record<number, boolean> = availableItems.reduce(
(acc, item) => {
acc[ItemUtils.getId(item)] = ItemUtils.canBeAddedToInventory(item);
return acc;
},
{}
);
return (
<WrappedComponent
items={availableItems}
itemCanBeAddedLookup={itemCanBeAddedLookup}
itemLoadingStatus={loadingStatus}
{...(this.props as JSX.LibraryManagedAttributes<
C,
React.ComponentProps<C>
>)}
/>
);
}
};
}
export default withAvailableItems;