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:
@@ -0,0 +1,357 @@
|
||||
import React from "react";
|
||||
|
||||
import {
|
||||
Constants,
|
||||
EntityAdjustmentConstraintContract,
|
||||
RuleData,
|
||||
RuleDataUtils,
|
||||
} from "@dndbeyond/character-rules-engine/es";
|
||||
|
||||
import {
|
||||
SIGNED_32BIT_INT_MAX_VALUE,
|
||||
SIGNED_32BIT_INT_MIN_VALUE,
|
||||
} from "~/subApps/sheet/constants";
|
||||
|
||||
import ValueEditorCheckboxProperty from "./ValueEditorCheckboxProperty";
|
||||
import ValueEditorNumberProperty from "./ValueEditorNumberProperty";
|
||||
import ValueEditorSelectProperty from "./ValueEditorSelectProperty";
|
||||
import ValueEditorTextProperty from "./ValueEditorTextProperty";
|
||||
|
||||
interface ConstraintProps {
|
||||
minimumValue?: number;
|
||||
maximumValue?: number;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
dataLookup: Partial<Record<Constants.AdjustmentTypeEnum, any>>;
|
||||
valueEditors: Array<number>; // TODO deal with enums not working with switch statement
|
||||
labelOverrides: Partial<Record<Constants.AdjustmentTypeEnum, string>>;
|
||||
optionRestrictions: Partial<Record<Constants.AdjustmentTypeEnum, Array<any>>>;
|
||||
defaultValues: Partial<Record<Constants.AdjustmentTypeEnum, any>>;
|
||||
layoutType: "standard" | "compact";
|
||||
onDataUpdate?: (
|
||||
propertyKey: Constants.AdjustmentTypeEnum,
|
||||
value: any,
|
||||
source: any
|
||||
) => void;
|
||||
ruleData: RuleData;
|
||||
className: string;
|
||||
}
|
||||
interface State {
|
||||
dataLookup: Partial<Record<Constants.AdjustmentTypeEnum, any>>;
|
||||
}
|
||||
export default class ValueEditor extends React.PureComponent<Props, State> {
|
||||
static defaultProps = {
|
||||
className: "",
|
||||
labelOverrides: {},
|
||||
optionRestrictions: {},
|
||||
defaultValues: {},
|
||||
layoutType: "standard",
|
||||
};
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = this.generateStateData(props);
|
||||
}
|
||||
|
||||
componentDidUpdate(
|
||||
prevProps: Readonly<Props>,
|
||||
prevState: Readonly<State>
|
||||
): void {
|
||||
const { dataLookup } = this.props;
|
||||
|
||||
if (dataLookup !== prevProps.dataLookup) {
|
||||
this.setState(this.generateStateData(this.props));
|
||||
}
|
||||
}
|
||||
|
||||
generateStateData = (props: Props): State => {
|
||||
const { dataLookup } = props;
|
||||
|
||||
return {
|
||||
dataLookup,
|
||||
};
|
||||
};
|
||||
|
||||
getNumberConstraintProps = (
|
||||
constraintLookup: Record<number, EntityAdjustmentConstraintContract>
|
||||
): ConstraintProps => {
|
||||
let constraintProps: ConstraintProps = {};
|
||||
if (constraintLookup[Constants.AdjustmentConstraintTypeEnum.MINIMUM]) {
|
||||
constraintProps.minimumValue = this.getConstraintValue(
|
||||
Constants.AdjustmentConstraintTypeEnum.MINIMUM,
|
||||
constraintLookup
|
||||
);
|
||||
} else {
|
||||
constraintProps.minimumValue = SIGNED_32BIT_INT_MIN_VALUE;
|
||||
}
|
||||
if (constraintLookup[Constants.AdjustmentConstraintTypeEnum.MAXIMUM]) {
|
||||
constraintProps.maximumValue = this.getConstraintValue(
|
||||
Constants.AdjustmentConstraintTypeEnum.MAXIMUM,
|
||||
constraintLookup
|
||||
);
|
||||
} else {
|
||||
constraintProps.maximumValue = SIGNED_32BIT_INT_MAX_VALUE;
|
||||
}
|
||||
return constraintProps;
|
||||
};
|
||||
|
||||
getConstraintValue = (
|
||||
constraintTypeId: Constants.AdjustmentConstraintTypeEnum,
|
||||
constraintLookup: Record<number, EntityAdjustmentConstraintContract>,
|
||||
fallback: any = null
|
||||
): any => {
|
||||
let constraint = constraintLookup[constraintTypeId];
|
||||
if (constraint) {
|
||||
return constraint.value;
|
||||
}
|
||||
return fallback;
|
||||
};
|
||||
|
||||
getPropertyValue = (key: Constants.AdjustmentTypeEnum): any => {
|
||||
const { dataLookup, defaultValues } = this.props;
|
||||
|
||||
let property = dataLookup[key];
|
||||
if (property) {
|
||||
return property.value;
|
||||
}
|
||||
|
||||
let defaultValue = defaultValues[key];
|
||||
if (defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
getPropertySource = (key: Constants.AdjustmentTypeEnum): string | null => {
|
||||
const { dataLookup } = this.state;
|
||||
let property = dataLookup[key];
|
||||
if (property) {
|
||||
return property.notes;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
restrictOptions = <T extends any>(
|
||||
key: Constants.AdjustmentTypeEnum,
|
||||
options: Array<T>
|
||||
): Array<T> => {
|
||||
const { optionRestrictions } = this.props;
|
||||
|
||||
let typeOptionRestrictions = optionRestrictions[key];
|
||||
|
||||
if (!typeOptionRestrictions || typeOptionRestrictions.length === 0) {
|
||||
return options;
|
||||
}
|
||||
|
||||
return options.filter((option) => {
|
||||
if (!typeOptionRestrictions) {
|
||||
return true;
|
||||
}
|
||||
// @ts-ignore
|
||||
return typeOptionRestrictions.includes(option.value);
|
||||
});
|
||||
};
|
||||
|
||||
handleDataUpdate = (
|
||||
key: Constants.AdjustmentTypeEnum,
|
||||
value: any,
|
||||
source: any
|
||||
): void => {
|
||||
const { onDataUpdate } = this.props;
|
||||
|
||||
this.setState((prevState: State): State => {
|
||||
let processedSource: string | null = source === "" ? null : source;
|
||||
if (
|
||||
onDataUpdate &&
|
||||
(this.getPropertyValue(key) !== value ||
|
||||
this.getPropertySource(key) !== processedSource)
|
||||
) {
|
||||
onDataUpdate(key, value, processedSource);
|
||||
}
|
||||
|
||||
return {
|
||||
...prevState,
|
||||
dataLookup: {
|
||||
...prevState.dataLookup,
|
||||
[key]: {
|
||||
value,
|
||||
notes: processedSource,
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { valueEditors, className, ruleData, labelOverrides, layoutType } =
|
||||
this.props;
|
||||
|
||||
let enableSource: boolean = layoutType === "standard";
|
||||
let layoutClass: string = layoutType === "compact" ? "compact" : "standard";
|
||||
|
||||
let classNames: Array<string> = [
|
||||
"ct-value-editor",
|
||||
`ct-value-editor--${layoutClass}`,
|
||||
className,
|
||||
];
|
||||
|
||||
return (
|
||||
<div className={classNames.join(" ")}>
|
||||
{valueEditors.map((valueTypeId) => {
|
||||
let valueDataTypeId = RuleDataUtils.getAdjustmentDataType(
|
||||
valueTypeId,
|
||||
ruleData
|
||||
);
|
||||
let constraintLookup = RuleDataUtils.getAdjustmentConstraintLookup(
|
||||
valueTypeId,
|
||||
ruleData
|
||||
);
|
||||
let valueName: string = "";
|
||||
if (labelOverrides.hasOwnProperty(valueTypeId)) {
|
||||
valueName = labelOverrides[valueTypeId];
|
||||
} else {
|
||||
let adjustmentName = RuleDataUtils.getAdjustmentName(
|
||||
valueTypeId,
|
||||
ruleData
|
||||
);
|
||||
if (adjustmentName) {
|
||||
valueName = adjustmentName;
|
||||
}
|
||||
}
|
||||
switch (valueDataTypeId) {
|
||||
case Constants.AdjustmentDataTypeEnum.STRING:
|
||||
return (
|
||||
<ValueEditorTextProperty
|
||||
key={valueTypeId}
|
||||
propertyKey={valueTypeId}
|
||||
defaultValue={this.getPropertyValue(valueTypeId)}
|
||||
label={valueName}
|
||||
onUpdate={this.handleDataUpdate}
|
||||
enableSource={enableSource}
|
||||
initialFocus={
|
||||
valueTypeId === Constants.AdjustmentTypeEnum.NAME_OVERRIDE
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
case Constants.AdjustmentDataTypeEnum.BOOLEAN:
|
||||
return (
|
||||
<ValueEditorCheckboxProperty
|
||||
key={valueTypeId}
|
||||
propertyKey={valueTypeId}
|
||||
initiallyEnabled={this.getPropertyValue(valueTypeId)}
|
||||
defaultSource={this.getPropertySource(valueTypeId)}
|
||||
label={valueName}
|
||||
onUpdate={this.handleDataUpdate}
|
||||
enableSource={enableSource}
|
||||
/>
|
||||
);
|
||||
|
||||
case Constants.AdjustmentDataTypeEnum.INTEGER:
|
||||
let baseProps = {
|
||||
key: valueTypeId,
|
||||
propertyKey: valueTypeId,
|
||||
defaultValue: this.getPropertyValue(valueTypeId),
|
||||
defaultSource: this.getPropertySource(valueTypeId),
|
||||
label: valueName,
|
||||
onUpdate: this.handleDataUpdate,
|
||||
enableSource: enableSource,
|
||||
};
|
||||
|
||||
switch (valueTypeId) {
|
||||
case Constants.AdjustmentTypeEnum.SKILL_STAT_OVERRIDE:
|
||||
return (
|
||||
<ValueEditorSelectProperty
|
||||
{...baseProps}
|
||||
options={RuleDataUtils.getStatOptions(ruleData)}
|
||||
/>
|
||||
);
|
||||
|
||||
case Constants.AdjustmentTypeEnum.DICE_TYPE_OVERRIDE:
|
||||
return (
|
||||
<ValueEditorSelectProperty
|
||||
{...baseProps}
|
||||
options={RuleDataUtils.getDieTypeOptions(ruleData)}
|
||||
/>
|
||||
);
|
||||
|
||||
case Constants.AdjustmentTypeEnum.SKILL_PROFICIENCY_LEVEL:
|
||||
case Constants.AdjustmentTypeEnum
|
||||
.SAVING_THROW_PROFICIENCY_LEVEL:
|
||||
return (
|
||||
<ValueEditorSelectProperty
|
||||
{...baseProps}
|
||||
options={RuleDataUtils.getProficiencyLevelOptions(
|
||||
ruleData
|
||||
)}
|
||||
/>
|
||||
);
|
||||
|
||||
case Constants.AdjustmentTypeEnum.CREATURE_ALIGNMENT:
|
||||
return (
|
||||
<ValueEditorSelectProperty
|
||||
{...baseProps}
|
||||
options={RuleDataUtils.getAlignmentOptions(ruleData)}
|
||||
/>
|
||||
);
|
||||
|
||||
case Constants.AdjustmentTypeEnum.CREATURE_SIZE:
|
||||
return (
|
||||
<ValueEditorSelectProperty
|
||||
{...baseProps}
|
||||
options={RuleDataUtils.getCreatureSizeOptions(ruleData)}
|
||||
/>
|
||||
);
|
||||
|
||||
case Constants.AdjustmentTypeEnum.CREATURE_TYPE_OVERRIDE:
|
||||
return (
|
||||
<ValueEditorSelectProperty
|
||||
{...baseProps}
|
||||
options={this.restrictOptions(
|
||||
valueTypeId,
|
||||
RuleDataUtils.getMonsterTypeOptions(ruleData)
|
||||
)}
|
||||
/>
|
||||
);
|
||||
|
||||
default:
|
||||
let constraintProps =
|
||||
this.getNumberConstraintProps(constraintLookup);
|
||||
return (
|
||||
<ValueEditorNumberProperty
|
||||
{...baseProps}
|
||||
{...constraintProps}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
case Constants.AdjustmentDataTypeEnum.DECIMAL:
|
||||
let constraintProps =
|
||||
this.getNumberConstraintProps(constraintLookup);
|
||||
return (
|
||||
<ValueEditorNumberProperty
|
||||
key={valueTypeId}
|
||||
step={0.01}
|
||||
propertyKey={valueTypeId}
|
||||
defaultValue={this.getPropertyValue(valueTypeId)}
|
||||
defaultSource={this.getPropertySource(valueTypeId)}
|
||||
label={valueName}
|
||||
onUpdate={this.handleDataUpdate}
|
||||
enableSource={enableSource}
|
||||
{...constraintProps}
|
||||
/>
|
||||
);
|
||||
|
||||
default:
|
||||
// not implemented
|
||||
}
|
||||
|
||||
return null;
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
import React from "react";
|
||||
|
||||
import { Checkbox } from "@dndbeyond/character-components/es";
|
||||
import { Constants } from "@dndbeyond/character-rules-engine/es";
|
||||
|
||||
import ValueEditorProperty from "../ValueEditorProperty";
|
||||
import ValueEditorPropertySource from "../ValueEditorPropertySource";
|
||||
import ValueEditorPropertyValue from "../ValueEditorPropertyValue";
|
||||
|
||||
interface Props {
|
||||
label: string;
|
||||
propertyKey: Constants.AdjustmentTypeEnum;
|
||||
initiallyEnabled: boolean;
|
||||
defaultSource: string | null;
|
||||
onUpdate?: (
|
||||
propertyKey: Constants.AdjustmentTypeEnum,
|
||||
isEnabled: boolean,
|
||||
source: string | null
|
||||
) => void;
|
||||
enableSource: boolean;
|
||||
}
|
||||
interface State {
|
||||
value: boolean;
|
||||
source: string | null;
|
||||
}
|
||||
export default class ValueEditorCheckboxProperty extends React.PureComponent<
|
||||
Props,
|
||||
State
|
||||
> {
|
||||
static defaultProps = {
|
||||
enableSource: true,
|
||||
};
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
value: props.initiallyEnabled,
|
||||
source: props.defaultSource,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidUpdate(
|
||||
prevProps: Readonly<Props>,
|
||||
prevState: Readonly<State>
|
||||
): void {
|
||||
const { initiallyEnabled } = this.props;
|
||||
const { value } = this.state;
|
||||
|
||||
if (
|
||||
initiallyEnabled !== prevProps.initiallyEnabled &&
|
||||
initiallyEnabled !== value
|
||||
) {
|
||||
this.setState({
|
||||
value: initiallyEnabled,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleChange = (isEnabled: boolean): void => {
|
||||
const { source } = this.state;
|
||||
const { propertyKey, onUpdate } = this.props;
|
||||
|
||||
if (onUpdate) {
|
||||
onUpdate(propertyKey, isEnabled, source);
|
||||
}
|
||||
};
|
||||
|
||||
handleSourceUpdate = (source: string | null): void => {
|
||||
const { value } = this.state;
|
||||
const { propertyKey, onUpdate } = this.props;
|
||||
|
||||
if (onUpdate) {
|
||||
onUpdate(propertyKey, value, source);
|
||||
}
|
||||
this.setState({
|
||||
source,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
propertyKey,
|
||||
label,
|
||||
initiallyEnabled,
|
||||
defaultSource,
|
||||
enableSource,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<ValueEditorProperty
|
||||
className="ct-value-editor__property--checkbox"
|
||||
propertyKey={propertyKey}
|
||||
>
|
||||
<ValueEditorPropertyValue>
|
||||
<Checkbox
|
||||
stopPropagation={true}
|
||||
label={label}
|
||||
initiallyEnabled={initiallyEnabled}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
</ValueEditorPropertyValue>
|
||||
{enableSource && (
|
||||
<ValueEditorPropertySource
|
||||
onUpdate={this.handleSourceUpdate}
|
||||
defaultValue={defaultSource}
|
||||
/>
|
||||
)}
|
||||
</ValueEditorProperty>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import ValueEditorCheckboxProperty from "./ValueEditorCheckboxProperty";
|
||||
|
||||
export default ValueEditorCheckboxProperty;
|
||||
export { ValueEditorCheckboxProperty };
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
import React from "react";
|
||||
|
||||
import { Constants, HelperUtils } from "@dndbeyond/character-rules-engine/es";
|
||||
|
||||
import ValueEditorProperty from "../ValueEditorProperty";
|
||||
import ValueEditorPropertyLabel from "../ValueEditorPropertyLabel";
|
||||
import ValueEditorPropertySource from "../ValueEditorPropertySource";
|
||||
import ValueEditorPropertyValue from "../ValueEditorPropertyValue";
|
||||
|
||||
interface Props {
|
||||
label: string;
|
||||
propertyKey: Constants.AdjustmentTypeEnum;
|
||||
defaultValue: number | null;
|
||||
defaultSource: string | null;
|
||||
minimumValue?: number;
|
||||
maximumValue?: number;
|
||||
onUpdate?: (
|
||||
propertyKey: Constants.AdjustmentTypeEnum,
|
||||
value: number | null,
|
||||
source: string | null
|
||||
) => void;
|
||||
enableSource: boolean;
|
||||
step: number;
|
||||
}
|
||||
interface State {
|
||||
value: number | null;
|
||||
source: string | null;
|
||||
}
|
||||
export default class ValueEditorNumberProperty extends React.PureComponent<
|
||||
Props,
|
||||
State
|
||||
> {
|
||||
static defaultProps = {
|
||||
enableSource: true,
|
||||
step: 1,
|
||||
};
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
value: props.defaultValue,
|
||||
source: props.defaultSource,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidUpdate(
|
||||
prevProps: Readonly<Props>,
|
||||
prevState: Readonly<State>
|
||||
): void {
|
||||
const { defaultValue } = this.props;
|
||||
const { value } = this.state;
|
||||
|
||||
if (defaultValue !== prevProps.defaultValue && defaultValue !== value) {
|
||||
this.setState({
|
||||
value: defaultValue,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getDataValue = (value: number | null): number | null => {
|
||||
const { minimumValue, maximumValue } = this.props;
|
||||
|
||||
if (value === null) {
|
||||
return null;
|
||||
}
|
||||
return HelperUtils.clampInt(
|
||||
value,
|
||||
minimumValue ? minimumValue : null,
|
||||
maximumValue
|
||||
);
|
||||
};
|
||||
|
||||
handleBlur = (evt: React.FocusEvent<HTMLInputElement>): void => {
|
||||
const { source } = this.state;
|
||||
const { propertyKey, onUpdate, step } = this.props;
|
||||
|
||||
let newValue = this.getDataValue(
|
||||
step < 1
|
||||
? HelperUtils.parseInputFloat(evt.target.value)
|
||||
: HelperUtils.parseInputInt(evt.target.value)
|
||||
);
|
||||
if (onUpdate) {
|
||||
onUpdate(propertyKey, newValue, source);
|
||||
}
|
||||
this.setState({
|
||||
value: newValue,
|
||||
});
|
||||
};
|
||||
|
||||
handleChange = (evt: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
const { step } = this.props;
|
||||
this.setState({
|
||||
value:
|
||||
step < 1
|
||||
? HelperUtils.parseInputFloat(evt.target.value)
|
||||
: HelperUtils.parseInputInt(evt.target.value),
|
||||
});
|
||||
};
|
||||
|
||||
handleSourceUpdate = (source: string | null): void => {
|
||||
const { value } = this.state;
|
||||
const { propertyKey, onUpdate } = this.props;
|
||||
|
||||
if (onUpdate) {
|
||||
onUpdate(propertyKey, this.getDataValue(value), source);
|
||||
}
|
||||
this.setState({
|
||||
source,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { value } = this.state;
|
||||
const {
|
||||
propertyKey,
|
||||
label,
|
||||
minimumValue,
|
||||
maximumValue,
|
||||
defaultSource,
|
||||
enableSource,
|
||||
step,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<ValueEditorProperty
|
||||
className="ct-value-editor__property--number"
|
||||
propertyKey={propertyKey}
|
||||
>
|
||||
<ValueEditorPropertyLabel>{label}</ValueEditorPropertyLabel>
|
||||
<ValueEditorPropertyValue>
|
||||
<input
|
||||
className="ct-value-editor__property-input"
|
||||
type="number"
|
||||
min={minimumValue}
|
||||
max={maximumValue}
|
||||
step={step}
|
||||
value={value === null ? "" : value}
|
||||
onBlur={this.handleBlur}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
</ValueEditorPropertyValue>
|
||||
{enableSource && (
|
||||
<ValueEditorPropertySource
|
||||
onUpdate={this.handleSourceUpdate}
|
||||
defaultValue={defaultSource}
|
||||
/>
|
||||
)}
|
||||
</ValueEditorProperty>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import ValueEditorNumberProperty from "./ValueEditorNumberProperty";
|
||||
|
||||
export default ValueEditorNumberProperty;
|
||||
export { ValueEditorNumberProperty };
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
import React from "react";
|
||||
|
||||
interface Props {
|
||||
isBlock: boolean;
|
||||
propertyKey: number;
|
||||
className: string;
|
||||
}
|
||||
export default class ValueEditorProperty extends React.PureComponent<Props> {
|
||||
static defaultProps = {
|
||||
isBlock: false,
|
||||
className: "",
|
||||
};
|
||||
|
||||
render() {
|
||||
const { className, isBlock, propertyKey } = this.props;
|
||||
|
||||
let classNames: Array<string> = [
|
||||
className,
|
||||
"ct-value-editor__property",
|
||||
`ct-value-editor__property--${propertyKey}`,
|
||||
];
|
||||
if (isBlock) {
|
||||
classNames.push("ct-value-editor__property--block");
|
||||
}
|
||||
|
||||
return <div className={classNames.join(" ")}>{this.props.children}</div>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import ValueEditorProperty from "./ValueEditorProperty";
|
||||
|
||||
export default ValueEditorProperty;
|
||||
export { ValueEditorProperty };
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import React from "react";
|
||||
|
||||
export default class ValueEditorPropertyLabel extends React.PureComponent {
|
||||
render() {
|
||||
return (
|
||||
<div className="ct-value-editor__property-label">
|
||||
{this.props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import ValueEditorPropertyLabel from "./ValueEditorPropertyLabel";
|
||||
|
||||
export default ValueEditorPropertyLabel;
|
||||
export { ValueEditorPropertyLabel };
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
import React from "react";
|
||||
|
||||
interface Props {
|
||||
defaultValue: string | null;
|
||||
placeholder: string;
|
||||
onUpdate?: (value: string) => void;
|
||||
}
|
||||
interface State {
|
||||
value: string | null;
|
||||
}
|
||||
export default class ValueEditorPropertySource extends React.PureComponent<
|
||||
Props,
|
||||
State
|
||||
> {
|
||||
static defaultProps = {
|
||||
placeholder: "Enter Source Notes...",
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
value: props.defaultValue,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidUpdate(
|
||||
prevProps: Readonly<Props>,
|
||||
prevState: Readonly<State>
|
||||
): void {
|
||||
const { defaultValue } = this.props;
|
||||
const { value } = this.state;
|
||||
|
||||
if (defaultValue !== prevProps.defaultValue && defaultValue !== value) {
|
||||
this.setState({
|
||||
value: defaultValue,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleChange = (evt: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
this.setState({
|
||||
value: evt.target.value,
|
||||
});
|
||||
};
|
||||
|
||||
handleBlur = (evt: React.FocusEvent<HTMLInputElement>): void => {
|
||||
const { onUpdate } = this.props;
|
||||
|
||||
let value = evt.target.value;
|
||||
if (onUpdate) {
|
||||
onUpdate(value);
|
||||
}
|
||||
this.setState({
|
||||
value,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { value } = this.state;
|
||||
const { placeholder } = this.props;
|
||||
|
||||
return (
|
||||
<div className="ct-value-editor__property-source">
|
||||
<input
|
||||
className="ct-value-editor__property-input"
|
||||
type="text"
|
||||
placeholder={placeholder}
|
||||
onChange={this.handleChange}
|
||||
onBlur={this.handleBlur}
|
||||
value={value === null ? "" : value}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import ValueEditorPropertySource from "./ValueEditorPropertySource";
|
||||
|
||||
export default ValueEditorPropertySource;
|
||||
export { ValueEditorPropertySource };
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import React from "react";
|
||||
|
||||
export default class ValueEditorPropertyValue extends React.PureComponent {
|
||||
render() {
|
||||
return (
|
||||
<div className="ct-value-editor__property-value">
|
||||
{this.props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import ValueEditorPropertyValue from "./ValueEditorPropertyValue";
|
||||
|
||||
export default ValueEditorPropertyValue;
|
||||
export { ValueEditorPropertyValue };
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
import React from "react";
|
||||
|
||||
import { Select } from "@dndbeyond/character-components/es";
|
||||
import { HelperUtils, Constants } from "@dndbeyond/character-rules-engine/es";
|
||||
|
||||
import ValueEditorProperty from "../ValueEditorProperty";
|
||||
import ValueEditorPropertyLabel from "../ValueEditorPropertyLabel";
|
||||
import ValueEditorPropertySource from "../ValueEditorPropertySource";
|
||||
import ValueEditorPropertyValue from "../ValueEditorPropertyValue";
|
||||
|
||||
interface Props {
|
||||
label: string;
|
||||
propertyKey: Constants.AdjustmentTypeEnum;
|
||||
defaultValue: number | null;
|
||||
defaultSource: string | null;
|
||||
options: Array<any>; // TODO figure out type
|
||||
selectProps: any; // TODO use Partial<Select.props> somehow
|
||||
onUpdate?: (
|
||||
propertyKey: Constants.AdjustmentTypeEnum,
|
||||
value: number | null,
|
||||
source: string | null
|
||||
) => void;
|
||||
enableSource: boolean;
|
||||
}
|
||||
interface State {
|
||||
value: number | null;
|
||||
source: string | null;
|
||||
}
|
||||
export default class ValueEditorSelectProperty extends React.PureComponent<
|
||||
Props,
|
||||
State
|
||||
> {
|
||||
static defaultProps = {
|
||||
selectProps: {},
|
||||
enableSource: true,
|
||||
};
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
value: props.defaultValue,
|
||||
source: props.defaultSource,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidUpdate(
|
||||
prevProps: Readonly<Props>,
|
||||
prevState: Readonly<State>
|
||||
): void {
|
||||
const { defaultValue } = this.props;
|
||||
const { value } = this.state;
|
||||
|
||||
if (defaultValue !== prevProps.defaultValue && defaultValue !== value) {
|
||||
this.setState({
|
||||
value: defaultValue,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleSelectChange = (value: string): void => {
|
||||
const { source } = this.state;
|
||||
const { propertyKey, onUpdate } = this.props;
|
||||
|
||||
let parsedValue = HelperUtils.parseInputInt(value);
|
||||
|
||||
if (onUpdate) {
|
||||
onUpdate(propertyKey, parsedValue, source);
|
||||
}
|
||||
this.setState({
|
||||
value: parsedValue,
|
||||
});
|
||||
};
|
||||
|
||||
handleSourceUpdate = (source: string | null): void => {
|
||||
const { value } = this.state;
|
||||
const { propertyKey, onUpdate } = this.props;
|
||||
|
||||
if (onUpdate) {
|
||||
onUpdate(propertyKey, value, source);
|
||||
}
|
||||
this.setState({
|
||||
source,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { value } = this.state;
|
||||
const {
|
||||
propertyKey,
|
||||
label,
|
||||
options,
|
||||
selectProps,
|
||||
defaultSource,
|
||||
enableSource,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<ValueEditorProperty
|
||||
className="ct-value-editor__property--select"
|
||||
propertyKey={propertyKey}
|
||||
>
|
||||
<ValueEditorPropertyLabel>{label}</ValueEditorPropertyLabel>
|
||||
<ValueEditorPropertyValue>
|
||||
<Select
|
||||
placeholder="--"
|
||||
{...selectProps}
|
||||
options={options}
|
||||
value={value}
|
||||
onChange={this.handleSelectChange}
|
||||
/>
|
||||
</ValueEditorPropertyValue>
|
||||
{enableSource && (
|
||||
<ValueEditorPropertySource
|
||||
onUpdate={this.handleSourceUpdate}
|
||||
defaultValue={defaultSource}
|
||||
/>
|
||||
)}
|
||||
</ValueEditorProperty>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import ValueEditorSelectProperty from "./ValueEditorSelectProperty";
|
||||
|
||||
export default ValueEditorSelectProperty;
|
||||
export { ValueEditorSelectProperty };
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
import React from "react";
|
||||
|
||||
import { Constants } from "@dndbeyond/character-rules-engine/es";
|
||||
|
||||
import ValueEditorProperty from "../ValueEditorProperty";
|
||||
import ValueEditorPropertyLabel from "../ValueEditorPropertyLabel";
|
||||
import ValueEditorPropertyValue from "../ValueEditorPropertyValue";
|
||||
|
||||
interface Props {
|
||||
label: string;
|
||||
propertyKey: Constants.AdjustmentTypeEnum;
|
||||
defaultValue: string | null;
|
||||
onUpdate?: (
|
||||
propertyKey: Constants.AdjustmentTypeEnum,
|
||||
value: string | null,
|
||||
source: string | null
|
||||
) => void;
|
||||
enableSource: boolean;
|
||||
initialFocus?: boolean;
|
||||
}
|
||||
interface State {
|
||||
value: string | null;
|
||||
}
|
||||
export default class ValueEditorTextProperty extends React.PureComponent<
|
||||
Props,
|
||||
State
|
||||
> {
|
||||
static defaultProps = {
|
||||
enableSource: true,
|
||||
};
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
value: props.defaultValue,
|
||||
};
|
||||
}
|
||||
inputRef = React.createRef<HTMLInputElement>();
|
||||
|
||||
componentDidMount() {
|
||||
if (this.inputRef.current && this.props.initialFocus) {
|
||||
this.inputRef.current.focus();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(
|
||||
prevProps: Readonly<Props>,
|
||||
prevState: Readonly<State>
|
||||
): void {
|
||||
const { defaultValue } = this.props;
|
||||
const { value } = this.state;
|
||||
|
||||
if (defaultValue !== prevProps.defaultValue && defaultValue !== value) {
|
||||
this.setState({
|
||||
value: defaultValue,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleBlur = (evt: React.FocusEvent<HTMLInputElement>): void => {
|
||||
const { propertyKey, onUpdate } = this.props;
|
||||
|
||||
if (onUpdate) {
|
||||
let value: string | null = evt.target.value ? evt.target.value : null;
|
||||
onUpdate(propertyKey, value, null);
|
||||
}
|
||||
};
|
||||
|
||||
handleChange = (evt: React.FocusEvent<HTMLInputElement>): void => {
|
||||
const { value } = this.state;
|
||||
|
||||
if (value !== evt.target.value) {
|
||||
this.setState({
|
||||
value: evt.target.value,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { propertyKey, label } = this.props;
|
||||
|
||||
const { value } = this.state;
|
||||
|
||||
return (
|
||||
<ValueEditorProperty
|
||||
className="ct-value-editor__property--text"
|
||||
propertyKey={propertyKey}
|
||||
isBlock={true}
|
||||
>
|
||||
<ValueEditorPropertyValue>
|
||||
<input
|
||||
type="text"
|
||||
value={value === null ? "" : value}
|
||||
onBlur={this.handleBlur}
|
||||
onChange={this.handleChange}
|
||||
className="ct-value-editor__property-input"
|
||||
ref={this.inputRef}
|
||||
/>
|
||||
</ValueEditorPropertyValue>
|
||||
<ValueEditorPropertyLabel>{label}</ValueEditorPropertyLabel>
|
||||
</ValueEditorProperty>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import ValueEditorTextProperty from "./ValueEditorTextProperty";
|
||||
|
||||
export default ValueEditorTextProperty;
|
||||
export { ValueEditorTextProperty };
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
import React from "react";
|
||||
|
||||
import { Constants } from "@dndbeyond/character-rules-engine/es";
|
||||
|
||||
import ValueEditorProperty from "../ValueEditorProperty";
|
||||
import ValueEditorPropertyLabel from "../ValueEditorPropertyLabel";
|
||||
import ValueEditorPropertyValue from "../ValueEditorPropertyValue";
|
||||
|
||||
interface Props {
|
||||
label: string;
|
||||
propertyKey: Constants.AdjustmentTypeEnum;
|
||||
defaultValue: string | null;
|
||||
onUpdate?: (
|
||||
propertyKey: Constants.AdjustmentTypeEnum,
|
||||
value: string | null,
|
||||
source: string | null
|
||||
) => void;
|
||||
enableSource: boolean;
|
||||
}
|
||||
interface State {
|
||||
value: string | null;
|
||||
}
|
||||
export default class ValueEditorTextareaProperty extends React.PureComponent<
|
||||
Props,
|
||||
State
|
||||
> {
|
||||
static defaultProps = {
|
||||
enableSource: true,
|
||||
};
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
value: props.defaultValue,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidUpdate(
|
||||
prevProps: Readonly<Props>,
|
||||
prevState: Readonly<State>
|
||||
): void {
|
||||
const { defaultValue } = this.props;
|
||||
const { value } = this.state;
|
||||
|
||||
if (defaultValue !== prevProps.defaultValue && defaultValue !== value) {
|
||||
this.setState({
|
||||
value: defaultValue,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleChange = (evt: React.FocusEvent<HTMLTextAreaElement>): void => {
|
||||
const { value } = this.state;
|
||||
|
||||
if (value !== evt.target.value) {
|
||||
this.setState({
|
||||
value: evt.target.value,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
handleBlur = (evt: React.FocusEvent<HTMLTextAreaElement>): void => {
|
||||
const { propertyKey, onUpdate } = this.props;
|
||||
|
||||
if (onUpdate) {
|
||||
let value: string | null = evt.target.value ? evt.target.value : null;
|
||||
onUpdate(propertyKey, value, null);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { propertyKey, label } = this.props;
|
||||
|
||||
const { value } = this.state;
|
||||
|
||||
return (
|
||||
<ValueEditorProperty
|
||||
className="ct-value-editor__property--textarea"
|
||||
propertyKey={propertyKey}
|
||||
isBlock={true}
|
||||
>
|
||||
<ValueEditorPropertyLabel>{label}</ValueEditorPropertyLabel>
|
||||
<ValueEditorPropertyValue>
|
||||
<textarea
|
||||
className="ct-value-editor__property-input"
|
||||
value={value === null ? "" : value}
|
||||
onBlur={this.handleBlur}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
</ValueEditorPropertyValue>
|
||||
</ValueEditorProperty>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import ValueEditorTextareaProperty from "./ValueEditorTextareaProperty";
|
||||
|
||||
export default ValueEditorTextareaProperty;
|
||||
export { ValueEditorTextareaProperty };
|
||||
@@ -0,0 +1,24 @@
|
||||
import ValueEditor from "./ValueEditor";
|
||||
import ValueEditorCheckboxProperty from "./ValueEditorCheckboxProperty";
|
||||
import ValueEditorNumberProperty from "./ValueEditorNumberProperty";
|
||||
import ValueEditorProperty from "./ValueEditorProperty";
|
||||
import ValueEditorPropertyLabel from "./ValueEditorPropertyLabel";
|
||||
import ValueEditorPropertySource from "./ValueEditorPropertySource";
|
||||
import ValueEditorPropertyValue from "./ValueEditorPropertyValue";
|
||||
import ValueEditorSelectProperty from "./ValueEditorSelectProperty";
|
||||
import ValueEditorTextProperty from "./ValueEditorTextProperty";
|
||||
import ValueEditorTextareaProperty from "./ValueEditorTextareaProperty";
|
||||
|
||||
export default ValueEditor;
|
||||
export {
|
||||
ValueEditor,
|
||||
ValueEditorCheckboxProperty,
|
||||
ValueEditorNumberProperty,
|
||||
ValueEditorProperty,
|
||||
ValueEditorPropertyLabel,
|
||||
ValueEditorPropertySource,
|
||||
ValueEditorPropertyValue,
|
||||
ValueEditorSelectProperty,
|
||||
ValueEditorTextareaProperty,
|
||||
ValueEditorTextProperty,
|
||||
};
|
||||
Reference in New Issue
Block a user