fix(ui): fix mouse interactions (#3764)

This commit is contained in:
blessedcoolant 2023-07-15 12:45:59 +12:00 committed by GitHub
commit 54b813c981
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 72 additions and 20 deletions

View File

@ -28,7 +28,7 @@ import {
useState,
} from 'react';
const numberStringRegex = /^-?(0\.)?\.?$/;
export const numberStringRegex = /^-?(0\.)?\.?$/;
interface Props extends Omit<NumberInputProps, 'onChange'> {
label?: string;

View File

@ -1,4 +1,5 @@
import { Flex, Heading, Icon, Tooltip } from '@chakra-ui/react';
import { DRAG_HANDLE_CLASSNAME } from 'features/nodes/hooks/useBuildInvocation';
import { memo } from 'react';
import { FaInfoCircle } from 'react-icons/fa';
@ -12,6 +13,7 @@ const IAINodeHeader = (props: IAINodeHeaderProps) => {
const { nodeId, title, description } = props;
return (
<Flex
className={DRAG_HANDLE_CLASSNAME}
sx={{
borderTopRadius: 'md',
alignItems: 'center',

View File

@ -1,25 +1,25 @@
import {
InputFieldTemplate,
InputFieldValue,
InvocationTemplate,
} from 'features/nodes/types/types';
import { memo, ReactNode, useCallback } from 'react';
import { map } from 'lodash-es';
import { useAppSelector } from 'app/store/storeHooks';
import { RootState } from 'app/store/store';
import {
Box,
Divider,
Flex,
FormControl,
FormLabel,
HStack,
Tooltip,
Divider,
} from '@chakra-ui/react';
import FieldHandle from '../FieldHandle';
import { RootState } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks';
import { useIsValidConnection } from 'features/nodes/hooks/useIsValidConnection';
import InputFieldComponent from '../InputFieldComponent';
import { HANDLE_TOOLTIP_OPEN_DELAY } from 'features/nodes/types/constants';
import {
InputFieldTemplate,
InputFieldValue,
InvocationTemplate,
} from 'features/nodes/types/types';
import { map } from 'lodash-es';
import { ReactNode, memo, useCallback } from 'react';
import FieldHandle from '../FieldHandle';
import InputFieldComponent from '../InputFieldComponent';
interface IAINodeInputProps {
nodeId: string;
@ -35,6 +35,7 @@ function IAINodeInput(props: IAINodeInputProps) {
return (
<Box
className="nopan"
position="relative"
borderColor={
!template
@ -136,7 +137,7 @@ const IAINodeInputs = (props: IAINodeInputsProps) => {
});
return (
<Flex flexDir="column" gap={2} p={2}>
<Flex className="nopan" flexDir="column" gap={2} p={2}>
{IAINodeInputsToRender}
</Flex>
);

View File

@ -23,7 +23,14 @@ export const InvocationComponent = memo((props: NodeProps<InvocationValue>) => {
if (!template) {
return (
<NodeWrapper selected={selected}>
<Flex sx={{ alignItems: 'center', justifyContent: 'center' }}>
<Flex
className="nopan"
sx={{
alignItems: 'center',
justifyContent: 'center',
cursor: 'auto',
}}
>
<Icon
as={FaExclamationCircle}
sx={{
@ -46,7 +53,9 @@ export const InvocationComponent = memo((props: NodeProps<InvocationValue>) => {
description={template.description}
/>
<Flex
className={'nopan'}
sx={{
cursor: 'auto',
flexDirection: 'column',
borderBottomRadius: 'md',
py: 2,

View File

@ -2,6 +2,8 @@ import { Box, useToken } from '@chakra-ui/react';
import { NODE_MIN_WIDTH } from 'app/constants';
import { PropsWithChildren } from 'react';
import { DRAG_HANDLE_CLASSNAME } from '../hooks/useBuildInvocation';
import { useAppSelector } from 'app/store/storeHooks';
type NodeWrapperProps = PropsWithChildren & {
selected: boolean;
@ -13,8 +15,11 @@ const NodeWrapper = (props: NodeWrapperProps) => {
'dark-lg',
]);
const shift = useAppSelector((state) => state.hotkeys.shift);
return (
<Box
className={shift ? DRAG_HANDLE_CLASSNAME : 'nopan'}
sx={{
position: 'relative',
borderRadius: 'md',

View File

@ -21,6 +21,7 @@ const ProgressImageNode = (props: NodeProps<InvocationValue>) => {
/>
<Flex
className="nopan"
sx={{
flexDirection: 'column',
borderBottomRadius: 'md',

View File

@ -6,6 +6,7 @@ import {
NumberInputStepper,
} from '@chakra-ui/react';
import { useAppDispatch } from 'app/store/storeHooks';
import { numberStringRegex } from 'common/components/IAINumberInput';
import { fieldValueChanged } from 'features/nodes/store/nodesSlice';
import {
FloatInputFieldTemplate,
@ -13,7 +14,7 @@ import {
IntegerInputFieldTemplate,
IntegerInputFieldValue,
} from 'features/nodes/types/types';
import { memo } from 'react';
import { memo, useEffect, useState } from 'react';
import { FieldComponentProps } from './types';
const NumberInputFieldComponent = (
@ -23,17 +24,42 @@ const NumberInputFieldComponent = (
>
) => {
const { nodeId, field } = props;
const dispatch = useAppDispatch();
const [valueAsString, setValueAsString] = useState<string>(
String(field.value)
);
const handleValueChanged = (_: string, value: number) => {
dispatch(fieldValueChanged({ nodeId, fieldName: field.name, value }));
const handleValueChanged = (v: string) => {
setValueAsString(v);
// This allows negatives and decimals e.g. '-123', `.5`, `-0.2`, etc.
if (!v.match(numberStringRegex)) {
// Cast the value to number. Floor it if it should be an integer.
dispatch(
fieldValueChanged({
nodeId,
fieldName: field.name,
value:
props.template.type === 'integer'
? Math.floor(Number(v))
: Number(v),
})
);
}
};
useEffect(() => {
if (
!valueAsString.match(numberStringRegex) &&
field.value !== Number(valueAsString)
) {
setValueAsString(String(field.value));
}
}, [field.value, valueAsString]);
return (
<NumberInput
onChange={handleValueChanged}
value={field.value}
value={valueAsString}
step={props.template.type === 'integer' ? 1 : 0.1}
precision={props.template.type === 'integer' ? 0 : 3}
>

View File

@ -18,6 +18,12 @@ const templatesSelector = createSelector(
(nodes) => nodes.invocationTemplates
);
export const DRAG_HANDLE_CLASSNAME = 'node-drag-handle';
export const SHARED_NODE_PROPERTIES: Partial<Node> = {
dragHandle: `.${DRAG_HANDLE_CLASSNAME}`,
};
export const useBuildInvocation = () => {
const invocationTemplates = useAppSelector(templatesSelector);
@ -32,6 +38,7 @@ export const useBuildInvocation = () => {
});
const node: Node = {
...SHARED_NODE_PROPERTIES,
id: 'progress_image',
type: 'progress_image',
position: { x: x, y: y },
@ -91,6 +98,7 @@ export const useBuildInvocation = () => {
});
const invocation: Node<InvocationValue> = {
...SHARED_NODE_PROPERTIES,
id: nodeId,
type: 'invocation',
position: { x: x, y: y },