1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

SearchInput refactoring

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
This commit is contained in:
Alex Andreev 2020-10-22 11:05:30 +03:00
parent 14e88a5bb6
commit de33f52a30
9 changed files with 75 additions and 55 deletions

View File

@ -11,7 +11,7 @@ import { navigation } from "../../navigation";
import { ItemListLayout } from "../item-object-list/item-list-layout";
import { t, Trans } from "@lingui/macro";
import { _i18n } from "../../i18n";
import { SearchInput } from "../input";
import { SearchInputUrl } from "../input";
enum sortBy {
name = "name",
@ -72,7 +72,7 @@ export class HelmCharts extends Component<Props> {
(items: HelmChart[]) => items.filter(item => !item.deprecated)
]}
customizeHeader={() => (
<SearchInput placeholder={_i18n._(t`Search Helm Charts`)} />
<SearchInputUrl placeholder={_i18n._(t`Search Helm Charts`)} />
)}
renderTableHeader={[
{ className: "icon" },

View File

@ -1,3 +1,4 @@
export * from './input'
export * from './search-input'
export * from './search-input-url'
export * from './file-input'

View File

@ -24,6 +24,7 @@ export type InputProps<T = string> = Omit<InputElementProps, "onChange" | "onSub
showValidationLine?: boolean; // show animated validation line for async validators
iconLeft?: string | React.ReactNode; // material-icon name in case of string-type
iconRight?: string | React.ReactNode;
contentRight?: string | React.ReactNode; // Any component of string goes after iconRight
validators?: Validator | Validator[];
onChange?(value: T, evt: React.ChangeEvent<InputElement>): void;
onSubmit?(value: T): void;
@ -258,7 +259,7 @@ export class Input extends React.Component<InputProps, State> {
render() {
const {
multiLine, showValidationLine, validators, theme, maxRows, children,
maxLength, rows, disabled, autoSelectOnFocus, iconLeft, iconRight,
maxLength, rows, disabled, autoSelectOnFocus, iconLeft, iconRight, contentRight,
...inputProps
} = this.props;
const { focused, dirty, valid, validating, errors } = this.state;
@ -291,6 +292,7 @@ export class Input extends React.Component<InputProps, State> {
{isString(iconLeft) ? <Icon material={iconLeft} /> : iconLeft}
{multiLine ? <textarea {...inputProps as any} /> : <input {...inputProps as any} />}
{isString(iconRight) ? <Icon material={iconRight} /> : iconRight}
{contentRight}
</label>
<div className="input-info flex gaps">
{!valid && dirty && (

View File

@ -0,0 +1,49 @@
import React from "react";
import debounce from "lodash/debounce";
import { autorun, observable } from "mobx";
import { disposeOnUnmount, observer } from "mobx-react";
import { getSearch, setSearch } from "../../navigation";
import { InputProps } from "./input";
import { SearchInput } from "./search-input";
interface Props extends InputProps {
compact?: boolean; // show only search-icon when not focused
}
@observer
export class SearchInputUrl extends React.Component<Props> {
@observable inputVal = ""; // fix: use empty string to avoid react warnings
@disposeOnUnmount
updateInput = autorun(() => this.inputVal = getSearch())
updateUrl = debounce((val: string) => setSearch(val), 250)
setValue = (value: string) => {
this.inputVal = value;
this.updateUrl(value);
}
clear = () => {
this.setValue("");
this.updateUrl.flush();
}
onChange = (val: string, evt: React.ChangeEvent<any>) => {
this.setValue(val);
if (this.props.onChange) {
this.props.onChange(val, evt);
}
}
render() {
const { inputVal } = this;
return (
<SearchInput
value={inputVal}
onChange={this.onChange}
onClear={this.clear}
{...this.props}
/>
)
}
}

View File

@ -6,7 +6,10 @@
> label {
color: inherit;
background: none;
border: none;
border-radius: $radius;
box-shadow: 0 0 0 1px $halfGray;
padding: 6px 6px 6px 10px;
.Icon {

View File

@ -1,24 +1,22 @@
import "./search-input.scss";
import React from "react";
import debounce from "lodash/debounce"
import { autorun, observable } from "mobx";
import { disposeOnUnmount, observer } from "mobx-react";
import { t } from "@lingui/macro";
import { Icon } from "../icon";
import { observer } from "mobx-react";
import { _i18n } from "../../i18n";
import { cssNames } from "../../utils";
import { Icon } from "../icon";
import { Input, InputProps } from "./input";
import { getSearch, setSearch } from "../../navigation";
import { _i18n } from '../../i18n';
interface Props extends InputProps {
compact?: boolean; // show only search-icon when not focused
updateUrl?: boolean;
closeIcon?: boolean;
onClear?: () => void;
}
const defaultProps: Partial<Props> = {
autoFocus: true,
updateUrl: true,
closeIcon: true,
get placeholder() {
return _i18n._(t`Search...`)
},
@ -28,36 +26,14 @@ const defaultProps: Partial<Props> = {
export class SearchInput extends React.Component<Props> {
static defaultProps = defaultProps as object;
@observable inputVal = this.props.value || ""; // fix: use empty string to avoid react warnings
@disposeOnUnmount
updateInput = autorun(() => {
if (this.props.updateUrl) this.inputVal = getSearch();
})
updateUrl = debounce((val: string) => setSearch(val), 250)
setValue = (value: string) => {
this.inputVal = value;
if (this.props.updateUrl) {
this.updateUrl(value);
}
}
clear = () => {
this.setValue("");
if (this.props.updateUrl) {
this.updateUrl.flush();
}
if (this.props.onChange) {
this.props.onChange("", null);
if (this.props.onClear) {
this.props.onClear();
}
}
onChange = (val: string, evt: React.ChangeEvent<any>) => {
this.setValue(val);
if (this.props.onChange) {
this.props.onChange(val, evt);
}
this.props.onChange(val, evt);
}
onKeyDown = (evt: React.KeyboardEvent<any>) => {
@ -73,16 +49,14 @@ export class SearchInput extends React.Component<Props> {
}
render() {
const { inputVal } = this;
const { className, compact, updateUrl, ...inputProps } = this.props;
const icon = inputVal
? <Icon small material="close" onClick={this.clear}/>
const { className, compact, closeIcon, onClear, ...inputProps } = this.props;
const icon = this.props.value
? closeIcon ? <Icon small material="close" onClick={this.clear}/> : null
: <Icon small material="search"/>
return (
<Input
{...inputProps}
className={cssNames("SearchInput", className, { compact })}
value={inputVal}
onChange={this.onChange}
onKeyDown={this.onKeyDown}
iconRight={icon}

View File

@ -22,15 +22,6 @@
}
}
}
.SearchInput {
label {
background: none;
border: none;
border-radius: $radius;
box-shadow: 0 0 0 1px $halfGray;
}
}
}
> .items {

View File

@ -12,7 +12,7 @@ import { AddRemoveButtons, AddRemoveButtonsProps } from "../add-remove-buttons";
import { NoItems } from "../no-items";
import { Spinner } from "../spinner";
import { ItemObject, ItemStore } from "../../item.store";
import { SearchInput } from "../input";
import { SearchInputUrl } from "../input";
import { namespaceStore } from "../+namespaces/namespace.store";
import { Filter, FilterType, pageFilters } from "./page-filters.store";
import { PageFiltersList } from "./page-filters-list";
@ -349,7 +349,7 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
[FilterType.NAMESPACE]: true, // namespace-select used instead
}}/>
</>,
search: <SearchInput/>,
search: <SearchInputUrl/>,
}
let header = this.renderHeaderContent(placeholders);
if (customizeHeader) {

View File

@ -4,7 +4,7 @@ import "./virtual-list.scss";
import React, { Component } from "react";
import { observer } from "mobx-react";
import { Align, ListChildComponentProps, VariableSizeList } from "react-window";
import { Align, ListChildComponentProps, ListOnScrollProps, VariableSizeList } from "react-window";
import { cssNames, noop } from "../../utils";
import { TableRowProps } from "../table/table-row";
import { ItemObject } from "../../item.store";
@ -22,7 +22,7 @@ interface Props<T extends ItemObject = any> {
readyOffset?: number;
selectedItemId?: string;
getRow?: (uid: string | number) => React.ReactElement<any>;
onScroll?: () => any;
onScroll?: (props: ListOnScrollProps) => any;
outerRef?: ((instance: unknown) => void) | React.MutableRefObject<unknown>
}
@ -107,7 +107,7 @@ export class VirtualList extends Component<Props, State> {
ref={this.listRef}
outerRef={outerRef}
children={Row}
onScroll={() => onScroll()}
onScroll={onScroll}
/>
</div>
);