feat(ui): add notes popover to field title bar

This commit is contained in:
psychedelicious
2025-01-17 16:44:00 +11:00
parent cfb63c1b81
commit fe86cf6d99
3 changed files with 88 additions and 0 deletions

View File

@@ -0,0 +1,64 @@
import {
FormControl,
FormLabel,
IconButton,
Popover,
PopoverContent,
PopoverTrigger,
Textarea,
} from '@invoke-ai/ui-library';
import { useAppDispatch } from 'app/store/storeHooks';
import { useFieldNotes } from 'features/nodes/hooks/useFieldNotes';
import { fieldNotesChanged } from 'features/nodes/store/nodesSlice';
import type { ChangeEvent } from 'react';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { PiNoteBold } from 'react-icons/pi';
type Props = {
nodeId: string;
fieldName: string;
};
export const FieldNotesIconButton = memo(({ nodeId, fieldName }: Props) => {
const dispatch = useAppDispatch();
const { t } = useTranslation();
const notes = useFieldNotes(nodeId, fieldName);
const onChange = useCallback(
(e: ChangeEvent<HTMLTextAreaElement>) => {
dispatch(fieldNotesChanged({ nodeId, fieldName, val: e.target.value }));
},
[dispatch, fieldName, nodeId]
);
return (
<Popover>
<PopoverTrigger>
<IconButton
variant="ghost"
tooltip={t('nodes.notes')}
aria-label={t('nodes.notes')}
icon={<PiNoteBold />}
pointerEvents="auto"
size="xs"
/>
</PopoverTrigger>
<PopoverContent p={2} w={256}>
<FormControl orientation="vertical">
<FormLabel>{t('nodes.notes')}</FormLabel>
<Textarea
className="nodrag nopan nowheel"
fontSize="sm"
value={notes ?? ''}
onChange={onChange}
p={2}
resize="none"
rows={5}
/>
</FormControl>
</PopoverContent>
</Popover>
);
});
FieldNotesIconButton.displayName = 'FieldNotesIconButton';

View File

@@ -1,4 +1,5 @@
import { Flex, FormControl } from '@invoke-ai/ui-library';
import { FieldNotesIconButton } from 'features/nodes/components/flow/nodes/Invocation/fields/FieldNotesIconButton';
import FieldResetToDefaultValueButton from 'features/nodes/components/flow/nodes/Invocation/fields/FieldResetToDefaultValueButton';
import { useConnectionState } from 'features/nodes/hooks/useConnectionState';
import { useFieldInputTemplate } from 'features/nodes/hooks/useFieldInputTemplate';
@@ -71,6 +72,7 @@ const InputField = ({ nodeId, fieldName }: Props) => {
<Flex flexDir="column" w="full" gap={1} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
<Flex gap={1}>
<EditableFieldTitle nodeId={nodeId} fieldName={fieldName} kind="inputs" isInvalid={isInvalid} withTooltip />
{isHovered && <FieldNotesIconButton nodeId={nodeId} fieldName={fieldName} />}
{isHovered && <FieldResetToDefaultValueButton nodeId={nodeId} fieldName={fieldName} />}
{isHovered && <FieldLinearViewToggle nodeId={nodeId} fieldName={fieldName} />}
</Flex>

View File

@@ -0,0 +1,22 @@
import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/store/storeHooks';
import { selectNodesSlice } from 'features/nodes/store/selectors';
import { isInvocationNode } from 'features/nodes/types/invocation';
import { useMemo } from 'react';
export const useFieldNotes = (nodeId: string, fieldName: string) => {
const selector = useMemo(
() =>
createSelector(selectNodesSlice, (nodes) => {
const node = nodes.nodes.find((node) => node.id === nodeId);
if (!isInvocationNode(node)) {
return;
}
return node?.data.inputs[fieldName]?.notes;
}),
[fieldName, nodeId]
);
const notes = useAppSelector(selector);
return notes;
};