editor.js/src/components/utils/search-input.ts
Peter Savchenko 8f156a87ea
feat(ui): the toolbox became vertical (#2014)
* the popover component, vertical toolbox

* toolbox position improved

* popover width improved

* always show the plus button

* search field added

* search input in popover

* trying to create mobile toolbox

* feat(toolbox): popover adapted for mobile devices (#2004)

* FIx mobile popover fixed positioning

* Add mobile popover overlay

* Hide mobile popover on scroll

* Alter toolbox buttons hover

* Fix closing popover on overlay click

* Tests fix

* Fix onchange test

* restore focus after toolbox closing by ESC

* don't move toolbar by block-hover on mobile

Resolves #1972

* popover mobile styles improved

* Cleanup

* Remove scroll event listener

* Lock scroll on mobile

* don't show shortcuts in mobile popover

* Change data attr name

* Remove unused styles

* Remove unused listeners

* disable hover on mobile popover

* Scroll fix

* Lint

* Revert "Scroll fix"

This reverts commit 82deae543e.

* Return back background color for active state of toolbox buttons

Co-authored-by: Peter Savchenko <specc.dev@gmail.com>

* Vertical toolbox fixes (#2017)

* Replace visibility property with display for hiding popover

* Disable arrow right and left keys for popover

* Revert "Replace visibility property with display for hiding popover"

This reverts commit af521cf6f2.

* Hide popover via setting max-height to 0 to fix animation in safari

* Remove redundant condition

* Extend element interface to avoid ts errors

* Do not subscribe to block hovered if mobile

* Add unsubscribing from overlay click event

* Rename isMobile to isMobileScreen

* Cleanup

* fix: popover opening direction (#2022)

* Change popover opening direction based on available space below it

* Update check

* Use cacheable decorator

* Update src/components/flipper.ts

Co-authored-by: George Berezhnoy <gohabereg@users.noreply.github.com>

* Fixes

* Fix test

* Clear search on popover hide

* Fix popover width

* Fix for tests

* Update todos

* Linter fixes

* rm todo about beforeInsert

because I have no idea what does it mean

* i18n for search labels done

* rm methods for hiding/showing of +

* some code style update

* Update CHANGELOG.md

* make the list items a little bit compact

* fix z-index issue caused by block-appearing animation

also, improve popover padding for two reasons:

- make the popover more consistent with the Table tool popover (in future, it can be done with the same api method)
- make popover looks better

Co-authored-by: Tanya Fomina <fomina.tatianaaa@yandex.ru>
Co-authored-by: George Berezhnoy <gohabereg@users.noreply.github.com>
2022-04-25 18:28:58 +03:00

153 lines
3.1 KiB
TypeScript

import Dom from '../dom';
import Listeners from './listeners';
/**
* Item that could be searched
*/
interface SearchableItem {
label: string;
}
/**
* Provides search input element and search logic
*/
export default class SearchInput {
/**
* Input wrapper element
*/
private wrapper: HTMLElement;
/**
* Editable input itself
*/
private input: HTMLInputElement;
/**
* The instance of the Listeners util
*/
private listeners: Listeners;
/**
* Items for local search
*/
private items: SearchableItem[];
/**
* Current search query
*/
private searchQuery: string;
/**
* Externally passed callback for the search
*/
private readonly onSearch: (items: SearchableItem[]) => void;
/**
* Styles
*/
private static get CSS(): {
input: string;
icon: string;
wrapper: string;
} {
return {
wrapper: 'cdx-search-field',
icon: 'cdx-search-field__icon',
input: 'cdx-search-field__input',
};
}
/**
* @param options - available config
* @param options.items - searchable items list
* @param options.onSearch - search callback
* @param options.placeholder - input placeholder
*/
constructor({ items, onSearch, placeholder }: {
items: SearchableItem[];
onSearch: (items: SearchableItem[]) => void;
placeholder: string;
}) {
this.listeners = new Listeners();
this.items = items;
this.onSearch = onSearch;
this.render(placeholder);
}
/**
* Returns search field element
*/
public getElement(): HTMLElement {
return this.wrapper;
}
/**
* Sets focus to the input
*/
public focus(): void {
this.input.focus();
}
/**
* Clears search query and results
*/
public clear(): void {
this.input.value = '';
this.searchQuery = '';
this.onSearch(this.foundItems);
}
/**
* Clears memory
*/
public destroy(): void {
this.listeners.removeAll();
}
/**
* Creates the search field
*
* @param placeholder - input placeholder
*/
private render(placeholder: string): void {
this.wrapper = Dom.make('div', SearchInput.CSS.wrapper);
const iconWrapper = Dom.make('div', SearchInput.CSS.icon);
const icon = Dom.svg('search', 16, 16);
this.input = Dom.make('input', SearchInput.CSS.input, {
placeholder,
}) as HTMLInputElement;
iconWrapper.appendChild(icon);
this.wrapper.appendChild(iconWrapper);
this.wrapper.appendChild(this.input);
this.listeners.on(this.input, 'input', () => {
this.searchQuery = this.input.value;
this.onSearch(this.foundItems);
});
}
/**
* Returns list of found items for the current search query
*/
private get foundItems(): SearchableItem[] {
return this.items.filter(item => this.checkItem(item));
}
/**
* Contains logic for checking whether passed item conforms the search query
*
* @param item - item to be checked
*/
private checkItem(item: SearchableItem): boolean {
const text = item.label.toLowerCase();
const query = this.searchQuery.toLowerCase();
return text.includes(query);
}
}