feat: Filter zurücksetzen button

This commit is contained in:
Ida 2026-05-27 10:38:01 +02:00
parent ece5f17e2a
commit 5aacf17b13
6 changed files with 132 additions and 21 deletions

View file

@ -0,0 +1,48 @@
.wrapper {
position: relative;
width: 100%;
}
.input {
width: 100%;
padding: 3px 30px 3px 6px;
font-size: 12px;
border: 1px solid var(--border-color, #ccc);
border-radius: 3px;
outline: none;
box-sizing: border-box;
background: var(--color-bg, #fff);
color: var(--color-text, #334155);
}
.input:focus {
border-color: var(--primary-color, #F25843);
}
.input::placeholder {
color: var(--color-text-muted, #94a3b8);
}
.clearBtn {
position: absolute;
right: 5px;
top: 3px;
bottom: 3px;
display: inline-flex;
align-items: center;
justify-content: center;
width: 25px;
padding: 0;
border: none;
border-radius: 3px;
background: none;
cursor: pointer;
font-size: 25px;
line-height: 1;
color: var(--color-text-secondary, #94a3b8);
}
.clearBtn:hover {
background: none;
color: var(--color-text-secondary, #94a3b8);
}

View file

@ -0,0 +1,69 @@
import React, { type Ref } from 'react';
import styles from './FilterSearchInput.module.css';
export interface FilterSearchInputProps {
value: string;
onChange: (value: string) => void;
placeholder?: string;
inputRef?: Ref<HTMLInputElement>;
onInputClick?: (e: React.MouseEvent<HTMLInputElement>) => void;
onFocus?: () => void;
onBlur?: () => void;
/** When set, only `inputClassName` styles the input (for floating-label toolbar search). */
variant?: 'compact' | 'inherit';
inputClassName?: string;
wrapperClassName?: string;
clearTitle?: string;
}
export function FilterSearchInput({
value,
onChange,
placeholder = 'Filter...',
inputRef,
onInputClick,
onFocus,
onBlur,
variant = 'compact',
inputClassName,
wrapperClassName,
clearTitle = 'Eingabe löschen',
}: FilterSearchInputProps) {
const inputClass = variant === 'inherit'
? inputClassName
: inputClassName
? `${styles.input} ${inputClassName}`
: styles.input;
return (
<div className={wrapperClassName ? `${styles.wrapper} ${wrapperClassName}` : styles.wrapper}>
<input
ref={inputRef}
type="text"
value={value}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
className={inputClass}
onClick={onInputClick}
onFocus={onFocus}
onBlur={onBlur}
/>
{value && (
<button
type="button"
className={styles.clearBtn}
onClick={(e) => {
e.stopPropagation();
onChange('');
}}
onMouseDown={(e) => e.preventDefault()}
title={clearTitle}
tabIndex={-1}
aria-label={clearTitle}
>
×
</button>
)}
</div>
);
}

View file

@ -0,0 +1,2 @@
export { FilterSearchInput } from './FilterSearchInput';
export type { FilterSearchInputProps } from './FilterSearchInput';

View file

@ -168,7 +168,7 @@
.searchInput {
width: 100%;
height: 40px;
padding: 8px 12px;
padding: 8px 28px 8px 12px;
border: 1px solid var(--color-border, #E2E8F0);
border-radius: 6px;
font-size: 14px;

View file

@ -2,6 +2,7 @@ import React from 'react';
import type { IconType } from 'react-icons';
import { useLanguage } from '../../../providers/language/LanguageContext';
import styles from './FormGeneratorControls.module.css';
import { FilterSearchInput } from '../FilterSearchInput';
import { Button } from '../../UiComponents/Button';
import { IoIosRefresh } from "react-icons/io";
import { FaTrash, FaDownload } from "react-icons/fa";
@ -189,14 +190,15 @@ export function FormGeneratorControls({
<div className={styles.searchContainer}>
{searchable && (
<div className={styles.floatingLabelInput}>
<input
type="text"
placeholder=" "
<FilterSearchInput
variant="inherit"
value={searchTerm}
onChange={(e) => onSearchChange(e.target.value)}
onChange={onSearchChange}
placeholder=" "
onFocus={() => onSearchFocus(true)}
onBlur={() => onSearchFocus(false)}
className={`${styles.searchInput} ${searchFocused || searchTerm ? styles.focused : ''}`}
inputClassName={`${styles.searchInput} ${searchFocused || searchTerm ? styles.focused : ''}`}
clearTitle={t('Suche löschen')}
/>
<label className={searchFocused || searchTerm ? styles.focusedLabel : styles.label}>
{t('Suchen...')}

View file

@ -69,6 +69,7 @@ import {
import { formatUnixTimestamp } from '../../../utils/time';
import { applyFrontendFormat } from '../../../utils/applyFrontendFormat';
import { FormGeneratorControls } from '../FormGeneratorControls';
import { FilterSearchInput } from '../FilterSearchInput';
import { CopyableTruncatedValue } from '../../UiComponents/CopyableTruncatedValue';
import {
isDateTimeType,
@ -446,22 +447,11 @@ function FilterValuesList({
<>
{showSearch && (
<div style={{ padding: '4px 6px', borderBottom: '1px solid var(--border-color, #ddd)' }}>
<input
ref={searchInputRef}
type="text"
<FilterSearchInput
inputRef={searchInputRef}
value={searchTerm}
onChange={(e) => { setSearchTerm(e.target.value); setDisplayCount(_FILTER_PAGE_SIZE); }}
placeholder="Filter..."
style={{
width: '100%',
padding: '3px 6px',
fontSize: '12px',
border: '1px solid var(--border-color, #ccc)',
borderRadius: '3px',
outline: 'none',
boxSizing: 'border-box',
}}
onClick={(e) => e.stopPropagation()}
onChange={(value) => { setSearchTerm(value); setDisplayCount(_FILTER_PAGE_SIZE); }}
onInputClick={(e) => e.stopPropagation()}
/>
</div>
)}