mirror of
https://github.com/actualbudget/actual.git
synced 2026-03-11 12:43:09 -05:00
♻️ (components) remove InputWithContent component (#4566)
This commit is contained in:
committed by
GitHub
parent
ebb83aca51
commit
0b9b440a7a
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
6
upcoming-release-notes/4566.md
Normal file
6
upcoming-release-notes/4566.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: Maintenance
|
||||
authors: [MatissJanis]
|
||||
---
|
||||
|
||||
Removing `InputWithContent` generic component - including some of its functionality in the consumers.
|
||||
Reference in New Issue
Block a user