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:
+186
@@ -0,0 +1,186 @@
|
||||
import React from "react";
|
||||
|
||||
import {
|
||||
AbilityLookup,
|
||||
DataOriginBaseAction,
|
||||
DataOriginSpell,
|
||||
Constants,
|
||||
EntityLimitedUseContract,
|
||||
LimitedUseUtils,
|
||||
RuleData,
|
||||
RuleDataUtils,
|
||||
CharacterTheme,
|
||||
} from "@dndbeyond/character-rules-engine/es";
|
||||
|
||||
import SlotManager from "../../../../Shared/components/SlotManager";
|
||||
import SlotManagerLarge from "../../../../Shared/components/SlotManagerLarge";
|
||||
|
||||
interface Props {
|
||||
component: DataOriginBaseAction | DataOriginSpell;
|
||||
limitedUse: EntityLimitedUseContract | null;
|
||||
onUseSet?: (
|
||||
component: DataOriginBaseAction | DataOriginSpell,
|
||||
uses: number
|
||||
) => void;
|
||||
|
||||
ruleData: RuleData;
|
||||
abilityLookup: AbilityLookup;
|
||||
isInteractive: boolean;
|
||||
largeLimitedUseAmount: number;
|
||||
proficiencyBonus: number;
|
||||
theme: CharacterTheme;
|
||||
}
|
||||
export default class FeatureSnippetLimitedUse extends React.PureComponent<Props> {
|
||||
static defaultProps = {
|
||||
largeLimitedUseAmount: 8,
|
||||
};
|
||||
|
||||
handleUseSet = (uses: number): void => {
|
||||
const { onUseSet, component } = this.props;
|
||||
|
||||
if (onUseSet) {
|
||||
onUseSet(component, uses);
|
||||
}
|
||||
};
|
||||
|
||||
renderSmallAmountSlotPool = (): React.ReactNode => {
|
||||
const {
|
||||
limitedUse,
|
||||
ruleData,
|
||||
abilityLookup,
|
||||
isInteractive,
|
||||
proficiencyBonus,
|
||||
} = this.props;
|
||||
|
||||
if (!limitedUse) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const numberUsed = LimitedUseUtils.getNumberUsed(limitedUse);
|
||||
const maxUses = LimitedUseUtils.deriveMaxUses(
|
||||
limitedUse,
|
||||
abilityLookup,
|
||||
ruleData,
|
||||
proficiencyBonus
|
||||
);
|
||||
|
||||
if (!maxUses) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<SlotManager
|
||||
used={numberUsed}
|
||||
available={maxUses}
|
||||
size={"small"}
|
||||
onSet={this.handleUseSet}
|
||||
isInteractive={isInteractive}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
renderLargeAmountSlotPool = (): React.ReactNode => {
|
||||
const {
|
||||
limitedUse,
|
||||
ruleData,
|
||||
abilityLookup,
|
||||
isInteractive,
|
||||
proficiencyBonus,
|
||||
} = this.props;
|
||||
|
||||
if (!limitedUse) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const numberUsed = LimitedUseUtils.getNumberUsed(limitedUse);
|
||||
const maxUses = LimitedUseUtils.deriveMaxUses(
|
||||
limitedUse,
|
||||
abilityLookup,
|
||||
ruleData,
|
||||
proficiencyBonus
|
||||
);
|
||||
|
||||
if (!maxUses) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<SlotManagerLarge
|
||||
label="Current:"
|
||||
available={maxUses}
|
||||
used={numberUsed}
|
||||
onSet={this.handleUseSet}
|
||||
isInteractive={isInteractive}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
limitedUse,
|
||||
ruleData,
|
||||
abilityLookup,
|
||||
largeLimitedUseAmount,
|
||||
proficiencyBonus,
|
||||
theme,
|
||||
} = this.props;
|
||||
|
||||
if (!limitedUse) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let resetType = LimitedUseUtils.getResetType(limitedUse);
|
||||
let maxUses = LimitedUseUtils.deriveMaxUses(
|
||||
limitedUse,
|
||||
abilityLookup,
|
||||
ruleData,
|
||||
proficiencyBonus
|
||||
);
|
||||
let numberUsed = LimitedUseUtils.getNumberUsed(limitedUse);
|
||||
let totalSlots = Math.max(maxUses, numberUsed);
|
||||
|
||||
let usagesNode: React.ReactNode;
|
||||
let extraNode: React.ReactNode;
|
||||
if (totalSlots >= largeLimitedUseAmount) {
|
||||
usagesNode = maxUses;
|
||||
extraNode = this.renderLargeAmountSlotPool();
|
||||
} else if (maxUses === -1) {
|
||||
usagesNode = "Unlimited";
|
||||
} else {
|
||||
usagesNode = this.renderSmallAmountSlotPool();
|
||||
}
|
||||
|
||||
let resetNode: React.ReactNode;
|
||||
if (
|
||||
resetType !== Constants.LimitedUseResetTypeEnum.SHORT_REST &&
|
||||
resetType !== Constants.LimitedUseResetTypeEnum.LONG_REST
|
||||
) {
|
||||
resetNode = "Special";
|
||||
} else {
|
||||
resetNode = RuleDataUtils.getLimitedUseResetTypeName(resetType, ruleData);
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div
|
||||
className={`ct-feature-snippet__limited-use ${
|
||||
theme.isDarkMode ? "ct-feature-snippet__limited-use--dark-mode" : ""
|
||||
}`}
|
||||
>
|
||||
<div className="ct-feature-snippet__limited-use-usages">
|
||||
{usagesNode}
|
||||
</div>
|
||||
<div className="ct-feature-snippet__limited-use-sep">/</div>
|
||||
<div className="ct-feature-snippet__limited-use-reset">
|
||||
{resetNode}
|
||||
</div>
|
||||
</div>
|
||||
{extraNode && (
|
||||
<div className="ct-feature-snippet__limited-use-extra">
|
||||
{extraNode}
|
||||
</div>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import FeatureSnippetLimitedUse from "./FeatureSnippetLimitedUse";
|
||||
|
||||
export default FeatureSnippetLimitedUse;
|
||||
export { FeatureSnippetLimitedUse };
|
||||
Reference in New Issue
Block a user