♻️ (components) remove InputWithContent component (#4566)

This commit is contained in:
Matiss Janis Aboltins
2025-03-10 17:21:00 +00:00
committed by GitHub
parent ebb83aca51
commit 0b9b440a7a
7 changed files with 172 additions and 187 deletions

View File

@@ -1,69 +0,0 @@
import { useState, type ComponentProps, type ReactNode } from 'react';
import { Input, defaultInputStyle } from '@actual-app/components/input';
import { type CSSProperties } from '@actual-app/components/styles';
import { theme } from '@actual-app/components/theme';
import { View } from '@actual-app/components/view';
type InputWithContentProps = ComponentProps<typeof Input> & {
leftContent?: ReactNode;
rightContent?: ReactNode;
inputStyle?: CSSProperties;
focusStyle?: CSSProperties;
style?: CSSProperties;
getStyle?: (focused: boolean) => CSSProperties;
focused?: boolean;
};
export function InputWithContent({
leftContent,
rightContent,
inputStyle,
focusStyle,
style,
getStyle,
...props
}: InputWithContentProps) {
const [focused, setFocused] = useState(props.focused ?? false);
return (
<View
style={{
...defaultInputStyle,
padding: 0,
flexDirection: 'row',
alignItems: 'center',
...style,
...(focused &&
(focusStyle ?? {
boxShadow: '0 0 0 1px ' + theme.formInputShadowSelected,
})),
...getStyle?.(focused),
}}
>
{leftContent}
<Input
{...props}
style={{
width: '100%',
...inputStyle,
flex: 1,
'&, &:focus, &:hover': {
border: 0,
backgroundColor: 'transparent',
boxShadow: 'none',
color: 'inherit',
},
}}
onFocus={e => {
setFocused(true);
props.onFocus?.(e);
}}
onBlur={e => {
setFocused(false);
props.onBlur?.(e);
}}
/>
{rightContent}
</View>
);
}

View File

@@ -1,21 +1,22 @@
import { type Ref } from 'react';
import { useState, type Ref } from 'react';
import { useTranslation } from 'react-i18next';
import { Button } from '@actual-app/components/button';
import { SvgRemove, SvgSearchAlternate } from '@actual-app/components/icons/v2';
import { defaultInputStyle, Input } from '@actual-app/components/input';
import { type CSSProperties } from '@actual-app/components/styles';
import { theme } from '@actual-app/components/theme';
import { View } from '@actual-app/components/view';
import { SvgRemove, SvgSearchAlternate } from '../../icons/v2';
import { theme } from '../../style';
import { InputWithContent } from './InputWithContent';
type SearchProps = {
inputRef?: Ref<HTMLInputElement>;
value: string;
onChange: (value: string) => void;
placeholder: string;
isInModal?: boolean;
width?: number;
width?: number | '100%';
height?: number;
inputStyle?: CSSProperties;
};
export function Search({
@@ -25,69 +26,99 @@ export function Search({
placeholder,
isInModal = false,
width = 250,
height,
inputStyle = {},
}: SearchProps) {
const { t } = useTranslation();
const [focused, setFocused] = useState(false);
const clearButtonPadding = ((height ?? 24) - 8) / 2;
return (
<InputWithContent
inputRef={inputRef}
<View
style={{
...defaultInputStyle,
padding: 0,
flexDirection: 'row',
alignItems: 'center',
width,
height,
flex: '',
borderColor: isInModal ? undefined : 'transparent',
backgroundColor: isInModal ? undefined : theme.formInputBackground,
...inputStyle,
...(focused && {
boxShadow: '0 0 0 1px ' + theme.formInputShadowSelected,
...(isInModal
? {}
: { backgroundColor: theme.formInputBackgroundSelected }),
}),
}}
focusStyle={
isInModal
? undefined
: {
boxShadow: '0 0 0 1px ' + theme.formInputShadowSelected,
backgroundColor: theme.formInputBackgroundSelected,
}
}
leftContent={
<SvgSearchAlternate
style={{
width: 13,
height: 13,
flexShrink: 0,
color: value ? theme.menuItemTextSelected : 'inherit',
margin: 5,
marginRight: 0,
}}
/>
}
rightContent={
value && (
<View title={t('Clear search term')}>
<Button
variant="bare"
style={{ padding: 8 }}
onPress={() => onChange('')}
>
<SvgRemove style={{ width: 8, height: 8 }} />
</Button>
</View>
)
}
inputStyle={{
'::placeholder': {
color: theme.formInputTextPlaceholder,
transition: 'color .25s',
},
':focus': isInModal
? {}
: {
'::placeholder': {
color: theme.formInputTextPlaceholderSelected,
>
<SvgSearchAlternate
style={{
width: 13,
height: 13,
flexShrink: 0,
color: value ? theme.menuItemTextSelected : 'inherit',
margin: 5,
marginRight: 0,
}}
/>
<Input
inputRef={inputRef}
value={value}
placeholder={placeholder}
onKeyDown={e => {
if (e.key === 'Escape') onChange('');
}}
onChangeValue={onChange}
style={{
width: '100%',
'::placeholder': {
color: theme.formInputTextPlaceholder,
transition: 'color .25s',
},
':focus': isInModal
? {}
: {
'::placeholder': {
color: theme.formInputTextPlaceholderSelected,
},
},
},
}}
value={value}
placeholder={placeholder}
onKeyDown={e => {
if (e.key === 'Escape') onChange('');
}}
onChangeValue={value => onChange(value)}
/>
flex: 1,
'&, &:focus, &:hover': {
border: 0,
backgroundColor: 'transparent',
boxShadow: 'none',
color: 'inherit',
},
}}
onFocus={() => {
setFocused(true);
}}
onBlur={() => {
setFocused(false);
}}
/>
{value && (
<View title={t('Clear search term')}>
<Button
variant="bare"
style={{
padding: `${clearButtonPadding}px 8px ${clearButtonPadding}px ${clearButtonPadding}px`,
}}
onPress={() => onChange('')}
>
<SvgRemove style={{ width: 8, height: 8 }} />
</Button>
</View>
)}
</View>
);
}

View File

@@ -3,15 +3,14 @@ import { useTranslation } from 'react-i18next';
import { Label } from '@actual-app/components/label';
import { styles } from '@actual-app/components/styles';
import { theme } from '@actual-app/components/theme';
import { View } from '@actual-app/components/view';
import { type AccountEntity } from 'loot-core/types/models';
import { type TransactionEntity } from 'loot-core/types/models/transaction';
import { SelectedProvider, useSelected } from '../../../hooks/useSelected';
import { SvgSearchAlternate } from '../../../icons/v2';
import { theme } from '../../../style';
import { InputWithContent } from '../../common/InputWithContent';
import { Search } from '../../common/Search';
import type { Binding, SheetNames, SheetFields } from '../../spreadsheet';
import { CellValue, CellValueText } from '../../spreadsheet/CellValue';
import { useSheetValue } from '../../spreadsheet/useSheetValue';
@@ -40,30 +39,18 @@ function TransactionSearchInput({
width: '100%',
}}
>
<InputWithContent
leftContent={
<SvgSearchAlternate
style={{
width: 13,
height: 13,
flexShrink: 0,
color: text ? theme.formInputTextHighlight : 'inherit',
margin: 5,
marginRight: 0,
}}
/>
}
<Search
value={text}
onChangeValue={text => {
onChange={text => {
setText(text);
onSearch(text);
}}
placeholder={placeholder}
style={{
width="100%"
height={styles.mobileMinHeight}
inputStyle={{
backgroundColor: theme.tableBackground,
border: `1px solid ${theme.formInputBorder}`,
flex: 1,
height: styles.mobileMinHeight,
borderColor: theme.formInputBorder,
}}
/>
</View>

View File

@@ -12,6 +12,7 @@ import { useTranslation } from 'react-i18next';
import { Button } from '@actual-app/components/button';
import { SvgAdd, SvgSubtract } from '@actual-app/components/icons/v1';
import { defaultInputStyle, Input } from '@actual-app/components/input';
import { theme } from '@actual-app/components/theme';
import { View } from '@actual-app/components/view';
@@ -20,7 +21,6 @@ import { amountToInteger, appendDecimals } from 'loot-core/shared/util';
import { useMergedRefs } from '../../hooks/useMergedRefs';
import { useSyncedPref } from '../../hooks/useSyncedPref';
import { InputWithContent } from '../common/InputWithContent';
import { useFormat } from '../spreadsheet/useFormat';
type AmountInputProps = {
@@ -61,6 +61,8 @@ export function AmountInput({
initialValue === 0 ? zeroSign : initialValue > 0 ? '+' : '-',
);
const [isFocused, setIsFocused] = useState(focused ?? false);
const initialValueAbsolute = format(Math.abs(initialValue || 0), 'financial');
const [value, setValue] = useState(initialValueAbsolute);
useEffect(() => setValue(initialValueAbsolute), [initialValueAbsolute]);
@@ -115,42 +117,70 @@ export function AmountInput({
}
return (
<InputWithContent
id={id}
inputRef={mergedRef}
inputMode="decimal"
leftContent={
<Button
variant="bare"
isDisabled={disabled}
aria-label={`Make ${symbol === '-' ? 'positive' : 'negative'}`}
style={{ padding: '0 7px' }}
onPress={onSwitch}
ref={buttonRef}
>
{symbol === '-' && (
<SvgSubtract style={{ width: 8, height: 8, color: 'inherit' }} />
)}
{symbol === '+' && (
<SvgAdd style={{ width: 8, height: 8, color: 'inherit' }} />
)}
</Button>
}
value={value}
disabled={disabled}
style={{ flex: 1, alignItems: 'stretch', ...style }}
inputStyle={inputStyle}
onKeyUp={e => {
if (e.key === 'Enter') {
const amount = getAmount();
fireUpdate(amount);
}
<View
style={{
...defaultInputStyle,
padding: 0,
flexDirection: 'row',
flex: 1,
alignItems: 'stretch',
...style,
...(isFocused && {
boxShadow: '0 0 0 1px ' + theme.formInputShadowSelected,
}),
}}
onChangeValue={onInputTextChange}
onBlur={onInputAmountBlur}
onFocus={onFocus}
onEnter={onEnter}
/>
>
<Button
variant="bare"
isDisabled={disabled}
aria-label={`Make ${symbol === '-' ? 'positive' : 'negative'}`}
style={{ padding: '0 7px' }}
onPress={onSwitch}
ref={buttonRef}
>
{symbol === '-' && (
<SvgSubtract style={{ width: 8, height: 8, color: 'inherit' }} />
)}
{symbol === '+' && (
<SvgAdd style={{ width: 8, height: 8, color: 'inherit' }} />
)}
</Button>
<Input
id={id}
inputRef={mergedRef}
inputMode="decimal"
value={value}
disabled={disabled}
style={{
width: '100%',
...inputStyle,
flex: 1,
'&, &:focus, &:hover': {
border: 0,
backgroundColor: 'transparent',
boxShadow: 'none',
color: 'inherit',
},
}}
onFocus={e => {
setIsFocused(true);
onFocus?.(e);
}}
onBlur={e => {
setIsFocused(false);
onInputAmountBlur(e);
}}
onKeyUp={e => {
if (e.key === 'Enter') {
const amount = getAmount();
fireUpdate(amount);
}
}}
onEnter={onEnter}
onChangeValue={onInputTextChange}
/>
</View>
);
}

View File

@@ -0,0 +1,6 @@
---
category: Maintenance
authors: [MatissJanis]
---
Removing `InputWithContent` generic component - including some of its functionality in the consumers.