// Copyright 2017-2026 @pezkuwi/react-params authors & contributors // SPDX-License-Identifier: Apache-2.0 import type { ParamDef, Props, RawParam } from '../types.js'; import React, { useCallback, useEffect, useState } from 'react'; import { Button } from '@pezkuwi/react-components'; import { BTreeMap } from '@pezkuwi/types'; import { isCodec, isUndefined } from '@pezkuwi/util'; import Params from '../index.js'; import getInitValue from '../initValue.js'; import { useTranslation } from '../translate.js'; import Base from './Base.js'; import useParamDefs from './useParamDefs.js'; function getParamType ([key, value]: ParamDef[]): ParamDef[] { return [{ name: '(Key, Value)', type: { info: 17, sub: [key.type, value.type], type: `(${key.type.type}, ${value.type.type})` } }]; } function getParam ([{ name, type }]: ParamDef[], index: number): ParamDef { return { name: `${index}: ${name || type.type}`, type }; } export function getParams (keyValueParam: ParamDef[], prev: ParamDef[], max: number): ParamDef[] { if (prev.length === max) { return prev; } const params: ParamDef[] = []; for (let index = 0; index < max; index++) { params.push(getParam(keyValueParam, index)); } return params; } export function getValues ({ isValid, value }: RawParam): RawParam[] { return (isValid && isCodec(value) && value instanceof BTreeMap) ? [...value.entries()].map(([key, value]: RawParam[]) => { return { isValid: true, value: [{ isValid: true, value: key }, { isValid: true, value }] }; }) : []; } function BTreeMapParam ({ className = '', defaultValue, isDisabled = false, label, onChange, overrides, registry, type, withLabel }: Props): React.ReactElement | null { const { t } = useTranslation(); const keyValueParam = getParamType(useParamDefs(registry, type)); const [values, setValues] = useState(() => getValues(defaultValue)); const [count, setCount] = useState(() => values.length); const [params, setParams] = useState(() => getParams(keyValueParam, [], count)); // build up the list of parameters we are using useEffect((): void => { keyValueParam.length && setParams((prev) => getParams(keyValueParam, prev, isDisabled ? values.length : count) ); }, [count, values, isDisabled, keyValueParam]); // when !isDisable, generating an input list based on count useEffect((): void => { !isDisabled && keyValueParam.length && setValues((values): RawParam[] => { if (values.length === count) { return values; } while (values.length < count) { const value = getInitValue(registry, keyValueParam[0].type); values.push({ isValid: !isUndefined(value), value }); } return values.slice(0, count); }); }, [count, defaultValue, keyValueParam, isDisabled, registry]); // when our values has changed, alert upstream useEffect((): void => { const output = new Map(); let isValid = true; for (const entry of values) { const [key, value] = entry.value as RawParam[]; if (output.has(key)) { isValid = false; console.error('BTreeMap: Duplicate key ', key); } output.set(key, value); isValid = isValid && entry.isValid; } onChange && onChange({ isValid, value: output }); }, [values, onChange]); const _rowAdd = useCallback( (): void => setCount((count) => count + 1), [] ); const _rowRemove = useCallback( (): void => setCount((count) => count - 1), [] ); return ( {!isDisabled && (
)} ); } export default React.memo(BTreeMapParam);