UNPKG

carbon-components-angular

Version:
350 lines (345 loc) 17.1 kB
import * as i0 from '@angular/core'; import { EventEmitter, Component, HostBinding, Input, Output, ViewChild, HostListener, NgModule } from '@angular/core'; import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms'; import * as i1 from 'carbon-components-angular/i18n'; import { I18nModule } from 'carbon-components-angular/i18n'; import * as i2 from '@angular/common'; import { CommonModule } from '@angular/common'; import * as i3 from 'carbon-components-angular/icon'; import { IconModule } from 'carbon-components-angular/icon'; /** * Get started with importing the module: * * ```typescript * import { SearchModule } from 'carbon-components-angular'; * ``` * * [See demo](../../?path=/story/components-search--basic) */ class Search { /** * Creates an instance of `Search`. * @param i18n The i18n translations. */ constructor(elementRef, i18n) { this.elementRef = elementRef; this.i18n = i18n; /** * @deprecated since v5 - Use `cdsLayer` directive instead * `light` or `dark` search theme. */ this.theme = "dark"; /** * Size of the search field. */ this.size = "md"; /** * Set to `true` for a disabled search input. */ this.disabled = false; /** * Set to `true` for a toolbar search component. */ this.toolbar = false; /** * Set to `true` to make the search component expandable. * `expandable` would override `toolbar` property behaviours. */ this.expandable = false; /** * Set to `true` for a loading search component. */ this.skeleton = false; /** * Set to `true` to expand the toolbar search component. */ this.active = false; /** * Specifies whether the search component is used in the table toolbar. */ this.tableSearch = false; /** * The unique id for the search component. */ this.id = `search-${Search.searchCount}`; /** * Sets the value attribute on the `input` element. */ this.value = ""; /** * Sets the autocomplete attribute on the `input` element. * For reference: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete#Values */ this.autocomplete = "on"; /** * Sets the text inside the `label` tag. */ this.label = this.i18n.get().SEARCH.LABEL; /** * Sets the placeholder attribute on the `input` element. */ this.placeholder = this.i18n.get().SEARCH.PLACEHOLDER; /** * Used to set the `title` attribute of the clear button. */ this.clearButtonTitle = this.i18n.get().SEARCH.CLEAR_BUTTON; /** * Title for the search trigger */ this.searchTitle = ""; /** * Emits an event when value is changed. */ this.valueChange = new EventEmitter(); this.open = new EventEmitter(); /** * Emits an event when the clear button is clicked. */ this.clear = new EventEmitter(); /** * Emits an event on enter. */ this.search = new EventEmitter(); /** * Sets `true` when composing text via IME. */ this.isComposing = false; /** * Called when search input is blurred. Needed to properly implement `ControlValueAccessor`. */ this.onTouched = () => { }; /** * Method set in `registerOnChange` to propagate changes back to the form. */ this.propagateChange = (_) => { }; Search.searchCount++; } get containerClass() { return !(this.toolbar || this.expandable); } /** * This is the initial value set to the component * @param value The input value. */ writeValue(value) { this.value = value; } /** * Sets a method in order to propagate changes back to the form. */ registerOnChange(fn) { this.propagateChange = fn; } /** * Registers a callback to be triggered when the control has been touched. * @param fn Callback to be triggered when the search input is touched. */ registerOnTouched(fn) { this.onTouched = fn; } /** * Called when text is written in the input. * @param search The input text. */ onSearch(search) { if (this.isComposing) { // check for IME use return; } this.value = search; this.doValueChange(); } /** * Called on enter. */ onEnter() { this.search.emit(this.value); } /** * Called when clear button is clicked. */ clearSearch() { this.value = ""; this.clear.emit(); this.propagateChange(this.value); } doValueChange() { this.valueChange.emit(this.value); this.propagateChange(this.value); } openSearch() { this.active = true; this.open.emit(this.active); setTimeout(() => this.inputRef.nativeElement.focus()); } keyDown(event) { if (this.toolbar || this.expandable) { if (event.key === "Escape") { if (this.value === "") { this.active = false; this.open.emit(this.active); } } else if (event.key === "Enter") { this.openSearch(); } } if (event.key === "Escape") { if (this.value !== "") { this.clearSearch(); } } } focusOut(event) { this.onTouched(); if ((this.expandable || this.toolbar) && this.inputRef && this.inputRef.nativeElement.value === "" && !this.elementRef.nativeElement.contains(event.relatedTarget)) { this.active = false; this.open.emit(this.active); } } focusIn(event) { this.onTouched(); // set input focus if search icon get focus from tab key press event. if ((this.expandable || this.toolbar) && this.inputRef && !event.relatedTarget && !this.elementRef.nativeElement.contains(event.relatedTarget)) { this.openSearch(); } } /** * Called when using IME composition. */ compositionStart(event) { this.isComposing = true; } /** * Called when IME composition finishes. */ compositionEnd(event) { this.isComposing = false; this.onSearch(this.value + event.data); } } /** * Variable used for creating unique ids for search components. */ Search.searchCount = 0; Search.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: Search, deps: [{ token: i0.ElementRef }, { token: i1.I18n }], target: i0.ɵɵFactoryTarget.Component }); Search.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: Search, selector: "cds-search, ibm-search", inputs: { theme: "theme", size: "size", disabled: "disabled", toolbar: "toolbar", expandable: "expandable", skeleton: "skeleton", active: "active", tableSearch: "tableSearch", name: "name", id: "id", required: "required", value: "value", autocomplete: "autocomplete", label: "label", placeholder: "placeholder", clearButtonTitle: "clearButtonTitle", searchTitle: "searchTitle", ariaLabel: "ariaLabel" }, outputs: { valueChange: "valueChange", open: "open", clear: "clear", search: "search" }, host: { listeners: { "keydown": "keyDown($event)", "focusout": "focusOut($event)", "focusin": "focusIn($event)", "compositionstart": "compositionStart($event)", "compositionend": "compositionEnd($event)" }, properties: { "class.cds--form-item": "this.containerClass" } }, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: Search, multi: true } ], viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["input"], descendants: true }], ngImport: i0, template: "<div\n\tclass=\"cds--search\"\n\t[ngClass]=\"{\n\t\t'cds--search--sm': size === 'sm',\n\t\t'cds--search--md': size === 'md',\n\t\t'cds--search--lg': size === 'lg',\n\t\t'cds--search--light': theme === 'light',\n\t\t'cds--skeleton': skeleton,\n\t\t'cds--search--expandable': expandable && !tableSearch,\n\t\t'cds--search--expanded': expandable && !tableSearch && active,\n\t\t'cds--toolbar-search': toolbar && !expandable,\n\t\t'cds--toolbar-search--active': toolbar && !expandable && active,\n\t\t'cds--toolbar-search-container-persistent': tableSearch && !expandable,\n\t\t'cds--toolbar-search-container-expandable': tableSearch && expandable,\n\t\t'cds--toolbar-search-container-active': tableSearch && expandable && active\n\t}\"\n\trole=\"search\"\n\t[attr.aria-label]=\"ariaLabel\"\n\t(click)=\"openSearch()\">\n\t<label class=\"cds--label\" [for]=\"id\">{{label}}</label>\n\n\t<div *ngIf=\"skeleton; else enableInput\" class=\"cds--search-input\"></div>\n\t<ng-template #enableInput>\n\t\t<input\n\t\t\t#input\n\t\t\tclass=\"cds--search-input\"\n\t\t\t[type]=\"tableSearch || !toolbar ? 'text' : 'search'\"\n\t\t\t[id]=\"id\"\n\t\t\t[value]=\"value\"\n\t\t\t[autocomplete]=\"autocomplete\"\n\t\t\t[placeholder]=\"placeholder\"\n\t\t\t[disabled]=\"disabled\"\n\t\t\t[required]=\"required\"\n\t\t\t(input)=\"onSearch($event.target.value)\"\n\t\t\t(keyup.enter)=\"onEnter()\"/>\n\t\t<button\n\t\t\t*ngIf=\"!tableSearch && toolbar\"\n\t\t\tclass=\"cds--toolbar-search__btn\"\n\t\t\t(click)=\"openSearch()\"\n\t\t\taria-label=\"Open search\">\n\t\t\t<svg cdsIcon=\"search\" size=\"16\" class=\"cds--search-magnifier-icon\"></svg>\n\t\t</button>\n\t\t<svg\n\t\t\tcdsIcon=\"search\"\n\t\t\t*ngIf=\"tableSearch || !toolbar\"\n\t\t\tclass=\"cds--search-magnifier-icon\"\n\t\t\tsize=\"16\">\n\t\t</svg>\n\t</ng-template>\n\n\t<button\n\t\t*ngIf=\"tableSearch || !toolbar\"\n\t\tclass=\"cds--search-close\"\n\t\t[ngClass]=\"{\n\t\t\t'cds--search-close--hidden': !value || value.length === 0\n\t\t}\"\n\t\t[title]=\"clearButtonTitle\"\n\t\t(click)=\"clearSearch()\">\n\t\t<span class=\"cds--visually-hidden\">{{ clearButtonTitle }}</span>\n\t\t<svg cdsIcon=\"close\" size=\"16\"></svg>\n\t</button>\n</div>\n", dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: Search, decorators: [{ type: Component, args: [{ selector: "cds-search, ibm-search", providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: Search, multi: true } ], template: "<div\n\tclass=\"cds--search\"\n\t[ngClass]=\"{\n\t\t'cds--search--sm': size === 'sm',\n\t\t'cds--search--md': size === 'md',\n\t\t'cds--search--lg': size === 'lg',\n\t\t'cds--search--light': theme === 'light',\n\t\t'cds--skeleton': skeleton,\n\t\t'cds--search--expandable': expandable && !tableSearch,\n\t\t'cds--search--expanded': expandable && !tableSearch && active,\n\t\t'cds--toolbar-search': toolbar && !expandable,\n\t\t'cds--toolbar-search--active': toolbar && !expandable && active,\n\t\t'cds--toolbar-search-container-persistent': tableSearch && !expandable,\n\t\t'cds--toolbar-search-container-expandable': tableSearch && expandable,\n\t\t'cds--toolbar-search-container-active': tableSearch && expandable && active\n\t}\"\n\trole=\"search\"\n\t[attr.aria-label]=\"ariaLabel\"\n\t(click)=\"openSearch()\">\n\t<label class=\"cds--label\" [for]=\"id\">{{label}}</label>\n\n\t<div *ngIf=\"skeleton; else enableInput\" class=\"cds--search-input\"></div>\n\t<ng-template #enableInput>\n\t\t<input\n\t\t\t#input\n\t\t\tclass=\"cds--search-input\"\n\t\t\t[type]=\"tableSearch || !toolbar ? 'text' : 'search'\"\n\t\t\t[id]=\"id\"\n\t\t\t[value]=\"value\"\n\t\t\t[autocomplete]=\"autocomplete\"\n\t\t\t[placeholder]=\"placeholder\"\n\t\t\t[disabled]=\"disabled\"\n\t\t\t[required]=\"required\"\n\t\t\t(input)=\"onSearch($event.target.value)\"\n\t\t\t(keyup.enter)=\"onEnter()\"/>\n\t\t<button\n\t\t\t*ngIf=\"!tableSearch && toolbar\"\n\t\t\tclass=\"cds--toolbar-search__btn\"\n\t\t\t(click)=\"openSearch()\"\n\t\t\taria-label=\"Open search\">\n\t\t\t<svg cdsIcon=\"search\" size=\"16\" class=\"cds--search-magnifier-icon\"></svg>\n\t\t</button>\n\t\t<svg\n\t\t\tcdsIcon=\"search\"\n\t\t\t*ngIf=\"tableSearch || !toolbar\"\n\t\t\tclass=\"cds--search-magnifier-icon\"\n\t\t\tsize=\"16\">\n\t\t</svg>\n\t</ng-template>\n\n\t<button\n\t\t*ngIf=\"tableSearch || !toolbar\"\n\t\tclass=\"cds--search-close\"\n\t\t[ngClass]=\"{\n\t\t\t'cds--search-close--hidden': !value || value.length === 0\n\t\t}\"\n\t\t[title]=\"clearButtonTitle\"\n\t\t(click)=\"clearSearch()\">\n\t\t<span class=\"cds--visually-hidden\">{{ clearButtonTitle }}</span>\n\t\t<svg cdsIcon=\"close\" size=\"16\"></svg>\n\t</button>\n</div>\n" }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i1.I18n }]; }, propDecorators: { containerClass: [{ type: HostBinding, args: ["class.cds--form-item"] }], theme: [{ type: Input }], size: [{ type: Input }], disabled: [{ type: Input }], toolbar: [{ type: Input }], expandable: [{ type: Input }], skeleton: [{ type: Input }], active: [{ type: Input }], tableSearch: [{ type: Input }], name: [{ type: Input }], id: [{ type: Input }], required: [{ type: Input }], value: [{ type: Input }], autocomplete: [{ type: Input }], label: [{ type: Input }], placeholder: [{ type: Input }], clearButtonTitle: [{ type: Input }], searchTitle: [{ type: Input }], ariaLabel: [{ type: Input }], valueChange: [{ type: Output }], open: [{ type: Output }], clear: [{ type: Output }], search: [{ type: Output }], inputRef: [{ type: ViewChild, args: ["input"] }], keyDown: [{ type: HostListener, args: ["keydown", ["$event"]] }], focusOut: [{ type: HostListener, args: ["focusout", ["$event"]] }], focusIn: [{ type: HostListener, args: ["focusin", ["$event"]] }], compositionStart: [{ type: HostListener, args: ["compositionstart", ["$event"]] }], compositionEnd: [{ type: HostListener, args: ["compositionend", ["$event"]] }] } }); // modules class SearchModule { } SearchModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: SearchModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); SearchModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.3.0", ngImport: i0, type: SearchModule, declarations: [Search], imports: [FormsModule, CommonModule, I18nModule, IconModule], exports: [Search] }); SearchModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: SearchModule, imports: [FormsModule, CommonModule, I18nModule, IconModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: SearchModule, decorators: [{ type: NgModule, args: [{ declarations: [ Search ], exports: [ Search ], imports: [ FormsModule, CommonModule, I18nModule, IconModule ] }] }] }); /** * Generated bundle index. Do not edit. */ export { Search, SearchModule }; //# sourceMappingURL=carbon-components-angular-search.mjs.map