-
-
Notifications
You must be signed in to change notification settings - Fork 170
Description
I am currently upgrading the original code to version 1.0. However, I encountered a problem of reading undefined. I couldn't figure out the cause.
This issue occurs at several different locations, but the triggering point is always the reading of the "missingSpace" parameter.
The code itself did not report any errors. The triggering points are all attempts to interact with a certain UI.
For example, one of the triggering points is an attempt to display and hide a panel of Buttons when hovering over a certain area. Another is a slider that I wrote myself, and the problem occurs when hovering as well.
Uncaught TypeError: Cannot read properties of undefined (reading 'missingSpace')
at addToSortedBuckets (mf-dep____vendor.31457598.js:838133:5)
at InstancedPanelGroup.insert (mf-dep____vendor.31457598.js:841725:95)
at InstancedPanel.requestShow (mf-dep____vendor.31457598.js:842081:20)
at p.x (mf-dep____vendor.31457598.js:841994:22)
at push../node_modules/@preact/signals-core/dist/signals-core.module.js.p.c (mf-dep____vendor.31457598.js:131621:4093)
at t (mf-dep____vendor.31457598.js:131621:181)
at r (mf-dep____vendor.31457598.js:131621:305)
at FlexNode.calculateLayout (mf-dep____vendor.31457598.js:840598:68)
at onFrame (mf-dep____vendor.31457598.js:840479:24)
at Fullscreen.update (mf-dep____vendor.31457598.js:839037:13)
at Fullscreen.update (mf-dep____vendor.31457598.js:839480:15)
at Object.current (mf-dep____vendor.31457598.js:892899:22)
at render$1 (mf-dep____vendor.31457598.js:165430:22)
at loop (mf-dep____vendor.31457598.js:165459:19)
My button:
import { ColorTheme } from "@/common/color-theme";
import { Container, ContainerProperties, DefaultProperties, withOpacity } from "@react-three/uikit";
import { ReactNode, useState } from "react";
export type UIKitButtonProps = ContainerProperties & {
disabled?: boolean;
isSelected?: boolean;
tooltip?: ReactNode;
/** Tooltip popup direction: 'top' | 'bottom' | 'left' | 'right'. Default: 'top' */
tooltipDirection?: 'top' | 'bottom' | 'left' | 'right';
};
type ButtonState = Pick<UIKitButtonProps, "disabled" | "isSelected">;
type ButtonVariantConfig = {
container: (state: ButtonState) => Partial<Omit<ContainerProperties, "hover">>;
hover?: (state: ButtonState) => ContainerProperties["hover"];
textColor?: (state: ButtonState & { isHovered?: boolean }) => string ;
};
// createUIKitButton centralizes shared hover/tooltip behavior for button variants.
const createUIKitButton = (variantConfig: ButtonVariantConfig) => {
const Button = ({
disabled,
isSelected,
tooltip,
tooltipDirection = 'top',
onClick,
onPointerEnter,
onPointerLeave,
hover,
positionType,
children,
...rest
}: UIKitButtonProps) => {
const [isHovered, setIsHovered] = useState(false);
const handleOnClick = (event: any) => {
if (disabled) return;
if (typeof onClick === 'function') {
onClick(event);
}
};
const handlePointerEnter = (event: any) => {
setIsHovered(true);
onPointerEnter?.(event);
};
const handlePointerLeave = (event: any) => {
setIsHovered(false);
onPointerLeave?.(event);
};
const containerOverrides = variantConfig.container({ disabled, isSelected });
const hoverProps = {
...(variantConfig.hover?.({ disabled, isSelected }) ?? {}),
...(hover ?? {}),
};
const tooltipVisible = Boolean(tooltip) && isHovered;
// Text color from variant config
const textColor = variantConfig.textColor?.({ disabled, isSelected, isHovered });
// Tooltip positioning styles
let tooltipPositionProps: Record<string, any> = {};
let tooltipMarginProps: Record<string, any> = {};
switch (tooltipDirection) {
case 'bottom':
tooltipPositionProps = { positionTop: '100%' };
tooltipMarginProps = { marginTop: 2 };
break;
case 'left':
tooltipPositionProps = { positionRight: '100%' };
tooltipMarginProps = { marginRight: 2 };
break;
case 'right':
tooltipPositionProps = { positionLeft: '100%' };
tooltipMarginProps = { marginLeft: 2 };
break;
case 'top':
default:
tooltipPositionProps = { positionBottom: '100%' };
tooltipMarginProps = { marginBottom: 2 };
break;
}
// 合并所有属性,确定最终的 positionType
const mergedProps = {
...rest,
...containerOverrides,
};
const finalPositionType = positionType ?? mergedProps.positionType ?? "relative";
const isAbsolute = finalPositionType === "absolute";
// 为绝对定位的元素强制设置 flex 属性以避免布局计算错误
if (isAbsolute) {
mergedProps.flexGrow = 0;
mergedProps.flexShrink = 0;
}
return (
<Container
minWidth={30}
minHeight={30}
alignItems="center"
justifyContent="center"
borderRadius={5}
positionType={finalPositionType}
hover={hoverProps}
{...mergedProps}
onClick={handleOnClick}
onPointerEnter={handlePointerEnter}
onPointerLeave={handlePointerLeave}
>
<Container opacity={disabled ? 0.5 : 1} color={textColor}
pointerEvents={"none"}
>
{children}
</Container>
{tooltipVisible && (
<Container
positionType="absolute"
{...tooltipPositionProps}
{...tooltipMarginProps}
alignItems="center"
pointerEvents="none"
zIndexOffset={5}
flexGrow={0}
flexShrink={0}
>
<Container
paddingX={8}
paddingY={4}
borderRadius={4}
backgroundColor={withOpacity(ColorTheme.colorBgDark, 0.6)}
fontSize={12} color={ColorTheme.textColor}
>
{tooltip??null}
</Container>
</Container>
)}
</Container>
);
};
return Button;
};
const primaryVariant: ButtonVariantConfig = {
container: ({ isSelected, disabled }) => ({
backgroundColor: withOpacity(
isSelected ? ColorTheme.primaryColor : ColorTheme.normalColor,
disabled ? 0.5 : 1
),
}),
hover: ({ isSelected }) => ({
backgroundColor: isSelected ? ColorTheme.highlightColor : ColorTheme.hoverColor,
}),
};
const secondaryVariant: ButtonVariantConfig = {
container: ({ isSelected, disabled }) => ({
backgroundColor: withOpacity(ColorTheme.colorBg, 0),
borderWidth: 1,
borderColor: withOpacity(
isSelected ? ColorTheme.highlightColor : ColorTheme.textColor,
disabled ? 0.5 : 1
),
}),
hover: ({ isSelected }) => ({
borderColor: isSelected ? ColorTheme.highlightColor2 : ColorTheme.highlightColor,
}),
textColor: ({ isSelected, isHovered }) => {
if (isHovered) {
return isSelected ? ColorTheme.highlightColor2 : ColorTheme.highlightColor;
}
if (isSelected) {
return ColorTheme.highlightColor;
}
return ColorTheme.textColor;
},
};
export const UIKitPrimaryButton = createUIKitButton(primaryVariant);
export const UIKitSecondaryButton = createUIKitButton(secondaryVariant);Also regarding the implementation of the button, I found that removing this piece of code of secondaryVariant would prevent this issue from occurring. However, overall, I do need this style change.
borderColor: withOpacity(
isSelected ? ColorTheme.highlightColor : ColorTheme.textColor,
disabled ? 0.5 : 1
),