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

View File

@ -1,4 +1,5 @@
import { Flex, Heading, Icon, Tooltip } from '@chakra-ui/react'; import { Flex, Heading, Icon, Tooltip } from '@chakra-ui/react';
import { DRAG_HANDLE_CLASSNAME } from 'features/nodes/hooks/useBuildInvocation';
import { memo } from 'react'; import { memo } from 'react';
import { FaInfoCircle } from 'react-icons/fa'; import { FaInfoCircle } from 'react-icons/fa';
@ -12,6 +13,7 @@ const IAINodeHeader = (props: IAINodeHeaderProps) => {
const { nodeId, title, description } = props; const { nodeId, title, description } = props;
return ( return (
<Flex <Flex
className={DRAG_HANDLE_CLASSNAME}
sx={{ sx={{
borderTopRadius: 'md', borderTopRadius: 'md',
alignItems: 'center', 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 { import {
Box, Box,
Divider,
Flex, Flex,
FormControl, FormControl,
FormLabel, FormLabel,
HStack, HStack,
Tooltip, Tooltip,
Divider,
} from '@chakra-ui/react'; } 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 { useIsValidConnection } from 'features/nodes/hooks/useIsValidConnection';
import InputFieldComponent from '../InputFieldComponent';
import { HANDLE_TOOLTIP_OPEN_DELAY } from 'features/nodes/types/constants'; 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 { interface IAINodeInputProps {
nodeId: string; nodeId: string;
@ -35,6 +35,7 @@ function IAINodeInput(props: IAINodeInputProps) {
return ( return (
<Box <Box
className="nopan"
position="relative" position="relative"
borderColor={ borderColor={
!template !template
@ -136,7 +137,7 @@ const IAINodeInputs = (props: IAINodeInputsProps) => {
}); });
return ( return (
<Flex flexDir="column" gap={2} p={2}> <Flex className="nopan" flexDir="column" gap={2} p={2}>
{IAINodeInputsToRender} {IAINodeInputsToRender}
</Flex> </Flex>
); );

View File

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

View File

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

View File

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

View File

@ -6,6 +6,7 @@ import {
NumberInputStepper, NumberInputStepper,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useAppDispatch } from 'app/store/storeHooks'; import { useAppDispatch } from 'app/store/storeHooks';
import { numberStringRegex } from 'common/components/IAINumberInput';
import { fieldValueChanged } from 'features/nodes/store/nodesSlice'; import { fieldValueChanged } from 'features/nodes/store/nodesSlice';
import { import {
FloatInputFieldTemplate, FloatInputFieldTemplate,
@ -13,7 +14,7 @@ import {
IntegerInputFieldTemplate, IntegerInputFieldTemplate,
IntegerInputFieldValue, IntegerInputFieldValue,
} from 'features/nodes/types/types'; } from 'features/nodes/types/types';
import { memo } from 'react'; import { memo, useEffect, useState } from 'react';
import { FieldComponentProps } from './types'; import { FieldComponentProps } from './types';
const NumberInputFieldComponent = ( const NumberInputFieldComponent = (
@ -23,17 +24,42 @@ const NumberInputFieldComponent = (
> >
) => { ) => {
const { nodeId, field } = props; const { nodeId, field } = props;
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const [valueAsString, setValueAsString] = useState<string>(
String(field.value)
);
const handleValueChanged = (_: string, value: number) => { const handleValueChanged = (v: string) => {
dispatch(fieldValueChanged({ nodeId, fieldName: field.name, value })); 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 ( return (
<NumberInput <NumberInput
onChange={handleValueChanged} onChange={handleValueChanged}
value={field.value} value={valueAsString}
step={props.template.type === 'integer' ? 1 : 0.1} step={props.template.type === 'integer' ? 1 : 0.1}
precision={props.template.type === 'integer' ? 0 : 3} precision={props.template.type === 'integer' ? 0 : 3}
> >

View File

@ -18,6 +18,12 @@ const templatesSelector = createSelector(
(nodes) => nodes.invocationTemplates (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 = () => { export const useBuildInvocation = () => {
const invocationTemplates = useAppSelector(templatesSelector); const invocationTemplates = useAppSelector(templatesSelector);
@ -32,6 +38,7 @@ export const useBuildInvocation = () => {
}); });
const node: Node = { const node: Node = {
...SHARED_NODE_PROPERTIES,
id: 'progress_image', id: 'progress_image',
type: 'progress_image', type: 'progress_image',
position: { x: x, y: y }, position: { x: x, y: y },
@ -91,6 +98,7 @@ export const useBuildInvocation = () => {
}); });
const invocation: Node<InvocationValue> = { const invocation: Node<InvocationValue> = {
...SHARED_NODE_PROPERTIES,
id: nodeId, id: nodeId,
type: 'invocation', type: 'invocation',
position: { x: x, y: y }, position: { x: x, y: y },