nitro-v36-with-renderer-v36
/
src /
components /
wired /
views /
extras /
WiredExtraPointerVariableView.tsx
WiredExtraPointerVariableView.tsx 6.6 Ko
Télécharger le fichier
import { FC, useEffect, useMemo, useState } from 'react';
import { BaseButton } from '../../../../common/BaseButton';
import {
isPointerAccessorCandidate,
LocalizeText,
POINTER_SOURCE_CONTEXT,
POINTER_SOURCE_FURNI,
POINTER_SOURCE_GLOBAL,
POINTER_SOURCE_USER,
readPointerEditor,
WiredFurniType,
writePointerEditor
} from '../../../../api';
import contextVariableIcon from '../../../../assets/images/wired/var/icon_source_context_clean.png';
import furniVariableIcon from '../../../../assets/images/wired/var/icon_source_furni.png';
import globalVariableIcon from '../../../../assets/images/wired/var/icon_source_global.png';
import userVariableIcon from '../../../../assets/images/wired/var/icon_source_user.png';
import { Text } from '../../../../common';
import { useWired, useWiredTools } from '../../../../hooks';
import { OctaneInput } from '../../../../layout';
import { WiredVariablePicker } from '../WiredVariablePicker';
import { buildWiredVariablePickerEntries, createCustomVariableToken, getCustomVariableItemId, IWiredVariablePickerEntry } from '../WiredVariablePickerData';
import { WiredExtraBaseView } from './WiredExtraBaseView';
import { NativeTextTree } from '../../../../common/native-text/NativeTextTree';
const MAX_NAME_LENGTH = 40;
/** AIR's header source type selector: the variable list the pointer is listed in. */
const SOURCE_BUTTONS: Array<{ value: number; key: string; icon: string }> = [
{ value: POINTER_SOURCE_FURNI, key: 'furni', icon: furniVariableIcon },
{ value: POINTER_SOURCE_USER, key: 'user', icon: userVariableIcon },
{ value: POINTER_SOURCE_GLOBAL, key: 'global', icon: globalVariableIcon },
{ value: POINTER_SOURCE_CONTEXT, key: 'context', icon: contextVariableIcon }
];
const normalizeVariableName = (value: string) => {
let normalizedValue = (value ?? '').replace(/[\t\r\n]/g, '');
if(normalizedValue.includes('=')) normalizedValue = normalizedValue.substring(0, normalizedValue.indexOf('=')).trim();
while(normalizedValue.startsWith('@') || normalizedValue.startsWith('~')) normalizedValue = normalizedValue.substring(1);
normalizedValue = normalizedValue.replace(/\s+/g, '_');
normalizedValue = normalizedValue.replace(/[^A-Za-z0-9_]/g, '');
return normalizedValue.slice(0, MAX_NAME_LENGTH);
};
/**
* The official pointer variable editor (AIR `PointerVariable`): the usage note, the variable's name and the accessor,
* a context variable that holds the furni id of the pointed variable's WIRED box while a stack runs. The header
* selector picks which variable list (furni, user, global, context) the pointer is listed in.
*/
export const WiredExtraPointerVariableView: FC<{}> = () => {
const { trigger = null, setIntParams = null, setStringParam = null, setVariableIds = null } = useWired();
const { contextVariableDefinitions = [] } = useWiredTools();
const [variableName, setVariableName] = useState('');
const [sourceType, setSourceType] = useState(POINTER_SOURCE_FURNI);
const [accessorToken, setAccessorToken] = useState('');
useEffect(() => {
if(!trigger) return;
const state = readPointerEditor(trigger.intData ?? [], trigger.stringData ?? '', trigger.variableIds ?? []);
setVariableName(normalizeVariableName(state.name));
setSourceType(state.sourceType);
setAccessorToken(createCustomVariableToken(state.accessorId));
}, [trigger]);
// AIR's accessor filter: a user-made context variable with a value that needs no running stack.
const accessorEntries = useMemo(
() => buildWiredVariablePickerEntries('context', 'change-reference', contextVariableDefinitions.filter(isPointerAccessorCandidate))
.filter((entry) => entry.kind === 'custom'),
[contextVariableDefinitions]
);
const save = () => {
const data = writePointerEditor({ sourceType, name: normalizeVariableName(variableName), accessorId: getCustomVariableItemId(accessorToken) });
setIntParams(data.intParams);
setStringParam(data.stringParam);
setVariableIds(data.variableIds);
};
const validate = () => !!normalizeVariableName(variableName) && getCustomVariableItemId(accessorToken) > 0;
return (
<NativeTextTree>
<WiredExtraBaseView hasSpecialInput={true} requiresFurni={WiredFurniType.STUFF_SELECTION_OPTION_NONE} save={save} validate={validate} cardStyle={{ width: 280 }}>
<div className="flex flex-col gap-2">
<div className="octane-wired__give-var-targets" role="radiogroup">
{SOURCE_BUTTONS.map((button) => (
<BaseButton
key={button.key}
type="button"
aria-checked={sourceType === button.value}
aria-label={button.key}
role="radio"
className={`octane-wired__give-var-target octane-wired__give-var-target--${button.key} ${sourceType === button.value ? 'is-active' : ''}`}
onClick={() => setSourceType(button.value)}
>
<img src={button.icon} alt={button.key} />
</BaseButton>
))}
</div>
<Text small className="whitespace-pre-line">{LocalizeText('wiredfurni.params.variables.pointer.usage_info').replace(/\\n/g, '\n')}</Text>
<div className="flex flex-col gap-1">
<Text>{LocalizeText('wiredfurni.params.variables.variable_name')}</Text>
<OctaneInput
maxLength={MAX_NAME_LENGTH}
type="text"
value={variableName}
onChange={(event) => setVariableName(normalizeVariableName(event.target.value))}
/>
</div>
<div className="flex flex-col gap-1">
<Text>{LocalizeText('wiredfurni.params.variables.pointer.accessor')}</Text>
<WiredVariablePicker
entries={accessorEntries as IWiredVariablePickerEntry[]}
recentScope="variable-pointer"
selectedToken={accessorToken}
onSelect={(entry) => setAccessorToken(entry.token)}
onClear={() => setAccessorToken('')}
/>
</div>
</div>
</WiredExtraBaseView>
</NativeTextTree>
);
};
