// Displays a find/replace dialog
const React = require('react');
const { useMemo, useState, useEffect } = require('react');
const MaterialCommunityIcon = require('react-native-vector-icons/MaterialCommunityIcons').default;
import { SearchControl, SearchState, EditorSettings } from './types';
import { _ } from '@joplin/lib/locale';
import { BackHandler, TextInput, View, Text, StyleSheet, ViewStyle } from 'react-native';
import { Theme } from '@joplin/lib/themes/type';
import CustomButton from '../CustomButton';
const buttonSize = 48;
type OnChangeCallback = (text: string)=> void;
type Callback = ()=> void;
export const defaultSearchState: SearchState = {
useRegex: false,
caseSensitive: false,
searchText: '',
replaceText: '',
dialogVisible: false,
};
export interface SearchPanelProps {
searchControl: SearchControl;
searchState: SearchState;
editorSettings: EditorSettings;
}
interface ActionButtonProps {
styles: any;
themeId: number;
iconName: string;
title: string;
onPress: Callback;
}
const ActionButton = (
props: ActionButtonProps
) => {
return (
);
};
interface ToggleButtonProps {
styles: any;
themeId: number;
iconName: string;
title: string;
active: boolean;
onToggle: Callback;
}
const ToggleButton = (props: ToggleButtonProps) => {
const active = props.active;
return (
);
};
const useStyles = (theme: Theme) => {
return useMemo(() => {
const buttonStyle: ViewStyle = {
width: buttonSize,
height: buttonSize,
backgroundColor: theme.backgroundColor4,
alignItems: 'center',
justifyContent: 'center',
flexShrink: 1,
};
const buttonTextStyle = {
color: theme.color4,
fontSize: 30,
};
return StyleSheet.create({
button: buttonStyle,
toggleButton: {
...buttonStyle,
},
toggleButtonActive: {
...buttonStyle,
backgroundColor: theme.backgroundColor3,
},
input: {
flexGrow: 1,
height: buttonSize,
backgroundColor: theme.backgroundColor4,
color: theme.color4,
},
buttonText: buttonTextStyle,
activeButtonText: {
...buttonTextStyle,
color: theme.color4,
},
text: {
color: theme.color,
},
labeledInput: {
flexGrow: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
marginLeft: 10,
},
});
}, [theme]);
};
export const SearchPanel = (props: SearchPanelProps) => {
const theme = props.editorSettings.themeData;
const placeholderColor = theme.color3;
const styles = useStyles(theme);
const [showingAdvanced, setShowAdvanced] = useState(false);
const state = props.searchState;
const control = props.searchControl;
const updateSearchState = (changedData: any) => {
const newState = { ...state, ...changedData };
control.setSearchState(newState);
};
// Creates a TextInut with the given parameters
const createInput = (
placeholder: string, value: string, onChange: OnChangeCallback, autoFocus: boolean
) => {
return (
);
};
// Close the search dialog on back button press
useEffect(() => {
// Only register the listener if the dialog is visible
if (!state.dialogVisible) {
return () => {};
}
const backListener = BackHandler.addEventListener('hardwareBackPress', () => {
control.hideSearch();
return true;
});
return () => backListener.remove();
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [state.dialogVisible]);
const themeId = props.editorSettings.themeId;
const closeButton = (
);
const showDetailsButton = (
setShowAdvanced(true)}
title={_('Show advanced')}
/>
);
const hideDetailsButton = (
setShowAdvanced(false)}
title={_('Hide advanced')}
/>
);
const searchTextInput = createInput(
_('Search for...'),
state.searchText,
(newText: string) => {
updateSearchState({
searchText: newText,
});
},
// Autofocus
true
);
const replaceTextInput = createInput(
_('Replace with...'),
state.replaceText,
(newText: string) => {
updateSearchState({
replaceText: newText,
});
},
// Don't autofocus
false
);
const labeledSearchInput = (
{_('Find: ')}
{ searchTextInput }
);
const labeledReplaceInput = (
{_('Replace: ')}
{ replaceTextInput }
);
const toNextButton = (
);
const toPrevButton = (
);
const replaceButton = (
);
const replaceAllButton = (
);
const regexpButton = (
{
updateSearchState({
useRegex: !state.useRegex,
});
}}
active={state.useRegex}
title={_('Regular expression')}
/>
);
const caseSensitiveButton = (
{
updateSearchState({
caseSensitive: !state.caseSensitive,
});
}}
active={state.caseSensitive}
title={_('Case sensitive')}
/>
);
const simpleLayout = (
{ closeButton }
{ searchTextInput }
{ showDetailsButton }
{ toPrevButton }
{ toNextButton }
);
const advancedLayout = (
{ closeButton }
{ labeledSearchInput }
{ hideDetailsButton }
{ toPrevButton }
{ toNextButton }
{ regexpButton }
{ caseSensitiveButton }
{ labeledReplaceInput }
{ replaceButton }
{ replaceAllButton }
);
if (!state.dialogVisible) {
return null;
}
return showingAdvanced ? advancedLayout : simpleLayout;
};
export default SearchPanel;