5180 fichiers 38.5 Mo 0 téléchargements 290 vues mis à jour il y a 6 heures ui
nitro-v36-with-renderer-v36 / src / components / wired / views / WiredValueOrVariableField.tsx
WiredValueOrVariableField.tsx 9.9 Ko Télécharger le fichier
import { FC, useMemo } from 'react';
import { NativeTextTree } from '../../../common/native-text/NativeTextTree';
import { useWired, useWiredTools } from '../../../hooks';
import { WiredFurniSelectionSourceRow } from './WiredFurniSelectionSourceRow';
import { sortWiredSourceOptions, useAvailableUserSources, WiredSourceOption } from './WiredSourcesSelector';
import { WiredValueOrVariableInput } from './WiredValueOrVariableInput';
import {
    buildWiredVariablePickerEntries,
    createCustomVariableToken,
    createFallbackVariableEntry,
    flattenWiredVariablePickerEntries,
    IWiredVariableDefinitionLike,
    IWiredVariablePickerEntry,
    isCustomVariableToken,
    WiredVariablePickerTarget,
    WiredVariablePickerUsage
} from './WiredVariablePickerData';

/** Where an official value variable is read, with the official variable target ids. */
export const WIRED_VALUE_TARGETS: Array<{ key: WiredVariablePickerTarget; value: number }> = [
    { key: 'furni', value: 0 },
    { key: 'user', value: 1 },
    { key: 'global', value: -10 },
    { key: 'context', value: -20 }
];

export const WIRED_VALUE_TARGET_FURNI = 0;
export const WIRED_VALUE_TARGET_USER = 1;
export const WIRED_VALUE_TARGET_GLOBAL = -10;
export const WIRED_VALUE_TARGET_CONTEXT = -20;

export const normalizeWiredValueTarget = (value: number) => (WIRED_VALUE_TARGETS.some((target) => target.value === value) ? value : 0);

export const wiredValueTargetKey = (value: number): WiredVariablePickerTarget => WIRED_VALUE_TARGETS.find((target) => target.value === value)?.key ?? 'furni';

export const wiredValueTargetValue = (key: WiredVariablePickerTarget): number => WIRED_VALUE_TARGETS.find((target) => target.key === key)?.value ?? 0;

const VALUE_FURNI_SOURCES = sortWiredSourceOptions(
    [
        { value: 0, label: 'wiredfurni.params.sources.furni.0' },
        { value: 200, label: 'wiredfurni.params.sources.furni.200' },
        { value: 201, label: 'wiredfurni.params.sources.furni.201' }
    ],
    'furni'
);

const VALUE_USER_SOURCES = sortWiredSourceOptions(
    [
        { value: 0, label: 'wiredfurni.params.sources.users.0' },
        { value: 11, label: 'wiredfurni.params.sources.users.11' },
        { value: 200, label: 'wiredfurni.params.sources.users.200' },
        { value: 201, label: 'wiredfurni.params.sources.users.201' }
    ],
    'users'
);

/** A room or context holder has one fixed source (AIR InputSourceControlPreset for a custom source type). */
export const WIRED_GLOBAL_HOLDER_SOURCES: WiredSourceOption[] = [{ value: 0, label: 'wiredfurni.params.sources.global' }];
export const WIRED_CONTEXT_HOLDER_SOURCES: WiredSourceOption[] = [{ value: 0, label: 'wiredfurni.params.sources.context' }];

/** The server gives and reads only variables made in the room (custom), not internal ones. */
const customOnly = (entries: IWiredVariablePickerEntry[]): IWiredVariablePickerEntry[] =>
    entries.flatMap((entry) => {
        if (entry.children?.length) {
            const children = customOnly(entry.children);

            return children.length ? [{ ...entry, children }] : [];
        }

        return isCustomVariableToken(entry.token) ? [entry] : [];
    });

/** Picker entries of the room's own variables, keeping a saved one that is gone. */
export const customVariablePickerEntries = (target: WiredVariablePickerTarget, usage: WiredVariablePickerUsage, definitions: IWiredVariableDefinitionLike[], token: string) => {
    const entries = customOnly(buildWiredVariablePickerEntries(target, usage, definitions));

    if (!token || flattenWiredVariablePickerEntries(entries).some((entry) => entry.token === token)) return entries;

    const fallback = createFallbackVariableEntry(target, token);

    return fallback ? [fallback, ...entries] : entries;
};

/** A box variable's token from the id the server sends: a bare box id, or the variable list's `<target>:<box id>`. */
export const variableTokenFromId = (text: string) => {
    const value = (text ?? '').trim();
    const listed = /^(?:user|furni|room|ctx|custom):(\d{1,10})$/.exec(value);
    const id = listed ? parseInt(listed[1], 10) : parseInt(value, 10);

    return id > 0 ? createCustomVariableToken(id) : '';
};

/** The room's own variables with a value on one holder type: what a value section can read. */
export const useWiredValueVariableEntries = (target: WiredVariablePickerTarget, token: string) => {
    const { userVariableDefinitions = [], furniVariableDefinitions = [], roomVariableDefinitions = [], contextVariableDefinitions = [] } = useWiredTools();

    return useMemo(() => {
        const definitions = { furni: furniVariableDefinitions, user: userVariableDefinitions, global: roomVariableDefinitions, context: contextVariableDefinitions }[target];

        return customVariablePickerEntries(target, 'change-reference', definitions.filter((definition) => definition.hasValue), token);
    }, [contextVariableDefinitions, furniVariableDefinitions, roomVariableDefinitions, target, token, userVariableDefinitions]);
};

/** The section's claimed merged source: the holder the variable is read on, shown first in the popup. */
export interface IWiredValueHolderSource {
    furniSource: number;
    userSource: number;
    onFurniSourceChange: (source: number) => void;
    onUserSourceChange: (source: number) => void;
}

/** The holder source of a box that offers only room and context variables: one fixed row per type. */
export const WIRED_FIXED_HOLDER_SOURCE: IWiredValueHolderSource = { furniSource: 0, userSource: 0, onFurniSourceChange: () => undefined, onUserSourceChange: () => undefined };

interface WiredValueOrVariableFieldProps {
    /** The field's accessible name, usually the section title. */
    label: string;
    isVariable: boolean;
    literal: string;
    /** The official value target (0 furni, 1 user, -10 global, -20 context). */
    target: number;
    token: string;
    /** The official targets this box offers (all four by default). */
    targets?: number[];
    min?: number;
    max?: number;
    disabled?: boolean;
    /**
     * The holder row of the claimed merged source (AIR ValueOrVariablePopupPreset.attachInputSource). Without it the
     * server reads the variable on the box's own holder, so the popup only offers the type selector.
     */
    holderSource?: IWiredValueHolderSource;
    onIsVariableChange: (isVariable: boolean) => void;
    onLiteralChange: (literal: string) => void;
    onTargetChange: (target: number) => void;
    onTokenChange: (token: string) => void;
    onValidityChange?: (valid: boolean) => void;
}

/**
 * AIR ValueOrVariableSection for the boxes whose value is a room variable read once on a holder of its own type:
 * the value field, and in its popup the holder source with the type selector and the variable picker.
 */
export const WiredValueOrVariableField: FC<WiredValueOrVariableFieldProps> = (props) => {
    const { label, isVariable, literal, target, token, targets = null, min = undefined, max = undefined, disabled = false, holderSource = null } = props;
    const { trigger = null } = useWired();
    const availableUserSources = useAvailableUserSources(trigger, VALUE_USER_SOURCES);
    const targetKey = wiredValueTargetKey(target);
    const targetKeys = useMemo(() => WIRED_VALUE_TARGETS.filter((entry) => !targets || targets.includes(entry.value)).map((entry) => entry.key), [targets]);
    const entries = useWiredValueVariableEntries(targetKey, token);

    const sourceOptions = targetKey === 'furni' ? VALUE_FURNI_SOURCES : targetKey === 'user' ? availableUserSources : targetKey === 'global' ? WIRED_GLOBAL_HOLDER_SOURCES : WIRED_CONTEXT_HOLDER_SOURCES;
    const sourceValue = !holderSource ? 0 : targetKey === 'furni' ? holderSource.furniSource : targetKey === 'user' ? holderSource.userSource : 0;

    return (
        <NativeTextTree>
            <WiredValueOrVariableInput
                disabled={disabled}
                entries={entries}
                isVariable={isVariable}
                label={label}
                literal={literal}
                max={max}
                min={min}
                target={targetKey}
                targets={targetKeys}
                token={token}
                renderSource={
                    holderSource
                        ? ({ typeSelector }) => (
                              // ValueOrVariablePopupPreset.attachInputSource: "Variable source:" with the type selector in its header.
                              <fieldset className="octane-wired__value-popup-locked" disabled={disabled}>
                                  <WiredFurniSelectionSourceRow
                                      headerContent={typeSelector}
                                      options={sourceOptions}
                                      selectionActive={false}
                                      selectionCount={0}
                                      selectionEnabledValues={[]}
                                      selectionKind="secondary"
                                      selectionLimit={0}
                                      showSelectionToggle={false}
                                      title="wiredfurni.params.sources.merged.title.variables"
                                      value={sourceValue}
                                      onChange={(source) => {
                                          if (targetKey === 'furni') holderSource.onFurniSourceChange(source);
                                          else if (targetKey === 'user') holderSource.onUserSourceChange(source);
                                      }}
                                  />
                              </fieldset>
                          )
                        : undefined
                }
                onIsVariableChange={props.onIsVariableChange}
                onLiteralChange={props.onLiteralChange}
                onTargetChange={(key) => props.onTargetChange(wiredValueTargetValue(key))}
                onTokenChange={props.onTokenChange}
                onValidityChange={props.onValidityChange}
            />
        </NativeTextTree>
    );
};
15Sujets
1Dépôts
20Membres
2En ligne
Profile
Inscrit
Dernière visite
Messages
0
Votes positifs
0
Votes négatifs
0

Nous utilisons des cookies pour assurer le bon fonctionnement du site et améliorer votre expérience. en savoir plus

Autoriser