New source found from dndbeyond.com

This commit is contained in:
2025-07-16 01:00:16 -07:00
parent 151590af7a
commit f9f8dd0e7a
25 changed files with 886 additions and 1299 deletions
@@ -0,0 +1,193 @@
import { FC, HTMLAttributes, useContext } from "react";
import { useDispatch, useSelector } from "react-redux";
import {
Action,
ActionUtils,
characterActions,
FeatManager,
HelperUtils,
RaceUtils,
RacialTrait,
RacialTraitUtils,
Spell,
SpellUtils,
} from "@dndbeyond/character-rules-engine";
import { FeatureChoices } from "~/components/FeatureChoices";
import { useSidebar } from "~/contexts/Sidebar";
import { useCharacterEngine } from "~/hooks/useCharacterEngine";
import { Header } from "~/subApps/sheet/components/Sidebar/components/Header";
import { Preview } from "~/subApps/sheet/components/Sidebar/components/Preview";
import {
PaneComponentEnum,
PaneIdentifiersRacialTrait,
} from "~/subApps/sheet/components/Sidebar/types";
import { SpeciesTraitFeatureSnippet } from "~/tools/js/CharacterSheet/components/FeatureSnippet";
import { CharacterFeaturesManagerContext } from "~/tools/js/Shared/managers/CharacterFeaturesManagerContext";
import { appEnvSelectors } from "~/tools/js/Shared/selectors";
import { PaneIdentifierUtils } from "~/tools/js/Shared/utils";
import { PaneInitFailureContent } from "../../components/PaneInitFailureContent";
interface Props extends HTMLAttributes<HTMLDivElement> {
identifiers: PaneIdentifiersRacialTrait | null;
}
export const SpeciesTraitPane: FC<Props> = ({ identifiers, ...props }) => {
const dispatch = useDispatch();
const {
race: species,
feats,
snippetData,
ruleData,
abilityLookup,
originRef: dataOriginRefData,
proficiencyBonus,
characterTheme: theme,
} = useCharacterEngine();
const { characterFeaturesManager } = useContext(
CharacterFeaturesManagerContext
);
const isReadonly = useSelector(appEnvSelectors.getIsReadonly);
const {
pane: { paneHistoryPush, paneHistoryStart },
} = useSidebar();
const speciesTrait = species
? RaceUtils.getVisibleRacialTraits(species).find(
(trait) => identifiers?.id === RacialTraitUtils.getId(trait)
)
: null;
const handleActionUseSet = (action: Action, uses: number): void => {
const id = ActionUtils.getId(action);
const entityTypeId = ActionUtils.getEntityTypeId(action);
if (id !== null && entityTypeId !== null) {
dispatch(
characterActions.actionUseSet(
id,
entityTypeId,
uses,
ActionUtils.getDataOriginType(action)
)
);
}
};
const handleSpellUseSet = (spell: Spell, uses: number): void => {
const mappingId = SpellUtils.getMappingId(spell);
const mappingEntityTypeId = SpellUtils.getMappingEntityTypeId(spell);
if (mappingId !== null && mappingEntityTypeId !== null) {
dispatch(
characterActions.spellUseSet(
mappingId,
mappingEntityTypeId,
uses,
SpellUtils.getDataOriginType(spell)
)
);
}
};
const handleSpellDetailShow = (spell: Spell): void => {
const mappingId = SpellUtils.getMappingId(spell);
if (mappingId !== null) {
paneHistoryPush(
PaneComponentEnum.CHARACTER_SPELL_DETAIL,
PaneIdentifierUtils.generateCharacterSpell(mappingId)
);
}
};
const handleSpeciesTraitShow = (speciesTrait: RacialTrait): void => {
paneHistoryStart(
PaneComponentEnum.SPECIES_TRAIT_DETAIL,
PaneIdentifierUtils.generateRacialTrait(
RacialTraitUtils.getId(speciesTrait)
)
);
};
const handleActionShow = (action: Action): void => {
const mappingId = ActionUtils.getMappingId(action);
const mappingEntityTypeId = ActionUtils.getMappingEntityTypeId(action);
if (mappingId !== null && mappingEntityTypeId !== null) {
paneHistoryPush(
PaneComponentEnum.ACTION,
PaneIdentifierUtils.generateAction(mappingId, mappingEntityTypeId)
);
}
};
const handleFeatShow = (feat: FeatManager): void => {
paneHistoryPush(
PaneComponentEnum.FEAT_DETAIL,
PaneIdentifierUtils.generateFeat(feat.getId())
);
};
const handleChoiceChange = (
choiceId: string,
type: number,
value: any
): void => {
if (!species || !speciesTrait) {
return;
}
dispatch(
characterActions.racialTraitChoiceSetRequest(
RacialTraitUtils.getId(speciesTrait),
type,
choiceId,
HelperUtils.parseInputInt(value)
)
);
};
if (species === null || !speciesTrait) {
return <PaneInitFailureContent />;
}
const portrait = RaceUtils.getPortraitAvatarUrl(species);
return (
<div key={RacialTraitUtils.getId(speciesTrait)} {...props}>
<Header
parent={RaceUtils.getFullName(species)}
preview={portrait && <Preview imageUrl={portrait} />}
>
{RacialTraitUtils.getName(speciesTrait)}
</Header>
<SpeciesTraitFeatureSnippet
speciesTrait={speciesTrait}
onActionUseSet={handleActionUseSet}
onActionClick={handleActionShow}
onSpellUseSet={handleSpellUseSet}
onSpellClick={handleSpellDetailShow}
onFeatureClick={handleSpeciesTraitShow}
showHeader={false}
showDescription={true}
feats={feats}
snippetData={snippetData}
ruleData={ruleData}
abilityLookup={abilityLookup}
dataOriginRefData={dataOriginRefData}
isReadonly={isReadonly}
proficiencyBonus={proficiencyBonus}
theme={theme}
onFeatClick={handleFeatShow}
featuresManager={characterFeaturesManager}
/>
<FeatureChoices
choices={RacialTraitUtils.getChoices(speciesTrait)}
onChoiceChange={handleChoiceChange}
collapseDescription={true}
showHeading={true}
/>
</div>
);
};